PluginProbe
Extendify / 3.1.3
Extendify v3.1.3
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
extendify / src / Agent / workflows / content / tools / get-post-strings.js

get-post-strings.js in Extendify 3.1.3, at src/Agent/workflows/content/tools/get-post-strings.js

95 lines 2.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import apiFetch from '@wordpress/api-fetch';
2 import { parse } from '@wordpress/block-serialization-default-parser';
3
4 export default async ({ postId, postType }) => {
5 const type = postType === 'page' ? 'pages' : 'posts';
6 const response = await apiFetch({
7 path: `/wp/v2/${type}/${postId}?context=edit`,
8 });
9 const blocks = parse(response.content.raw);
10 const postStrings = [response.title.raw, ...extractTextFromBlocks(blocks)];
11
12 // Get active template part slugs from the DOM
13 const slugs = [
14 ...new Set(
15 [...document.querySelectorAll('[data-extendify-part-slug]')].map(
16 (el) => el.dataset.extendifyPartSlug,
17 ),
18 ),
19 ];
20
21 if (!slugs.length) {
22 return { post_strings: dedupeStrings(postStrings), parts_used: [] };
23 }
24
25 let allParts = [];
26 try {
27 allParts = await apiFetch({
28 path: '/wp/v2/template-parts?per_page=100&context=edit',
29 });
30 } catch {
31 try {
32 await new Promise((resolve) => setTimeout(resolve, 1000));
33 allParts = await apiFetch({
34 path: '/wp/v2/template-parts?per_page=100&context=edit',
35 });
36 } catch {
37 // Maybe error to the user, but we retried twice
38 }
39 }
40 const activeParts = allParts.filter((p) => slugs.includes(p.slug));
41 const partsUsed = activeParts.map((part) => {
42 const partBlocks = parse(part.content.raw);
43 postStrings.push(...extractTextFromBlocks(partBlocks));
44 return { id: part.id, area: part.area };
45 });
46
47 return {
48 post_strings: dedupeStrings(postStrings),
49 parts_used: partsUsed,
50 };
51 };
52
53 const newSet = (arr) => new Set(arr.filter(Boolean));
54 const dedupeStrings = (arr) => [...newSet(arr)];
55
56 const stripHtml = (html) =>
57 html
58 .replace(/<[^>]+>/g, '')
59 .replace(/\s+/g, ' ')
60 .trim();
61
62 // Handles image stuff
63 const extractAltAndTitleFromHtml = (html) => {
64 const matches = [];
65 const altMatch = html.match(/alt="([^"]*)"/);
66 if (altMatch?.[1]) matches.push(altMatch[1].trim());
67 const titleMatch = html.match(/title="([^"]*)"/);
68 if (titleMatch?.[1]) matches.push(titleMatch[1].trim());
69 return matches;
70 };
71
72 const extractTextFromBlocks = (blocks) => {
73 if (!blocks || blocks.length === 0) return [];
74 return blocks.flatMap((block) => [
75 // Extract from innerContent (rendered HTML)
76 ...(block.innerContent
77 ? block.innerContent
78 .filter(Boolean)
79 .flatMap((html) => [
80 stripHtml(html),
81 ...extractAltAndTitleFromHtml(html),
82 ])
83 .filter(Boolean)
84 : []),
85 // Extract from relevant string attributes
86 ...['content', 'caption', 'alt', 'title', 'value']
87 .map((key) =>
88 typeof block.attrs?.[key] === 'string' ? block.attrs[key].trim() : null,
89 )
90 .filter(Boolean),
91 // Recurse into innerBlocks
92 ...extractTextFromBlocks(block.innerBlocks || []),
93 ]);
94 };
95