PluginProbe
AI Builder – Generate pages, blocks, images & translate with AI / 2.7.10
AI Builder – Generate pages, blocks, images & translate with AI v2.7.10
2.8.0 2.7.10 2.7.9 2.7.8 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 All 123 releases
← All changes | assets/js/multi-page-apply.js +123 -22 2.1.9 → 2.7.10 View file →
@@ -6,15 +6,15 @@
6 6
7 7 // Wait for Gutenberg editor readiness
8 8 await (async function waitForEditorReady() {
9 9 const start = Date.now();
10 - const timeoutMs = 15000;
10 + const timeoutMs = 40000; // Increased to 40 seconds for slower servers
11 11 while (Date.now() - start < timeoutMs) {
12 12 if (window.wp && wp.blocks && wp.data && wp.data.select('core/block-editor')) {
13 13 const dispatcher = wp.data.dispatch('core/block-editor');
14 14 if (dispatcher && typeof dispatcher.insertBlocks === 'function') break;
15 15 }
16 - await new Promise(r => setTimeout(r, 200));
16 + await new Promise(r => setTimeout(r, 300)); // Increased check interval from 200ms to 300ms
17 17 }
18 18 })();
19 19 if (!window.wp || !wp.blocks || !wp.data) return;
20 20
@@ -33,17 +33,32 @@
33 33 if (!closeBtn && dialog) {
34 34 const evt = new KeyboardEvent('keydown', { key: 'Escape', keyCode: 27, which: 27, bubbles: true });
35 35 document.dispatchEvent(evt);
36 36 }
37 - }, 200);
37 + }, 500); // Increased from 200ms to 500ms for slower servers
38 38 } catch (e) { }
39 39
40 - // Fetch generation by ID
40 + // Fetch generation by ID with timeout
41 + let timeoutId;
42 + const controller = new AbortController();
43 + timeoutId = setTimeout(() => controller.abort(), 20000); // 20 second timeout
44 +
41 45 const res = await fetch(aiBuilderVars.ajaxurl, {
42 46 method: 'POST',
43 47 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
44 48 body: `action=aibui_get_generation&nonce=${aiBuilderVars.nonce}&id=${encodeURIComponent(genId)}`,
49 + signal: controller.signal,
45 50 });
51 +
52 + clearTimeout(timeoutId);
53 +
54 + if (!res.ok) {
55 + if (res.status === 500) {
56 + console.error('Server error while loading generation');
57 + }
58 + return;
59 + }
60 +
46 61 const data = await res.json();
47 62 if (!data.success) return;
48 63
49 64 const gen = data.data;
@@ -108,51 +123,132 @@
108 123 `;
109 124 document.head.appendChild(style);
110 125 }
111 126
112 - // Save CSS/meta through existing chat-widget helpers if available
113 - async function saveMetaAndCss() {
114 - try {
115 - if (gen.cssContent && typeof saveCSSInPostMeta === 'function' && typeof loadCSSFromPostMeta === 'function') {
116 - await saveCSSInPostMeta(gen.cssContent, 'page');
117 - await loadCSSFromPostMeta();
118 - }
119 - if (gen.metaDesc && typeof setMetaDescriptionField === 'function') {
120 - await setMetaDescriptionField(gen.metaDesc);
121 - }
122 - } catch (e) {
123 - // Silent fail
124 - }
127 + // Apply meta description field in the editor (DOM-based, no post ID needed)
128 + if (gen.metaDesc && typeof setMetaDescriptionField === 'function') {
129 + try { await setMetaDescriptionField(gen.metaDesc); } catch (e) { }
125 130 }
126 - await saveMetaAndCss();
127 131
128 - // Auto-save the post (leave as draft by default)
132 + // Auto-save the post so the post ID is assigned before saving post meta
129 133 try {
130 134 await wp.data.dispatch('core/editor').savePost();
131 135 } catch (e) { }
132 136
137 + // Save CSS/JS directly to post meta via AJAX (same meta keys as chat widget)
138 + async function savePostMeta(postId) {
139 + const ajaxUrl = aiBuilderVars.ajaxurl;
140 + const nonce = aiBuilderVars.nonce;
141 +
142 + if (gen.cssContent) {
143 + try {
144 + const formData = new URLSearchParams();
145 + formData.append('action', 'aibui_save_post_css');
146 + formData.append('nonce', nonce);
147 + formData.append('post_id', postId);
148 + formData.append('css_content', gen.cssContent);
149 + formData.append('css_type', 'page');
150 + await fetch(ajaxUrl, {
151 + method: 'POST',
152 + headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
153 + body: formData.toString(),
154 + });
155 + } catch (e) {
156 + console.error('AI Builder: failed to save CSS to post meta', e);
157 + }
158 + }
159 +
160 + if (gen.jsContent) {
161 + try {
162 + const formData = new URLSearchParams();
163 + formData.append('action', 'aibui_save_post_js');
164 + formData.append('nonce', nonce);
165 + formData.append('post_id', postId);
166 + formData.append('js_content', gen.jsContent);
167 + formData.append('js_type', 'page');
168 + await fetch(ajaxUrl, {
169 + method: 'POST',
170 + headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
171 + body: formData.toString(),
172 + });
173 + } catch (e) {
174 + console.error('AI Builder: failed to save JS to post meta', e);
175 + }
176 + }
177 + }
178 +
133 179 // Mark generation as applied (attach pageId if available)
134 180 const postId = (wp.data.select('core/editor').getCurrentPostId && wp.data.select('core/editor').getCurrentPostId()) || 0;
181 +
182 + // Save CSS/JS to post meta now that the post ID is known
183 + if (postId) {
184 + await savePostMeta(postId);
185 +
186 + // Inject CSS into editor DOM so it's visible immediately
187 + if (gen.cssContent) {
188 + const styleId = 'ai-builder-editor-css';
189 + let styleEl = document.getElementById(styleId);
190 + if (!styleEl) {
191 + styleEl = document.createElement('style');
192 + styleEl.id = styleId;
193 + styleEl.type = 'text/css';
194 + document.head.appendChild(styleEl);
195 + }
196 + styleEl.textContent = gen.cssContent;
197 + }
198 +
199 + // Inject JS into editor DOM so it runs immediately
200 + if (gen.jsContent) {
201 + const scriptId = 'ai-builder-editor-js';
202 + let scriptEl = document.getElementById(scriptId);
203 + if (!scriptEl) {
204 + scriptEl = document.createElement('script');
205 + scriptEl.id = scriptId;
206 + scriptEl.type = 'text/javascript';
207 + document.head.appendChild(scriptEl);
208 + }
209 + scriptEl.textContent = gen.jsContent;
210 + }
211 + }
135 212 try {
213 + const markController = new AbortController();
214 + const markTimeoutId = setTimeout(() => markController.abort(), 20000); // 20 second timeout
215 +
136 216 await fetch(aiBuilderVars.ajaxurl, {
137 217 method: 'POST',
138 218 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
139 219 body: `action=aibui_mark_generation_applied&nonce=${aiBuilderVars.nonce}&id=${encodeURIComponent(genId)}&page_id=${encodeURIComponent(postId)}`,
220 + signal: markController.signal,
140 221 });
141 - } catch (e) { }
142 222
223 + clearTimeout(markTimeoutId);
224 + } catch (e) {
225 + if (e.name !== 'AbortError') {
226 + console.error('Error marking generation as applied:', e);
227 + }
228 + }
229 +
143 230 // Mark page as created via AI
144 231 if (postId) {
145 232 try {
233 + const markAiController = new AbortController();
234 + const markAiTimeoutId = setTimeout(() => markAiController.abort(), 20000); // 20 second timeout
235 +
146 236 await fetch(aiBuilderVars.ajaxurl, {
147 237 method: 'POST',
148 238 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
149 239 body: `action=aibui_mark_ai_created&nonce=${aiBuilderVars.nonce}&post_id=${encodeURIComponent(postId)}`,
240 + signal: markAiController.signal,
150 241 });
242 +
243 + clearTimeout(markAiTimeoutId);
244 +
151 245 // Injecter le CSS admin immédiatement
152 246 injectAICreatedAdminCSS();
153 247 } catch (e) {
154 - console.error('Error marking page as AI-created:', e);
248 + if (e.name !== 'AbortError') {
249 + console.error('Error marking page as AI-created:', e);
250 + }
155 251 }
156 252 }
157 253
158 254 // Clean URL param to avoid reapplying on refresh
@@ -159,9 +255,14 @@
159 255 const url = new URL(window.location.href);
160 256 url.searchParams.delete('aibui_gen_id');
161 257 window.history.replaceState({}, '', url.toString());
162 258 } catch (e) {
163 - // Silent
259 + // Handle timeout/abort errors
260 + if (e.name === 'AbortError' || e.message?.includes('timeout')) {
261 + console.error('Timeout error while applying generation:', e);
262 + } else {
263 + console.error('Error applying generation:', e);
264 + }
164 265 }
165 266 });
166 267
167 268