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 / AutoLaunch / functions / wp.js

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

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