| @@ -1,7 +1,8 @@ | ||
| 1 | 1 | import { handleDesignBuild } from '@auto-launch/fetchers/get-design-build'; |
| 2 | 2 | import { handleHome } from '@auto-launch/fetchers/get-home'; |
| 3 | 3 | import { handleSiteImages } from '@auto-launch/fetchers/get-images'; |
| 4 | +import { handleLaunchDecisions } from '@auto-launch/fetchers/get-launch-decisions'; | |
| 4 | 5 | import { handleSiteLogo } from '@auto-launch/fetchers/get-logo'; |
| 5 | 6 | import { handlePages } from '@auto-launch/fetchers/get-pages'; |
| 6 | 7 | import { handleSitePlugins } from '@auto-launch/fetchers/get-plugins'; |
| 7 | 8 | import { handleSiteProfile } from '@auto-launch/fetchers/get-profile'; |
| @@ -18,10 +19,13 @@ | ||
| 18 | 19 | updateSinglePageLinksToSections, |
| 19 | 20 | } from '@auto-launch/functions/links'; |
| 20 | 21 | import { |
| 21 | 22 | addPageLinksToNav, |
| 23 | + addSectionLinksFromDesign, | |
| 22 | 24 | addSectionLinksToNav, |
| 23 | 25 | createNavigation, |
| 26 | + injectNavExtras, | |
| 27 | + injectWooCommerceIcons, | |
| 24 | 28 | updateNavAttributes, |
| 25 | 29 | } from '@auto-launch/functions/nav'; |
| 26 | 30 | import { |
| 27 | 31 | addImprintPage, |
| @@ -26,8 +30,9 @@ | ||
| 26 | 30 | import { |
| 27 | 31 | addImprintPage, |
| 28 | 32 | createWpPages, |
| 29 | 33 | getPagesToCreate, |
| 34 | + isBlogPage, | |
| 30 | 35 | PLUGIN_OWNED_PAGES, |
| 31 | 36 | setHelloWorldFeaturedImage, |
| 32 | 37 | updatePageTitlePattern, |
| 33 | 38 | } from '@auto-launch/functions/pages'; |
| @@ -32,24 +37,26 @@ | ||
| 32 | 37 | updatePageTitlePattern, |
| 33 | 38 | } from '@auto-launch/functions/pages'; |
| 34 | 39 | import { generatePageContent } from '@auto-launch/functions/patterns'; |
| 35 | 40 | import { |
| 36 | - activatePlugin, | |
| 37 | 41 | alreadyActive, |
| 42 | + ensurePluginsActive, | |
| 38 | 43 | getActivePlugins, |
| 39 | - installPlugin, | |
| 40 | 44 | replacePlaceholderPatterns, |
| 45 | + reportFailedDependencies, | |
| 46 | + reportInactivePlugins, | |
| 41 | 47 | } from '@auto-launch/functions/plugins'; |
| 42 | 48 | import { |
| 43 | 49 | postLaunchFunctions, |
| 44 | 50 | prefetchAssistData, |
| 45 | 51 | } from '@auto-launch/functions/setup'; |
| 52 | +import { applySocialProfiles } from '@auto-launch/functions/social-links'; | |
| 46 | 53 | import { |
| 47 | 54 | setThemeRenderingMode, |
| 48 | 55 | updateTemplatePart, |
| 49 | 56 | updateVariation, |
| 50 | 57 | } from '@auto-launch/functions/theme'; |
| 51 | -import { computeVibeAdjustedBlocks } from '@auto-launch/functions/vibes'; | |
| 58 | +import { computeVibeAdjustments } from '@auto-launch/functions/vibes'; | |
| 52 | 59 | import { |
| 53 | 60 | createBlogSampleData, |
| 54 | 61 | getOption, |
| 55 | 62 | getPageById, |
| @@ -57,22 +64,22 @@ | ||
| 57 | 64 | updateOption, |
| 58 | 65 | } from '@auto-launch/functions/wp'; |
| 59 | 66 | import { useWarnOnLeave } from '@auto-launch/hooks/useWarnOnLeave'; |
| 60 | 67 | import { useLaunchDataStore } from '@auto-launch/state/launch-data'; |
| 68 | +import { launchStrings } from '@auto-launch/strings'; | |
| 61 | 69 | import { digest } from '@shared/api/digest'; |
| 70 | +import { siteImageUrls } from '@shared/lib/site-images'; | |
| 62 | 71 | import { useAIConsentStore } from '@shared/state/ai-consent'; |
| 63 | 72 | import { useEffect, useRef, useState } from '@wordpress/element'; |
| 64 | 73 | import { __ } from '@wordpress/i18n'; |
| 65 | 74 | import useSWRImmutable from 'swr/immutable'; |
| 66 | 75 | |
| 67 | -const { homeUrl, showImprint, wpLanguage, installedPluginsSlugs } = | |
| 68 | - window.extSharedData; | |
| 76 | +const { homeUrl, showImprint, wpLanguage } = window.extSharedData; | |
| 69 | 77 | |
| 70 | 78 | // TODO: I think a good strategy is "if something fails, try to refetch some state" |
| 71 | 79 | |
| 72 | 80 | export const useCreateSite = () => { |
| 73 | - // All the data we need to finish | |
| 74 | - const { setErrorMessage, addStatusMessage, needToStall, ...data } = | |
| 81 | + const { setErrorMessage, addStatusMessage, needToStall, setData, ...data } = | |
| 75 | 82 | useLaunchDataStore(); |
| 76 | 83 | const { setUserGaveConsent } = useAIConsentStore(); |
| 77 | 84 | const homeStretch = useRef(false); |
| 78 | 85 | const [warnOnReload, setWarnOnReload] = useState(!needToStall()); |
| @@ -113,8 +120,11 @@ | ||
| 113 | 120 | useRunStep( |
| 114 | 121 | 'siteLogo', |
| 115 | 122 | () => { |
| 116 | 123 | if (!data.siteProfile?.title) return null; |
| 124 | + // Logo was already uploaded by handleDesignBuild; | |
| 125 | + // generating an AI logo here is not necessary. | |
| 126 | + if (data.designBuild?.logoUrl) return null; | |
| 117 | 127 | return data; |
| 118 | 128 | }, |
| 119 | 129 | async (params) => { |
| 120 | 130 | checkIn({ stage: 'get_logo' }); |
| @@ -122,13 +132,12 @@ | ||
| 122 | 132 | }, |
| 123 | 133 | ); |
| 124 | 134 | |
| 125 | 135 | // needs: siteProfile |
| 126 | - // provides:sitePlugins: [{name, wordpressSlug}] | |
| 136 | + // provides: sitePlugins: [{name, wordpressSlug}] | |
| 127 | 137 | useRunStep( |
| 128 | 138 | 'sitePlugins', |
| 129 | 139 | () => { |
| 130 | - // We just need the site profile, which has this | |
| 131 | 140 | if (!data.siteProfile?.title) return null; |
| 132 | 141 | return data; |
| 133 | 142 | }, |
| 134 | 143 | async (params) => { |
| @@ -138,24 +147,17 @@ | ||
| 138 | 147 | ); |
| 139 | 148 | |
| 140 | 149 | useEffect(() => { |
| 141 | 150 | // Start installing the partner plugins asap |
| 142 | - if (!data.sitePlugins) return; | |
| 151 | + if (!data.sitePlugins?.length) return; | |
| 143 | 152 | |
| 144 | - const pluginsToInstall = data.sitePlugins.filter( | |
| 145 | - ({ wordpressSlug: slug }) => !installedPluginsSlugs?.includes(slug), | |
| 146 | - ); | |
| 147 | - if (pluginsToInstall.length === 0) return; | |
| 148 | 153 | setStatus( |
| 149 | 154 | // translators: this is for a action log UI. Keep it short |
| 150 | - __('Setting up functionality for your website', 'extendify-local'), | |
| 155 | + launchStrings().statusFunctionality, | |
| 151 | 156 | ); |
| 152 | - (async function install() { | |
| 153 | - for (const { wordpressSlug: slug } of pluginsToInstall) { | |
| 154 | - const p = await installPlugin(slug); | |
| 155 | - await activatePlugin(p?.plugin ?? slug); | |
| 156 | - } | |
| 157 | - })(); | |
| 157 | + ensurePluginsActive( | |
| 158 | + data.sitePlugins.map(({ wordpressSlug }) => wordpressSlug), | |
| 159 | + ); | |
| 158 | 160 | }, [data.sitePlugins]); |
| 159 | 161 | |
| 160 | 162 | // needs: siteProfile |
| 161 | 163 | // provides: style: {} |
| @@ -161,9 +163,8 @@ | ||
| 161 | 163 | // provides: style: {} |
| 162 | 164 | useRunStep( |
| 163 | 165 | 'siteStyle', |
| 164 | 166 | () => { |
| 165 | - // We just need the site profile, which has this | |
| 166 | 167 | if (!data.siteProfile?.title) return null; |
| 167 | 168 | return data; |
| 168 | 169 | }, |
| 169 | 170 | async (params) => { |
| @@ -176,9 +177,8 @@ | ||
| 176 | 177 | // provides: aiHeaders: [], aiBlogTitles: [] |
| 177 | 178 | useRunStep( |
| 178 | 179 | 'siteStrings', |
| 179 | 180 | () => { |
| 180 | - // We just need the site profile, which has this | |
| 181 | 181 | if (!data.siteProfile?.title) return null; |
| 182 | 182 | return data; |
| 183 | 183 | }, |
| 184 | 184 | async (params) => { |
| @@ -191,9 +191,8 @@ | ||
| 191 | 191 | // provides: siteImages: [] |
| 192 | 192 | useRunStep( |
| 193 | 193 | 'siteImages', |
| 194 | 194 | () => { |
| 195 | - // We just need the site profile, which has this | |
| 196 | 195 | if (!data.siteProfile?.title) return null; |
| 197 | 196 | return data; |
| 198 | 197 | }, |
| 199 | 198 | async (params) => { |
| @@ -201,14 +200,27 @@ | ||
| 201 | 200 | return await handleSiteImages(params); |
| 202 | 201 | }, |
| 203 | 202 | ); |
| 204 | 203 | |
| 204 | + // needs: siteProfile | |
| 205 | + // provides: launchDecisions: { navExtras, navButtonLabel } | |
| 206 | + useRunStep( | |
| 207 | + 'launchDecisions', | |
| 208 | + () => { | |
| 209 | + if (!data.siteProfile?.title) return null; | |
| 210 | + return data; | |
| 211 | + }, | |
| 212 | + async (params) => { | |
| 213 | + checkIn({ stage: 'get_launch_decisions' }); | |
| 214 | + return await handleLaunchDecisions(params); | |
| 215 | + }, | |
| 216 | + ); | |
| 217 | + | |
| 205 | 218 | // needs: siteProfile, sitePlugins, siteStyle, siteImages, aiHeaders |
| 206 | 219 | // provides: home: { id, slug, patterns, siteStyle } |
| 207 | 220 | useRunStep( |
| 208 | 221 | 'home', |
| 209 | 222 | () => { |
| 210 | - // Checking various data from calls above | |
| 211 | 223 | const ok = [ |
| 212 | 224 | data.siteProfile, |
| 213 | 225 | data.siteStyle, |
| 214 | 226 | data.siteImages, |
| @@ -222,14 +234,13 @@ | ||
| 222 | 234 | return await handleHome(params); |
| 223 | 235 | }, |
| 224 | 236 | ); |
| 225 | 237 | |
| 226 | - // siteProfile, sitePlugins, siteStyle, siteImages | |
| 238 | + // needs: siteProfile, sitePlugins, siteStyle, siteImages | |
| 227 | 239 | // provides: pages: [{ id, slug, name, patterns, siteStyle }] |
| 228 | 240 | useRunStep( |
| 229 | 241 | 'pages', |
| 230 | 242 | () => { |
| 231 | - // Checking various data from calls above | |
| 232 | 243 | const ok = [ |
| 233 | 244 | data.siteProfile, |
| 234 | 245 | data.siteStyle, |
| 235 | 246 | data.siteImages, |
| @@ -256,14 +267,11 @@ | ||
| 256 | 267 | checkIn({ stage: 'set_general', siteProfile, sitePlugins, siteStyle }); |
| 257 | 268 | |
| 258 | 269 | const { title } = siteProfile; |
| 259 | 270 | // translators: this is for a action log UI. Keep it short |
| 260 | - addStatusMessage(__('Adding admin configurations', 'extendify-local')); | |
| 261 | - // update permalinks | |
| 271 | + addStatusMessage(launchStrings().statusAdmin); | |
| 262 | 272 | await updateOption('permalink_structure', '/%postname%/'); |
| 263 | - // make sure consent is set | |
| 264 | 273 | setUserGaveConsent(true); |
| 265 | - // Update title | |
| 266 | 274 | if (title) await updateOption('blogname', title); |
| 267 | 275 | }, |
| 268 | 276 | ); |
| 269 | 277 | |
| @@ -301,8 +309,9 @@ | ||
| 301 | 309 | siteStyle, |
| 302 | 310 | aiBlogTitles, |
| 303 | 311 | siteImages, |
| 304 | 312 | designBuild, |
| 313 | + launchDecisions, | |
| 305 | 314 | } = data; |
| 306 | 315 | // pages could be [] and pass here, that's ok |
| 307 | 316 | if (!home || !pages) return; |
| 308 | 317 | if (homeStretch.current) return; |
| @@ -308,10 +317,23 @@ | ||
| 308 | 317 | if (homeStretch.current) return; |
| 309 | 318 | homeStretch.current = true; |
| 310 | 319 | (async () => { |
| 311 | 320 | const { objective, structure, category } = siteProfile; |
| 321 | + const builtHome = designBuild?.builtPages?.find((p) => p.slug === 'home'); | |
| 322 | + // Must match get-home.js's full-page test; if they drift, the home is | |
| 323 | + // built one way and planted another. | |
| 324 | + const isSinglePageDesign = | |
| 325 | + structure === 'single-page' && | |
| 326 | + Boolean(builtHome?.fullPage && builtHome.patterns?.length) && | |
| 327 | + Boolean(designBuild?.pages?.length); | |
| 328 | + const imageUrls = siteImageUrls(siteImages); | |
| 329 | + const intendedPlugins = (sitePlugins ?? []).map( | |
| 330 | + ({ wordpressSlug }) => wordpressSlug, | |
| 331 | + ); | |
| 312 | 332 | |
| 313 | - // Do they need an imprint page? | |
| 333 | + // Guarantee plugins are active before the pattern imports below rely on them. | |
| 334 | + await ensurePluginsActive(intendedPlugins); | |
| 335 | + | |
| 314 | 336 | const needsImprint = Array.isArray(showImprint) |
| 315 | 337 | ? showImprint.includes(wpLanguage ?? '') && category === 'Business' |
| 316 | 338 | : false; |
| 317 | 339 | |
| @@ -320,9 +342,9 @@ | ||
| 320 | 342 | let variation = siteStyle?.variation; |
| 321 | 343 | if (customFonts?.length) { |
| 322 | 344 | checkIn({ stage: 'install_fonts' }); |
| 323 | 345 | // translators: this is for a action log UI. Keep it short |
| 324 | - addStatusMessage(__('Installing fonts locally', 'extendify-local')); | |
| 346 | + addStatusMessage(launchStrings().statusFonts); | |
| 325 | 347 | const installed = await installFontFamilies(customFonts).catch( |
| 326 | 348 | () => [], |
| 327 | 349 | ); |
| 328 | 350 | variation = mergeFontsIntoVariation(siteStyle.variation, installed); |
| @@ -329,19 +351,15 @@ | ||
| 329 | 351 | } |
| 330 | 352 | |
| 331 | 353 | if (siteStyle?.vibe && siteStyle.vibe !== 'natural-1') { |
| 332 | 354 | // translators: vibe in this context is a noun - the feeling of their site design. |
| 333 | - addStatusMessage(__('Setting the website style', 'extendify-local')); | |
| 355 | + addStatusMessage(launchStrings().statusSiteStyle); | |
| 334 | 356 | checkIn({ stage: 'compute_vibe' }); |
| 335 | - const vibeBlocks = await computeVibeAdjustedBlocks( | |
| 357 | + const vibe = await computeVibeAdjustments( | |
| 336 | 358 | siteStyle.vibe, |
| 359 | + variation, | |
| 337 | 360 | ).catch(() => null); |
| 338 | - if (vibeBlocks) { | |
| 339 | - variation = { | |
| 340 | - ...variation, | |
| 341 | - styles: { ...variation.styles, blocks: vibeBlocks }, | |
| 342 | - }; | |
| 343 | - } | |
| 361 | + if (vibe) variation = { ...variation, ...vibe }; | |
| 344 | 362 | } |
| 345 | 363 | |
| 346 | 364 | checkIn({ stage: 'set_vibe' }); |
| 347 | 365 | await updateVariation(variation); |
| @@ -346,9 +364,9 @@ | ||
| 346 | 364 | checkIn({ stage: 'set_vibe' }); |
| 347 | 365 | await updateVariation(variation); |
| 348 | 366 | |
| 349 | 367 | // navigation menu |
| 350 | - addStatusMessage(__('Working on the navigation', 'extendify-local')); | |
| 368 | + addStatusMessage(launchStrings().statusNavigation); | |
| 351 | 369 | const { id: headerNavId } = await createNavigation({ |
| 352 | 370 | title: __('Header Navigation', 'extendify-local'), |
| 353 | 371 | slug: 'site-navigation', |
| 354 | 372 | }); |
| @@ -354,12 +372,13 @@ | ||
| 354 | 372 | }); |
| 355 | 373 | let headerCode = updateNavAttributes(home.headerCode || '', { |
| 356 | 374 | ref: headerNavId, |
| 357 | 375 | }); |
| 376 | + headerCode = injectNavExtras(headerCode, launchDecisions); | |
| 358 | 377 | // remove the header navigation from the landing page |
| 359 | 378 | if (objective === 'landing-page') { |
| 360 | 379 | // translators: this is for a action log UI. Keep it short |
| 361 | - addStatusMessage(__('Perfecting a landing page', 'extendify-local')); | |
| 380 | + addStatusMessage(launchStrings().statusLanding); | |
| 362 | 381 | const social = |
| 363 | 382 | /<!--\s*wp:social-links\b[^>]*>.*?<!--\s*\/wp:social-links\s*-->/gis; |
| 364 | 383 | headerCode = headerCode |
| 365 | 384 | .replace(/<!--\s*wp:navigation\b[^>]*.*\/-->/gis, '') |
| @@ -364,23 +383,27 @@ | ||
| 364 | 383 | headerCode = headerCode |
| 365 | 384 | .replace(/<!--\s*wp:navigation\b[^>]*.*\/-->/gis, '') |
| 366 | 385 | .replace(social, ''); |
| 367 | 386 | } |
| 368 | - if (typeof siteProfile.phoneNumber === 'string') { | |
| 369 | - headerCode = headerCode.replaceAll( | |
| 370 | - // Hardcoded in the template | |
| 371 | - '206-555-0100', | |
| 372 | - siteProfile.phoneNumber || | |
| 373 | - // translators: Use a number that is appropriate for the locale. It does not need to be this exact number. This is a placeholder phone number. For example, in pt_BR you could use (11) 91234-5678. | |
| 374 | - __('206-555-0100', 'extendify-local'), | |
| 375 | - ); | |
| 376 | - } | |
| 387 | + headerCode = headerCode.replaceAll( | |
| 388 | + '206-555-0100', | |
| 389 | + (typeof siteProfile.phoneNumber === 'string' && | |
| 390 | + siteProfile.phoneNumber) || | |
| 391 | + // translators: Use a number that is appropriate for the locale. It does not need to be this exact number. This is a placeholder phone number. For example, in pt_BR you could use (11) 91234-5678. | |
| 392 | + __('206-555-0100', 'extendify-local'), | |
| 393 | + ); | |
| 377 | 394 | checkIn({ stage: 'set_navigation' }); |
| 378 | - await updateTemplatePart('extendable/header', headerCode); | |
| 379 | 395 | |
| 380 | 396 | // footer |
| 381 | 397 | let footerNavId = null; |
| 382 | 398 | let footerCode = home.footerCode || ''; |
| 399 | + // The logo already carries the brand, so the site title would be redundant. | |
| 400 | + if (designBuild?.hasExternalLogo && footerCode.includes('wp:site-logo')) { | |
| 401 | + footerCode = footerCode.replace( | |
| 402 | + /\s*<!--\s*wp:site-title[\s\S]*?\/-->/g, | |
| 403 | + '', | |
| 404 | + ); | |
| 405 | + } | |
| 383 | 406 | if (needsImprint) { |
| 384 | 407 | const nav = await createNavigation({ |
| 385 | 408 | title: __('Footer Navigation', 'extendify-local'), |
| 386 | 409 | slug: 'footer-navigation', |
| @@ -387,14 +410,15 @@ | ||
| 387 | 410 | }); |
| 388 | 411 | footerNavId = nav.id; |
| 389 | 412 | footerCode = updateNavAttributes(footerCode, { ref: footerNavId }); |
| 390 | 413 | } |
| 414 | + footerCode = applySocialProfiles(footerCode, siteProfile.socialProfiles); | |
| 391 | 415 | checkIn({ stage: 'set_footer' }); |
| 392 | 416 | await updateTemplatePart('extendable/footer', footerCode); |
| 393 | 417 | |
| 394 | 418 | // pages |
| 395 | 419 | // translators: this is for a action log UI. Keep it short |
| 396 | - addStatusMessage(__('Creating pages', 'extendify-local')); | |
| 420 | + addStatusMessage(launchStrings().statusCreatingPages); | |
| 397 | 421 | const pagesToCreate = getPagesToCreate(data); |
| 398 | 422 | const titlePattern = pages?.[0]?.patterns?.find((p) => |
| 399 | 423 | p.patternTypes?.includes('page-title'), |
| 400 | 424 | ); |
| @@ -403,9 +427,9 @@ | ||
| 403 | 427 | await updatePageTitlePattern(titlePattern.code); |
| 404 | 428 | } |
| 405 | 429 | |
| 406 | 430 | const activePlugins = await getActivePlugins(); |
| 407 | - // This lets us keep plugin pages in th enav but skip making the page | |
| 431 | + // Keep plugin pages in the nav but skip creating the page itself. | |
| 408 | 432 | const reservedSlugs = new Set( |
| 409 | 433 | PLUGIN_OWNED_PAGES.filter( |
| 410 | 434 | ({ plugin }) => |
| 411 | 435 | sitePlugins.some((p) => p.wordpressSlug === plugin) || |
| @@ -429,25 +453,43 @@ | ||
| 429 | 453 | } |
| 430 | 454 | checkIn({ stage: 'generate_page_content' }); |
| 431 | 455 | const customPages = await generatePageContent(pagesReplaced, data); |
| 432 | 456 | |
| 433 | - const stickyNav = | |
| 434 | - structure === 'single-page' && objective !== 'landing-page'; | |
| 435 | - const createdPagesWP = await createWpPages(customPages, { stickyNav }); | |
| 457 | + // Update heroDescription to the actual AI-rewritten hero content | |
| 458 | + const homePage = customPages.find((p) => p.slug === 'home'); | |
| 459 | + const heroPattern = homePage?.patterns?.find((p) => | |
| 460 | + p.patternTypes?.includes('hero-header'), | |
| 461 | + ); | |
| 462 | + const pMatch = heroPattern?.code?.match(/<p[^>]*>([\s\S]*?)<\/p>/); | |
| 463 | + const heroDesc = pMatch?.[1]?.replace(/<[^>]+>/g, '').trim(); | |
| 464 | + const heroDescription = heroDesc || data.heroDescription; | |
| 465 | + setData('heroDescription', heroDescription); | |
| 466 | + if (heroDescription) { | |
| 467 | + await updateOption('extendify_hero_description', heroDescription).catch( | |
| 468 | + () => null, | |
| 469 | + ); | |
| 470 | + } | |
| 471 | + | |
| 472 | + const createdPagesWP = await createWpPages(customPages, { | |
| 473 | + skipSectionIds: isSinglePageDesign, | |
| 474 | + }); | |
| 436 | 475 | // Aux pages |
| 437 | - const hasBlogPattern = home?.patterns?.some((pattern) => | |
| 476 | + const blogPattern = home?.patterns?.find((pattern) => | |
| 438 | 477 | pattern.patternTypes.includes('blog-section'), |
| 439 | 478 | ); |
| 440 | - if (objective === 'blog' || hasBlogPattern) { | |
| 479 | + if (siteProfile.blog || blogPattern) { | |
| 441 | 480 | checkIn({ stage: 'create_blog_sample_data' }); |
| 442 | 481 | // translators: this is for a action log UI. Keep it short |
| 443 | - addStatusMessage(__('Creating blog sample data', 'extendify-local')); | |
| 444 | - await createBlogSampleData({ aiBlogTitles }, siteImages); | |
| 482 | + addStatusMessage(launchStrings().statusBlog); | |
| 483 | + await createBlogSampleData( | |
| 484 | + { aiBlogTitles }, | |
| 485 | + imageUrls, | |
| 486 | + blogPattern?.blogImages, | |
| 487 | + ); | |
| 445 | 488 | } |
| 446 | - // If we have site images then set up the hello world image | |
| 447 | - if (siteImages?.length) { | |
| 489 | + if (imageUrls.length) { | |
| 448 | 490 | checkIn({ stage: 'set_hello_world_image' }); |
| 449 | - await setHelloWorldFeaturedImage(siteImages); | |
| 491 | + await setHelloWorldFeaturedImage(imageUrls); | |
| 450 | 492 | } |
| 451 | 493 | |
| 452 | 494 | let imprint = {}; |
| 453 | 495 | if (needsImprint) { |
| @@ -459,9 +501,9 @@ | ||
| 459 | 501 | if (alreadyActive(activePlugins, 'woocommerce')) { |
| 460 | 502 | checkIn({ stage: 'import_woocommerce_products' }); |
| 461 | 503 | addStatusMessage( |
| 462 | 504 | // translators: this is for a action log UI. Keep it short |
| 463 | - __('Setting up your online store', 'extendify-local'), | |
| 505 | + launchStrings().statusStore, | |
| 464 | 506 | ); |
| 465 | 507 | await apiFetchWithTimeout({ |
| 466 | 508 | path: '/extendify/v1/auto-launch/import-woocommerce', |
| 467 | 509 | }).catch(() => null); |
| @@ -476,18 +518,36 @@ | ||
| 476 | 518 | link: `${homeUrl}/events`, |
| 477 | 519 | }); |
| 478 | 520 | } |
| 479 | 521 | |
| 522 | + // The design's page list omits the posts page like it omits shop, so the | |
| 523 | + // nav needs it here — but it's ours to create, not a PLUGIN_OWNED_PAGES. | |
| 524 | + pluginPages.push(...createdPagesWP.filter(isBlogPage)); | |
| 525 | + | |
| 480 | 526 | // Adding pages to the nav |
| 481 | 527 | checkIn({ stage: 'set_page_links' }); |
| 482 | - const pagesWithLinksUpdated = | |
| 483 | - structure === 'single-page' | |
| 484 | - ? await updateSinglePageLinksToSections(createdPagesWP, customPages, { | |
| 485 | - objective, | |
| 486 | - activePlugins, | |
| 487 | - landingPageCTALink: siteProfile.landingPageCTALink, | |
| 488 | - }) | |
| 489 | - : await updateButtonLinks(createdPagesWP, pluginPages); | |
| 528 | + let linksResult = { wpPages: createdPagesWP, headerCode }; | |
| 529 | + if (!isSinglePageDesign) { | |
| 530 | + linksResult = | |
| 531 | + structure === 'single-page' | |
| 532 | + ? await updateSinglePageLinksToSections( | |
| 533 | + createdPagesWP, | |
| 534 | + customPages, | |
| 535 | + { | |
| 536 | + objective, | |
| 537 | + activePlugins, | |
| 538 | + landingPageCTALink: siteProfile.landingPageCTALink, | |
| 539 | + }, | |
| 540 | + headerCode, | |
| 541 | + ) | |
| 542 | + : await updateButtonLinks(createdPagesWP, pluginPages, headerCode); | |
| 543 | + } | |
| 544 | + const pagesWithLinksUpdated = linksResult.wpPages; | |
| 545 | + headerCode = linksResult.headerCode; | |
| 546 | + if (alreadyActive(activePlugins, 'woocommerce')) { | |
| 547 | + headerCode = injectWooCommerceIcons(headerCode); | |
| 548 | + } | |
| 549 | + await updateTemplatePart('extendable/header', headerCode); | |
| 490 | 550 | const footerNavPages = []; |
| 491 | 551 | if (footerNavId && imprint?.title) { |
| 492 | 552 | const { originalSlug, title } = imprint; |
| 493 | 553 | footerNavPages.push({ |
| @@ -500,9 +560,20 @@ | ||
| 500 | 560 | |
| 501 | 561 | checkIn({ stage: 'set_navigation_links' }); |
| 502 | 562 | if (objective !== 'landing-page') { |
| 503 | 563 | const orderedSlugs = designBuild?.pages?.map((p) => p.slug) ?? []; |
| 504 | - if (structure === 'single-page') { | |
| 564 | + // The tag only exists where the sections came back matched 1:1 to our list; | |
| 565 | + // read it off what was planted, so menu and section ids can't disagree. | |
| 566 | + const designOwnsNav = | |
| 567 | + isSinglePageDesign || | |
| 568 | + Boolean(homePage?.patterns?.some(({ navSlug }) => navSlug)); | |
| 569 | + if (designOwnsNav) { | |
| 570 | + await addSectionLinksFromDesign( | |
| 571 | + headerNavId, | |
| 572 | + designBuild.pages, | |
| 573 | + pluginPages, | |
| 574 | + ); | |
| 575 | + } else if (structure === 'single-page') { | |
| 505 | 576 | await addSectionLinksToNav( |
| 506 | 577 | headerNavId, |
| 507 | 578 | home?.patterns, |
| 508 | 579 | pluginPages, |
| @@ -534,14 +605,18 @@ | ||
| 534 | 605 | await prefetchAssistData(); |
| 535 | 606 | checkIn({ stage: 'final_steps' }); |
| 536 | 607 | await setThemeRenderingMode('template-locked'); |
| 537 | 608 | await postLaunchFunctions(); |
| 538 | - if (siteImages?.length) { | |
| 609 | + if (imageUrls.length) { | |
| 539 | 610 | await storeSiteImages(siteImages).catch(() => null); |
| 540 | 611 | } |
| 541 | 612 | // translators: this is for a action log UI. Keep it short |
| 542 | - addStatusMessage(__('All done!', 'extendify-local')); | |
| 543 | - await checkIn({ stage: 'finished', siteProfile, sitePlugins, siteStyle }); | |
| 613 | + addStatusMessage(launchStrings().statusDone); | |
| 614 | + await Promise.all([ | |
| 615 | + reportInactivePlugins(intendedPlugins).catch(() => null), | |
| 616 | + reportFailedDependencies(pagesReplaced), | |
| 617 | + checkIn({ stage: 'finished', siteProfile, sitePlugins, siteStyle }), | |
| 618 | + ]); | |
| 544 | 619 | setWarnOnReload(false); |
| 545 | 620 | setDone(true); |
| 546 | 621 | })().catch((error) => { |
| 547 | 622 | console.error(error); |
| @@ -551,14 +626,9 @@ | ||
| 551 | 626 | }); |
| 552 | 627 | // if we error here we can try again by resetting the home stretch and stalling again to refetch data |
| 553 | 628 | homeStretch.current = false; |
| 554 | 629 | needToStall(true); |
| 555 | - setErrorMessage( | |
| 556 | - __( | |
| 557 | - 'Something went wrong during the final steps. We will try again but you may need to refresh the page.', | |
| 558 | - 'extendify-local', | |
| 559 | - ), | |
| 560 | - ); | |
| 630 | + setErrorMessage(launchStrings().errorFinalSteps); | |
| 561 | 631 | }); |
| 562 | 632 | }, [data, needToStall, setUserGaveConsent]); |
| 563 | 633 | |
| 564 | 634 | return { done }; |
| @@ -582,12 +652,7 @@ | ||
| 582 | 652 | useEffect(() => { |
| 583 | 653 | if (!error || needToStall()) return; |
| 584 | 654 | console.error(error); |
| 585 | 655 | digest({ error, details: { source: 'auto-launch', caller: 'run-step' } }); |
| 586 | - setErrorMessage( | |
| 587 | - __( | |
| 588 | - 'Having some trouble with this step. Trying again...', | |
| 589 | - 'extendify-local', | |
| 590 | - ), | |
| 591 | - ); | |
| 656 | + setErrorMessage(launchStrings().errorStep); | |
| 592 | 657 | }, [error, setErrorMessage, needToStall]); |
| 593 | 658 | }; |