PluginProbe
Extendify / 3.0.6
Extendify v3.0.6
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.6, at src/AutoLaunch/functions/wp.js

260 lines 6.6 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 storeSiteImages = (siteImages) =>
39 apiFetch({
40 path: '/extendify/v1/shared/site-images',
41 method: 'POST',
42 data: { siteImages },
43 });
44
45 export const clearSiteImages = () =>
46 apiFetch({
47 path: '/extendify/v1/shared/site-images/clear',
48 method: 'POST',
49 });
50
51 export const getPageById = (id) => {
52 try {
53 return apiFetch({ path: `/wp/v2/pages/${id}` });
54 } catch {
55 return null;
56 }
57 };
58
59 const getTemplateParts = () => apiFetch({ path: '/wp/v2/template-parts' });
60
61 export const getHeadersAndFooters = async ({
62 useNavFooter = false,
63 siteProfile = {},
64 } = {}) => {
65 const patterns = await getTemplateParts();
66 const extendablePatterns = patterns.filter(
67 ({ theme }) => theme === 'extendable',
68 );
69 const headerSlugs =
70 siteProfile.type === 'home services' ? homeServicesHeaders : allowedHeaders;
71 const headers = extendablePatterns?.filter(({ slug }) =>
72 headerSlugs.includes(slug),
73 );
74
75 const footerNav =
76 useNavFooter &&
77 patterns?.some(({ slug }) => allowedFootersWithNav.includes(slug));
78 const footerSlugsToUse = footerNav ? allowedFootersWithNav : allowedFooters;
79
80 const footers = extendablePatterns.filter(({ slug }) =>
81 footerSlugsToUse.includes(slug),
82 );
83 return { headers, footers };
84 };
85
86 export const uploadMedia = (formData) =>
87 apiFetch({ path: 'wp/v2/media', body: formData, method: 'POST' });
88
89 export const importImage = async (imageUrl, metadata) => {
90 try {
91 const loadImage = (img) => {
92 return new Promise((resolve, reject) => {
93 img.onload = () => resolve();
94 img.onerror = () => reject(new Error('Failed to load image.'));
95 });
96 };
97
98 const image = new Image();
99 image.src = imageUrl;
100 image.crossOrigin = 'anonymous';
101 await loadImage(image);
102
103 const canvas = document.createElement('canvas');
104 canvas.width = image.width;
105 canvas.height = image.height;
106
107 const ctx = canvas.getContext('2d');
108 if (!ctx) return null; // Fail silently
109
110 ctx.drawImage(image, 0, 0);
111
112 const blob = await new Promise((resolve, reject) => {
113 canvas.toBlob((blob) => {
114 if (blob) resolve(blob);
115 else reject(new Error('Failed to convert canvas to Blob.'));
116 }, 'image/jpeg');
117 });
118
119 const formData = new FormData();
120 formData.append(
121 'file',
122 new File([blob], metadata.filename, { type: 'image/jpeg' }),
123 );
124 formData.append('alt_text', metadata.alt || '');
125 formData.append('caption', metadata.caption || '');
126 formData.append('status', 'publish');
127
128 return await uploadMedia(formData);
129 } catch (_error) {
130 // Fail silently, return null
131 return null;
132 }
133 };
134
135 export const createPost = (data) =>
136 apiFetch({ path: '/wp/v2/posts', method: 'POST', data });
137
138 export const createTag = (data) =>
139 apiFetch({ path: '/wp/v2/tags', method: 'POST', data });
140
141 export const createCategory = (data) =>
142 apiFetch({ path: '/wp/v2/categories', method: 'POST', data });
143
144 export const createBlogSampleData = async (siteStrings, siteImages) => {
145 const localizedBlogSampleData =
146 blogSampleData[window.extSharedData?.wpLanguage || 'en_US'] ||
147 blogSampleData.en_US;
148
149 const categories =
150 (await createWpCategories(localizedBlogSampleData.categories)) || [];
151 const tags = (await createWpTags(localizedBlogSampleData.tags)) || [];
152 const formatImageUrl = (image) =>
153 image?.includes('?q=80&w=1470') ? image : `${image}?q=80&w=1470`;
154 const imagesArray = (siteImages || []).sort(() => Math.random() - 0.5);
155
156 const replacePostContentImages = (content, images) =>
157 (content.match(/https:\/\/images\.unsplash\.com\/[^\s"]+/g) || []).reduce(
158 (updated, match, i) =>
159 updated.replace(match, formatImageUrl(images[i] || match)),
160 content,
161 );
162
163 const posts = Array.from({ length: 8 }, (_, i) => {
164 const title =
165 siteStrings?.aiBlogTitles?.[i] ||
166 // translators: %s is a post number
167 sprintf(__('Blog Post %s', 'extendify-local'), i + 1);
168 const featuredImage = imagesArray[i % imagesArray.length]
169 ? formatImageUrl(imagesArray[i % imagesArray.length])
170 : null;
171 return {
172 name: title,
173 featured_image: featuredImage,
174 post_content: replacePostContentImages(
175 localizedBlogSampleData.post_content,
176 imagesArray,
177 ),
178 };
179 });
180
181 for (const [index, post] of posts.entries()) {
182 try {
183 const mediaId = post.featured_image
184 ? (
185 await importImage(post.featured_image, {
186 alt: '',
187 filename: `featured-image-${index}.jpg`,
188 caption: '',
189 })
190 )?.id || null
191 : null;
192
193 const category = categories.length
194 ? categories[index % categories.length]?.id
195 : [];
196
197 const tagFeaturedPost =
198 index < 4
199 ? [tags.find((tag) => tag.slug === 'featured')?.id].filter(Boolean)
200 : [];
201
202 const postData = {
203 title: post.name,
204 content: post.post_content,
205 status: 'publish',
206 featured_media: mediaId || null,
207 categories: category,
208 tags: tagFeaturedPost,
209 meta: { made_with_extendify_launch: true },
210 };
211
212 await createPost(postData);
213 } catch (_error) {
214 // Fail silently
215 }
216 }
217 };
218
219 export const createWpCategories = async (categories) => {
220 const responses = [];
221 for (const category of categories) {
222 const categoryData = {
223 name: category.name,
224 slug: category.slug,
225 description: category.description,
226 };
227 let newCategory;
228 try {
229 newCategory = await createCategory(categoryData);
230 } catch (_e) {
231 // Fail silently
232 }
233 if (newCategory?.id && newCategory?.slug) {
234 responses.push({ id: newCategory.id, slug: newCategory.slug });
235 }
236 }
237 return responses;
238 };
239
240 export const createWpTags = async (tags) => {
241 const responses = [];
242 for (const tag of tags) {
243 const tagData = {
244 name: tag.name,
245 slug: tag.slug,
246 description: tag.description,
247 };
248 let newTag;
249 try {
250 newTag = await createTag(tagData);
251 } catch (_e) {
252 // Fail silently
253 }
254 if (newTag?.id && newTag?.slug) {
255 responses.push({ id: newTag.id, slug: newTag.slug });
256 }
257 }
258 return responses;
259 };
260