Changeset 3286404
- Timestamp:
- 05/02/2025 04:18:40 PM (11 months ago)
- Location:
- topirank-integration
- Files:
-
- 41 added
- 18 edited
-
tags/2.0 (added)
-
tags/2.0/admin (added)
-
tags/2.0/admin/admin-page.php (added)
-
tags/2.0/admin/batch-page.php (added)
-
tags/2.0/admin/menu.php (added)
-
tags/2.0/assets (added)
-
tags/2.0/assets/css (added)
-
tags/2.0/assets/css/batch-conflicts.css (added)
-
tags/2.0/assets/css/batch-process.css (added)
-
tags/2.0/assets/css/topirank-admin-style.css (added)
-
tags/2.0/assets/css/topirank-editor-style.css (added)
-
tags/2.0/assets/css/topirank-normalize.css (added)
-
tags/2.0/assets/css/topirank-post-admin-style.css (added)
-
tags/2.0/assets/js (added)
-
tags/2.0/assets/js/batch-conflicts.js (added)
-
tags/2.0/assets/js/batch-process.js (added)
-
tags/2.0/assets/js/topirank-admin-scripts.js (added)
-
tags/2.0/assets/js/topirank-normalize.js (added)
-
tags/2.0/includes (added)
-
tags/2.0/includes/api-integration.php (added)
-
tags/2.0/includes/batch-processing.php (added)
-
tags/2.0/includes/batch-processor.php (added)
-
tags/2.0/includes/class-topirank-integration.php (added)
-
tags/2.0/includes/create-template.php (added)
-
tags/2.0/includes/extract-and-create.php (added)
-
tags/2.0/includes/file-upload.php (added)
-
tags/2.0/includes/helpers.php (added)
-
tags/2.0/includes/init.php (added)
-
tags/2.0/includes/process-folders.php (added)
-
tags/2.0/includes/register-files.php (added)
-
tags/2.0/includes/resource-cleaner.php (added)
-
tags/2.0/includes/topirank-template.php (added)
-
tags/2.0/includes/update-content-and-seo.php (added)
-
tags/2.0/includes/update-functionality.php (added)
-
tags/2.0/includes/utils.php (added)
-
tags/2.0/languages (added)
-
tags/2.0/languages/topirank-integration-fr_FR.mo (added)
-
tags/2.0/languages/topirank-integration-fr_FR.po (added)
-
tags/2.0/languages/topirank-integration.pot (added)
-
tags/2.0/readme.txt (added)
-
tags/2.0/topirank-integration.php (added)
-
trunk/admin/admin-page.php (modified) (3 diffs)
-
trunk/admin/menu.php (modified) (2 diffs)
-
trunk/assets/js/topirank-admin-scripts.js (modified) (5 diffs)
-
trunk/includes/api-integration.php (modified) (8 diffs)
-
trunk/includes/extract-and-create.php (modified) (8 diffs)
-
trunk/includes/file-upload.php (modified) (7 diffs)
-
trunk/includes/helpers.php (modified) (3 diffs)
-
trunk/includes/init.php (modified) (2 diffs)
-
trunk/includes/process-folders.php (modified) (1 diff)
-
trunk/includes/register-files.php (modified) (2 diffs)
-
trunk/includes/topirank-template.php (modified) (1 diff)
-
trunk/includes/update-content-and-seo.php (modified) (7 diffs)
-
trunk/includes/update-functionality.php (modified) (2 diffs)
-
trunk/languages/topirank-integration-fr_FR.mo (modified) (previous)
-
trunk/languages/topirank-integration-fr_FR.po (modified) (2 diffs)
-
trunk/languages/topirank-integration.pot (modified) (3 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/topirank-integration.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
topirank-integration/trunk/admin/admin-page.php
r3234611 r3286404 19 19 <div id="notification" class="notification"></div> 20 20 <div class="topirank_wrap"> 21 <div class="topirank_main_content_line server_status_line"> 22 <div class="topirank_line_left_column"> 23 <div class="topirank_line_title"><?php esc_html_e('Server Status', 'topirank-integration'); ?></div> 24 </div> 25 <div class="topirank_line_right_column"> 26 <div class="server-status-container"> 27 <span class="server-status-indicator" id="server-status-indicator"></span> 28 <span class="server-status-text" id="server-status-text"></span> 29 </div> 30 </div> 31 </div> 32 21 33 <form method="POST" enctype="multipart/form-data" action="<?php echo esc_url(admin_url('admin.php?page=topirank_process_upload')); ?>"> 22 34 <div class="topirank_main_content_line first_line"> … … 38 50 39 51 </div> 52 40 53 </div> 41 54 … … 98 111 </div> 99 112 </div> 113 114 <script> 115 jQuery(document).ready(function($) { 116 function updateServerStatus() { 117 $.ajax({ 118 url: '<?php echo esc_url(rest_url('topirank-integration/ready')); ?>', 119 method: 'GET', 120 success: function(response) { 121 const isReady = response.ready; 122 const indicator = $('#server-status-indicator'); 123 const text = $('#server-status-text'); 124 const uploadBtn = $('.topirank_outline_button[type="submit"]'); 125 126 if (isReady) { 127 indicator.removeClass('not-ready').addClass('ready'); 128 text.text('<?php esc_html_e('Ready to upload', 'topirank-integration'); ?>'); 129 uploadBtn.prop('disabled', false); 130 } else { 131 indicator.removeClass('ready').addClass('not-ready'); 132 text.text('<?php esc_html_e('Server is busy', 'topirank-integration'); ?>'); 133 uploadBtn.prop('disabled', true); 134 } 135 }, 136 error: function() { 137 const indicator = $('#server-status-indicator'); 138 const text = $('#server-status-text'); 139 const uploadBtn = $('.topirank_outline_button[type="submit"]'); 140 141 indicator.removeClass('ready').addClass('not-ready'); 142 text.text('<?php esc_html_e('Server is busy', 'topirank-integration'); ?>'); 143 uploadBtn.prop('disabled', true); 144 } 145 }); 146 } 147 148 setInterval(updateServerStatus, 5000); 149 updateServerStatus(); 150 }); 151 </script> 152 153 <style> 154 .topirank_wrap .server-status-container { 155 display: flex; 156 align-items: center; 157 gap: 10px; 158 } 159 160 .topirank_wrap .server-status-indicator { 161 width: 12px; 162 height: 12px; 163 border-radius: 50%; 164 display: inline-block; 165 } 166 167 .topirank_wrap .server-status-indicator.ready { 168 background-color: #46b450; 169 } 170 171 .topirank_wrap .server-status-indicator.not-ready { 172 background-color: #dc3232; 173 } 174 175 .topirank_wrap .server-status-text { 176 font-weight: 500; 177 } 178 179 .topirank_wrap .button:disabled, 180 .topirank_wrap .topirank_solid_button:disabled, 181 .topirank_wrap .topirank_outline_button:disabled { 182 opacity: 0.7; 183 cursor: not-allowed; 184 } 185 </style> 100 186 <?php 101 187 } -
topirank-integration/trunk/admin/menu.php
r3220350 r3286404 18 18 19 19 add_action('admin_menu', function () { 20 // Hidden upload processing page 20 21 add_submenu_page( 21 22 null, … … 26 27 'topirank_render_process_upload_page' 27 28 ); 29 30 // Hidden batch processing page 31 add_submenu_page( 32 null, 33 ('Batch Processing'), 34 ('Batch Processing'), 35 'manage_options', 36 'topirank_batch_processing', 37 'topirank_render_batch_page' 38 ); 28 39 }); -
topirank-integration/trunk/assets/js/topirank-admin-scripts.js
r3237927 r3286404 1 1 document.addEventListener('DOMContentLoaded', function () { 2 // Helper function to make API requests 3 function makeApiRequest(url, method = 'GET', data = null) { 4 const headers = { 5 'X-WP-Nonce': topirank_ajax.nonce, 6 'Content-Type': 'application/json' 7 }; 8 9 const options = { 10 method: method, 11 headers: headers, 12 credentials: 'same-origin' 13 }; 14 15 if (data) { 16 options.body = JSON.stringify(data); 17 } 18 19 console.log('Making API request:', { 20 url: url, 21 method: method, 22 headers: headers, 23 data: data 24 }); 25 26 return fetch(url, options) 27 .then(response => { 28 console.log('API response:', response); 29 if (!response.ok) { 30 return response.json().then(errorData => { 31 console.error('API error:', errorData); 32 throw new Error(errorData.message || 'Network response was not ok'); 33 }); 34 } 35 return response.json(); 36 }) 37 .then(data => { 38 console.log('API success:', data); 39 return data; 40 }) 41 .catch(error => { 42 console.error('API request failed:', error); 43 throw error; 44 }); 45 } 46 2 47 document.querySelectorAll('.update-post').forEach(button => { 3 48 button.addEventListener('click', function () { … … 8 53 const selstyle = this.getAttribute('data-selstyle'); 9 54 10 const data = new FormData(); 11 data.append('action', 'topirank_handle_conflict'); 12 data.append('title', title); 13 data.append('file', file); 14 data.append('archive', archive); 15 data.append('replace', true); 16 data.append('selstyle', selstyle); 17 18 fetch(ajaxurl, { 19 method: 'POST', 20 body: data, 21 }) 22 .then(response => response.json()) 55 const data = { 56 title: title, 57 file: file, 58 archive: archive, 59 replace: true, 60 selstyle: selstyle 61 }; 62 63 makeApiRequest(topirank_ajax.resolve_conflicts_url, 'POST', data) 23 64 .then(result => { 24 65 if (result.success) { … … 27 68 parent.innerHTML = `<div class="error-message">${result.data.message}</div>`; 28 69 } 70 }) 71 .catch(error => { 72 console.error('Error:', error); 73 parent.innerHTML = `<div class="error-message">An error occurred: ${error.message}</div>`; 29 74 }); 30 75 }); … … 36 81 const title = this.getAttribute('data-title'); 37 82 38 const data = new FormData(); 39 data.append('action', 'topirank_handle_conflict'); 40 data.append('title', title); 41 data.append('replace', false); 42 43 fetch(ajaxurl, { 44 method: 'POST', 45 body: data, 46 }) 47 .then(response => response.json()) 83 const data = { 84 title: title, 85 replace: false 86 }; 87 88 makeApiRequest(topirank_ajax.resolve_conflicts_url, 'POST', data) 48 89 .then(result => { 49 90 if (result.success) { … … 52 93 parent.innerHTML = `<div class="error-message">${result.data.message}</div>`; 53 94 } 95 }) 96 .catch(error => { 97 console.error('Error:', error); 98 parent.innerHTML = `<div class="error-message">An error occurred: ${error.message}</div>`; 54 99 }); 55 100 }); -
topirank-integration/trunk/includes/api-integration.php
r3268778 r3286404 25 25 'methods' => 'GET', 26 26 'callback' => 'topirank_check_token_endpoint', 27 ]); 28 29 register_rest_route('topirank-integration', '/progress', [ 30 'methods' => 'GET', 31 'callback' => 'topirank_get_upload_progress', 32 'permission_callback' => 'topirank_plugin_check_token', 33 ]); 34 35 register_rest_route('topirank-integration', '/ready', [ 36 'methods' => 'GET', 37 'callback' => 'topirank_get_upload_status', 38 'permission_callback' => '__return_true', 39 ]); 40 41 register_rest_route('topirank-integration', '/reset', [ 42 'methods' => 'POST', 43 'callback' => 'topirank_hard_reset', 44 'permission_callback' => 'topirank_plugin_check_token', 27 45 ]); 28 46 } … … 93 111 } 94 112 113 function topirank_process_files_via_api($zip_path, $extracted_path, $selected_style, $selected_type) 114 { 115 try { 116 117 // Remove filters that might interfere with the process 118 remove_all_filters('wp_redirect'); 119 remove_all_filters('wp_safe_redirect'); 120 remove_filter('content_save_pre', 'wp_filter_post_kses'); 121 remove_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 122 remove_all_filters('the_content'); 123 remove_all_filters('the_editor_content'); 124 remove_all_filters('tiny_mce_before_init'); 125 126 // Get original archive name without extension 127 $archive_name = pathinfo($zip_path, PATHINFO_FILENAME); 128 129 130 // Check if there's an active batch 131 $processor = Topirank_Batch_Processor::get_instance(); 132 if ($processor->is_batch_active()) { 133 134 $processor->clear_batch_data(); 135 } 136 137 $zip = new ZipArchive; 138 if ($zip->open($zip_path) !== true) { 139 140 topirank_set_processing_status(false); 141 // Restore filters before returning 142 add_filter('content_save_pre', 'wp_filter_post_kses'); 143 add_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 144 return array( 145 'success' => false, 146 'message' => 'Failed to open ZIP archive' 147 ); 148 } 149 150 151 $zip->extractTo($extracted_path); 152 $zip->close(); 153 154 155 // Normalize file names and encoding 156 topirank_normalize_folder_names($extracted_path); 157 158 159 // Process files using the same logic as extract-and-create.php 160 $archive_name = topirank_process_extracted_files($extracted_path, $archive_name, $selected_style); 161 162 163 // Get list of HTML files 164 165 $files = array(); 166 $iterator = new RecursiveIteratorIterator( 167 new RecursiveDirectoryIterator($extracted_path, RecursiveDirectoryIterator::SKIP_DOTS), 168 RecursiveIteratorIterator::SELF_FIRST 169 ); 170 171 foreach ($iterator as $file) { 172 if ($file->isFile() && $file->getExtension() === 'html') { 173 // Process HTML file encoding 174 $content = file_get_contents($file->getPathname()); 175 if ($content !== false) { 176 // Convert to UTF-8 if needed 177 if (!mb_check_encoding($content, 'UTF-8')) { 178 $content = mb_convert_encoding($content, 'UTF-8'); 179 } 180 // Fix HTML entities 181 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8'); 182 // Save with UTF-8 encoding 183 file_put_contents($file->getPathname(), $content); 184 } 185 $files[] = $file->getPathname(); 186 } 187 } 188 189 if (!empty($files)) { 190 $processor = Topirank_Batch_Processor::get_instance(); 191 $replace = isset($request['replace']) && $request['replace'] === 'true'; 192 $processor->init_batch($files, $selected_style, $selected_type, $archive_name, $replace, true); 193 194 // Process all files in the batch 195 $results = array(); 196 $batch_count = 0; 197 198 // Process all batches until complete 199 while (!$processor->is_batch_complete()) { 200 $batch_count++; 201 202 $batch_result = $processor->process_next_batch(); 203 $results[] = $batch_result; 204 205 // Continue processing even if we have conflicts 206 if (!empty($batch_result['conflicts'])) { 207 error_log('Conflicts found in batch, continuing processing'); 208 } 209 } 210 211 // Final result when all batches are complete 212 $last_result = end($results); 213 214 // Restore filters before returning 215 add_filter('content_save_pre', 'wp_filter_post_kses'); 216 add_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 217 218 return array( 219 'success' => true, 220 'message' => 'All files processed successfully', 221 'current_batch' => $last_result['processed'], 222 'total_files' => $last_result['total'], 223 'completed' => true, 224 'conflicts' => $last_result['conflicts'], 225 'messages' => array_merge(...array_column($results, 'messages')) 226 ); 227 } 228 229 // Restore filters before returning 230 add_filter('content_save_pre', 'wp_filter_post_kses'); 231 add_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 232 233 return array( 234 'success' => false, 235 'message' => 'No HTML files found in the archive' 236 ); 237 } catch (Exception $e) { 238 error_log('Error in process_files_via_api: ' . $e->getMessage()); 239 topirank_set_processing_status(false); 240 // Restore filters before returning 241 add_filter('content_save_pre', 'wp_filter_post_kses'); 242 add_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 243 return array( 244 'success' => false, 245 'message' => 'Processing error: ' . $e->getMessage() 246 ); 247 } 248 } 249 95 250 function topirank_handle_rest_file_upload(WP_REST_Request $request) 96 251 { 97 98 252 /* phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing */ 99 253 100 254 $file = $_FILES['html_archive']; 255 256 if (!$file || $file['error'] !== UPLOAD_ERR_OK) { 257 topirank_set_processing_status(false); 258 return new WP_REST_Response(['message' => 'Error uploading chunk.'], 400); 259 } 101 260 102 261 $chunkIndex = intval($request->get_param('chunkIndex')); … … 107 266 $selected_type = isset($request['type']) ? sanitize_key($request['type']) : 'page'; 108 267 109 if (!$file || $file['error'] !== UPLOAD_ERR_OK) { 110 return new WP_REST_Response(['message' => 'Error uploading chunk.'], 400); 111 } 268 269 // Set processing status at the start of upload 270 if ($chunkIndex === 0) { 271 topirank_set_processing_status(true); 272 topirank_update_progress(0); 273 } 274 275 // Calculate progress based on chunks 276 $progress = floor(($chunkIndex + 1) / $totalChunks * 100); 277 topirank_update_progress($progress); 112 278 113 279 $upload_dir = wp_upload_dir(); 114 280 $base_temp_dir = $upload_dir['basedir'] . '/topirank-temp'; 115 116 281 $temp_dir = $base_temp_dir . '/' . md5($fileName); 117 118 282 119 283 if (!file_exists($temp_dir)) { … … 122 286 123 287 $temp_file_path = $temp_dir . '/' . $fileName . '.part'; 124 125 288 $handle = fopen($temp_file_path, 'ab'); 289 126 290 if (!$handle) { 291 topirank_set_processing_status(false); 292 error_log('Failed to open temp file: ' . $temp_file_path); 127 293 return new WP_REST_Response(['message' => 'Error opening temp file.'], 500); 128 294 } … … 140 306 141 307 if (!rename($temp_file_path, $final_path)) { 308 topirank_set_processing_status(false); 309 error_log('Failed to move temp file to final location: ' . $final_path); 142 310 return new WP_REST_Response(['message' => 'Failed to finalize file upload.'], 500); 143 311 } … … 145 313 $file_extension = pathinfo($final_path, PATHINFO_EXTENSION); 146 314 if ($file_extension !== 'zip') { 315 topirank_set_processing_status(false); 316 error_log('Invalid file extension: ' . $file_extension); 147 317 return new WP_REST_Response(['message' => 'Please upload a ZIP archive.'], 400); 148 318 } … … 151 321 if (!file_exists($topirank_dir)) { 152 322 wp_mkdir_p($topirank_dir); 323 error_log('Created topirank directory: ' . $topirank_dir); 153 324 } 154 325 155 326 $extracted_path = $topirank_dir . '/' . basename($final_path, '.zip'); 156 327 157 if (!function_exists('wp_handle_upload')) { 158 require_once ABSPATH . 'wp-admin/includes/file.php'; 159 } 160 161 remove_filter('content_save_pre', 'wp_filter_post_kses'); 162 remove_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 163 ob_start(); 164 $process_result = topirank_extract_and_create_posts($final_path, $extracted_path, $replace, $selected_style, $selected_type); 165 ob_end_clean(); 166 add_filter('content_save_pre', 'wp_filter_post_kses'); 167 add_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 168 169 if ($process_result) { 170 wp_delete_file($final_path); 171 topirank_recursive_delete($extracted_path); 172 } else { 173 return new WP_REST_Response(['message' => 'Failed to process the uploaded file.'], 500); 174 } 175 328 // Clean up temporary directory 176 329 $files = glob($temp_dir . '/*'); 177 330 foreach ($files as $file) { … … 182 335 rmdir($temp_dir); 183 336 184 return new WP_REST_Response(['message' => 'The file has been successfully uploaded and processed.'], 201); 337 // Remove filters that might interfere with the process 338 remove_all_filters('wp_redirect'); 339 remove_all_filters('wp_safe_redirect'); 340 remove_filter('content_save_pre', 'wp_filter_post_kses'); 341 remove_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 342 remove_all_filters('the_content'); 343 remove_all_filters('the_editor_content'); 344 remove_all_filters('tiny_mce_before_init'); 345 346 try { 347 error_log('Starting file unpacking'); 348 349 // Extract the zip file 350 $zip = new ZipArchive; 351 if ($zip->open($final_path) !== true) { 352 error_log('Failed to open ZIP archive: ' . $final_path); 353 topirank_set_processing_status(false); 354 return new WP_REST_Response(['message' => 'Failed to open ZIP archive'], 500); 355 } 356 357 $zip->extractTo($extracted_path); 358 $zip->close(); 359 error_log('Zip extraction completed'); 360 361 // Get original archive name without extension and remove --(N) suffix if present 362 $archive_name = pathinfo($final_path, PATHINFO_FILENAME); 363 $archive_name = preg_replace('/--\(\d+\)$/', '', $archive_name); 364 error_log('Base archive name: ' . $archive_name); 365 366 // Normalize file names and encoding 367 topirank_normalize_folder_names($extracted_path); 368 369 // Process files using the same logic as extract-and-create.php 370 $archive_name = topirank_process_extracted_files($extracted_path, $archive_name, $selected_style); 371 error_log('Files processed with archive name: ' . $archive_name); 372 373 // Get list of HTML files 374 $files = array(); 375 $iterator = new RecursiveIteratorIterator( 376 new RecursiveDirectoryIterator($extracted_path, RecursiveDirectoryIterator::SKIP_DOTS), 377 RecursiveIteratorIterator::SELF_FIRST 378 ); 379 380 foreach ($iterator as $file) { 381 if ($file->isFile() && $file->getExtension() === 'html') { 382 $files[] = $file->getPathname(); 383 } 384 } 385 error_log('Found ' . count($files) . ' HTML files'); 386 387 if (!empty($files)) { 388 // Initialize batch processing 389 $processor = Topirank_Batch_Processor::get_instance(); 390 if ($processor->is_batch_active()) { 391 $processor->clear_batch_data(); 392 } 393 394 $processor->init_batch($files, $selected_style, $selected_type, $archive_name, $replace, true); 395 error_log('Batch processing initialized with ' . count($files) . ' files'); 396 397 $batch_size = 5; 398 $total_batches = ceil(count($files) / $batch_size); 399 400 // Save processing data 401 $processing_data = array( 402 'final_path' => $final_path, 403 'extracted_path' => $extracted_path, 404 'selected_style' => $selected_style, 405 'selected_type' => $selected_type, 406 'archive_name' => $archive_name, 407 'files' => $files, 408 'current_batch' => 0, 409 'total_batches' => $total_batches, 410 'total_files' => count($files), 411 'batch_size' => $batch_size 412 ); 413 update_option('topirank_processing_data', $processing_data); 414 error_log('Processing data saved'); 415 416 // Restore filters 417 add_filter('content_save_pre', 'wp_filter_post_kses'); 418 add_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 419 420 return new WP_REST_Response([ 421 'message' => 'File uploaded and unpacked successfully', 422 'status' => 'unpacked', 423 'total_files' => count($files), 424 'total_batches' => $total_batches, 425 'batch_size' => $batch_size 426 ], 201); 427 } else { 428 error_log('No HTML files found in archive'); 429 return new WP_REST_Response(['message' => 'No HTML files found'], 404); 430 } 431 } catch (Exception $e) { 432 error_log('Error during unpacking: ' . $e->getMessage()); 433 topirank_set_processing_status(false); 434 // Restore filters before returning 435 add_filter('content_save_pre', 'wp_filter_post_kses'); 436 add_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 437 return new WP_REST_Response(['message' => 'Unpacking error: ' . $e->getMessage()], 500); 438 } 185 439 } 186 440 187 441 return new WP_REST_Response(['message' => 'Chunk uploaded successfully.'], 200); 188 442 } 443 444 // Add endpoint for processing next batch 445 add_action('rest_api_init', function () { 446 register_rest_route('topirank-integration', '/process-batch', array( 447 'methods' => 'POST', 448 'callback' => 'topirank_process_next_batch', 449 'permission_callback' => 'topirank_plugin_check_token', 450 )); 451 }); 452 453 function topirank_process_next_batch(WP_REST_Request $request) 454 { 455 try { 456 error_log('Processing next batch requested'); 457 $processing_data = get_option('topirank_processing_data'); 458 459 if (!$processing_data) { 460 error_log('No processing data found'); 461 return new WP_REST_Response(['message' => 'No processing data found'], 404); 462 } 463 464 // Initialize batch processing if not already done 465 $processor = Topirank_Batch_Processor::get_instance(); 466 if (!$processor->is_batch_active()) { 467 error_log('Initializing batch processing'); 468 $replace = isset($request['replace']) && $request['replace'] === 'true'; 469 $processor->init_batch($processing_data['files'], $processing_data['selected_style'], $processing_data['selected_type'], $processing_data['archive_name'], $replace, true); 470 error_log('Batch processing initialized with ' . count($processing_data['files']) . ' files'); 471 } 472 473 // Process next batch 474 $batch_result = $processor->process_next_batch(); 475 476 // Update processing data 477 $processing_data['current_batch']++; 478 update_option('topirank_processing_data', $processing_data); 479 480 // Check if processing is complete 481 if ($processor->is_batch_complete()) { 482 error_log('Batch processing completed'); 483 // Clean up files after successful processing 484 wp_delete_file($processing_data['final_path']); 485 topirank_recursive_delete($processing_data['extracted_path']); 486 delete_option('topirank_processing_data'); 487 topirank_set_processing_status(false); 488 error_log('Files cleaned up after successful processing'); 489 490 return new WP_REST_Response([ 491 'message' => 'Processing completed', 492 'completed' => true, 493 'result' => $batch_result, 494 'current_batch' => $processing_data['current_batch'], 495 'total_batches' => $processing_data['total_batches'] 496 ], 200); 497 } 498 499 return new WP_REST_Response([ 500 'message' => 'Batch processed successfully', 501 'completed' => false, 502 'result' => $batch_result, 503 'current_batch' => $processing_data['current_batch'], 504 'total_batches' => $processing_data['total_batches'] 505 ], 200); 506 } catch (Exception $e) { 507 error_log('Error during batch processing: ' . $e->getMessage()); 508 topirank_set_processing_status(false); 509 return new WP_REST_Response(['message' => 'Processing error: ' . $e->getMessage()], 500); 510 } 511 } 512 513 function topirank_get_upload_progress() 514 { 515 $batch_data = get_option('topirank_batch_data'); 516 if (!$batch_data) { 517 return new WP_REST_Response(array('message' => 0)); 518 } 519 520 $total = $batch_data['total_files']; 521 $processed = $batch_data['processed_files']; 522 523 if ($total > 0) { 524 $progress = round(($processed / $total) * 100); 525 } else { 526 $progress = 0; 527 } 528 529 return new WP_REST_Response(array('message' => $progress)); 530 } 531 532 function topirank_get_upload_status() 533 { 534 $is_processing = get_option('topirank_is_processing', false); 535 $last_activity = get_option('topirank_last_activity', 0); 536 537 if ($is_processing && (time() - $last_activity > 600)) { 538 error_log('Processing seems stuck, auto-resetting status'); 539 topirank_set_processing_status(false); 540 $is_processing = false; 541 } 542 543 $is_ready = !$is_processing; 544 545 return new WP_REST_Response(array( 546 'ready' => $is_ready, 547 'message' => $is_ready, 548 'last_activity' => $last_activity ? date('Y-m-d H:i:s', $last_activity) : null 549 )); 550 } 551 552 // Helper functions to update progress and status 553 function topirank_update_progress($progress) 554 { 555 update_option('topirank_upload_progress', $progress); 556 topirank_update_activity(); 557 } 558 559 function topirank_set_processing_status($is_processing) 560 { 561 update_option('topirank_is_processing', $is_processing); 562 if ($is_processing) { 563 update_option('topirank_last_activity', time()); 564 } else { 565 delete_option('topirank_last_activity'); 566 } 567 } 568 569 function topirank_update_activity() 570 { 571 if (get_option('topirank_is_processing', false)) { 572 update_option('topirank_last_activity', time()); 573 } 574 } 575 576 function topirank_hard_reset() 577 { 578 error_log('Performing hard reset of all processing data'); 579 580 delete_option('topirank_is_processing'); 581 delete_option('topirank_last_activity'); 582 delete_option('topirank_batch_data'); 583 delete_option('topirank_processing_data'); 584 delete_option('topirank_upload_progress'); 585 586 $upload_dir = wp_upload_dir(); 587 $temp_dir = $upload_dir['basedir'] . '/topirank-temp'; 588 $import_dir = $upload_dir['basedir'] . '/topirank-import-files'; 589 590 if (file_exists($temp_dir)) { 591 topirank_recursive_delete($temp_dir); 592 wp_mkdir_p($temp_dir); 593 error_log('Temp directory cleaned: ' . $temp_dir); 594 } 595 596 if (file_exists($import_dir)) { 597 topirank_recursive_delete($import_dir); 598 wp_mkdir_p($import_dir); 599 error_log('Import directory cleaned: ' . $import_dir); 600 } 601 602 return new WP_REST_Response(array( 603 'message' => 'All processing data has been reset', 604 'status' => 'success', 605 'cleaned' => array( 606 'options' => [ 607 'topirank_is_processing', 608 'topirank_last_activity', 609 'topirank_batch_data', 610 'topirank_processing_data', 611 'topirank_upload_progress' 612 ], 613 'directories' => [ 614 'temp' => $temp_dir, 615 'import' => $import_dir 616 ] 617 ) 618 ), 200); 619 } 620 621 function topirank_process_extracted_files($extracted_path, $archive_name, $selected_style) 622 { 623 // Create base directories 624 $upload_dir = wp_upload_dir(); 625 $base_upload_path = $upload_dir['basedir']; 626 $topirank_base_dir = $base_upload_path . '/topirank'; 627 topirank_create_base_directories($topirank_base_dir); 628 629 // Process CSS files 630 $css_destination = $topirank_base_dir . '/css/' . $archive_name; 631 $css_destination = topirank_ensure_unique_directory($css_destination, $archive_name); 632 $archive_name = basename($css_destination); 633 634 $css_files = topirank_search_files($extracted_path, 'css'); 635 topirank_copy_files($css_files, $css_destination, $selected_style); 636 $css_files = topirank_search_files($css_destination, 'css'); 637 638 // Process fonts 639 $fonts_destination = $topirank_base_dir . '/fonts/' . $archive_name; 640 $fonts_destination = topirank_ensure_unique_directory($fonts_destination, $archive_name); 641 $fonts_folder = topirank_search_directory($extracted_path, 'fonts'); 642 643 if ($fonts_folder) { 644 $font_files = topirank_search_files($fonts_folder, ['ttf', 'woff', 'woff2', 'eot', 'otf']); 645 topirank_copy_files($font_files, $fonts_destination, $selected_style); 646 } 647 648 topirank_process_css_fonts($css_files, $fonts_destination, $upload_dir['baseurl'] . '/topirank/fonts/' . $archive_name); 649 650 // Process JS files 651 $js_destination = $topirank_base_dir . '/js/' . $archive_name; 652 $js_destination = topirank_ensure_unique_directory($js_destination, $archive_name); 653 topirank_copy_files( 654 topirank_search_files($extracted_path, 'js'), 655 $js_destination, 656 $selected_style 657 ); 658 659 return $archive_name; 660 } -
topirank-integration/trunk/includes/extract-and-create.php
r3268778 r3286404 1 1 <?php 2 if (session_status() === PHP_SESSION_NONE) { 3 session_start(); 4 } 2 5 3 6 if (! defined('ABSPATH')) exit; 4 7 8 // Start output buffering to prevent headers already sent error 9 ob_start(); 10 5 11 function topirank_extract_and_create_posts($zip_path, $extracted_path, $replace, $selected_style, $selected_type, $check_delete = true) 6 12 { 13 topirank_set_processing_status(true); 14 15 // Get original archive name without extension 16 $archive_name = pathinfo($zip_path, PATHINFO_FILENAME); 17 18 // Check if there's an active batch 19 $processor = Topirank_Batch_Processor::get_instance(); 20 if ($processor->is_batch_active()) { 21 $processor->clear_batch_data(); 22 } 23 7 24 $zip = new ZipArchive; 8 25 if ($zip->open($zip_path) !== true) { 9 echo '<div class="topirank_main_content_line without_space_between"> 10 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 11 <path d="M12 22C17.523 22 22 17.523 22 12C22 6.477 17.523 2 12 2C6.477 2 2 6.477 2 12C2 17.523 6.477 22 12 22Z" stroke="#CF2323" stroke-width="1.5" stroke-linejoin="round"/> 12 <path d="M14.8289 9.17188L9.17188 14.8289M9.17188 9.17188L14.8289 14.8289" stroke="#CF2323" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> 13 </svg> 14 <div class="topirank_line_title">'; 15 esc_html_e('Error unpacking the archive.', 'topirank-integration'); 16 echo '</div> 17 </div>'; 18 return; 26 topirank_set_processing_status(false); 27 return false; 19 28 } 20 29 … … 24 33 topirank_normalize_folder_names($extracted_path); 25 34 26 echo '<div class="topirank_main_content_line without_space_between">27 <svg width="28" height="29" viewBox="0 0 28 29" fill="none" xmlns="http://www.w3.org/2000/svg">28 <path d="M10.5 14.5L12.8333 16.8333L17.5 12.1667M3.5 14.5C3.5 15.8789 3.77159 17.2443 4.29926 18.5182C4.82694 19.7921 5.60036 20.9496 6.57538 21.9246C7.55039 22.8996 8.70791 23.6731 9.98182 24.2007C11.2557 24.7284 12.6211 25 14 25C15.3789 25 16.7443 24.7284 18.0182 24.2007C19.2921 23.6731 20.4496 22.8996 21.4246 21.9246C22.3996 20.9496 23.1731 19.7921 23.7007 18.5182C24.2284 17.2443 24.5 15.8789 24.5 14.5C24.5 13.1211 24.2284 11.7557 23.7007 10.4818C23.1731 9.20791 22.3996 8.05039 21.4246 7.07538C20.4496 6.10036 19.2921 5.32694 18.0182 4.79927C16.7443 4.27159 15.3789 4 14 4C12.6211 4 11.2557 4.27159 9.98182 4.79927C8.70791 5.32694 7.55039 6.10036 6.57538 7.07538C5.60036 8.05039 4.82694 9.20791 4.29926 10.4818C3.77159 11.7557 3.5 13.1211 3.5 14.5Z" stroke="#21A816" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>29 </svg>30 <div class="topirank_line_title">';31 esc_html_e('The archive has been successfully unpacked!', 'topirank-integration');32 echo '</div>33 </div>';34 35 35 $upload_dir = wp_upload_dir(); 36 36 $base_upload_path = $upload_dir['basedir']; … … 39 39 topirank_create_base_directories($topirank_base_dir); 40 40 41 $archive_name = pathinfo($zip_path, PATHINFO_FILENAME);42 $archive_name = str_replace(' ', '-', $archive_name);43 44 41 $css_destination = $topirank_base_dir . '/css/' . $archive_name; 45 topirank_ensure_unique_directory($css_destination, $archive_name); 42 $css_destination = topirank_ensure_unique_directory($css_destination, $archive_name); 43 // Update archive name if it was changed 44 $archive_name = basename($css_destination); 45 46 46 $css_files = topirank_search_files($extracted_path, 'css'); 47 47 topirank_copy_files($css_files, $css_destination, $selected_style); … … 49 49 50 50 $fonts_destination = $topirank_base_dir . '/fonts/' . $archive_name; 51 topirank_ensure_unique_directory($fonts_destination, $archive_name);51 $fonts_destination = topirank_ensure_unique_directory($fonts_destination, $archive_name); 52 52 $fonts_folder = topirank_search_directory($extracted_path, 'fonts'); 53 53 … … 58 58 59 59 topirank_process_css_fonts($css_files, $fonts_destination, $upload_dir['baseurl'] . '/topirank/fonts/' . $archive_name); 60 61 60 $js_destination = $topirank_base_dir . '/js/' . $archive_name; 62 topirank_ensure_unique_directory($js_destination, $archive_name);61 $js_destination = topirank_ensure_unique_directory($js_destination, $archive_name); 63 62 topirank_copy_files( 64 63 topirank_search_files($extracted_path, 'js'), … … 67 66 ); 68 67 69 topirank_process_folders($extracted_path, $archive_name, $replace, $selected_style, $selected_type, $check_delete); 68 $files = array(); 69 $iterator = new RecursiveIteratorIterator( 70 new RecursiveDirectoryIterator($extracted_path, RecursiveDirectoryIterator::SKIP_DOTS), 71 RecursiveIteratorIterator::SELF_FIRST 72 ); 73 74 foreach ($iterator as $file) { 75 if ($file->isFile() && $file->getExtension() === 'html') { 76 $files[] = $file->getPathname(); 77 } 78 } 79 80 if (!empty($files)) { 81 // Initialize batch processing with unique archive name 82 $processor = Topirank_Batch_Processor::get_instance(); 83 $processor->init_batch($files, $selected_style, $selected_type, $archive_name, $replace); 84 85 86 // Store success message in session 87 $_SESSION['topirank_upload_message'] = array( 88 'type' => 'success', 89 'message' => 'The archive has been successfully unpacked!' 90 ); 91 92 // Redirect to batch processing page 93 wp_safe_redirect(admin_url('admin.php?page=topirank_batch_processing')); 94 exit; 95 } 70 96 71 97 return true; … … 92 118 } 93 119 94 function topirank_ensure_unique_directory(&$path, &$archive_name)120 function topirank_ensure_unique_directory(&$path, $archive_name) 95 121 { 96 122 $wp_filesystem = topirank_get_filesystem(); … … 99 125 $original_name = $archive_name; 100 126 $counter = 1; 127 $current_name = $archive_name; 101 128 102 129 while ($wp_filesystem->is_dir($path)) { 103 $ archive_name = $original_name . '--(' . $counter . ')';104 $path = dirname($original_path) . '/' . $ archive_name;130 $current_name = $original_name . '--(' . $counter . ')'; 131 $path = dirname($original_path) . '/' . $current_name; 105 132 $counter++; 106 133 } -
topirank-integration/trunk/includes/file-upload.php
r3268778 r3286404 24 24 function topirank_handle_file_upload() 25 25 { 26 error_log('Starting file upload handler'); 27 26 28 if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') { 29 error_log('POST request detected'); 30 27 31 if (!isset($_FILES['html_archive']) || empty($_FILES['html_archive']['tmp_name'])) { 32 error_log('No file uploaded or empty file'); 28 33 echo '<div class="topirank_main_content_line without_space_between"> 29 34 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> … … 38 43 } 39 44 45 error_log('File upload detected: ' . print_r($_FILES['html_archive'], true)); 46 40 47 $file = isset($_FILES['html_archive']) && is_array($_FILES['html_archive']) 41 48 ? array_map('sanitize_text_field', $_FILES['html_archive']) … … 43 50 44 51 if (is_array($file) && isset($file['name'], $file['tmp_name'])) { 52 error_log('Valid file array detected'); 53 45 54 $upload_dir = wp_upload_dir(); 46 55 $topirank_dir = $upload_dir['basedir'] . '/topirank-import-files'; 47 topirank_recursive_delete($topirank_dir); 56 57 error_log('Upload directory: ' . $topirank_dir); 58 59 // Clean the topirank-import-files directory before uploading new archive 60 if (file_exists($topirank_dir)) { 61 $wp_filesystem = topirank_get_filesystem(); 62 if ($wp_filesystem) { 63 $items = $wp_filesystem->dirlist($topirank_dir); 64 if ($items) { 65 foreach ($items as $item => $info) { 66 $item_path = trailingslashit($topirank_dir) . $item; 67 if ($wp_filesystem->is_dir($item_path)) { 68 $wp_filesystem->rmdir($item_path, true); 69 } else { 70 $wp_filesystem->delete($item_path); 71 } 72 } 73 } 74 } 75 } 48 76 49 77 $selected_style = isset($_POST['style']) ? sanitize_text_field(wp_unslash($_POST['style'])) : ''; … … 51 79 $replace = ''; 52 80 81 error_log('Selected style: ' . $selected_style); 82 error_log('Selected type: ' . $selected_type); 83 53 84 $file_extension = pathinfo($file['name'], PATHINFO_EXTENSION); 54 85 55 86 if (strtolower($file_extension) !== 'zip') { 87 error_log('Invalid file extension: ' . $file_extension); 56 88 echo '<div class="error notice"><p>'; 57 89 esc_html_e('Please upload a ZIP archive.', 'topirank-integration'); … … 61 93 62 94 if (!file_exists($topirank_dir)) { 95 error_log('Creating directory: ' . $topirank_dir); 63 96 wp_mkdir_p($topirank_dir); 64 97 } 65 98 99 error_log('Handling file upload with wp_handle_upload'); 66 100 $uploaded_file = wp_handle_upload($file, array('test_form' => false)); 101 error_log('wp_handle_upload result: ' . print_r($uploaded_file, true)); 67 102 68 103 if (isset($uploaded_file['file']) && ! isset($uploaded_file['error'])) { 104 error_log('File uploaded successfully'); 105 69 106 $original_path = $uploaded_file['file']; 70 107 $zip_path = $topirank_dir . '/' . basename($original_path); 108 109 error_log('Original path: ' . $original_path); 110 error_log('Zip path: ' . $zip_path); 71 111 72 112 $wp_filesystem = topirank_get_filesystem(); 73 113 74 114 if ($wp_filesystem->move($original_path, $zip_path, true)) { 115 error_log('File moved successfully to: ' . $zip_path); 116 75 117 $extracted_path = $topirank_dir . '/' . basename($file['name'], '.zip'); 118 error_log('Extracted path will be: ' . $extracted_path); 119 120 // Remove filters that might interfere with the process 121 error_log('Removing redirect filters'); 122 remove_all_filters('wp_redirect'); 123 remove_all_filters('wp_safe_redirect'); 124 125 // Process the files 126 error_log('Starting file extraction and post creation'); 76 127 topirank_extract_and_create_posts($zip_path, $extracted_path, $replace, $selected_style, $selected_type); 128 error_log('File extraction and post creation completed'); 77 129 78 if ($wp_filesystem->exists($zip_path)) { 79 $wp_filesystem->delete($zip_path); 80 } 130 // If we're still here (no redirect happened), redirect manually 131 error_log('Attempting manual redirect to batch processing page'); 132 wp_safe_redirect(admin_url('admin.php?page=topirank_batch_processing')); 133 exit; 81 134 } else { 135 error_log('Failed to move file from ' . $original_path . ' to ' . $zip_path); 82 136 echo '<div class="topirank_main_content_line">'; 83 137 echo '<div class="topirank_line_title">'; … … 87 141 } 88 142 } else { 143 error_log('Upload failed: ' . print_r($uploaded_file, true)); 89 144 echo '<div class="topirank_main_content_line">'; 90 145 echo '<div class="topirank_line_title">'; … … 98 153 } 99 154 } else { 155 error_log('Invalid file array structure'); 100 156 esc_html_e('Invalid file upload.', 'topirank-integration'); 101 157 } 158 } else { 159 error_log('Not a POST request'); 102 160 } 103 161 } -
topirank-integration/trunk/includes/helpers.php
r3266247 r3286404 5 5 function topirank_create_posts_from_html($folder_path, $archive_name, $replace, $selected_style, $selected_type, &$check_delete) 6 6 { 7 set_time_limit(0);8 7 $wp_filesystem = topirank_get_filesystem(); 9 8 $post_type_to_create = ($selected_type === 'article') ? 'post' : 'page'; 10 9 10 // Store original archive name 11 $original_archive_name = $archive_name; 11 12 $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($folder_path)); 12 13 $post_ids = []; 13 14 $conflicts = []; 15 $messages = []; 16 $conflict_data = []; 14 17 15 18 foreach ($files as $file) { 16 19 if (pathinfo($file, PATHINFO_EXTENSION) === 'html') { 17 20 $directory_name = basename(dirname($file)); 18 if ($directory_name === '404' || basename($file) === '404.html') {19 continue;20 }21 21 $file_path = $file->getPathname(); 22 22 23 $content = $wp_filesystem->get_contents($file_path); 24 23 25 $article_title = topirank_extract_title_from_html($file_path); 24 26 … … 53 55 54 56 if (!is_wp_error($post_id)) { 55 topirank_update_post_content($post_id, $file->getPathname(), $archive_name, $selected_style); 57 topirank_update_post_content($post_id, $file_path, $archive_name, $selected_style); 58 $messages[] = sprintf( 59 __('Post "%s" updated successfully!', 'topirank-integration'), 60 get_the_title($post_id) 61 ); 56 62 } 57 63 } else { 58 $conflicts[] = ['title' => $article_title, 'file' => $file->getPathname()]; 64 $conflicts[] = ['title' => $article_title, 'file' => $file_path]; 65 $conflict_data[] = [ 66 'title' => $article_title, 67 'file' => $file_path, 68 'selected_style' => $selected_style, 69 'archive_name' => $original_archive_name 70 ]; 59 71 } 60 72 continue; 61 73 } 62 63 $directory_name = basename(dirname($file->getPathname()));64 74 65 75 $post_id = wp_insert_post([ … … 67 77 'post_content' => $content, 68 78 'post_status' => 'publish', 69 'post_type' => $post_type_to_create,79 'post_type' => $post_type_to_create, 70 80 'post_name' => sanitize_title($directory_name), 71 81 ]); 72 82 73 83 if ($post_id && !is_wp_error($post_id)) { 74 $post_ids[$file->getPathname()] = $post_id; 75 ?> 76 <div class="topirank_main_content_line without_space_between"> 77 <svg width="28" height="29" viewBox="0 0 28 29" fill="none" xmlns="http://www.w3.org/2000/svg"> 78 <path d="M10.5 14.5L12.8333 16.8333L17.5 12.1667M3.5 14.5C3.5 15.8789 3.77159 17.2443 4.29926 18.5182C4.82694 19.7921 5.60036 20.9496 6.57538 21.9246C7.55039 22.8996 8.70791 23.6731 9.98182 24.2007C11.2557 24.7284 12.6211 25 14 25C15.3789 25 16.7443 24.7284 18.0182 24.2007C19.2921 23.6731 20.4496 22.8996 21.4246 21.9246C22.3996 20.9496 23.1731 19.7921 23.7007 18.5182C24.2284 17.2443 24.5 15.8789 24.5 14.5C24.5 13.1211 24.2284 11.7557 23.7007 10.4818C23.1731 9.20791 22.3996 8.05039 21.4246 7.07538C20.4496 6.10036 19.2921 5.32694 18.0182 4.79927C16.7443 4.27159 15.3789 4 14 4C12.6211 4 11.2557 4.27159 9.98182 4.79927C8.70791 5.32694 7.55039 6.10036 6.57538 7.07538C5.60036 8.05039 4.82694 9.20791 4.29926 10.4818C3.77159 11.7557 3.5 13.1211 3.5 14.5Z" stroke="#21A816" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> 79 </svg> 80 <div class="topirank_line_title"> 81 <?php 82 echo sprintf( 83 // translators: %s: The title of the created post 84 esc_html__('Post "%s" created successfully!', 'topirank-integration'), 85 esc_html(get_the_title($post_id)) 86 ); 87 ?> 88 </div> 89 </div> 90 <?php 84 // Use original archive name for meta 85 update_post_meta($post_id, '_topirank_import_archive', $archive_name); 86 87 topirank_update_post_content($post_id, $file_path, $archive_name, $selected_style); 88 $post_ids[$file_path] = $post_id; 89 $messages[] = sprintf( 90 __('Post "%s" created successfully!', 'topirank-integration'), 91 get_the_title($post_id) 92 ); 91 93 } else { 92 ?> 93 <div class="topirank_main_content_line without_space_between"> 94 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 95 <path d="M12 22C17.523 22 22 17.523 22 12C22 6.477 17.523 2 12 2C6.477 2 2 6.477 2 12C2 17.523 6.477 22 12 22Z" stroke="#CF2323" stroke-width="1.5" stroke-linejoin="round" /> 96 <path d="M14.8289 9.17188L9.17188 14.8289M9.17188 9.17188L14.8289 14.8289" stroke="#CF2323" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> 97 </svg> 98 <div class="topirank_line_title"> 99 <?php 100 echo sprintf( 101 // translators: %s is the file name from which we attempted to create a post. 102 esc_html__('Error creating post from file: %s', 'topirank-integration'), 103 esc_html($file) 104 ); 105 ?> 106 </div> 107 </div> 108 <?php 94 $messages[] = sprintf( 95 __('Error creating post from file: %s', 'topirank-integration'), 96 $file 97 ); 109 98 } 110 99 } 111 100 } 112 101 113 if (empty($replace)) { 114 if (!empty($conflicts)) { 115 wp_localize_script('topirank-admin-script', 'hapConflicts', $conflicts); 116 } 117 118 if (!empty($conflicts)) { 119 $check_delete = false; 120 ?> 121 <div class="topirank_main_content_line topirank_conflict_line column_direction"> 122 <div class="topirank_line_title topirank_line_conflict_title"> 123 <strong><?php esc_html_e('The following conflicts occurred:', 'topirank-integration'); ?></strong> 124 <div class="topirank_conflict_buttons"> 125 <button class="topirank_solid_button update-all"> 126 <?php esc_html_e('Update All', 'topirank-integration'); ?> 127 </button> 128 <button class="topirank_outline_button skip-all"> 129 <?php esc_html_e('Skip All', 'topirank-integration'); ?> 130 </button> 131 </div> 132 </div> 133 <div class="topirank_conflict_items"> 134 <?php 135 foreach ($conflicts as $conflict) { ?> 136 <div class="topirank_conflict_item"> 137 <div class="topirank_conflict_item_left_column"> 138 <div class="notification-icon"> 139 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 140 <path d="M12 22C17.523 22 22 17.523 22 12C22 6.477 17.523 2 12 2C6.477 2 2 6.477 2 12C2 17.523 6.477 22 12 22Z" stroke="#CF2323" stroke-width="1.5" stroke-linejoin="round" /> 141 <path d="M14.8289 9.17188L9.17188 14.8289M9.17188 9.17188L14.8289 14.8289" stroke="#CF2323" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> 142 </svg> 143 </div> 144 <div class="topirank_conflict_item_content"> 145 <div class="topirank_line_title"> 146 <strong> 147 <?php esc_html_e('Conflict', 'topirank-integration'); ?> 148 </strong> 149 </div> 150 <div class="topirank_line_text"> 151 <strong> 152 <?php 153 echo sprintf( 154 // translators: %s is the title of the created post. 155 esc_html__('A post with the title "%s" already exists.', 'topirank-integration'), 156 esc_html($conflict['title']) 157 ); 158 ?> 159 </strong> 160 </div> 161 </div> 162 </div> 163 <div class="topirank_conflict_item_right_column"> 164 <button 165 class="topirank_solid_button update-post" 166 data-selstyle="<?php echo esc_attr($selected_style); ?>" 167 data-archive="<?php echo esc_attr($archive_name); ?>" 168 data-title="<?php echo esc_attr($conflict['title']); ?>" 169 data-file="<?php echo esc_attr($conflict['file']); ?>"> 170 <?php esc_html_e('Update', 'topirank-integration'); ?> 171 </button> 172 <button 173 class="topirank_outline_button skip-post" 174 data-title="<?php echo esc_attr($conflict['title']); ?>"> 175 <?php esc_html_e('Skip', 'topirank-integration'); ?> 176 </button> 177 </div> 178 </div> 179 <?php } ?> 180 </div> 181 </div> 182 183 <?php 184 } 102 if (empty($replace) && !empty($conflicts)) { 103 wp_localize_script('topirank-admin-script', 'hapConflicts', $conflicts); 104 $check_delete = false; 185 105 } 186 106 187 foreach ($files as $file) {188 if (pathinfo($file, PATHINFO_EXTENSION) === 'html' && isset($post_ids[$file->getPathname()])) {189 topirank_update_post_content($post_ids[$file->getPathname()], $file->getPathname(), $archive_name, $selected_style);190 }191 }107 return [ 108 'success' => true, 109 'messages' => $messages, 110 'conflicts' => $conflict_data 111 ]; 192 112 } 193 113 -
topirank-integration/trunk/includes/init.php
r3234611 r3286404 9 9 if (empty($wp_filesystem)) { 10 10 require_once ABSPATH . 'wp-admin/includes/file.php'; 11 WP_Filesystem(); 11 12 if (!function_exists('WP_Filesystem')) { 13 return false; 14 } 15 16 $credentials = request_filesystem_credentials(''); 17 if (false === $credentials) { 18 return false; 19 } 20 21 if (!WP_Filesystem($credentials)) { 22 return false; 23 } 24 25 if (empty($wp_filesystem) || !is_object($wp_filesystem)) { 26 return false; 27 } 12 28 } 13 29 … … 30 46 31 47 topirank_plugin_register_hooks(); 32 33 add_action('admin_init', function () {34 if (isset($_GET['page']) && sanitize_text_field(wp_unslash($_GET['page'])) === 'topirank_process_upload') {35 if (!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'POST') {36 wp_redirect(admin_url('admin.php?page=topirank_plugin'));37 exit;38 }39 }40 }); -
topirank-integration/trunk/includes/process-folders.php
r3266247 r3286404 1 1 <?php 2 2 3 if (! defined('ABSPATH')) exit;3 // if (! defined('ABSPATH')) exit; 4 4 5 function topirank_process_folders($base_path, $archive_name, $replace, $selected_style, $selected_type, $check_delete)6 {7 $folders = array_filter(glob($base_path . '/*'), 'is_dir');8 foreach ($folders as $folder) {9 topirank_create_posts_from_html($folder, $archive_name, $replace, $selected_style, $selected_type, $check_delete);10 }5 // function topirank_process_folders($base_path, $archive_name, $replace, $selected_style, $selected_type, $check_delete) 6 // { 7 // $folders = array_filter(glob($base_path . '/*'), 'is_dir'); 8 // foreach ($folders as $folder) { 9 // topirank_create_posts_from_html($folder, $archive_name, $replace, $selected_style, $selected_type, $check_delete); 10 // } 11 11 12 if ($check_delete) {13 topirank_recursive_delete($base_path);14 }15 }12 // if ($check_delete) { 13 // topirank_recursive_delete($base_path); 14 // } 15 // } -
topirank-integration/trunk/includes/register-files.php
r3271065 r3286404 13 13 'toplevel_page_topirank_plugin', 14 14 'admin_page_topirank_process_upload', 15 'admin_page_topirank_batch_processing' 15 16 ]; 16 17 … … 22 23 'topirank-admin-style', 23 24 plugin_dir_url(dirname(__FILE__)) . 'assets/css/topirank-admin-style.css', 25 [], 26 '1.0.0' 27 ); 28 29 wp_enqueue_style( 30 'topirank-batch-css', 31 plugin_dir_url(dirname(__FILE__)) . 'assets/css/batch-process.css', 24 32 [], 25 33 '1.0.0' -
topirank-integration/trunk/includes/topirank-template.php
r3268778 r3286404 12 12 get_header(); 13 13 $choose_styles = get_post_meta($post->ID, 'choose_styles', true); 14 $arhive_name = get_post_meta($post->ID, '_topirank_archive_name', true); 15 var_dump($arhive_name); 14 16 if ($choose_styles == "wp") { 15 17 $choose_styles_class = "wordpress-styles"; -
topirank-integration/trunk/includes/update-content-and-seo.php
r3268778 r3286404 5 5 function topirank_update_post_content($post_id, $file, $archive_name, $selected_style) 6 6 { 7 8 if (!$post_id || !$file || !$archive_name) { 9 return new WP_Error('missing_params', 'Missing required parameters'); 10 } 11 12 if (!file_exists($file)) { 13 return new WP_Error('file_not_found', 'File does not exist'); 14 } 15 7 16 topirank_delete_page_images($post_id); 8 17 9 18 $wp_filesystem = topirank_get_filesystem(); 19 if (!$wp_filesystem) { 20 return new WP_Error('filesystem_error', 'Failed to initialize filesystem'); 21 } 10 22 11 23 $choose_styles = ($selected_style === 'wp') ? 'wp' : 'topirank-integration'; … … 14 26 update_post_meta($post_id, '_wp_page_template', 'includes/topirank-template.php'); 15 27 28 16 29 $content = $wp_filesystem->get_contents($file); 30 if ($content === false) { 31 return new WP_Error('read_error', 'Failed to read file contents'); 32 } 17 33 18 34 if (preg_match('/<title>(.*?)<\/title>/is', $content, $title_match)) { … … 31 47 32 48 libxml_use_internal_errors(true); 33 $dom = new DOMDocument(); 34 35 $encoded_content = html_entity_decode(htmlspecialchars($content, ENT_QUOTES | ENT_HTML5, 'UTF-8')); 36 $dom->loadHTML($encoded_content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); 49 $dom = new DOMDocument('1.0', 'UTF-8'); 50 $dom->preserveWhiteSpace = false; 51 $dom->formatOutput = true; 52 53 // Add UTF-8 meta tag and properly encode content 54 $content = '<?xml encoding="UTF-8">' . $content; 55 $dom->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOWARNING); 37 56 libxml_clear_errors(); 38 57 … … 122 141 123 142 $elementsWithStyle = $xpath->query('.//*[@style]', $container); 124 removeStyles($elementsWithStyle, ['color', 'background-color', 'accent-color', 'font-size', 'line-height']); 125 143 removeStyles($elementsWithStyle, ['color', 'background-color', 'accent-color', 'font-size', 'line-height', 'font-family']); 126 144 127 145 $content = preg_replace('/color\s*:\s*[^;"]+;?/i', '', $content); 146 $content = preg_replace('/font-family\s*:\s*[^;"]+;?/i', '', $content); 128 147 129 148 $buttons = $container->getElementsByTagName('button'); … … 141 160 } 142 161 } 143 144 $content = $dom->saveHTML(); 145 $content = preg_replace('/font-family:[^;"]+;?/i', '', $content); 146 147 $dom = new DOMDocument(); 148 libxml_use_internal_errors(true); 149 $dom->loadHTML(html_entity_decode(htmlspecialchars($content, ENT_QUOTES | ENT_HTML5, 'UTF-8')), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); 150 libxml_clear_errors(); 151 } 152 } 153 154 $content = $dom->saveHTML(); 155 162 } 163 } 164 165 // Save HTML without XML declaration and doctype 166 $content = preg_replace('/<\?xml[^>]+>/', '', $dom->saveHTML()); 156 167 $content = preg_replace('/<head\b[^>]*>.*?<\/head>/is', '', $content); 157 168 … … 211 222 } 212 223 213 214 wp_update_post([ 215 'ID' => $post_id, 216 'post_content' => $content, 217 'filter' => 'raw', 218 ]); 219 220 wp_reset_postdata(); 224 $update_args = array( 225 'ID' => $post_id, 226 'post_content' => $content 227 ); 228 229 remove_filter('content_save_pre', 'wp_filter_post_kses'); 230 remove_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 231 remove_all_filters('the_content'); 232 remove_all_filters('the_editor_content'); 233 remove_all_filters('tiny_mce_before_init'); 234 235 $result = wp_update_post($update_args, true); 236 237 add_filter('content_save_pre', 'wp_filter_post_kses'); 238 add_filter('content_filtered_save_pre', 'wp_filter_post_kses'); 239 240 if (is_wp_error($result)) { 241 error_log('Failed to update post: ' . $result->get_error_message()); 242 return $result; 243 } 221 244 222 245 if (class_exists('WPSEO_Meta')) { 223 224 246 if ($title) { 225 247 WPSEO_Meta::set_value('opengraph-title', $title, $post_id); … … 234 256 } 235 257 } 258 259 return true; 236 260 } 237 261 -
topirank-integration/trunk/includes/update-functionality.php
r3236026 r3286404 2 2 3 3 if (! defined('ABSPATH')) exit; 4 5 require_once plugin_dir_path(__FILE__) . 'update-content-and-seo.php'; 4 6 5 7 function topirank_generate_unique_title($title) … … 16 18 function topirank_handle_conflict() 17 19 { 18 /* phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing */ 19 $title = isset($_POST['title']) ? sanitize_text_field(wp_unslash($_POST['title'])) : null; 20 $file = isset($_POST['file']) ? sanitize_text_field(wp_unslash($_POST['file'])) : null; 21 $archive_name = isset($_POST['archive']) ? sanitize_text_field(wp_unslash($_POST['archive'])) : null; 22 $replace = isset($_POST['replace']) ? filter_var(wp_unslash($_POST['replace']), FILTER_VALIDATE_BOOLEAN) : false; 23 $selected_style = isset($_POST['selstyle']) ? sanitize_text_field(wp_unslash($_POST['selstyle'])) : null; 20 check_ajax_referer('wp_rest', '_ajax_nonce'); 24 21 25 if (!$title) { 26 wp_send_json_error(['message' => __('Missing or invalid title.', 'topirank-integration')]); 22 if (!isset($_POST['resolutions']) || !is_array($_POST['resolutions'])) { 23 wp_send_json_error(['message' => __('Missing or invalid resolutions data.', 'topirank-integration')]); 24 return; 27 25 } 28 26 29 $title = trim(preg_replace('/\s+/', ' ', $title)); 27 $resolutions = $_POST['resolutions']; 28 $results = []; 29 $success = true; 30 30 31 $post = topirank_get_post_by_title($title); 31 foreach ($resolutions as $file_path => $resolution) { 32 if (!is_array($resolution)) { 33 continue; 34 } 32 35 33 if (!$post) { 34 wp_send_json_error(['message' => __('Post not found.', 'topirank-integration')]); 36 $post_id = isset($resolution['post_id']) ? intval($resolution['post_id']) : 0; 37 $file = isset($resolution['file']) ? sanitize_text_field($resolution['file']) : null; 38 $archive_name = isset($resolution['archive']) ? sanitize_text_field($resolution['archive']) : null; 39 $selected_style = isset($resolution['style']) ? sanitize_text_field($resolution['style']) : null; 40 $action = isset($resolution['action']) ? sanitize_text_field($resolution['action']) : null; 41 42 if (!$post_id || !$file || !$action) { 43 $success = false; 44 $results[$file_path] = __('Missing required data', 'topirank-integration'); 45 continue; 46 } 47 48 $post = get_post($post_id); 49 if (!$post) { 50 $success = false; 51 $results[$file_path] = __('Post not found', 'topirank-integration'); 52 error_log('Post not found for ID: ' . $post_id); 53 continue; 54 } 55 56 if ($action === 'UPDATE') { 57 if (!$archive_name || !$selected_style) { 58 $success = false; 59 $results[$file_path] = __('Missing archive name or style for update', 'topirank-integration'); 60 continue; 61 } 62 63 try { 64 error_log('Attempting to update post: ' . $post_id . ' with file: ' . $file); 65 $update_result = topirank_update_post_content($post_id, $file, $archive_name, $selected_style); 66 67 if (is_wp_error($update_result)) { 68 $success = false; 69 $results[$file_path] = $update_result->get_error_message(); 70 } else { 71 $results[$file_path] = sprintf( 72 __('Post "%s" updated successfully', 'topirank-integration'), 73 $post->post_title 74 ); 75 } 76 } catch (Exception $e) { 77 $success = false; 78 $results[$file_path] = $e->getMessage(); 79 } 80 } elseif ($action === 'SKIP') { 81 $results[$file_path] = sprintf( 82 __('Post "%s" skipped', 'topirank-integration'), 83 $post->post_title 84 ); 85 } else { 86 $success = false; 87 $results[$file_path] = __('Invalid action', 'topirank-integration'); 88 } 35 89 } 36 90 37 if ($replace && $file) { 38 topirank_update_post_content($post->ID, $file, $archive_name, $selected_style); 91 if ($success) { 39 92 wp_send_json_success([ 40 // translators: %s is the title of the created post. 41 'message' => sprintf(__('Post "%s" updated successfully.', 'topirank-integration'), $title), 93 'message' => __('All conflicts resolved successfully', 'topirank-integration'), 94 'results' => $results 95 ]); 96 } else { 97 wp_send_json_error([ 98 'message' => __('Some conflicts could not be resolved', 'topirank-integration'), 99 'results' => $results 42 100 ]); 43 101 } 44 45 if (!$replace) {46 wp_send_json_success([47 // translators: %s is the title of the created post.48 'message' => sprintf(__('Post "%s" skipped.', 'topirank-integration'), $title),49 ]);50 }51 52 wp_send_json_error(['message' => __('Invalid request.', 'topirank-integration')]);53 102 } 54 103 55 104 function topirank_get_post_by_title($title) 56 105 { 57 $args = [ 58 'post_type' => 'page', 59 'title' => $title, 60 'post_status' => 'any', 61 'posts_per_page' => 1, 62 ]; 106 global $wpdb; 63 107 64 $ query = new WP_Query($args);108 $title = trim($title); 65 109 66 if ($query->have_posts()) { 67 $query->the_post(); 68 $post = get_post(); 69 wp_reset_postdata(); 110 $post = $wpdb->get_row($wpdb->prepare( 111 "SELECT * FROM $wpdb->posts WHERE post_title = %s AND post_type = 'post' AND post_status IN ('publish', 'draft', 'private', 'pending')", 112 $title 113 )); 114 115 if ($post) { 70 116 return $post; 71 117 } 72 118 73 wp_reset_postdata(); 119 $normalized_title = mb_strtolower(trim(preg_replace('/\s+/', ' ', $title)), 'UTF-8'); 120 121 $posts = $wpdb->get_results($wpdb->prepare( 122 "SELECT * FROM $wpdb->posts WHERE post_type = 'post' AND post_status IN ('publish', 'draft', 'private', 'pending')" 123 )); 124 125 foreach ($posts as $post) { 126 $current_normalized = mb_strtolower(trim(preg_replace('/\s+/', ' ', $post->post_title)), 'UTF-8'); 127 if ($current_normalized === $normalized_title) { 128 return $post; 129 } 130 } 131 74 132 return null; 75 133 } -
topirank-integration/trunk/languages/topirank-integration-fr_FR.po
r3220350 r3286404 3 3 msgid "" 4 4 msgstr "" 5 "Project-Id-Version: Topirank Integration 1. 0.2\n"5 "Project-Id-Version: Topirank Integration 1.1.6\n" 6 6 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/topirank-" 7 7 "integration\n" 8 "POT-Creation-Date: 2025-0 1-07T12:23:19+00:00\n"9 "PO-Revision-Date: 2025-0 1-07 14:25+0200\n"8 "POT-Creation-Date: 2025-05-02T12:06:58+00:00\n" 9 "PO-Revision-Date: 2025-05-02 15:13+0300\n" 10 10 "Last-Translator: \n" 11 11 "Language-Team: \n" … … 32 32 msgstr "Topirank" 33 33 34 #: admin/admin-page.php:25 34 #: admin/admin-page.php:23 35 msgid "Server Status" 36 msgstr "Statut du serveur" 37 38 #: admin/admin-page.php:36 35 39 msgid "Upload HTML archive" 36 40 msgstr "Télécharger l'archive HTML" 37 41 38 #: admin/admin-page.php: 2742 #: admin/admin-page.php:38 39 43 msgid "Easily upload all your data as an HTML archive" 40 msgstr "" 41 "Téléchargez facilement toutes vos données sous forme d'archive HTML" 42 43 #: admin/admin-page.php:28 44 msgstr "Téléchargez facilement toutes vos données sous forme d'archive HTML" 45 46 #: admin/admin-page.php:39 44 47 msgid "Maximum upload file size" 45 48 msgstr "Taille maximale du fichier à télécharger" 46 49 47 #: admin/admin-page.php: 34 includes/register-files.php:3750 #: admin/admin-page.php:45 includes/register-files.php:53 48 51 msgid "Choose a file" 49 52 msgstr "Choisissez un fichier" 50 53 51 #: admin/admin-page.php: 3854 #: admin/admin-page.php:49 52 55 msgid "Upload and create posts" 53 56 msgstr "Télécharger et créer des publications" 54 57 55 #: admin/admin-page.php: 4558 #: admin/admin-page.php:57 56 59 msgid "Choose styles for your posts" 57 60 msgstr "Choisissez des styles pour vos publications" 58 61 59 #: admin/admin-page.php: 6162 #: admin/admin-page.php:73 60 63 msgid "Managing API Token" 61 64 msgstr "Gestion des jetons API" 62 65 63 #: admin/admin-page.php: 6366 #: admin/admin-page.php:75 64 67 msgid "Generate and manage your API token securely" 65 68 msgstr "Générez et gérez votre token API en toute sécurité" 66 69 67 #: admin/admin-page.php: 6870 #: admin/admin-page.php:81 68 71 msgid "Get token" 69 72 msgstr "Obtenir un jeton" 70 73 71 #: admin/admin-page.php: 7074 #: admin/admin-page.php:83 72 75 msgid "Copy Domain" 73 76 msgstr "Copier le domaine" 74 77 75 #: admin/admin-page.php: 8778 #: admin/admin-page.php:100 76 79 msgid "New token successfully created. Check it below and save!" 77 80 msgstr "" 78 "Nouveau token créé avec succès. Vérifiez-le ci-dessous et " 79 "enregistrez-le !" 80 81 #: admin/admin-page.php:89 81 "Nouveau token créé avec succès. Vérifiez-le ci-dessous et enregistrez-le !" 82 83 #: admin/admin-page.php:102 82 84 msgid "Your new token:" 83 85 msgstr "Votre nouveau token :" 84 86 85 #: admin/admin-page.php: 9487 #: admin/admin-page.php:107 86 88 msgid "Copy" 87 89 msgstr "Copie" 88 90 89 #: includes/api-integration.php:50 91 #: admin/admin-page.php:128 92 msgid "Ready to upload" 93 msgstr "Prêt à télécharger" 94 95 #: admin/admin-page.php:132 admin/admin-page.php:142 96 msgid "Server is busy" 97 msgstr "Le serveur est occupé" 98 99 #: admin/batch-page.php:30 100 msgid "Conflicts Occurred" 101 msgstr "Des conflits ont eu lieu" 102 103 #: admin/batch-page.php:31 104 msgid "Conflict" 105 msgstr "Conflit" 106 107 #: admin/batch-page.php:32 108 msgid "A post with title \"%s\" already exists" 109 msgstr "Un message avec le titre \"%s\" existe déjà" 110 111 #: admin/batch-page.php:33 112 msgid "Update All" 113 msgstr "Tout mettre à jour" 114 115 #: admin/batch-page.php:34 116 msgid "Skip All" 117 msgstr "Sauter tout" 118 119 #: admin/batch-page.php:35 120 msgid "Update" 121 msgstr "Mise à jour" 122 123 #: admin/batch-page.php:36 124 msgid "Skip" 125 msgstr "Sauter" 126 127 #: admin/batch-page.php:57 includes/file-upload.php:12 128 msgid "Go Back to Main Page" 129 msgstr "Retourner à la page principale" 130 131 #: admin/batch-page.php:62 132 msgid "Batch Processing" 133 msgstr "Traitement par lots" 134 135 #: admin/batch-page.php:78 136 msgid "Ready to process" 137 msgstr "Prêt à être traité" 138 139 #: includes/api-integration.php:86 90 140 msgid "Authorization header is missing or invalid." 91 141 msgstr "L'en-tête d'autorisation est manquant ou non valide." 92 142 93 #: includes/api-integration.php: 61143 #: includes/api-integration.php:97 94 144 msgid "No token is stored in the database." 95 145 msgstr "Aucun jeton n'est stocké dans la base de données." 96 146 97 #: includes/api-integration.php: 69147 #: includes/api-integration.php:105 98 148 msgid "The provided token is invalid." 99 149 msgstr "Le jeton fourni n'est pas valide." 100 150 101 #: includes/extract-and-create.php:13 102 msgid "Error unpacking the archive." 103 msgstr "Erreur lors du déballage de l'archive." 104 105 #: includes/extract-and-create.php:29 106 msgid "The archive has been successfully unpacked!" 107 msgstr "L'archive a été décompressée avec succès !" 108 109 #: includes/file-upload.php:10 110 msgid "Go Back to Main Page" 111 msgstr "Retourner à la page principale" 112 113 #: includes/file-upload.php:42 151 #: includes/batch-processor.php:165 includes/batch-processor.php:332 152 #: includes/helpers.php:68 153 msgid "Post \"%s\" updated successfully!" 154 msgstr "Le message \"%s\" a été mis à jour avec succès." 155 156 #: includes/batch-processor.php:171 includes/batch-processor.php:338 157 msgid "Failed to update post \"%s\"" 158 msgstr "Échec de la mise à jour du message \"%s\"" 159 160 #: includes/batch-processor.php:202 includes/batch-processor.php:369 161 #: includes/batch-processor.php:449 includes/helpers.php:99 162 msgid "Post \"%s\" created successfully!" 163 msgstr "Le message \"%s\" a été créé avec succès !" 164 165 #: includes/batch-processor.php:208 includes/batch-processor.php:375 166 #: includes/batch-processor.php:455 167 msgid "Failed to create post from file: %s" 168 msgstr "Échec de la création de la publication à partir du fichier : %s" 169 170 #: includes/batch-processor.php:391 171 msgid "Skipping existing post \"%s\"" 172 msgstr "Ignorer la publication existante \"%s\"" 173 174 #: includes/batch-processor.php:407 175 msgid "File \"%s\" has a conflict with existing post \"%s\" - will be reviewed" 176 msgstr "" 177 "Le fichier « %s » est en conflit avec la publication existante \"%s\" - sera " 178 "examiné" 179 180 #: includes/file-upload.php:39 includes/file-upload.php:156 181 msgid "Invalid file upload." 182 msgstr "Téléchargement de fichier invalide." 183 184 #: includes/file-upload.php:89 114 185 msgid "Please upload a ZIP archive." 115 186 msgstr "Veuillez télécharger une archive ZIP." 116 187 117 #: includes/file-upload.php: 69188 #: includes/file-upload.php:138 118 189 msgid "Could not move the uploaded file." 119 190 msgstr "Impossible de déplacer le fichier téléchargé." 120 191 121 #: includes/file-upload.php: 79192 #: includes/file-upload.php:149 122 193 msgid "Upload failed. Please try again." 123 194 msgstr "Le téléchargement a échoué. Veuillez réessayer." 124 195 125 #: includes/file-upload.php:85 126 msgid "Invalid file upload." 127 msgstr "Téléchargement de fichier invalide." 128 129 #. translators: %s: The title of the created post 130 #: includes/helpers.php:74 131 msgid "Post \"%s\" created successfully!" 132 msgstr "Le message \"%s\" a été créé avec succès !" 133 134 #. translators: %s is the file name from which we attempted to create a post. 135 #: includes/helpers.php:92 196 #: includes/helpers.php:104 136 197 msgid "Error creating post from file: %s" 137 msgstr "" 138 "Erreur lors de la création de la publication à partir du fichier : " 139 "%s" 140 141 #: includes/helpers.php:113 142 msgid "The following conflicts occurred:" 143 msgstr "Les conflits suivants se sont produits :" 144 145 #: includes/helpers.php:116 146 msgid "Update All" 147 msgstr "Tout mettre à jour" 148 149 #: includes/helpers.php:119 150 msgid "Skip All" 151 msgstr "Sauter tout" 152 153 #: includes/helpers.php:137 154 msgid "Conflict" 155 msgstr "Conflit" 156 157 #. translators: %s is the title of the created post. 158 #: includes/helpers.php:145 159 msgid "A post with the title \"%s\" already exists." 160 msgstr "Un message avec le titre \"%s\" existe déjà." 161 162 #: includes/helpers.php:160 163 msgid "Update" 164 msgstr "Mise à jour" 165 166 #: includes/helpers.php:165 167 msgid "Skip" 168 msgstr "Sauter" 169 170 #: includes/register-files.php:38 198 msgstr "Erreur lors de la création de la publication à partir du fichier : %s" 199 200 #: includes/register-files.php:54 171 201 msgid "Domain copied to clipboard!" 172 202 msgstr "Domaine copié dans le presse-papiers !" 173 203 174 #: includes/register-files.php: 39204 #: includes/register-files.php:55 175 205 msgid "Failed to copy domain. Please try again." 176 206 msgstr "Impossible de copier le domaine. Veuillez réessayer." 177 207 178 #: includes/register-files.php: 40208 #: includes/register-files.php:56 179 209 msgid "Token copied to clipboard!" 180 210 msgstr "Jeton copié dans le presse-papiers !" 181 211 182 #: includes/register-files.php: 41212 #: includes/register-files.php:57 183 213 msgid "Failed to copy token. Please try again." 184 214 msgstr "Impossible de copier le jeton. Veuillez réessayer." 185 215 186 216 #: includes/update-functionality.php:23 187 msgid "Missing or invalid title." 188 msgstr "Titre manquant ou invalide." 189 190 #: includes/update-functionality.php:31 191 msgid "Post not found." 217 msgid "Missing or invalid resolutions data." 218 msgstr "Données de résolution manquantes ou non valides." 219 220 #: includes/update-functionality.php:44 221 msgid "Missing required data" 222 msgstr "Données requises manquantes" 223 224 #: includes/update-functionality.php:51 225 msgid "Post not found" 192 226 msgstr "Publication non trouvée." 193 227 194 #. translators: %s is the title of the created post. 195 #: includes/update-functionality.php:38 196 msgid "Post \"%s\" updated successfully." 228 #: includes/update-functionality.php:59 229 msgid "Missing archive name or style for update" 230 msgstr "Nom d'archive ou style manquant pour la mise à jour" 231 232 #: includes/update-functionality.php:72 233 msgid "Post \"%s\" updated successfully" 197 234 msgstr "Le message \"%s\" a été mis à jour avec succès." 198 235 199 #. translators: %s is the title of the created post. 200 #: includes/update-functionality.php:45 201 msgid "Post \"%s\" skipped." 236 #: includes/update-functionality.php:82 237 msgid "Post \"%s\" skipped" 202 238 msgstr "Message \"%s\" ignoré." 203 239 204 #: includes/update-functionality.php:49 205 msgid "Invalid request." 206 msgstr "" 240 #: includes/update-functionality.php:87 241 msgid "Invalid action" 242 msgstr "Action invalide" 243 244 #: includes/update-functionality.php:93 245 msgid "All conflicts resolved successfully" 246 msgstr "Tous les conflits ont été résolus avec succès" 247 248 #: includes/update-functionality.php:98 249 msgid "Some conflicts could not be resolved" 250 msgstr "Certains conflits n'ont pas pu être résolus" 251 252 #: admin/batch-page.php:37 253 msgid "Processing completed successfully!" 254 msgstr "Traitement terminé avec succès !" 255 256 #: admin/batch-page.php:38 257 msgid "Processing batch..." 258 msgstr "Traitement par lots en cours..." 259 260 #: admin/batch-page.php:39 261 msgid "Processing completed, but failed to clear data" 262 msgstr "Traitement terminé, mais échec de la suppression des données" 263 264 #: admin/batch-page.php:40 265 msgid "Error processing batch" 266 msgstr "Erreur lors du traitement par lots" 267 268 #: admin/batch-page.php:41 269 msgid "Error connecting to server: %s" 270 msgstr "Erreur de connexion au serveur : %s" 271 272 #: admin/batch-page.php:76 273 msgid "files processed" 274 msgstr "fichiers traités" -
topirank-integration/trunk/languages/topirank-integration.pot
r3220350 r3286404 3 3 msgid "" 4 4 msgstr "" 5 "Project-Id-Version: Topirank Integration 1. 0.2\n"5 "Project-Id-Version: Topirank Integration 1.1.6\n" 6 6 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/topirank-integration\n" 7 7 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" … … 10 10 "Content-Type: text/plain; charset=UTF-8\n" 11 11 "Content-Transfer-Encoding: 8bit\n" 12 "POT-Creation-Date: 2025-0 1-07T12:23:19+00:00\n"12 "POT-Creation-Date: 2025-05-02T12:06:58+00:00\n" 13 13 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 14 "X-Generator: WP-CLI 2.11.0\n" … … 30 30 msgstr "" 31 31 32 #: admin/admin-page.php:25 32 #: admin/admin-page.php:23 33 msgid "Server Status" 34 msgstr "" 35 36 #: admin/admin-page.php:36 33 37 msgid "Upload HTML archive" 34 38 msgstr "" 35 39 36 #: admin/admin-page.php: 2740 #: admin/admin-page.php:38 37 41 msgid "Easily upload all your data as an HTML archive" 38 42 msgstr "" 39 43 40 #: admin/admin-page.php: 2844 #: admin/admin-page.php:39 41 45 msgid "Maximum upload file size" 42 46 msgstr "" 43 47 44 #: admin/admin-page.php: 3445 #: includes/register-files.php: 3748 #: admin/admin-page.php:45 49 #: includes/register-files.php:53 46 50 msgid "Choose a file" 47 51 msgstr "" 48 52 49 #: admin/admin-page.php: 3853 #: admin/admin-page.php:49 50 54 msgid "Upload and create posts" 51 55 msgstr "" 52 56 53 #: admin/admin-page.php: 4557 #: admin/admin-page.php:57 54 58 msgid "Choose styles for your posts" 55 59 msgstr "" 56 60 57 #: admin/admin-page.php: 6161 #: admin/admin-page.php:73 58 62 msgid "Managing API Token" 59 63 msgstr "" 60 64 61 #: admin/admin-page.php: 6365 #: admin/admin-page.php:75 62 66 msgid "Generate and manage your API token securely" 63 67 msgstr "" 64 68 65 #: admin/admin-page.php: 6869 #: admin/admin-page.php:81 66 70 msgid "Get token" 67 71 msgstr "" 68 72 69 #: admin/admin-page.php: 7073 #: admin/admin-page.php:83 70 74 msgid "Copy Domain" 71 75 msgstr "" 72 76 73 #: admin/admin-page.php: 8777 #: admin/admin-page.php:100 74 78 msgid "New token successfully created. Check it below and save!" 75 79 msgstr "" 76 80 77 #: admin/admin-page.php: 8981 #: admin/admin-page.php:102 78 82 msgid "Your new token:" 79 83 msgstr "" 80 84 81 #: admin/admin-page.php: 9485 #: admin/admin-page.php:107 82 86 msgid "Copy" 83 87 msgstr "" 84 88 85 #: includes/api-integration.php:50 89 #: admin/admin-page.php:128 90 msgid "Ready to upload" 91 msgstr "" 92 93 #: admin/admin-page.php:132 94 #: admin/admin-page.php:142 95 msgid "Server is busy" 96 msgstr "" 97 98 #: admin/batch-page.php:30 99 msgid "Conflicts Occurred" 100 msgstr "" 101 102 #: admin/batch-page.php:31 103 msgid "Conflict" 104 msgstr "" 105 106 #: admin/batch-page.php:32 107 msgid "A post with title \"%s\" already exists" 108 msgstr "" 109 110 #: admin/batch-page.php:33 111 msgid "Update All" 112 msgstr "" 113 114 #: admin/batch-page.php:34 115 msgid "Skip All" 116 msgstr "" 117 118 #: admin/batch-page.php:35 119 msgid "Update" 120 msgstr "" 121 122 #: admin/batch-page.php:36 123 msgid "Skip" 124 msgstr "" 125 126 #: admin/batch-page.php:37 127 msgid "Processing completed successfully!" 128 msgstr "" 129 130 #: admin/batch-page.php:38 131 msgid "Processing batch..." 132 msgstr "" 133 134 #: admin/batch-page.php:39 135 msgid "Processing completed, but failed to clear data" 136 msgstr "" 137 138 #: admin/batch-page.php:40 139 msgid "Error processing batch" 140 msgstr "" 141 142 #: admin/batch-page.php:41 143 msgid "Error connecting to server: %s" 144 msgstr "" 145 146 #: admin/batch-page.php:57 147 #: includes/file-upload.php:12 148 msgid "Go Back to Main Page" 149 msgstr "" 150 151 #: admin/batch-page.php:62 152 msgid "Batch Processing" 153 msgstr "" 154 155 #: admin/batch-page.php:78 156 msgid "Ready to process" 157 msgstr "" 158 159 #: admin/batch-page.php:76 160 msgid "files processed" 161 msgstr "" 162 163 #: includes/api-integration.php:86 86 164 msgid "Authorization header is missing or invalid." 87 165 msgstr "" 88 166 89 #: includes/api-integration.php: 61167 #: includes/api-integration.php:97 90 168 msgid "No token is stored in the database." 91 169 msgstr "" 92 170 93 #: includes/api-integration.php: 69171 #: includes/api-integration.php:105 94 172 msgid "The provided token is invalid." 95 173 msgstr "" 96 174 97 #: includes/extract-and-create.php:13 98 msgid "Error unpacking the archive." 99 msgstr "" 100 101 #: includes/extract-and-create.php:29 102 msgid "The archive has been successfully unpacked!" 103 msgstr "" 104 105 #: includes/file-upload.php:10 106 msgid "Go Back to Main Page" 107 msgstr "" 108 109 #: includes/file-upload.php:42 175 #: includes/batch-processor.php:165 176 #: includes/batch-processor.php:332 177 #: includes/helpers.php:68 178 msgid "Post \"%s\" updated successfully!" 179 msgstr "" 180 181 #: includes/batch-processor.php:171 182 #: includes/batch-processor.php:338 183 msgid "Failed to update post \"%s\"" 184 msgstr "" 185 186 #: includes/batch-processor.php:202 187 #: includes/batch-processor.php:369 188 #: includes/batch-processor.php:449 189 #: includes/helpers.php:99 190 msgid "Post \"%s\" created successfully!" 191 msgstr "" 192 193 #: includes/batch-processor.php:208 194 #: includes/batch-processor.php:375 195 #: includes/batch-processor.php:455 196 msgid "Failed to create post from file: %s" 197 msgstr "" 198 199 #: includes/batch-processor.php:391 200 msgid "Skipping existing post \"%s\"" 201 msgstr "" 202 203 #: includes/batch-processor.php:407 204 msgid "File \"%s\" has a conflict with existing post \"%s\" - will be reviewed" 205 msgstr "" 206 207 #: includes/file-upload.php:39 208 #: includes/file-upload.php:156 209 msgid "Invalid file upload." 210 msgstr "" 211 212 #: includes/file-upload.php:89 110 213 msgid "Please upload a ZIP archive." 111 214 msgstr "" 112 215 113 #: includes/file-upload.php: 69216 #: includes/file-upload.php:138 114 217 msgid "Could not move the uploaded file." 115 218 msgstr "" 116 219 117 #: includes/file-upload.php: 79220 #: includes/file-upload.php:149 118 221 msgid "Upload failed. Please try again." 119 222 msgstr "" 120 223 121 #: includes/file-upload.php:85 122 msgid "Invalid file upload." 123 msgstr "" 124 125 #. translators: %s: The title of the created post 126 #: includes/helpers.php:74 127 msgid "Post \"%s\" created successfully!" 128 msgstr "" 129 130 #. translators: %s is the file name from which we attempted to create a post. 131 #: includes/helpers.php:92 224 #: includes/helpers.php:104 132 225 msgid "Error creating post from file: %s" 133 226 msgstr "" 134 227 135 #: includes/helpers.php:113 136 msgid "The following conflicts occurred:" 137 msgstr "" 138 139 #: includes/helpers.php:116 140 msgid "Update All" 141 msgstr "" 142 143 #: includes/helpers.php:119 144 msgid "Skip All" 145 msgstr "" 146 147 #: includes/helpers.php:137 148 msgid "Conflict" 149 msgstr "" 150 151 #. translators: %s is the title of the created post. 152 #: includes/helpers.php:145 153 msgid "A post with the title \"%s\" already exists." 154 msgstr "" 155 156 #: includes/helpers.php:160 157 msgid "Update" 158 msgstr "" 159 160 #: includes/helpers.php:165 161 msgid "Skip" 162 msgstr "" 163 164 #: includes/register-files.php:38 228 #: includes/register-files.php:54 165 229 msgid "Domain copied to clipboard!" 166 230 msgstr "" 167 231 168 #: includes/register-files.php: 39232 #: includes/register-files.php:55 169 233 msgid "Failed to copy domain. Please try again." 170 234 msgstr "" 171 235 172 #: includes/register-files.php: 40236 #: includes/register-files.php:56 173 237 msgid "Token copied to clipboard!" 174 238 msgstr "" 175 239 176 #: includes/register-files.php: 41240 #: includes/register-files.php:57 177 241 msgid "Failed to copy token. Please try again." 178 242 msgstr "" 179 243 180 244 #: includes/update-functionality.php:23 181 msgid "Missing or invalid title." 182 msgstr "" 183 184 #: includes/update-functionality.php:31 185 msgid "Post not found." 186 msgstr "" 187 188 #. translators: %s is the title of the created post. 189 #: includes/update-functionality.php:38 190 msgid "Post \"%s\" updated successfully." 191 msgstr "" 192 193 #. translators: %s is the title of the created post. 194 #: includes/update-functionality.php:45 195 msgid "Post \"%s\" skipped." 196 msgstr "" 197 198 #: includes/update-functionality.php:49 199 msgid "Invalid request." 200 msgstr "" 245 msgid "Missing or invalid resolutions data." 246 msgstr "" 247 248 #: includes/update-functionality.php:44 249 msgid "Missing required data" 250 msgstr "" 251 252 #: includes/update-functionality.php:51 253 msgid "Post not found" 254 msgstr "" 255 256 #: includes/update-functionality.php:59 257 msgid "Missing archive name or style for update" 258 msgstr "" 259 260 #: includes/update-functionality.php:72 261 msgid "Post \"%s\" updated successfully" 262 msgstr "" 263 264 #: includes/update-functionality.php:82 265 msgid "Post \"%s\" skipped" 266 msgstr "" 267 268 #: includes/update-functionality.php:87 269 msgid "Invalid action" 270 msgstr "" 271 272 #: includes/update-functionality.php:93 273 msgid "All conflicts resolved successfully" 274 msgstr "" 275 276 #: includes/update-functionality.php:98 277 msgid "Some conflicts could not be resolved" 278 msgstr "" -
topirank-integration/trunk/readme.txt
r3271065 r3286404 3 3 Tags: seo, posts, parsing 4 4 Requires at least: 6.0 5 Tested up to: 6. 7.26 Stable tag: 1.1.65 Tested up to: 6.8 6 Stable tag: 2.0 7 7 Requires PHP: 7.3 8 8 License: GPLv2 or later … … 66 66 67 67 == Changelog == 68 69 = 2.0 = 70 - Refactored data upload functionality (manual and via API). 71 - Improved process logging. 72 - Added server availability check for new requests. 73 - Resolved timeout() handling issue. 74 - Updated parser behavior. 75 - Fixed HTML parsing errors. 76 - Enhanced CPT selection functionality. 77 - Redesigned admin UI with visual controls. 78 - Rebuilt post skip and update logic. 79 - Improved error logging. 80 - Tested with WordPress version 6.8 81 68 82 69 83 = 1.1.6 = -
topirank-integration/trunk/topirank-integration.php
r3271065 r3286404 3 3 Plugin Name: Topirank Integration 4 4 Description: Plugin for parsing pages 5 Version: 1.1.65 Version: 2.0 6 6 Author: Topirank 7 7 License: GPLv2 or later … … 13 13 } 14 14 15 // Load batch processor first to ensure it's available for other files 16 require_once plugin_dir_path(__FILE__) . 'includes/batch-processor.php'; 15 17 16 18 require_once plugin_dir_path(__FILE__) . 'admin/menu.php'; 17 19 require_once plugin_dir_path(__FILE__) . 'admin/admin-page.php'; 20 require_once plugin_dir_path(__FILE__) . 'admin/batch-page.php'; 18 21 require_once plugin_dir_path(__FILE__) . 'includes/utils.php'; 19 22 require_once plugin_dir_path(__FILE__) . 'includes/init.php';
Note: See TracChangeset
for help on using the changeset viewer.