PluginProbe
Extendify / 3.2.2
Extendify v3.2.2
3.2.2 3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 All 128 releases
← All changes | src/AutoLaunch/fetchers/get-design-build.js +65 -46 3.1.3 → 3.2.2 View file →
@@ -1,6 +1,6 @@
1 -import { uploadLogo } from '@auto-launch/fetchers/get-logo';
2 -import { getThemeVariation } from '@auto-launch/fetchers/get-variation';
1 +import { isExternalLogo, uploadLogo } from '@auto-launch/fetchers/get-logo';
2 +import { getStyleDocument } from '@auto-launch/fetchers/get-style-document';
3 3 import {
4 4 getDesignBuildShape,
5 5 getLogoShape,
6 6 getPluginsShape,
@@ -5,8 +5,9 @@
5 5 getLogoShape,
6 6 getPluginsShape,
7 7 getStyleShape,
8 8 } from '@auto-launch/fetchers/shape';
9 +import { importBuiltPagesImages } from '@auto-launch/functions/get-imported-images';
9 10 import {
10 11 fetchWithTimeout,
11 12 retryTwice,
12 13 setStatus,
@@ -12,22 +13,28 @@
12 13 setStatus,
13 14 } from '@auto-launch/functions/helpers';
14 15 import { updateOption } from '@auto-launch/functions/wp';
15 16 import { useLaunchDataStore } from '@auto-launch/state/launch-data';
17 +import { launchStrings } from '@auto-launch/strings';
16 18 import { AI_HOST } from '@constants';
17 19 import { digest } from '@shared/api/digest';
18 -import { __ } from '@wordpress/i18n';
19 20 import { mutate } from 'swr';
20 21
21 22 const fallback = null;
22 23 const headers = { 'Content-Type': 'application/json' };
23 24
25 +// Left set, the launch screen waits forever on a design that never arrives.
26 +const dropBuildId = () =>
27 + useLaunchDataStore.setState((s) => ({
28 + urlParams: { ...s.urlParams, 'build-id': '' },
29 + }));
30 +
24 31 export const handleDesignBuild = async ({ urlParams }) => {
25 32 const buildId = urlParams?.['build-id'];
26 33 if (!buildId) return fallback;
27 34
28 35 // translators: this is for a action log UI. Keep it short
29 - setStatus(__('Loading your design', 'extendify-local'));
36 + setStatus(launchStrings().statusDesign);
30 37
31 38 const url = `${AI_HOST}/api/design/${encodeURIComponent(buildId)}`;
32 39 const response = await retryTwice(() =>
33 40 fetchWithTimeout(url, { headers }),
@@ -43,8 +50,9 @@
43 50 status: response.status,
44 51 },
45 52 details: { source: 'auto-launch', caller: 'handleDesignBuild' },
46 53 });
54 + dropBuildId();
47 55 return fallback;
48 56 }
49 57
50 58 try {
@@ -54,17 +62,16 @@
54 62 const profile = parsed.siteProfile;
55 63 await updateOption('extendify_site_profile', JSON.stringify(profile));
56 64 mutate('siteProfile', { siteProfile: profile }, false);
57 65
58 - // Stash the site style and variation
59 66 const style = parsed.siteStyle;
60 - const fonts =
61 - style.fonts?.heading || style.fonts?.body ? style.fonts : null;
62 - const variation = await getThemeVariation(
63 - { slug: style.colorPalette, fonts },
64 - { fallback: true },
65 - );
67 + const variation = await getStyleDocument({
68 + colorPalette: style.colorPalette,
69 + fonts: style.fonts,
70 + });
66 71 const siteStyle = { ...style, variation };
72 + // The Agent reads extendify_siteStyle; the legacy row keeps old readers.
73 + await updateOption('extendify_siteStyle', siteStyle);
67 74 await updateOption('extendify_site_style', siteStyle);
68 75 await updateOption('extendify_animation_settings', {
69 76 type: style.animation ?? 'fade',
70 77 speed: 'medium',
@@ -74,15 +81,39 @@
74 81 // Stash the plugins
75 82 const sitePlugins = parsed.selectedPlugins;
76 83 mutate('sitePlugins', getPluginsShape.parse({ sitePlugins }), false);
77 84
78 - // Stash the logo
79 - await uploadLogo(parsed.logoUrl);
80 - mutate('siteLogo', getLogoShape.parse({ logoUrl: parsed.logoUrl }), false);
85 + // The logo upload swaps logoUrl for a Media Library URL without the
86 + // logos-custom/ marker, so capture "is the brand's own logo" from the
87 + // source URL now.
88 + const hasExternalLogo = isExternalLogo(parsed.logoUrl);
81 89
82 - const designBuild = { buildId, ...parsed, siteProfile: profile, siteStyle };
83 - // Spreading it here sets it for other state values we override
84 - return { designBuild, ...designBuild };
90 + // Sideload the built-page images, and upload the logo alongside when the
91 + // build provided one. logoUrl is nullable; without it we skip the upload
92 + // so the siteLogo step falls through to AI logo generation.
93 + const uploads = [importBuiltPagesImages(parsed.builtPages)];
94 + if (parsed.logoUrl) {
95 + mutate(
96 + 'siteLogo',
97 + getLogoShape.parse({ logoUrl: parsed.logoUrl }),
98 + false,
99 + );
100 + uploads.push(uploadLogo(parsed.logoUrl, { external: hasExternalLogo }));
101 + }
102 + const [builtPages] = await Promise.all(uploads);
103 +
104 + const designBuild = {
105 + buildId,
106 + ...parsed,
107 + builtPages,
108 + hasExternalLogo,
109 + siteProfile: profile,
110 + siteStyle,
111 + };
112 + // Exclude `pages` from the spread: the pages step owns it (templates with
113 + // patterns); designBuild.pages (slug/name only) would clobber it.
114 + const { pages, ...topLevel } = designBuild;
115 + return { designBuild, ...topLevel };
85 116 } catch (e) {
86 117 digest({
87 118 error: e,
88 119 details: { source: 'auto-launch', caller: 'handleDesignBuild::parsing' },
@@ -87,30 +118,32 @@
87 118 error: e,
88 119 details: { source: 'auto-launch', caller: 'handleDesignBuild::parsing' },
89 120 });
90 121 console.error('handleDesignBuild:', e);
91 - // Drop the build-id so downstream checks (e.g. skipDescription) fallback
92 - useLaunchDataStore.setState((s) => ({
93 - urlParams: { ...s.urlParams, 'build-id': '' },
94 - }));
122 + dropBuildId();
95 123 return fallback;
96 124 }
97 125 };
98 126
99 -// Prepend the design build hero; flagged so it skips content regeneration.
127 +// Prepend the design build's hero to the fetched home template. Full-page
128 +// builds skip /api/home entirely and are assembled in handleHome.
100 129 export const applyDesignBuildHero = (patterns, designBuild) => {
101 - if (!designBuild?.patternCode) return patterns;
102 - return [
103 - {
104 - name: designBuild.patternId,
105 - code: designBuild.patternCode,
106 - patternTypes: ['hero-header'],
107 - contentGenerated: true,
108 - },
109 - ...patterns,
110 - ];
130 + const builtHome = designBuild?.builtPages?.find((p) => p.slug === 'home');
131 + if (!builtHome?.patterns?.length) return patterns;
132 + return [...builtHome.patterns, ...patterns];
111 133 };
112 134
135 +// /api/home answers a locked nav with one section per entry, in order, and holds back
136 +// the hero, so a count mismatch means that broke: leave the names to the pattern types.
137 +export const applyDesignBuildNav = (patterns, designBuild, structure) => {
138 + const pages = designBuild?.pages ?? [];
139 + if (structure !== 'single-page' || patterns.length !== pages.length) {
140 + return patterns;
141 + }
142 +
143 + return patterns.map((pattern, i) => ({ ...pattern, navSlug: pages[i].slug }));
144 +};
145 +
113 146 // Reorder pages to match the design build's page order; extras fall to the end.
114 147 export const applyDesignBuildOrder = (pages, designBuild) => {
115 148 const order = designBuild?.pages?.map((p) => p.slug) ?? [];
116 149 if (!order.length) return pages;
@@ -117,19 +150,5 @@
117 150 return [
118 151 ...order.map((slug) => pages.find((t) => t.slug === slug)).filter(Boolean),
119 152 ...pages.filter((t) => !order.includes(t.slug)),
120 153 ];
121 -};
122 -
123 -// Tag non-hero patterns with their aligned design build page slug/name.
124 -// For single-page sites mainly
125 -export const applyDesignBuildNav = (patterns, designBuild) => {
126 - const pages = designBuild?.pages ?? [];
127 - if (!pages.length) return patterns;
128 - let i = 0;
129 - return patterns.map((pattern) => {
130 - if (pattern.patternTypes?.includes('hero-header')) return pattern;
131 - const page = pages[i++];
132 - if (!page) return pattern;
133 - return { ...pattern, navSlug: page.slug, navLabel: page.name };
134 - });
135 154 };