PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
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.23.2.1 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;