PluginProbe
Extendify / trunk
Extendify vtrunk
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 0.6.0 All 127 releases
← All changes | src/AutoLaunch/functions/nav.js +86 -40 3.1.2 → trunk View file →
@@ -23,8 +23,24 @@
23 23 method: 'POST',
24 24 data: { content },
25 25 });
26 26
27 +const navLink = (attributes) =>
28 + `<!-- wp:navigation-link ${JSON.stringify(attributes)} /-->`;
29 +
30 +const pluginPageLink = (page) =>
31 + navLink({
32 + label: page.title?.rendered ?? page.name,
33 + id: page.id,
34 + type: page.type,
35 + url: page.link,
36 + kind: page.id ? 'post-type' : 'custom',
37 + isTopLevelLink: true,
38 + });
39 +
40 +const anchorLink = ({ label, url }) =>
41 + navLink({ label, type: 'custom', url, kind: 'custom', isTopLevelLink: true });
42 +
27 43 export const addSectionLinksToNav = async (
28 44 navigationId,
29 45 homePatterns = [],
30 46 pluginPages = [],
@@ -47,12 +63,9 @@
47 63 const lookup =
48 64 Object.values(pageNames).find(({ alias }) =>
49 65 alias.includes(patternType),
50 66 ) || {};
51 - return {
52 - label: pattern.navLabel ?? lookup.title,
53 - slug: pattern.navSlug ?? lookup.slug,
54 - };
67 + return { label: lookup.title, slug: lookup.slug };
55 68 };
56 69
57 70 const sectionPatterns = homePatterns.filter((pattern) => {
58 71 const { slug } = resolve(pattern);
@@ -70,34 +83,13 @@
70 83 const url = pages.includes(slug)
71 84 ? `${window.extSharedData.homeUrl}/${slug}`
72 85 : `${window.extSharedData.homeUrl}/#${slug}`;
73 86
74 - const attributes = JSON.stringify({
75 - label,
76 - type: 'custom',
77 - url,
78 - kind: 'custom',
79 - isTopLevelLink: true,
80 - });
81 -
82 - return `<!-- wp:navigation-link ${attributes} /-->`;
87 + return anchorLink({ label, url });
83 88 });
84 89
85 - const pluginPagesNavigationLinks = pluginPages.map(
86 - ({ title, id, type, link }) => {
87 - const attributes = JSON.stringify({
88 - label: title.rendered,
89 - id,
90 - type,
91 - url: link,
92 - kind: id ? 'post-type' : 'custom',
93 - isTopLevelLink: true,
94 - });
90 + const pluginPagesNavigationLinks = pluginPages.map(pluginPageLink);
95 91
96 - return `<!-- wp:navigation-link ${attributes} /-->`;
97 - },
98 - );
99 -
100 92 // When an ordered slug list is provided, interleave plugin pages by slug
101 93 // so e.g. "shop" lands where the design preview placed it.
102 94 let navigationLinks;
103 95 if (orderedSlugs.length) {
@@ -130,8 +122,42 @@
130 122
131 123 await updateNavigation(navigationId, navigationLinks);
132 124 };
133 125
126 +// Full-page single-page: the design build's page list IS the menu, in order —
127 +// the same list the preview nav used — and the BE baked matching #section
128 +// anchors into the page HTML. Build straight from it; no pattern derivation.
129 +export const addSectionLinksFromDesign = async (
130 + navigationId,
131 + designPages = [],
132 + pluginPages = [],
133 +) => {
134 + const { homeUrl } = window.extSharedData;
135 + const pluginBySlug = new Map(pluginPages.map((page) => [page.slug, page]));
136 +
137 + const sectionLink = ({ slug, name }) =>
138 + anchorLink({ label: name, url: `${homeUrl}/#${slug}` });
139 +
140 + const seen = new Set();
141 + const links = [];
142 + for (const { slug, name } of designPages) {
143 + if (!slug || slug === 'home' || seen.has(slug)) continue;
144 + seen.add(slug);
145 + const pluginPage = pluginBySlug.get(slug);
146 + links.push(
147 + pluginPage ? pluginPageLink(pluginPage) : sectionLink({ slug, name }),
148 + );
149 + }
150 + // An active plugin page the design didn't place still belongs in the nav.
151 + for (const page of pluginPages) {
152 + if (!page.slug || seen.has(page.slug)) continue;
153 + seen.add(page.slug);
154 + links.push(pluginPageLink(page));
155 + }
156 +
157 + await updateNavigation(navigationId, links.join(''));
158 +};
159 +
134 160 export const addPageLinksToNav = async (
135 161 navigationId,
136 162 allPages,
137 163 createdPages,
@@ -157,9 +183,18 @@
157 183 Object.values(pageNames).find((p) => p.alias?.includes(slug))?.navOrder ??
158 184 Object.keys(pageNames).length + 1
159 185 );
160 186 };
161 - const mergedPages = [...filteredCreatedPages, ...pluginPages];
187 + const seen = new Set();
188 + const mergedPages = [...filteredCreatedPages, ...pluginPages].filter(
189 + (page) => {
190 + const slug = getSlug(page);
191 + if (!slug) return true;
192 + if (seen.has(slug)) return false;
193 + seen.add(slug);
194 + return true;
195 + },
196 + );
162 197
163 198 let finalPages;
164 199 if (orderedSlugs.length) {
165 200 const indexOf = (p) => orderedSlugs.indexOf(getSlug(p));
@@ -190,21 +225,10 @@
190 225 })()
191 226 : sortedPages;
192 227 }
193 228
194 - const pageLinks = finalPages.map(({ id, title, link, type }) => {
195 - const attributes = JSON.stringify({
196 - label: title.rendered,
197 - id,
198 - type,
199 - url: link,
200 - kind: id ? 'post-type' : 'custom',
201 - isTopLevelLink: true,
202 - });
229 + const pageLinks = finalPages.map(pluginPageLink);
203 230
204 - return `<!-- wp:navigation-link ${attributes} /-->`;
205 - });
206 -
207 231 const topLevelLinks = pageLinks.slice(0, 5).join('');
208 232 const submenuLinks = pageLinks.slice(5);
209 233 // We want a max of 6 top-level links, but if 7+, then move the last
210 234 // two+ to a submenu.
@@ -272,8 +296,30 @@
272 296 <!-- /wp:social-links -->`;
273 297 default:
274 298 return null;
275 299 }
300 +};
301 +
302 +// Woo auto-inserts these after the nav, but WP suppresses them when AutoLaunch
303 +// saves the header directly — insert them ourselves so they render. fontSize
304 +// matches Extendable's nav (`small`).
305 +export const injectWooCommerceIcons = (headerCode) => {
306 + // The fetched header can already carry them: WP materializes hooked blocks
307 + // into REST responses once Woo is active (e.g. on a re-launch).
308 + if (/wp:woocommerce\/(mini-cart|customer-account)/.test(headerCode)) {
309 + return headerCode;
310 + }
311 +
312 + // After updateNavAttributes the nav block is always self-closing.
313 + const navBlock = /<!--\s*wp:navigation\b[^>]*?\/-->/i;
314 + if (!navBlock.test(headerCode)) return headerCode;
315 +
316 + const icons = [
317 + '<!-- wp:woocommerce/customer-account {"displayStyle":"icon_only","iconStyle":"line","iconClass":"wc-block-customer-account__account-icon","fontSize":"small"} /-->',
318 + '<!-- wp:woocommerce/mini-cart {"fontSize":"small"} /-->',
319 + ].join('\n');
320 +
321 + return headerCode.replace(navBlock, (nav) => `${nav}\n${icons}`);
276 322 };
277 323
278 324 export const injectNavExtras = (headerCode, launchDecisions) => {
279 325 const navExtras = launchDecisions?.navExtras;