PluginProbe
Extendify / 3.2.2
Extendify v3.2.2
3.2.2 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 All 128 releases
← All changes | src/Shared/api/wp.js +70 -5 3.0.6 → 3.2.2 View file →
@@ -1,6 +1,8 @@
1 1 import { AI_HOST } from '@constants';
2 +import { renderAiLabelPill, stampAiLabel } from '@shared/lib/ai-label';
2 3 import apiFetch from '@wordpress/api-fetch';
4 +import { sprintf } from '@wordpress/i18n';
3 5 import { addQueryArgs } from '@wordpress/url';
4 6
5 7 export const getPlugin = async (slug) => {
6 8 const response = await apiFetch({
@@ -25,10 +27,23 @@
25 27
26 28 return response;
27 29 };
28 30
31 +export const enableAutoUpdate = async (plugin) => {
32 + if (!plugin) return;
33 + try {
34 + await apiFetch({
35 + path: '/extendify/v1/shared/enable-auto-update',
36 + method: 'POST',
37 + data: { plugin },
38 + });
39 + } catch (_e) {
40 + // Best-effort: the install already succeeded.
41 + }
42 +};
43 +
29 44 export const installPlugin = async (slug) => {
30 - return await apiFetch({
45 + const plugin = await apiFetch({
31 46 path: '/wp/v2/plugins',
32 47 method: 'POST',
33 48 data: {
34 49 slug,
@@ -33,8 +48,12 @@
33 48 data: {
34 49 slug,
35 50 },
36 51 });
52 +
53 + await enableAutoUpdate(plugin?.plugin);
54 +
55 + return plugin;
37 56 };
38 57
39 58 export const activatePlugin = async (slug) => {
40 59 const plugin = await getPlugin(slug);
@@ -54,8 +73,18 @@
54 73 img.onerror = (e) => reject(e);
55 74 });
56 75 };
57 76
77 +const shouldDisclose = (metadata) =>
78 + Boolean(metadata.aiGenerated) && Boolean(metadata.disclose);
79 +
80 +const altText = (metadata) => {
81 + if (!shouldDisclose(metadata)) return metadata.alt ?? '';
82 + const pattern =
83 + window.extSharedData?.aiImageAltPattern ?? '%s (AI-generated)';
84 + return sprintf(pattern, metadata.alt ?? '').trim();
85 +};
86 +
58 87 export const importImage = async (imageUrl, metadata = {}) => {
59 88 const image = new Image();
60 89 image.src = imageUrl;
61 90 image.crossOrigin = 'anonymous';
@@ -67,8 +96,11 @@
67 96
68 97 const ctx = canvas.getContext('2d');
69 98 if (!ctx) return;
70 99 ctx.drawImage(image, 0, 0);
100 + if (shouldDisclose(metadata)) {
101 + stampAiLabel(ctx, canvas.width, canvas.height);
102 + }
71 103
72 104 const blob = await new Promise((resolve) => {
73 105 canvas.toBlob((blob) => {
74 106 blob && resolve(blob);
@@ -76,11 +108,14 @@
76 108 });
77 109
78 110 const formData = new FormData();
79 111 formData.append('file', new File([blob], metadata.filename));
80 - formData.append('alt_text', metadata.alt ?? '');
112 + formData.append('alt_text', altText(metadata));
81 113 formData.append('caption', metadata.caption ?? '');
82 114 formData.append('status', 'publish');
115 + if (metadata.aiGenerated) {
116 + formData.append('meta[extendify_ai_generated]', '1');
117 + }
83 118
84 119 return await apiFetch({
85 120 path: 'wp/v2/media',
86 121 method: 'POST',
@@ -91,10 +126,22 @@
91 126 export const importImageServer = async (src, metadata = {}) => {
92 127 const formData = new FormData();
93 128 formData.append('source', src);
94 129 // Fallback doesn't support custom file_name
95 - formData.append('alt_text', metadata.alt ?? '');
130 + formData.append('alt_text', altText(metadata));
96 131 formData.append('caption', metadata.caption ?? '');
132 + if (metadata.aiGenerated) {
133 + formData.append('ai_generated', '1');
134 + if (shouldDisclose(metadata)) {
135 + const pill = await renderAiLabelPill();
136 + if (pill) {
137 + formData.append(
138 + 'disclosure_label',
139 + new File([pill], 'disclosure-label.png', { type: 'image/png' }),
140 + );
141 + }
142 + }
143 + }
97 144
98 145 return await apiFetch({
99 146 path: '/extendify/v1/draft/upload-image',
100 147 method: 'POST',
@@ -109,22 +156,40 @@
109 156 unsplashId,
110 157 metadata = { alt: '', caption: '' },
111 158 ) => {
112 159 let image;
160 + const aiGenerated = source === 'ai-generated';
113 161 if (unsplashId) {
114 162 await downloadPing(id, source, { unsplashId });
163 + } else if (aiGenerated && id) {
164 + await downloadPing(id, source, { disclose: metadata.disclose });
115 165 }
166 +
167 + let filename = metadata.filename ?? 'image.jpg';
168 + if (aiGenerated && !filename.includes('ai-generated')) {
169 + const parts = filename.split('.');
170 + if (parts.length > 1) {
171 + const ext = parts.pop();
172 + filename = `${parts.join('.')}-ai-generated.${ext}`;
173 + } else {
174 + filename = `${filename}-ai-generated`;
175 + }
176 + }
177 +
116 178 try {
117 179 image = await importImage(src, {
118 180 alt: metadata.alt,
119 - filename: 'image.jpg',
181 + filename,
120 182 caption: metadata.caption,
183 + aiGenerated,
184 + disclose: metadata.disclose,
121 185 });
122 186 } catch (_e) {
123 187 image = await importImageServer(src, {
124 188 alt: metadata.alt,
125 - filename: 'image.jpg',
126 189 caption: metadata.caption,
190 + aiGenerated,
191 + disclose: metadata.disclose,
127 192 });
128 193 }
129 194
130 195 return image;