PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.1
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.1
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
metasync / views / js / metasync-import-external-data.js

metasync-import-external-data.js in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.7.1, at views/js/metasync-import-external-data.js

286 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* global metasyncImportData, jQuery, ajaxurl */
2 /**
3 * MetaSync Import External Data
4 *
5 * Extracted for Phase 5, #887.
6 * Handles importing external plugin data (redirections, SEO metadata)
7 * with batch progress tracking for SEO metadata imports.
8 *
9 * Localized object: metasyncImportData
10 * - importNonce (string) Nonce for metasync_import_external_data
11 * - seoImportNonce (string) Nonce for metasync_import_seo_metadata
12 *
13 * @since Phase 5
14 */
15 jQuery(document).ready(function ($) {
16 var importNonce = metasyncImportData.importNonce;
17 var seoImportNonce = metasyncImportData.seoImportNonce;
18 var currentImportData = null;
19
20 // Handle import button clicks
21 $('.metasync-import-btn').on('click', function () {
22 var btn = $(this);
23 var type = btn.data('type');
24 var plugin = btn.data('plugin');
25 var card = btn.closest('.metasync-plugin-card');
26
27 // Special handling for SEO metadata - show options modal
28 if (type === 'seo_metadata') {
29 currentImportData = {
30 btn: btn,
31 type: type,
32 plugin: plugin,
33 card: card
34 };
35 $('#metasync-seo-options-modal').addClass('active');
36 return;
37 }
38
39 // Indexation imports are batched to avoid PHP memory exhaustion on large sites
40 if (type === 'indexation') {
41 performIndexationImport(btn, type, plugin, card);
42 return;
43 }
44
45 // For other import types, proceed directly
46 performImport(btn, type, plugin, card);
47 });
48
49 // Modal close handlers
50 $('.metasync-modal-close, #modal-cancel').on('click', function () {
51 $('#metasync-seo-options-modal').removeClass('active');
52 $('.metasync-progress-container').removeClass('active');
53 $('.metasync-progress-fill').css('width', '0%');
54 $('.metasync-progress-text').text('0%');
55 $('.metasync-progress-status').text('');
56 currentImportData = null;
57 });
58
59 // Click outside modal to close
60 $('.metasync-modal-overlay').on('click', function (e) {
61 if (e.target === this) {
62 $(this).find('.metasync-modal-close').click();
63 }
64 });
65
66 // Start Import button in modal
67 $('#modal-start-import').on('click', function () {
68 if (!currentImportData) {
69 return;
70 }
71
72 var options = {
73 import_titles: $('#import-titles').is(':checked'),
74 import_descriptions: $('#import-descriptions').is(':checked'),
75 import_social_text: $('#import-social-text').is(':checked'),
76 import_social_images: $('#import-social-images').is(':checked'),
77 overwrite_existing: $('#overwrite-existing').is(':checked')
78 };
79
80 // Disable form elements
81 $('#modal-start-import, #modal-cancel, #import-titles, #import-descriptions, #import-social-text, #import-social-images, #overwrite-existing')
82 .prop('disabled', true);
83
84 // Show progress
85 $('.metasync-progress-container').addClass('active');
86
87 // Start batch import
88 performBatchImport(currentImportData, options);
89 });
90
91 // Perform direct import (for non-SEO metadata types)
92 function performImport(btn, type, plugin, card) {
93 var resultDiv = card.find('.metasync-import-result');
94
95 btn.prop('disabled', true).text('Importing...');
96 resultDiv.removeClass('success error').hide();
97
98 $.ajax({
99 url: ajaxurl,
100 type: 'POST',
101 data: {
102 action: 'metasync_import_external_data',
103 nonce: importNonce,
104 type: type,
105 plugin: plugin
106 },
107 success: function (response) {
108 if (response.success) {
109 btn.addClass('success').text('\u2713 Imported');
110 resultDiv.addClass('success').text(response.data.message).slideDown();
111 } else {
112 btn.prop('disabled', false).text('Import ' + type.charAt(0).toUpperCase() + type.slice(1));
113 resultDiv.addClass('error').text(response.data.message || 'Import failed.').slideDown();
114 }
115 },
116 error: function () {
117 btn.prop('disabled', false).text('Retry Import');
118 resultDiv.addClass('error').text('Network error. Please try again.').slideDown();
119 }
120 });
121 }
122
123 // Perform batched indexation import with progress tracking
124 function performIndexationImport(btn, type, plugin, card) {
125 var resultDiv = card.find('.metasync-import-result');
126 var progressContainer = card.find('.metasync-progress-container');
127 var progressFill = card.find('.metasync-progress-fill');
128 var progressText = card.find('.metasync-progress-text');
129 var offset = 0;
130 var totalImported = 0;
131 var totalSkipped = 0;
132
133 btn.prop('disabled', true).text('Importing...');
134 resultDiv.removeClass('success error').hide();
135 progressFill.css('width', '0%');
136 progressText.text('0%');
137 progressContainer.addClass('active');
138
139 function processBatch() {
140 $.ajax({
141 url: ajaxurl,
142 type: 'POST',
143 data: {
144 action: 'metasync_import_external_data',
145 nonce: importNonce,
146 type: type,
147 plugin: plugin,
148 offset: offset
149 },
150 success: function (response) {
151 if (response.success && response.data) {
152 var data = response.data;
153 totalImported += data.imported || 0;
154 totalSkipped += data.skipped || 0;
155
156 var percent = data.progress_percent || 0;
157 progressFill.css('width', percent + '%');
158 progressText.text(percent + '%');
159
160 resultDiv.removeClass('error').addClass('success')
161 .text('Processing... ' + (data.processed || 0).toLocaleString() + ' of ' + (data.total || 0).toLocaleString() + ' posts')
162 .show();
163
164 if (data.is_complete) {
165 progressFill.css('width', '100%');
166 progressText.text('100%');
167 btn.addClass('success').text('✓ Imported');
168 resultDiv.text('✓ Import Complete! Imported: ' + totalImported.toLocaleString() + ' | Skipped: ' + totalSkipped.toLocaleString());
169 } else {
170 offset = data.processed || 0;
171 processBatch();
172 }
173 } else {
174 btn.prop('disabled', false).text('Retry Import');
175 progressContainer.removeClass('active');
176 var errMsg = (response.data && response.data.message) ? response.data.message : 'Import failed.';
177 resultDiv.removeClass('success').addClass('error').text(errMsg).show();
178 }
179 },
180 error: function () {
181 btn.prop('disabled', false).text('Retry Import');
182 progressContainer.removeClass('active');
183 resultDiv.removeClass('success').addClass('error').text('Network error. Please try again.').show();
184 }
185 });
186 }
187
188 processBatch();
189 }
190
191 // Perform batch import with progress tracking (for SEO metadata)
192 function performBatchImport(importData, options) {
193 var offset = 0;
194 var totalImported = 0;
195 var totalSkipped = 0;
196 var totalUnresolved = 0;
197
198 function processBatch() {
199 $.ajax({
200 url: ajaxurl,
201 type: 'POST',
202 data: {
203 action: 'metasync_import_seo_metadata',
204 nonce: seoImportNonce,
205 plugin: importData.plugin,
206 import_titles: options.import_titles ? 1 : 0,
207 import_descriptions: options.import_descriptions ? 1 : 0,
208 import_social_text: options.import_social_text ? 1 : 0,
209 import_social_images: options.import_social_images ? 1 : 0,
210 overwrite_existing: options.overwrite_existing ? 1 : 0,
211 offset: offset
212 },
213 success: function (response) {
214 if (response.success && response.data) {
215 var data = response.data;
216 totalImported += data.imported || 0;
217 totalSkipped += data.skipped || 0;
218 // Accumulate across batches — a single batch's count is
219 // not the whole import.
220 totalUnresolved += data.unresolved || 0;
221
222 // Update progress bar
223 var percent = data.progress_percent || 0;
224 $('.metasync-progress-fill').css('width', percent + '%');
225 $('.metasync-progress-text').text(percent + '%');
226 $('.metasync-progress-status').text(
227 'Processing... ' + (data.processed || 0) + ' of ' + (data.total || 0) + ' posts'
228 );
229
230 if (data.is_complete) {
231 // Import complete
232 var $seoStatus = $('.metasync-progress-status').empty()
233 .append($('<strong>').css('color', 'var(--dashboard-success)').text('\u2713 Import Complete!'))
234 .append(document.createTextNode(' Imported: ' + totalImported + ' posts | Skipped: ' + totalSkipped + ' posts'));
235
236 importData.btn.addClass('success').text('\u2713 Imported');
237
238 if (totalUnresolved > 0) {
239 $seoStatus.append(
240 $('<div>')
241 .css({ 'color': 'var(--dashboard-warning)', 'margin-top': '8px' })
242 .text('\u26a0 ' + totalUnresolved + ' value(s) skipped because placeholders could not be resolved.')
243 );
244 // Leave the modal open so the warning is actually
245 // read rather than auto-dismissed after 2s.
246 $('#modal-start-import, #modal-cancel, #import-titles, #import-descriptions, #import-social-text, #import-social-images, #overwrite-existing')
247 .prop('disabled', false);
248 } else {
249 // Close modal after 2 seconds
250 setTimeout(function () {
251 $('#metasync-seo-options-modal .metasync-modal-close').click();
252 // Re-enable button for future imports
253 $('#modal-start-import, #modal-cancel, #import-titles, #import-descriptions, #import-social-text, #import-social-images, #overwrite-existing')
254 .prop('disabled', false);
255 }, 2000);
256 }
257 } else {
258 // Continue with next batch
259 offset = data.processed || 0;
260 processBatch();
261 }
262 } else {
263 // Error occurred
264 var importErrMsg = (response.data && response.data.message ? response.data.message : 'Unknown error occurred');
265 var $importStatus = $('.metasync-progress-status').empty();
266 $importStatus.append($('<strong>').css('color', 'var(--dashboard-error)').text('\u2717 Import Failed'));
267 $importStatus[0].appendChild(document.createTextNode(' ' + importErrMsg));
268 $('#modal-start-import, #modal-cancel, #import-titles, #import-descriptions, #import-social-text, #import-social-images, #overwrite-existing')
269 .prop('disabled', false);
270 }
271 },
272 error: function () {
273 $('.metasync-progress-status').empty()
274 .append($('<strong>').css('color', 'var(--dashboard-error)').text('\u2717 Network Error'))
275 .append(document.createTextNode(' Please try again'));
276 $('#modal-start-import, #modal-cancel, #import-titles, #import-descriptions, #import-social-text, #import-social-images, #overwrite-existing')
277 .prop('disabled', false);
278 }
279 });
280 }
281
282 // Start first batch
283 processBatch();
284 }
285 });
286