Plugin Directory

Changeset 3286404


Ignore:
Timestamp:
05/02/2025 04:18:40 PM (11 months ago)
Author:
topirank
Message:

Init version 2.0

Location:
topirank-integration
Files:
41 added
18 edited

Legend:

Unmodified
Added
Removed
  • topirank-integration/trunk/admin/admin-page.php

    r3234611 r3286404  
    1919        <div id="notification" class="notification"></div>
    2020        <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
    2133            <form method="POST" enctype="multipart/form-data" action="<?php echo esc_url(admin_url('admin.php?page=topirank_process_upload')); ?>">
    2234                <div class="topirank_main_content_line first_line">
     
    3850
    3951                    </div>
     52
    4053                </div>
    4154
     
    98111        </div>
    99112    </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>
    100186<?php
    101187}
  • topirank-integration/trunk/admin/menu.php

    r3220350 r3286404  
    1818
    1919add_action('admin_menu', function () {
     20    // Hidden upload processing page
    2021    add_submenu_page(
    2122        null,
     
    2627        'topirank_render_process_upload_page'
    2728    );
     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    );
    2839});
  • topirank-integration/trunk/assets/js/topirank-admin-scripts.js

    r3237927 r3286404  
    11document.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
    247    document.querySelectorAll('.update-post').forEach(button => {
    348        button.addEventListener('click', function () {
     
    853            const selstyle = this.getAttribute('data-selstyle');
    954
    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)
    2364                .then(result => {
    2465                    if (result.success) {
     
    2768                        parent.innerHTML = `<div class="error-message">${result.data.message}</div>`;
    2869                    }
     70                })
     71                .catch(error => {
     72                    console.error('Error:', error);
     73                    parent.innerHTML = `<div class="error-message">An error occurred: ${error.message}</div>`;
    2974                });
    3075        });
     
    3681            const title = this.getAttribute('data-title');
    3782
    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)
    4889                .then(result => {
    4990                    if (result.success) {
     
    5293                        parent.innerHTML = `<div class="error-message">${result.data.message}</div>`;
    5394                    }
     95                })
     96                .catch(error => {
     97                    console.error('Error:', error);
     98                    parent.innerHTML = `<div class="error-message">An error occurred: ${error.message}</div>`;
    5499                });
    55100        });
  • topirank-integration/trunk/includes/api-integration.php

    r3268778 r3286404  
    2525        'methods' => 'GET',
    2626        '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',
    2745    ]);
    2846}
     
    93111}
    94112
     113function 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
    95250function topirank_handle_rest_file_upload(WP_REST_Request $request)
    96251{
    97 
    98252    /* phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing */
    99253
    100254    $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    }
    101260
    102261    $chunkIndex = intval($request->get_param('chunkIndex'));
     
    107266    $selected_type = isset($request['type']) ? sanitize_key($request['type']) : 'page';
    108267
    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);
    112278
    113279    $upload_dir = wp_upload_dir();
    114280    $base_temp_dir = $upload_dir['basedir'] . '/topirank-temp';
    115 
    116281    $temp_dir = $base_temp_dir . '/' . md5($fileName);
    117 
    118282
    119283    if (!file_exists($temp_dir)) {
     
    122286
    123287    $temp_file_path = $temp_dir . '/' . $fileName . '.part';
    124 
    125288    $handle = fopen($temp_file_path, 'ab');
     289
    126290    if (!$handle) {
     291        topirank_set_processing_status(false);
     292        error_log('Failed to open temp file: ' . $temp_file_path);
    127293        return new WP_REST_Response(['message' => 'Error opening temp file.'], 500);
    128294    }
     
    140306
    141307        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);
    142310            return new WP_REST_Response(['message' => 'Failed to finalize file upload.'], 500);
    143311        }
     
    145313        $file_extension = pathinfo($final_path, PATHINFO_EXTENSION);
    146314        if ($file_extension !== 'zip') {
     315            topirank_set_processing_status(false);
     316            error_log('Invalid file extension: ' . $file_extension);
    147317            return new WP_REST_Response(['message' => 'Please upload a ZIP archive.'], 400);
    148318        }
     
    151321        if (!file_exists($topirank_dir)) {
    152322            wp_mkdir_p($topirank_dir);
     323            error_log('Created topirank directory: ' . $topirank_dir);
    153324        }
    154325
    155326        $extracted_path = $topirank_dir . '/' . basename($final_path, '.zip');
    156327
    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
    176329        $files = glob($temp_dir . '/*');
    177330        foreach ($files as $file) {
     
    182335        rmdir($temp_dir);
    183336
    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        }
    185439    }
    186440
    187441    return new WP_REST_Response(['message' => 'Chunk uploaded successfully.'], 200);
    188442}
     443
     444// Add endpoint for processing next batch
     445add_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
     453function 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
     513function 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
     532function 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
     553function topirank_update_progress($progress)
     554{
     555    update_option('topirank_upload_progress', $progress);
     556    topirank_update_activity();
     557}
     558
     559function 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
     569function topirank_update_activity()
     570{
     571    if (get_option('topirank_is_processing', false)) {
     572        update_option('topirank_last_activity', time());
     573    }
     574}
     575
     576function 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
     621function 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  
    11<?php
     2if (session_status() === PHP_SESSION_NONE) {
     3    session_start();
     4}
    25
    36if (! defined('ABSPATH')) exit;
    47
     8// Start output buffering to prevent headers already sent error
     9ob_start();
     10
    511function topirank_extract_and_create_posts($zip_path, $extracted_path, $replace, $selected_style, $selected_type, $check_delete = true)
    612{
     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
    724    $zip = new ZipArchive;
    825    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;
    1928    }
    2029
     
    2433    topirank_normalize_folder_names($extracted_path);
    2534
    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 
    3535    $upload_dir = wp_upload_dir();
    3636    $base_upload_path = $upload_dir['basedir'];
     
    3939    topirank_create_base_directories($topirank_base_dir);
    4040
    41     $archive_name = pathinfo($zip_path, PATHINFO_FILENAME);
    42     $archive_name = str_replace(' ', '-', $archive_name);
    43 
    4441    $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
    4646    $css_files = topirank_search_files($extracted_path, 'css');
    4747    topirank_copy_files($css_files, $css_destination, $selected_style);
     
    4949
    5050    $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);
    5252    $fonts_folder = topirank_search_directory($extracted_path, 'fonts');
    5353
     
    5858
    5959    topirank_process_css_fonts($css_files, $fonts_destination, $upload_dir['baseurl'] . '/topirank/fonts/' . $archive_name);
    60 
    6160    $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);
    6362    topirank_copy_files(
    6463        topirank_search_files($extracted_path, 'js'),
     
    6766    );
    6867
    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    }
    7096
    7197    return true;
     
    92118}
    93119
    94 function topirank_ensure_unique_directory(&$path, &$archive_name)
     120function topirank_ensure_unique_directory(&$path, $archive_name)
    95121{
    96122    $wp_filesystem = topirank_get_filesystem();
     
    99125    $original_name = $archive_name;
    100126    $counter = 1;
     127    $current_name = $archive_name;
    101128
    102129    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;
    105132        $counter++;
    106133    }
  • topirank-integration/trunk/includes/file-upload.php

    r3268778 r3286404  
    2424function topirank_handle_file_upload()
    2525{
     26  error_log('Starting file upload handler');
     27
    2628  if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
     29    error_log('POST request detected');
     30
    2731    if (!isset($_FILES['html_archive']) || empty($_FILES['html_archive']['tmp_name'])) {
     32      error_log('No file uploaded or empty file');
    2833      echo '<div class="topirank_main_content_line without_space_between">
    2934        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
     
    3843    }
    3944
     45    error_log('File upload detected: ' . print_r($_FILES['html_archive'], true));
     46
    4047    $file = isset($_FILES['html_archive']) && is_array($_FILES['html_archive'])
    4148      ? array_map('sanitize_text_field', $_FILES['html_archive'])
     
    4350
    4451    if (is_array($file) && isset($file['name'], $file['tmp_name'])) {
     52      error_log('Valid file array detected');
     53
    4554      $upload_dir   = wp_upload_dir();
    4655      $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      }
    4876
    4977      $selected_style = isset($_POST['style']) ? sanitize_text_field(wp_unslash($_POST['style'])) : '';
     
    5179      $replace = '';
    5280
     81      error_log('Selected style: ' . $selected_style);
     82      error_log('Selected type: ' . $selected_type);
     83
    5384      $file_extension = pathinfo($file['name'], PATHINFO_EXTENSION);
    5485
    5586      if (strtolower($file_extension) !== 'zip') {
     87        error_log('Invalid file extension: ' . $file_extension);
    5688        echo '<div class="error notice"><p>';
    5789        esc_html_e('Please upload a ZIP archive.', 'topirank-integration');
     
    6193
    6294      if (!file_exists($topirank_dir)) {
     95        error_log('Creating directory: ' . $topirank_dir);
    6396        wp_mkdir_p($topirank_dir);
    6497      }
    6598
     99      error_log('Handling file upload with wp_handle_upload');
    66100      $uploaded_file = wp_handle_upload($file, array('test_form' => false));
     101      error_log('wp_handle_upload result: ' . print_r($uploaded_file, true));
    67102
    68103      if (isset($uploaded_file['file']) && ! isset($uploaded_file['error'])) {
     104        error_log('File uploaded successfully');
     105
    69106        $original_path = $uploaded_file['file'];
    70107        $zip_path      = $topirank_dir . '/' . basename($original_path);
     108
     109        error_log('Original path: ' . $original_path);
     110        error_log('Zip path: ' . $zip_path);
    71111
    72112        $wp_filesystem = topirank_get_filesystem();
    73113
    74114        if ($wp_filesystem->move($original_path, $zip_path, true)) {
     115          error_log('File moved successfully to: ' . $zip_path);
     116
    75117          $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');
    76127          topirank_extract_and_create_posts($zip_path, $extracted_path, $replace, $selected_style, $selected_type);
     128          error_log('File extraction and post creation completed');
    77129
    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;
    81134        } else {
     135          error_log('Failed to move file from ' . $original_path . ' to ' . $zip_path);
    82136          echo '<div class="topirank_main_content_line">';
    83137          echo '<div class="topirank_line_title">';
     
    87141        }
    88142      } else {
     143        error_log('Upload failed: ' . print_r($uploaded_file, true));
    89144        echo '<div class="topirank_main_content_line">';
    90145        echo '<div class="topirank_line_title">';
     
    98153      }
    99154    } else {
     155      error_log('Invalid file array structure');
    100156      esc_html_e('Invalid file upload.', 'topirank-integration');
    101157    }
     158  } else {
     159    error_log('Not a POST request');
    102160  }
    103161}
  • topirank-integration/trunk/includes/helpers.php

    r3266247 r3286404  
    55function topirank_create_posts_from_html($folder_path, $archive_name, $replace, $selected_style, $selected_type, &$check_delete)
    66{
    7     set_time_limit(0);
    87    $wp_filesystem = topirank_get_filesystem();
    98    $post_type_to_create = ($selected_type === 'article') ? 'post' : 'page';
    109
     10    // Store original archive name
     11    $original_archive_name = $archive_name;
    1112    $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($folder_path));
    1213    $post_ids = [];
    1314    $conflicts = [];
     15    $messages = [];
     16    $conflict_data = [];
    1417
    1518    foreach ($files as $file) {
    1619        if (pathinfo($file, PATHINFO_EXTENSION) === 'html') {
    1720            $directory_name = basename(dirname($file));
    18             if ($directory_name === '404' || basename($file) === '404.html') {
    19                 continue;
    20             }
    2121            $file_path = $file->getPathname();
     22
    2223            $content = $wp_filesystem->get_contents($file_path);
     24
    2325            $article_title = topirank_extract_title_from_html($file_path);
    2426
     
    5355
    5456                    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                        );
    5662                    }
    5763                } 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                    ];
    5971                }
    6072                continue;
    6173            }
    62 
    63             $directory_name = basename(dirname($file->getPathname()));
    6474
    6575            $post_id = wp_insert_post([
     
    6777                'post_content' => $content,
    6878                'post_status'  => 'publish',
    69                 'post_type'      => $post_type_to_create,
     79                'post_type'    => $post_type_to_create,
    7080                'post_name'    => sanitize_title($directory_name),
    7181            ]);
    7282
    7383            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                );
    9193            } 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                );
    10998            }
    11099        }
    111100    }
    112101
    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;
    185105    }
    186106
    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    ];
    192112}
    193113
  • topirank-integration/trunk/includes/init.php

    r3234611 r3286404  
    99  if (empty($wp_filesystem)) {
    1010    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    }
    1228  }
    1329
     
    3046
    3147topirank_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  
    11<?php
    22
    3 if (! defined('ABSPATH')) exit;
     3// if (! defined('ABSPATH')) exit;
    44
    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//     }
    1111
    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  
    1313        'toplevel_page_topirank_plugin',
    1414        'admin_page_topirank_process_upload',
     15        'admin_page_topirank_batch_processing'
    1516    ];
    1617
     
    2223        'topirank-admin-style',
    2324        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',
    2432        [],
    2533        '1.0.0'
  • topirank-integration/trunk/includes/topirank-template.php

    r3268778 r3286404  
    1212get_header();
    1313$choose_styles = get_post_meta($post->ID, 'choose_styles', true);
     14$arhive_name = get_post_meta($post->ID, '_topirank_archive_name', true);
     15var_dump($arhive_name);
    1416if ($choose_styles == "wp") {
    1517    $choose_styles_class = "wordpress-styles";
  • topirank-integration/trunk/includes/update-content-and-seo.php

    r3268778 r3286404  
    55function topirank_update_post_content($post_id, $file, $archive_name, $selected_style)
    66{
     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
    716  topirank_delete_page_images($post_id);
    817
    918  $wp_filesystem = topirank_get_filesystem();
     19  if (!$wp_filesystem) {
     20    return new WP_Error('filesystem_error', 'Failed to initialize filesystem');
     21  }
    1022
    1123  $choose_styles = ($selected_style === 'wp') ? 'wp' : 'topirank-integration';
     
    1426  update_post_meta($post_id, '_wp_page_template', 'includes/topirank-template.php');
    1527
     28
    1629  $content = $wp_filesystem->get_contents($file);
     30  if ($content === false) {
     31    return new WP_Error('read_error', 'Failed to read file contents');
     32  }
    1733
    1834  if (preg_match('/<title>(.*?)<\/title>/is', $content, $title_match)) {
     
    3147
    3248  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);
    3756  libxml_clear_errors();
    3857
     
    122141
    123142      $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']);
    126144
    127145      $content = preg_replace('/color\s*:\s*[^;"]+;?/i', '', $content);
     146      $content = preg_replace('/font-family\s*:\s*[^;"]+;?/i', '', $content);
    128147
    129148      $buttons = $container->getElementsByTagName('button');
     
    141160        }
    142161      }
    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());
    156167  $content = preg_replace('/<head\b[^>]*>.*?<\/head>/is', '', $content);
    157168
     
    211222  }
    212223
    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  }
    221244
    222245  if (class_exists('WPSEO_Meta')) {
    223 
    224246    if ($title) {
    225247      WPSEO_Meta::set_value('opengraph-title', $title, $post_id);
     
    234256    }
    235257  }
     258
     259  return true;
    236260}
    237261
  • topirank-integration/trunk/includes/update-functionality.php

    r3236026 r3286404  
    22
    33if (! defined('ABSPATH')) exit;
     4
     5require_once plugin_dir_path(__FILE__) . 'update-content-and-seo.php';
    46
    57function topirank_generate_unique_title($title)
     
    1618function topirank_handle_conflict()
    1719{
    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');
    2421
    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;
    2725    }
    2826
    29     $title = trim(preg_replace('/\s+/', ' ', $title));
     27    $resolutions = $_POST['resolutions'];
     28    $results = [];
     29    $success = true;
    3030
    31     $post = topirank_get_post_by_title($title);
     31    foreach ($resolutions as $file_path => $resolution) {
     32        if (!is_array($resolution)) {
     33            continue;
     34        }
    3235
    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        }
    3589    }
    3690
    37     if ($replace && $file) {
    38         topirank_update_post_content($post->ID, $file, $archive_name, $selected_style);
     91    if ($success) {
    3992        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
    42100        ]);
    43101    }
    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')]);
    53102}
    54103
    55104function topirank_get_post_by_title($title)
    56105{
    57     $args = [
    58         'post_type'      => 'page',
    59         'title'          => $title,
    60         'post_status'    => 'any',
    61         'posts_per_page' => 1,
    62     ];
     106    global $wpdb;
    63107
    64     $query = new WP_Query($args);
     108    $title = trim($title);
    65109
    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) {
    70116        return $post;
    71117    }
    72118
    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
    74132    return null;
    75133}
  • topirank-integration/trunk/languages/topirank-integration-fr_FR.po

    r3220350 r3286404  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Topirank Integration 1.0.2\n"
     5"Project-Id-Version: Topirank Integration 1.1.6\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/topirank-"
    77"integration\n"
    8 "POT-Creation-Date: 2025-01-07T12:23:19+00:00\n"
    9 "PO-Revision-Date: 2025-01-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"
    1010"Last-Translator: \n"
    1111"Language-Team: \n"
     
    3232msgstr "Topirank"
    3333
    34 #: admin/admin-page.php:25
     34#: admin/admin-page.php:23
     35msgid "Server Status"
     36msgstr "Statut du serveur"
     37
     38#: admin/admin-page.php:36
    3539msgid "Upload HTML archive"
    3640msgstr "Télécharger l'archive HTML"
    3741
    38 #: admin/admin-page.php:27
     42#: admin/admin-page.php:38
    3943msgid "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
     44msgstr "Téléchargez facilement toutes vos données sous forme d'archive HTML"
     45
     46#: admin/admin-page.php:39
    4447msgid "Maximum upload file size"
    4548msgstr "Taille maximale du fichier à télécharger"
    4649
    47 #: admin/admin-page.php:34 includes/register-files.php:37
     50#: admin/admin-page.php:45 includes/register-files.php:53
    4851msgid "Choose a file"
    4952msgstr "Choisissez un fichier"
    5053
    51 #: admin/admin-page.php:38
     54#: admin/admin-page.php:49
    5255msgid "Upload and create posts"
    5356msgstr "Télécharger et créer des publications"
    5457
    55 #: admin/admin-page.php:45
     58#: admin/admin-page.php:57
    5659msgid "Choose styles for your posts"
    5760msgstr "Choisissez des styles pour vos publications"
    5861
    59 #: admin/admin-page.php:61
     62#: admin/admin-page.php:73
    6063msgid "Managing API Token"
    6164msgstr "Gestion des jetons API"
    6265
    63 #: admin/admin-page.php:63
     66#: admin/admin-page.php:75
    6467msgid "Generate and manage your API token securely"
    6568msgstr "Générez et gérez votre token API en toute sécurité"
    6669
    67 #: admin/admin-page.php:68
     70#: admin/admin-page.php:81
    6871msgid "Get token"
    6972msgstr "Obtenir un jeton"
    7073
    71 #: admin/admin-page.php:70
     74#: admin/admin-page.php:83
    7275msgid "Copy Domain"
    7376msgstr "Copier le domaine"
    7477
    75 #: admin/admin-page.php:87
     78#: admin/admin-page.php:100
    7679msgid "New token successfully created. Check it below and save!"
    7780msgstr ""
    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
    8284msgid "Your new token:"
    8385msgstr "Votre nouveau token :"
    8486
    85 #: admin/admin-page.php:94
     87#: admin/admin-page.php:107
    8688msgid "Copy"
    8789msgstr "Copie"
    8890
    89 #: includes/api-integration.php:50
     91#: admin/admin-page.php:128
     92msgid "Ready to upload"
     93msgstr "Prêt à télécharger"
     94
     95#: admin/admin-page.php:132 admin/admin-page.php:142
     96msgid "Server is busy"
     97msgstr "Le serveur est occupé"
     98
     99#: admin/batch-page.php:30
     100msgid "Conflicts Occurred"
     101msgstr "Des conflits ont eu lieu"
     102
     103#: admin/batch-page.php:31
     104msgid "Conflict"
     105msgstr "Conflit"
     106
     107#: admin/batch-page.php:32
     108msgid "A post with title \"%s\" already exists"
     109msgstr "Un message avec le titre \"%s\" existe déjà"
     110
     111#: admin/batch-page.php:33
     112msgid "Update All"
     113msgstr "Tout mettre à jour"
     114
     115#: admin/batch-page.php:34
     116msgid "Skip All"
     117msgstr "Sauter tout"
     118
     119#: admin/batch-page.php:35
     120msgid "Update"
     121msgstr "Mise à jour"
     122
     123#: admin/batch-page.php:36
     124msgid "Skip"
     125msgstr "Sauter"
     126
     127#: admin/batch-page.php:57 includes/file-upload.php:12
     128msgid "Go Back to Main Page"
     129msgstr "Retourner à la page principale"
     130
     131#: admin/batch-page.php:62
     132msgid "Batch Processing"
     133msgstr "Traitement par lots"
     134
     135#: admin/batch-page.php:78
     136msgid "Ready to process"
     137msgstr "Prêt à être traité"
     138
     139#: includes/api-integration.php:86
    90140msgid "Authorization header is missing or invalid."
    91141msgstr "L'en-tête d'autorisation est manquant ou non valide."
    92142
    93 #: includes/api-integration.php:61
     143#: includes/api-integration.php:97
    94144msgid "No token is stored in the database."
    95145msgstr "Aucun jeton n'est stocké dans la base de données."
    96146
    97 #: includes/api-integration.php:69
     147#: includes/api-integration.php:105
    98148msgid "The provided token is invalid."
    99149msgstr "Le jeton fourni n'est pas valide."
    100150
    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
     153msgid "Post \"%s\" updated successfully!"
     154msgstr "Le message \"%s\" a été mis à jour avec succès."
     155
     156#: includes/batch-processor.php:171 includes/batch-processor.php:338
     157msgid "Failed to update post \"%s\""
     158msgstr "É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
     162msgid "Post \"%s\" created successfully!"
     163msgstr "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
     167msgid "Failed to create post from file: %s"
     168msgstr "Échec de la création de la publication à partir du fichier : %s"
     169
     170#: includes/batch-processor.php:391
     171msgid "Skipping existing post \"%s\""
     172msgstr "Ignorer la publication existante \"%s\""
     173
     174#: includes/batch-processor.php:407
     175msgid "File \"%s\" has a conflict with existing post \"%s\" - will be reviewed"
     176msgstr ""
     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
     181msgid "Invalid file upload."
     182msgstr "Téléchargement de fichier invalide."
     183
     184#: includes/file-upload.php:89
    114185msgid "Please upload a ZIP archive."
    115186msgstr "Veuillez télécharger une archive ZIP."
    116187
    117 #: includes/file-upload.php:69
     188#: includes/file-upload.php:138
    118189msgid "Could not move the uploaded file."
    119190msgstr "Impossible de déplacer le fichier téléchargé."
    120191
    121 #: includes/file-upload.php:79
     192#: includes/file-upload.php:149
    122193msgid "Upload failed. Please try again."
    123194msgstr "Le téléchargement a échoué. Veuillez réessayer."
    124195
    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
    136197msgid "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
     198msgstr "Erreur lors de la création de la publication à partir du fichier : %s"
     199
     200#: includes/register-files.php:54
    171201msgid "Domain copied to clipboard!"
    172202msgstr "Domaine copié dans le presse-papiers !"
    173203
    174 #: includes/register-files.php:39
     204#: includes/register-files.php:55
    175205msgid "Failed to copy domain. Please try again."
    176206msgstr "Impossible de copier le domaine. Veuillez réessayer."
    177207
    178 #: includes/register-files.php:40
     208#: includes/register-files.php:56
    179209msgid "Token copied to clipboard!"
    180210msgstr "Jeton copié dans le presse-papiers !"
    181211
    182 #: includes/register-files.php:41
     212#: includes/register-files.php:57
    183213msgid "Failed to copy token. Please try again."
    184214msgstr "Impossible de copier le jeton. Veuillez réessayer."
    185215
    186216#: 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."
     217msgid "Missing or invalid resolutions data."
     218msgstr "Données de résolution manquantes ou non valides."
     219
     220#: includes/update-functionality.php:44
     221msgid "Missing required data"
     222msgstr "Données requises manquantes"
     223
     224#: includes/update-functionality.php:51
     225msgid "Post not found"
    192226msgstr "Publication non trouvée."
    193227
    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
     229msgid "Missing archive name or style for update"
     230msgstr "Nom d'archive ou style manquant pour la mise à jour"
     231
     232#: includes/update-functionality.php:72
     233msgid "Post \"%s\" updated successfully"
    197234msgstr "Le message \"%s\" a été mis à jour avec succès."
    198235
    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
     237msgid "Post \"%s\" skipped"
    202238msgstr "Message \"%s\" ignoré."
    203239
    204 #: includes/update-functionality.php:49
    205 msgid "Invalid request."
    206 msgstr ""
     240#: includes/update-functionality.php:87
     241msgid "Invalid action"
     242msgstr "Action invalide"
     243
     244#: includes/update-functionality.php:93
     245msgid "All conflicts resolved successfully"
     246msgstr "Tous les conflits ont été résolus avec succès"
     247
     248#: includes/update-functionality.php:98
     249msgid "Some conflicts could not be resolved"
     250msgstr "Certains conflits n'ont pas pu être résolus"
     251
     252#: admin/batch-page.php:37
     253msgid "Processing completed successfully!"
     254msgstr "Traitement terminé avec succès !"
     255
     256#: admin/batch-page.php:38
     257msgid "Processing batch..."
     258msgstr "Traitement par lots en cours..."
     259
     260#: admin/batch-page.php:39
     261msgid "Processing completed, but failed to clear data"
     262msgstr "Traitement terminé, mais échec de la suppression des données"
     263
     264#: admin/batch-page.php:40
     265msgid "Error processing batch"
     266msgstr "Erreur lors du traitement par lots"
     267
     268#: admin/batch-page.php:41
     269msgid "Error connecting to server: %s"
     270msgstr "Erreur de connexion au serveur : %s"
     271
     272#: admin/batch-page.php:76
     273msgid "files processed"
     274msgstr "fichiers traités"
  • topirank-integration/trunk/languages/topirank-integration.pot

    r3220350 r3286404  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Topirank Integration 1.0.2\n"
     5"Project-Id-Version: Topirank Integration 1.1.6\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/topirank-integration\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2025-01-07T12:23:19+00:00\n"
     12"POT-Creation-Date: 2025-05-02T12:06:58+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.11.0\n"
     
    3030msgstr ""
    3131
    32 #: admin/admin-page.php:25
     32#: admin/admin-page.php:23
     33msgid "Server Status"
     34msgstr ""
     35
     36#: admin/admin-page.php:36
    3337msgid "Upload HTML archive"
    3438msgstr ""
    3539
    36 #: admin/admin-page.php:27
     40#: admin/admin-page.php:38
    3741msgid "Easily upload all your data as an HTML archive"
    3842msgstr ""
    3943
    40 #: admin/admin-page.php:28
     44#: admin/admin-page.php:39
    4145msgid "Maximum upload file size"
    4246msgstr ""
    4347
    44 #: admin/admin-page.php:34
    45 #: includes/register-files.php:37
     48#: admin/admin-page.php:45
     49#: includes/register-files.php:53
    4650msgid "Choose a file"
    4751msgstr ""
    4852
    49 #: admin/admin-page.php:38
     53#: admin/admin-page.php:49
    5054msgid "Upload and create posts"
    5155msgstr ""
    5256
    53 #: admin/admin-page.php:45
     57#: admin/admin-page.php:57
    5458msgid "Choose styles for your posts"
    5559msgstr ""
    5660
    57 #: admin/admin-page.php:61
     61#: admin/admin-page.php:73
    5862msgid "Managing API Token"
    5963msgstr ""
    6064
    61 #: admin/admin-page.php:63
     65#: admin/admin-page.php:75
    6266msgid "Generate and manage your API token securely"
    6367msgstr ""
    6468
    65 #: admin/admin-page.php:68
     69#: admin/admin-page.php:81
    6670msgid "Get token"
    6771msgstr ""
    6872
    69 #: admin/admin-page.php:70
     73#: admin/admin-page.php:83
    7074msgid "Copy Domain"
    7175msgstr ""
    7276
    73 #: admin/admin-page.php:87
     77#: admin/admin-page.php:100
    7478msgid "New token successfully created. Check it below and save!"
    7579msgstr ""
    7680
    77 #: admin/admin-page.php:89
     81#: admin/admin-page.php:102
    7882msgid "Your new token:"
    7983msgstr ""
    8084
    81 #: admin/admin-page.php:94
     85#: admin/admin-page.php:107
    8286msgid "Copy"
    8387msgstr ""
    8488
    85 #: includes/api-integration.php:50
     89#: admin/admin-page.php:128
     90msgid "Ready to upload"
     91msgstr ""
     92
     93#: admin/admin-page.php:132
     94#: admin/admin-page.php:142
     95msgid "Server is busy"
     96msgstr ""
     97
     98#: admin/batch-page.php:30
     99msgid "Conflicts Occurred"
     100msgstr ""
     101
     102#: admin/batch-page.php:31
     103msgid "Conflict"
     104msgstr ""
     105
     106#: admin/batch-page.php:32
     107msgid "A post with title \"%s\" already exists"
     108msgstr ""
     109
     110#: admin/batch-page.php:33
     111msgid "Update All"
     112msgstr ""
     113
     114#: admin/batch-page.php:34
     115msgid "Skip All"
     116msgstr ""
     117
     118#: admin/batch-page.php:35
     119msgid "Update"
     120msgstr ""
     121
     122#: admin/batch-page.php:36
     123msgid "Skip"
     124msgstr ""
     125
     126#: admin/batch-page.php:37
     127msgid "Processing completed successfully!"
     128msgstr ""
     129
     130#: admin/batch-page.php:38
     131msgid "Processing batch..."
     132msgstr ""
     133
     134#: admin/batch-page.php:39
     135msgid "Processing completed, but failed to clear data"
     136msgstr ""
     137
     138#: admin/batch-page.php:40
     139msgid "Error processing batch"
     140msgstr ""
     141
     142#: admin/batch-page.php:41
     143msgid "Error connecting to server: %s"
     144msgstr ""
     145
     146#: admin/batch-page.php:57
     147#: includes/file-upload.php:12
     148msgid "Go Back to Main Page"
     149msgstr ""
     150
     151#: admin/batch-page.php:62
     152msgid "Batch Processing"
     153msgstr ""
     154
     155#: admin/batch-page.php:78
     156msgid "Ready to process"
     157msgstr ""
     158
     159#: admin/batch-page.php:76
     160msgid "files processed"
     161msgstr ""
     162
     163#: includes/api-integration.php:86
    86164msgid "Authorization header is missing or invalid."
    87165msgstr ""
    88166
    89 #: includes/api-integration.php:61
     167#: includes/api-integration.php:97
    90168msgid "No token is stored in the database."
    91169msgstr ""
    92170
    93 #: includes/api-integration.php:69
     171#: includes/api-integration.php:105
    94172msgid "The provided token is invalid."
    95173msgstr ""
    96174
    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
     178msgid "Post \"%s\" updated successfully!"
     179msgstr ""
     180
     181#: includes/batch-processor.php:171
     182#: includes/batch-processor.php:338
     183msgid "Failed to update post \"%s\""
     184msgstr ""
     185
     186#: includes/batch-processor.php:202
     187#: includes/batch-processor.php:369
     188#: includes/batch-processor.php:449
     189#: includes/helpers.php:99
     190msgid "Post \"%s\" created successfully!"
     191msgstr ""
     192
     193#: includes/batch-processor.php:208
     194#: includes/batch-processor.php:375
     195#: includes/batch-processor.php:455
     196msgid "Failed to create post from file: %s"
     197msgstr ""
     198
     199#: includes/batch-processor.php:391
     200msgid "Skipping existing post \"%s\""
     201msgstr ""
     202
     203#: includes/batch-processor.php:407
     204msgid "File \"%s\" has a conflict with existing post \"%s\" - will be reviewed"
     205msgstr ""
     206
     207#: includes/file-upload.php:39
     208#: includes/file-upload.php:156
     209msgid "Invalid file upload."
     210msgstr ""
     211
     212#: includes/file-upload.php:89
    110213msgid "Please upload a ZIP archive."
    111214msgstr ""
    112215
    113 #: includes/file-upload.php:69
     216#: includes/file-upload.php:138
    114217msgid "Could not move the uploaded file."
    115218msgstr ""
    116219
    117 #: includes/file-upload.php:79
     220#: includes/file-upload.php:149
    118221msgid "Upload failed. Please try again."
    119222msgstr ""
    120223
    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
    132225msgid "Error creating post from file: %s"
    133226msgstr ""
    134227
    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
    165229msgid "Domain copied to clipboard!"
    166230msgstr ""
    167231
    168 #: includes/register-files.php:39
     232#: includes/register-files.php:55
    169233msgid "Failed to copy domain. Please try again."
    170234msgstr ""
    171235
    172 #: includes/register-files.php:40
     236#: includes/register-files.php:56
    173237msgid "Token copied to clipboard!"
    174238msgstr ""
    175239
    176 #: includes/register-files.php:41
     240#: includes/register-files.php:57
    177241msgid "Failed to copy token. Please try again."
    178242msgstr ""
    179243
    180244#: 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 ""
     245msgid "Missing or invalid resolutions data."
     246msgstr ""
     247
     248#: includes/update-functionality.php:44
     249msgid "Missing required data"
     250msgstr ""
     251
     252#: includes/update-functionality.php:51
     253msgid "Post not found"
     254msgstr ""
     255
     256#: includes/update-functionality.php:59
     257msgid "Missing archive name or style for update"
     258msgstr ""
     259
     260#: includes/update-functionality.php:72
     261msgid "Post \"%s\" updated successfully"
     262msgstr ""
     263
     264#: includes/update-functionality.php:82
     265msgid "Post \"%s\" skipped"
     266msgstr ""
     267
     268#: includes/update-functionality.php:87
     269msgid "Invalid action"
     270msgstr ""
     271
     272#: includes/update-functionality.php:93
     273msgid "All conflicts resolved successfully"
     274msgstr ""
     275
     276#: includes/update-functionality.php:98
     277msgid "Some conflicts could not be resolved"
     278msgstr ""
  • topirank-integration/trunk/readme.txt

    r3271065 r3286404  
    33Tags: seo, posts, parsing
    44Requires at least: 6.0
    5 Tested up to: 6.7.2
    6 Stable tag: 1.1.6
     5Tested up to: 6.8
     6Stable tag: 2.0
    77Requires PHP: 7.3
    88License: GPLv2 or later
     
    6666
    6767== 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
    6882
    6983= 1.1.6 =
  • topirank-integration/trunk/topirank-integration.php

    r3271065 r3286404  
    33Plugin Name: Topirank Integration
    44Description: Plugin for parsing pages
    5 Version: 1.1.6
     5Version: 2.0
    66Author: Topirank
    77License: GPLv2 or later
     
    1313}
    1414
     15// Load batch processor first to ensure it's available for other files
     16require_once plugin_dir_path(__FILE__) . 'includes/batch-processor.php';
    1517
    1618require_once plugin_dir_path(__FILE__) . 'admin/menu.php';
    1719require_once plugin_dir_path(__FILE__) . 'admin/admin-page.php';
     20require_once plugin_dir_path(__FILE__) . 'admin/batch-page.php';
    1821require_once plugin_dir_path(__FILE__) . 'includes/utils.php';
    1922require_once plugin_dir_path(__FILE__) . 'includes/init.php';
Note: See TracChangeset for help on using the changeset viewer.