PluginProbe
Extendify / 3.0.4
Extendify v3.0.4
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 / AutoLaunch / functions / wp.js

wp.js in Extendify 3.0.4, at src/AutoLaunch/functions/wp.js

247 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // Functions that interact with WordPress
2
3 import blogSampleData from '@launch/_data/blog-sample.json';
4 import apiFetch from '@wordpress/api-fetch';
5 import { __, sprintf } from '@wordpress/i18n';
6 import { addQueryArgs } from '@wordpress/url';
7
8 const allowedHeaders = [
9 'header',
10 'header-with-center-nav-and-social',
11 'header-atlas-beacon',
12 'header-ember-harbor',
13 'header-catalina-skyline',
14 'header-ceadar-peak',
15 ];
16 const homeServicesHeaders = ['header-center-nav-with-phone'];
17 const allowedFooters = [
18 'footer',
19 'footer-social-icons',
20 'footer-with-center-logo-and-menu',
21 ];
22 const allowedFootersWithNav = [
23 'footer-with-nav',
24 'footer-with-center-logo-social-nav',
25 ];
26
27 export const updateOption = (option, value) =>
28 apiFetch({
29 path: '/extendify/v1/auto-launch/options',
30 method: 'POST',
31 data: { option, value },
32 });
33 export const getOption = (option) =>
34 apiFetch({
35 path: addQueryArgs(`/extendify/v1/auto-launch/options`, { option }),
36 });
37
38 export const getPageById = (id) => {
39 try {
40 return apiFetch({ path: `/wp/v2/pages/${id}` });
41 } catch {
42 return null;
43 }
44 };
45
46 const getTemplateParts = () => apiFetch({ path: '/wp/v2/template-parts' });
47
48 export const getHeadersAndFooters = async ({
49 useNavFooter = false,
50 siteProfile = {},
51 } = {}) => {
52 const patterns = await getTemplateParts();
53 const extendablePatterns = patterns.filter(
54 ({ theme }) => theme === 'extendable',
55 );
56 const headerSlugs =
57 siteProfile.type === 'home services' ? homeServicesHeaders : allowedHeaders;
58 const headers = extendablePatterns?.filter(({ slug }) =>
59 headerSlugs.includes(slug),
60 );
61
62 const footerNav =
63 useNavFooter &&
64 patterns?.some(({ slug }) => allowedFootersWithNav.includes(slug));
65 const footerSlugsToUse = footerNav ? allowedFootersWithNav : allowedFooters;
66
67 const footers = extendablePatterns.filter(({ slug }) =>
68 footerSlugsToUse.includes(slug),
69 );
70 return { headers, footers };
71 };
72
73 export const uploadMedia = (formData) =>
74 apiFetch({ path: 'wp/v2/media', body: formData, method: 'POST' });
75
76 export const importImage = async (imageUrl, metadata) => {
77 try {
78 const loadImage = (img) => {
79 return new Promise((resolve, reject) => {
80 img.onload = () => resolve();
81 img.onerror = () => reject(new Error('Failed to load image.'));
82 });
83 };
84
85 const image = new Image();
86 image.src = imageUrl;
87 image.crossOrigin = 'anonymous';
88 await loadImage(image);
89
90 const canvas = document.createElement('canvas');
91 canvas.width = image.width;
92 canvas.height = image.height;
93
94 const ctx = canvas.getContext('2d');
95 if (!ctx) return null; // Fail silently
96
97 ctx.drawImage(image, 0, 0);
98
99 const blob = await new Promise((resolve, reject) => {
100 canvas.toBlob((blob) => {
101 if (blob) resolve(blob);
102 else reject(new Error('Failed to convert canvas to Blob.'));
103 }, 'image/jpeg');
104 });
105
106 const formData = new FormData();
107 formData.append(
108 'file',
109 new File([blob], metadata.filename, { type: 'image/jpeg' }),
110 );
111 formData.append('alt_text', metadata.alt || '');
112 formData.append('caption', metadata.caption || '');
113 formData.append('status', 'publish');
114
115 return await uploadMedia(formData);
116 } catch (_error) {
117 // Fail silently, return null
118 return null;
119 }
120 };
121
122 export const createPost = (data) =>
123 apiFetch({ path: '/wp/v2/posts', method: 'POST', data });
124
125 export const createTag = (data) =>
126 apiFetch({ path: '/wp/v2/tags', method: 'POST', data });
127
128 export const createCategory = (data) =>
129 apiFetch({ path: '/wp/v2/categories', method: 'POST', data });
130
131 export const createBlogSampleData = async (siteStrings, siteImages) => {
132 const localizedBlogSampleData =
133 blogSampleData[window.extSharedData?.wpLanguage || 'en_US'] ||
134 blogSampleData.en_US;
135
136 const categories =
137 (await createWpCategories(localizedBlogSampleData.categories)) || [];
138 const tags = (await createWpTags(localizedBlogSampleData.tags)) || [];
139 const formatImageUrl = (image) =>
140 image?.includes('?q=80&w=1470') ? image : `${image}?q=80&w=1470`;
141 const imagesArray = (siteImages || []).sort(() => Math.random() - 0.5);
142
143 const replacePostContentImages = (content, images) =>
144 (content.match(/https:\/\/images\.unsplash\.com\/[^\s"]+/g) || []).reduce(
145 (updated, match, i) =>
146 updated.replace(match, formatImageUrl(images[i] || match)),
147 content,
148 );
149
150 const posts = Array.from({ length: 8 }, (_, i) => {
151 const title =
152 siteStrings?.aiBlogTitles?.[i] ||
153 // translators: %s is a post number
154 sprintf(__('Blog Post %s', 'extendify-local'), i + 1);
155 const featuredImage = imagesArray[i % imagesArray.length]
156 ? formatImageUrl(imagesArray[i % imagesArray.length])
157 : null;
158 return {
159 name: title,
160 featured_image: featuredImage,
161 post_content: replacePostContentImages(
162 localizedBlogSampleData.post_content,
163 imagesArray,
164 ),
165 };
166 });
167
168 for (const [index, post] of posts.entries()) {
169 try {
170 const mediaId = post.featured_image
171 ? (
172 await importImage(post.featured_image, {
173 alt: '',
174 filename: `featured-image-${index}.jpg`,
175 caption: '',
176 })
177 )?.id || null
178 : null;
179
180 const category = categories.length
181 ? categories[index % categories.length]?.id
182 : [];
183
184 const tagFeaturedPost =
185 index < 4
186 ? [tags.find((tag) => tag.slug === 'featured')?.id].filter(Boolean)
187 : [];
188
189 const postData = {
190 title: post.name,
191 content: post.post_content,
192 status: 'publish',
193 featured_media: mediaId || null,
194 categories: category,
195 tags: tagFeaturedPost,
196 meta: { made_with_extendify_launch: true },
197 };
198
199 await createPost(postData);
200 } catch (_error) {
201 // Fail silently
202 }
203 }
204 };
205
206 export const createWpCategories = async (categories) => {
207 const responses = [];
208 for (const category of categories) {
209 const categoryData = {
210 name: category.name,
211 slug: category.slug,
212 description: category.description,
213 };
214 let newCategory;
215 try {
216 newCategory = await createCategory(categoryData);
217 } catch (_e) {
218 // Fail silently
219 }
220 if (newCategory?.id && newCategory?.slug) {
221 responses.push({ id: newCategory.id, slug: newCategory.slug });
222 }
223 }
224 return responses;
225 };
226
227 export const createWpTags = async (tags) => {
228 const responses = [];
229 for (const tag of tags) {
230 const tagData = {
231 name: tag.name,
232 slug: tag.slug,
233 description: tag.description,
234 };
235 let newTag;
236 try {
237 newTag = await createTag(tagData);
238 } catch (_e) {
239 // Fail silently
240 }
241 if (newTag?.id && newTag?.slug) {
242 responses.push({ id: newTag.id, slug: newTag.slug });
243 }
244 }
245 return responses;
246 };
247