Plugin Directory

Changeset 3470610


Ignore:
Timestamp:
02/26/2026 06:08:35 PM (4 weeks ago)
Author:
bigdropgr
Message:

Update to version 3.3.0

Location:
greek-multi-tool
Files:
25 edited

Legend:

Unmodified
Added
Removed
  • greek-multi-tool/trunk/admin/class-grmlt-plugin-admin.php

    r3463358 r3470610  
    202202    public static function register_grmlt_option_triggers() {
    203203
    204         // Check if grmlt_text is set to on ( The Greeklish Permalinks Switch in settings page ).
    205         if  (get_option( 'grmlt_text' ) == 'on'){
    206 
    207             // Check if grmlt_diphthongs is set to `Enabled` ( The Greeklish Permalinks Convert Diphthongs Switch in settings page ).
    208             if  (get_option( 'grmlt_diphthongs' ) == 'simple'){
    209                 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/functions/translator-diphthongs.php';
    210                 add_filter('sanitize_title', 'grmlt_title_sanitizer_diphthongs_simple', 1);
     204        $permalinks_on = ( get_option( 'grmlt_text' ) === 'on' );
     205        $media_on      = ( get_option( 'grmlt_media_file_name' ) === 'on' );
     206
     207        // Load translator files if either permalinks or media conversion is enabled
     208        if ( $permalinks_on || $media_on ) {
     209            require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/functions/translator-diphthongs.php';
     210            require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/functions/translator.php';
     211        }
     212
     213        // Register sanitize_title filters for permalink conversion.
     214        // Now passes 3 accepted args so callbacks receive $raw_title and $context
     215        // for ACF compatibility (skips transliteration on ACF internal post types).
     216        if ( $permalinks_on ) {
     217
     218            if ( get_option( 'grmlt_diphthongs' ) === 'simple' ) {
     219                add_filter( 'sanitize_title', 'grmlt_title_sanitizer_diphthongs_simple', 1, 3 );
    211220            } else {
    212                 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/functions/translator-diphthongs.php';
    213                 add_filter('sanitize_title', 'grmlt_title_sanitizer_diphthongs_advanced', 1);
     221                add_filter( 'sanitize_title', 'grmlt_title_sanitizer_diphthongs_advanced', 1, 3 );
    214222            }
    215223
    216             // Call and add_filter for title sanitization when text sanitize option is 'enabled'.
    217             require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/functions/translator.php';
    218             add_filter('sanitize_title', 'grmlt_title_sanitizer', 1);
     224            add_filter( 'sanitize_title', 'grmlt_title_sanitizer', 1, 3 );
     225        }
     226
     227        // Register sanitize_file_name filter for Greek media file name conversion on upload.
     228        if ( $media_on ) {
     229            add_filter( 'sanitize_file_name', 'grmlt_file_name_sanitizer', 1 );
    219230        }
    220231
  • greek-multi-tool/trunk/admin/functions/function.js

    r2812381 r3470610  
    8484
    8585jQuery( document ).ready(function($) {
    86     $( ":uppercase:not(input[type!=submit], textarea, .no-remove-accents)" ).removeAcc();
    87     $( ":smallcaps:not(input[type!=submit], textarea, .no-remove-accents)" ).removeAcc();
    88     $( ".remove-accents, .remove-accents > *:not(input[type!=submit], textarea, .no-remove-accents)" ).removeAcc();
     86    /**
     87     * Apply accent removal to all matching elements.
     88     * Scoped to an optional root element for performance with MutationObserver.
     89     */
     90    function grmltApplyAccentRemoval( root ) {
     91        var $scope = root ? $( root ) : $( document );
     92        $scope.find( ":uppercase:not(input[type!=submit], textarea, .no-remove-accents)" ).removeAcc();
     93        $scope.find( ":smallcaps:not(input[type!=submit], textarea, .no-remove-accents)" ).removeAcc();
     94        $scope.find( ".remove-accents, .remove-accents > *:not(input[type!=submit], textarea, .no-remove-accents)" ).removeAcc();
     95        // Also apply to root itself if it matches
     96        if ( root ) {
     97            $( root ).filter( ":uppercase:not(input[type!=submit], textarea, .no-remove-accents)" ).removeAcc();
     98            $( root ).filter( ":smallcaps:not(input[type!=submit], textarea, .no-remove-accents)" ).removeAcc();
     99        }
     100    }
     101
     102    // Initial application on page load
     103    grmltApplyAccentRemoval();
     104
     105    // Re-apply after any AJAX request (covers classic WP AJAX, WP Bakery AJAX loading, etc.)
    89106    $( document ).ajaxComplete(function( event, request, settings ) {
    90         $( ":uppercase:not(input[type!=submit], textarea, .no-remove-accents)" ).removeAcc();
    91         $( ":smallcaps:not(input[type!=submit], textarea, .no-remove-accents)" ).removeAcc();
    92         $( ".remove-accents, .remove-accents > *:not(input[type!=submit], textarea, .no-remove-accents)" ).removeAcc();
     107        grmltApplyAccentRemoval();
     108    });
     109
     110    /**
     111     * MutationObserver for dynamic content loaded by page builders.
     112     *
     113     * WP Bakery (frontend editor), Elementor, and other page builders insert
     114     * content dynamically into the DOM. The MutationObserver watches for new
     115     * nodes and applies accent removal to them automatically.
     116     */
     117    if ( typeof MutationObserver !== 'undefined' ) {
     118        var grmltDebounceTimer = null;
     119        var grmltObserver = new MutationObserver(function( mutations ) {
     120            // Debounce to avoid running on every tiny DOM change
     121            if ( grmltDebounceTimer ) {
     122                clearTimeout( grmltDebounceTimer );
     123            }
     124            grmltDebounceTimer = setTimeout(function() {
     125                var hasNewContent = false;
     126                for ( var i = 0; i < mutations.length; i++ ) {
     127                    if ( mutations[ i ].addedNodes && mutations[ i ].addedNodes.length > 0 ) {
     128                        for ( var j = 0; j < mutations[ i ].addedNodes.length; j++ ) {
     129                            var node = mutations[ i ].addedNodes[ j ];
     130                            if ( node.nodeType === 1 ) { // Element nodes only
     131                                grmltApplyAccentRemoval( node );
     132                                hasNewContent = true;
     133                            }
     134                        }
     135                    }
     136                }
     137                // Full re-scan if many nodes changed (page builder re-render)
     138                if ( hasNewContent ) {
     139                    grmltApplyAccentRemoval();
     140                }
     141            }, 100 );
     142        });
     143
     144        grmltObserver.observe( document.body, {
     145            childList: true,
     146            subtree: true
     147        });
     148
     149        // Elementor frontend: also observe the preview iframe if present
     150        $( window ).on( 'elementor/frontend/init', function() {
     151            setTimeout(function() {
     152                grmltApplyAccentRemoval();
     153            }, 500 );
     154        });
     155    }
     156
     157    // WP Bakery frontend editor: listen for vc-shortcode-render events
     158    $( document ).on( 'vc-full-width-row vc-shortcodes-rendered', function() {
     159        grmltApplyAccentRemoval();
     160    });
     161
     162    // Elementor: listen for its frontend initialization events
     163    $( window ).on( 'elementor/frontend/init', function() {
     164        if ( typeof elementorFrontend !== 'undefined' && elementorFrontend.hooks ) {
     165            elementorFrontend.hooks.addAction( 'frontend/element_ready/global', function( $element ) {
     166                grmltApplyAccentRemoval( $element[0] );
     167            });
     168        }
    93169    });
    94170});
  • greek-multi-tool/trunk/admin/functions/greek-excerpts.php

    r3255049 r3470610  
    144144 * Create a Greek-friendly excerpt
    145145 *
     146 * Supports content from all major page builders including WP Bakery,
     147 * Elementor, Gutenberg Blocks, Divi, Beaver Builder, and Avada.
     148 *
    146149 * @param string $text Text to create excerpt from
    147150 * @param int $length Optional. Length of excerpt in words. Default 55.
     
    153156        $length = get_option('grmlt_excerpt_length', 55);
    154157    }
    155    
     158
    156159    if ($more === null) {
    157160        $more = get_option('grmlt_excerpt_more', '&hellip;');
    158161    }
    159    
    160     // Remove shortcodes
    161     $text = strip_shortcodes($text);
    162    
    163     // Remove page builder specific shortcodes
    164     $text = preg_replace('/\[\/?vc_.*?\]/', '', $text); // WP Bakery shortcodes
    165     $text = preg_replace('/\[\/?et_.*?\]/', '', $text); // Divi Builder shortcodes
    166     $text = preg_replace('/\[\/?fl_.*?\]/', '', $text); // Beaver Builder shortcodes
    167     $text = preg_replace('/\[\/?fusion_.*?\]/', '', $text); // Fusion Builder (Avada) shortcodes
    168     $text = preg_replace('/\[\/?elementor_.*?\]/', '', $text); // Elementor shortcodes
    169    
    170     // Remove Gutenberg blocks
    171     $text = excerpt_remove_blocks($text);
    172    
    173     // Remove HTML tags
    174     $text = wp_strip_all_tags($text);
    175    
    176     // Remove excessive whitespace
    177     $text = preg_replace('/\s+/', ' ', $text);
    178     $text = trim($text);
     162
     163    // Use the page builder compatibility layer for clean text extraction
     164    if (function_exists('grmlt_extract_clean_text')) {
     165        $text = grmlt_extract_clean_text($text);
     166    } else {
     167        // Fallback if compat layer isn't loaded yet
     168        $text = strip_shortcodes($text);
     169        $text = preg_replace('/\[\/?vc_[^\]]*\]/s', '', $text);
     170        $text = preg_replace('/\[\/?et_[^\]]*\]/s', '', $text);
     171        $text = preg_replace('/\[\/?fl_[^\]]*\]/s', '', $text);
     172        $text = preg_replace('/\[\/?fusion_[^\]]*\]/s', '', $text);
     173        $text = preg_replace('/\[\/?elementor[^\]]*\]/s', '', $text);
     174        $text = preg_replace('/\[\/?[^\]]+\]/', '', $text);
     175        if (function_exists('excerpt_remove_blocks')) {
     176            $text = excerpt_remove_blocks($text);
     177        }
     178        $text = wp_strip_all_tags($text);
     179        $text = preg_replace('/\s+/', ' ', $text);
     180        $text = trim($text);
     181    }
    179182   
    180183    // Detect if text contains Greek characters
     
    212215 * Override the default get_the_excerpt function with Greek-friendly version
    213216 *
     217 * Supports all major page builders (WP Bakery, Elementor, Gutenberg, etc.)
     218 * by using the page builder compatibility layer for content extraction.
     219 *
    214220 * @param string $post_excerpt The post excerpt
    215221 * @param WP_Post $post The post object
     
    221227        return $post_excerpt;
    222228    }
    223    
     229
    224230    // If an explicit excerpt is set, return it unchanged
    225231    if (!empty($post_excerpt)) {
    226232        return $post_excerpt;
    227233    }
    228    
    229     // Otherwise, generate a proper Greek-friendly excerpt
     234
     235    // Use the page builder compat layer for best content extraction
     236    if (function_exists('grmlt_get_post_clean_text') && !empty($post->ID)) {
     237        $clean_text = grmlt_get_post_clean_text($post->ID);
     238        if (!empty($clean_text)) {
     239            // Apply excerpt length and "more" text to the clean content
     240            $length = get_option('grmlt_excerpt_length', 55);
     241            $more = get_option('grmlt_excerpt_more', '&hellip;');
     242            $words = preg_split('/\s+/u', $clean_text, -1, PREG_SPLIT_NO_EMPTY);
     243            if (count($words) > $length) {
     244                return implode(' ', array_slice($words, 0, $length)) . $more;
     245            }
     246            return $clean_text;
     247        }
     248    }
     249
     250    // Fallback to standard excerpt generation
    230251    return grmlt_greek_excerpt($post->post_content);
    231252}
     
    422443    // Get post content
    423444    $post = get_post($post_id);
    424    
     445
    425446    if (!$post) {
    426447        wp_send_json_error(__('Post not found', 'greek-multi-tool'));
    427448    }
    428    
    429     // Generate excerpt
     449
     450    // Use page builder compat layer for best content extraction
     451    if (function_exists('grmlt_get_post_clean_text')) {
     452        $clean_text = grmlt_get_post_clean_text($post_id);
     453        if (!empty($clean_text)) {
     454            $more = get_option('grmlt_excerpt_more', '&hellip;');
     455            $words = preg_split('/\s+/u', $clean_text, -1, PREG_SPLIT_NO_EMPTY);
     456            $actual_length = ($length !== null) ? $length : get_option('grmlt_excerpt_length', 55);
     457            if (count($words) > $actual_length) {
     458                $excerpt = implode(' ', array_slice($words, 0, $actual_length)) . $more;
     459            } else {
     460                $excerpt = $clean_text;
     461            }
     462            wp_send_json_success($excerpt);
     463            return;
     464        }
     465    }
     466
     467    // Fallback: Generate excerpt from raw post_content
    430468    $excerpt = grmlt_greek_excerpt($post->post_content, $length);
    431469   
  • greek-multi-tool/trunk/admin/functions/oldtranslator.php

    r3463358 r3470610  
    7070    global $wpdb;
    7171
    72     // Get posts with non-Latin characters in post_name
    73     $posts = $wpdb->get_results("SELECT ID, post_name, post_title FROM {$wpdb->posts} WHERE post_name REGEXP('[^A-Za-z0-9\-]+') AND post_status IN ('publish', 'future', 'private')");
    74    
     72    // Get posts with non-Latin characters in post_name (includes attachments via 'inherit' status)
     73    $posts = $wpdb->get_results("SELECT ID, post_name, post_title, post_type FROM {$wpdb->posts} WHERE post_name REGEXP('[^A-Za-z0-9\-]+') AND post_status IN ('publish', 'future', 'private', 'inherit')");
     74
    7575    foreach ((array) $posts as $post) {
    7676        $sanitized_name_var = grmlt_old_sanitizer($post->post_title);
    7777        $sanitized_name = preg_replace("/[^A-Za-z0-9-]+/", "", $sanitized_name_var);
    78        
     78
    7979        if ($post->post_name != $sanitized_name) {
    8080            // Sanitize the post data before database operation
    8181            $wpdb->update(
    82                 $wpdb->posts, 
    83                 array('post_name' => $sanitized_name), 
     82                $wpdb->posts,
     83                array('post_name' => $sanitized_name),
    8484                array('ID' => absint($post->ID))
    8585            );
    8686            clean_post_cache(absint($post->ID));
    8787
    88             // Check if redirect option is ON/OFF.
     88            // Create 301 redirect for non-attachment post types only.
     89            // Attachment URLs are served from /wp-content/uploads/ and don't use slugs in the same way.
    8990            $red_option = get_option('grmlt_redirect');
    90             if ($red_option == 1) {
     91            if ($red_option == 1 && $post->post_type !== 'attachment') {
    9192                // Prepare old permalink - sanitize
    9293                $old_permalink = $post->post_title;
     
    9798                $old_permalink = esc_url_raw(get_site_url() . "/" . $old_permalink . "/");
    9899                $new_permalink = esc_url_raw(get_site_url() . "/" . $sanitized_name . "/");
    99                
     100
    100101                // Insert into database with proper sanitization
    101102                $wpdb->insert(
    102                     $wpdb->prefix . 'grmlt', 
     103                    $wpdb->prefix . 'grmlt',
    103104                    array(
    104105                        'post_id' => absint($post->ID),
  • greek-multi-tool/trunk/admin/functions/text-analysis.php

    r3463358 r3470610  
    387387    <script>
    388388    jQuery(document).ready(function($) {
     389        /**
     390         * Extract content from the current editor, supporting:
     391         * - WordPress Gutenberg (Block Editor)
     392         * - Classic Editor (TinyMCE / textarea)
     393         * - WP Bakery Page Builder (backend & frontend)
     394         * - Elementor Page Builder
     395         */
     396        function grmltGetEditorContent() {
     397            var content = '';
     398
     399            // --- 1. Gutenberg Block Editor ---
     400            if (typeof wp !== 'undefined' && wp.data && wp.data.select) {
     401                try {
     402                    var editor = wp.data.select('core/editor');
     403                    if (editor && typeof editor.getEditedPostContent === 'function') {
     404                        content = editor.getEditedPostContent();
     405                        if (content && content.trim().length > 0) {
     406                            return content;
     407                        }
     408                    }
     409                } catch(e) {}
     410
     411                // Try core/block-editor for newer WP versions
     412                try {
     413                    var blockEditor = wp.data.select('core/block-editor');
     414                    if (blockEditor && typeof blockEditor.getBlocks === 'function') {
     415                        var blocks = blockEditor.getBlocks();
     416                        if (blocks && blocks.length > 0) {
     417                            content = wp.blocks.serialize(blocks);
     418                            if (content && content.trim().length > 0) {
     419                                return content;
     420                            }
     421                        }
     422                    }
     423                } catch(e) {}
     424            }
     425
     426            // --- 2. WP Bakery Page Builder ---
     427            // WP Bakery backend editor: content is in the #content textarea (raw shortcodes)
     428            // Also try WP Bakery's own content areas
     429            if (typeof vc !== 'undefined' || $('#wpb_visual_composer').length > 0 || $('[data-vc-shortcode]').length > 0) {
     430                // Try to get content from WP Bakery's internal storage
     431                if (typeof vc !== 'undefined' && typeof vc.builder !== 'undefined') {
     432                    try {
     433                        content = vc.builder.getContent();
     434                        if (content && content.trim().length > 0) {
     435                            return content;
     436                        }
     437                    } catch(e) {}
     438                }
     439
     440                // Try the Visual Composer shortcode textarea
     441                if ($('#wpb_vc_js_status').length && $('#wpb_vc_js_status').val() === 'true') {
     442                    // WP Bakery visual mode is active, get from hidden textarea
     443                    content = $('#content').val();
     444                    if (content && content.trim().length > 0) {
     445                        return content;
     446                    }
     447                }
     448
     449                // Try to scrape text from WP Bakery visual editor elements
     450                var vcTexts = [];
     451                $('.wpb_text_column .wpb_wrapper, .vc_element .wpb_wrapper, [data-vc-content] .wpb_wrapper').each(function() {
     452                    var txt = $(this).text().trim();
     453                    if (txt.length > 0) {
     454                        vcTexts.push(txt);
     455                    }
     456                });
     457                if (vcTexts.length > 0) {
     458                    content = vcTexts.join(' ');
     459                    if (content.trim().length > 0) {
     460                        return content;
     461                    }
     462                }
     463            }
     464
     465            // --- 3. Elementor ---
     466            // When editing with Elementor, the main editor is not present;
     467            // content comes from the server via post_id fallback.
     468            // But try the preview iframe if available
     469            if (typeof elementor !== 'undefined' || typeof elementorFrontend !== 'undefined') {
     470                try {
     471                    var $previewFrame = $('#elementor-preview-iframe');
     472                    if ($previewFrame.length) {
     473                        var iframeContent = $previewFrame.contents().find('.elementor-widget-container');
     474                        if (iframeContent.length) {
     475                            var elTexts = [];
     476                            iframeContent.each(function() {
     477                                var txt = $(this).text().trim();
     478                                if (txt.length > 0) {
     479                                    elTexts.push(txt);
     480                                }
     481                            });
     482                            if (elTexts.length > 0) {
     483                                content = elTexts.join(' ');
     484                                return content;
     485                            }
     486                        }
     487                    }
     488                } catch(e) {}
     489            }
     490
     491            // --- 4. Classic Editor (TinyMCE) ---
     492            if (typeof tinyMCE !== 'undefined' && tinyMCE.activeEditor && !tinyMCE.activeEditor.isHidden()) {
     493                content = tinyMCE.activeEditor.getContent();
     494                if (content && content.trim().length > 0) {
     495                    return content;
     496                }
     497            }
     498
     499            // --- 5. Plain textarea fallback ---
     500            if ($('#content').length && $('#content').val()) {
     501                content = $('#content').val();
     502                if (content && content.trim().length > 0) {
     503                    return content;
     504                }
     505            }
     506
     507            return content || '';
     508        }
     509
     510        /**
     511         * Strip HTML tags and shortcodes from content client-side.
     512         */
     513        function grmltStripContent(content) {
     514            if (!content) return '';
     515
     516            // Remove Gutenberg block comments
     517            content = content.replace(/<!--\s*\/?wp:.*?-->/gs, '');
     518
     519            // Remove shortcode tags but keep their inner content
     520            // Matches [shortcode attr="val"]...[/shortcode] and standalone [shortcode /]
     521            content = content.replace(/\[\/?[^\]]+\]/g, ' ');
     522
     523            // Strip HTML tags
     524            var div = document.createElement('div');
     525            div.innerHTML = content;
     526            content = div.textContent || div.innerText || '';
     527
     528            // Normalize whitespace
     529            content = content.replace(/\s+/g, ' ').trim();
     530
     531            return content;
     532        }
     533
    389534        $('#grmlt-analyze-button').on('click', function() {
    390535            // Get content from the editor
    391             let content = '';
    392            
    393             if (typeof wp !== 'undefined' && wp.data && wp.data.select('core/editor')) {
    394                 // For Gutenberg
    395                 content = wp.data.select('core/editor').getEditedPostContent();
    396             } else {
    397                 // For Classic Editor
    398                 if (typeof tinyMCE !== 'undefined' && tinyMCE.activeEditor && !tinyMCE.activeEditor.isHidden()) {
    399                     content = tinyMCE.activeEditor.getContent();
    400                 } else {
    401                     content = $('#content').val();
    402                 }
    403             }
    404            
    405             // Strip HTML tags
    406             const div = document.createElement('div');
    407             div.innerHTML = content;
    408             content = div.textContent || div.innerText || '';
    409            
     536            var rawContent = grmltGetEditorContent();
     537            var content = grmltStripContent(rawContent);
     538
     539            // Get post ID for server-side fallback
     540            var postId = 0;
     541            if ($('#post_ID').length) {
     542                postId = $('#post_ID').val();
     543            } else if (typeof wp !== 'undefined' && wp.data && wp.data.select) {
     544                try {
     545                    postId = wp.data.select('core/editor').getCurrentPostId();
     546                } catch(e) {}
     547            }
     548
    410549            // AJAX request to analyze text
    411550            $.ajax({
     
    415554                    action: 'grmlt_analyze_text',
    416555                    content: content,
     556                    post_id: postId,
    417557                    nonce: $('#grmlt_text_analysis_nonce').val()
    418558                },
     
    422562                success: function(response) {
    423563                    if (response.success) {
    424                         let html = '<div class="grmlt-analysis-stats">';
     564                        var html = '<div class="grmlt-analysis-stats">';
    425565                        html += '<h4><?php _e('Text Statistics', 'greek-multi-tool'); ?></h4>';
    426566                        html += '<p><?php _e('Characters:', 'greek-multi-tool'); ?> ' + response.data.stats.total_chars + '</p>';
     
    429569                        html += ' (' + response.data.stats.percent_greek + '%)</p>';
    430570                        html += '<p><?php _e('Accented characters:', 'greek-multi-tool'); ?> ' + response.data.stats.accented_chars + '</p>';
    431                        
     571
    432572                        if (response.data.issues.length > 0) {
    433573                            html += '<h4><?php _e('Accent Rule Issues', 'greek-multi-tool'); ?></h4>';
    434574                            html += '<ul class="grmlt-issues-list">';
    435                            
     575
    436576                            $.each(response.data.issues, function(index, issue) {
    437                                 html += '<li>' + issue + '</li>';
     577                                html += '<li>' + $('<span>').text(issue).html() + '</li>';
    438578                            });
    439                            
     579
    440580                            html += '</ul>';
    441581                        } else {
    442582                            html += '<p class="grmlt-no-issues"><?php _e('No accent rule issues found!', 'greek-multi-tool'); ?></p>';
    443583                        }
    444                        
     584
    445585                        html += '</div>';
    446586                        $('#grmlt-analysis-results').html(html);
    447587                    } else {
    448                         $('#grmlt-analysis-results').html('<p class="grmlt-error">' + response.data + '</p>');
     588                        $('#grmlt-analysis-results').html('<p class="grmlt-error">' + $('<span>').text(response.data).html() + '</p>');
    449589                    }
    450590                },
     
    461601/**
    462602 * AJAX handler for text analysis
     603 *
     604 * Accepts content from the client-side editor, but also supports a post_id
     605 * fallback for page builders (WP Bakery, Elementor, etc.) where client-side
     606 * content extraction may not capture the full text.
    463607 */
    464608function grmlt_ajax_analyze_text() {
    465609    // Check nonce for security
    466610    check_ajax_referer('grmlt_text_analysis_nonce', 'nonce');
    467    
     611
    468612    // Check if user has permission
    469613    if (!current_user_can('edit_posts')) {
    470614        wp_send_json_error(__('You do not have permission to perform this action.', 'greek-multi-tool'));
    471615    }
    472    
     616
    473617    // Get content from request
    474618    $content = isset($_POST['content']) ? sanitize_textarea_field($_POST['content']) : '';
    475    
     619    $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
     620
     621    // If content is empty or too short, try server-side extraction from the post
     622    if ((empty($content) || mb_strlen($content) < 10) && $post_id > 0) {
     623        // Load page builder compat if not already loaded
     624        if (!function_exists('grmlt_get_post_clean_text')) {
     625            require_once plugin_dir_path(__FILE__) . 'page-builder-compat.php';
     626        }
     627
     628        $server_content = grmlt_get_post_clean_text($post_id);
     629
     630        // Use server content if it's longer than client content
     631        if (mb_strlen($server_content) > mb_strlen($content)) {
     632            $content = $server_content;
     633        }
     634    }
     635
     636    // If content still contains shortcode-like patterns, clean them
     637    if (!empty($content) && preg_match('/\[\w+/', $content)) {
     638        if (!function_exists('grmlt_extract_clean_text')) {
     639            require_once plugin_dir_path(__FILE__) . 'page-builder-compat.php';
     640        }
     641        $content = grmlt_extract_clean_text($content);
     642    }
     643
    476644    if (empty($content)) {
    477         wp_send_json_error(__('No content to analyze.', 'greek-multi-tool'));
    478     }
    479    
     645        wp_send_json_error(__('No content to analyze. If you are using a page builder, please save the post first and try again.', 'greek-multi-tool'));
     646    }
     647
    480648    // Analyze text
    481649    $results = grmlt_analyze_text($content);
    482    
     650
    483651    // Send results
    484652    wp_send_json_success($results);
  • greek-multi-tool/trunk/admin/functions/translator-diphthongs.php

    r2812381 r3470610  
    1 <?php
    2 function grmlt_title_sanitizer_diphthongs_simple($text) {
     1<?php
     2/**
     3 * Diphthong transliteration functions for Greek Multi Tool.
     4 *
     5 * Contains both reusable helper functions for pure transliteration
     6 * and sanitize_title callbacks with context checking.
     7 *
     8 * @since    1.0.0
     9 * @since    3.3.0 Refactored for ACF compatibility and media support.
     10 * @package  Grmlt_Plugin
     11 */
     12
     13/**
     14 * Pure diphthong transliteration - simple mode.
     15 * Reusable helper used by both sanitize_title callback and file name sanitizer.
     16 *
     17 * @since 3.3.0
     18 * @param string $text The text to transliterate.
     19 * @return string The transliterated text.
     20 */
     21function grmlt_apply_diphthongs_simple($text) {
    322
    423    $diphthongs = array(
     
    2948}
    3049
    31 function grmlt_title_sanitizer_diphthongs_advanced($text) {
     50/**
     51 * Pure diphthong transliteration - advanced mode.
     52 * Reusable helper used by both sanitize_title callback and file name sanitizer.
     53 *
     54 * @since 3.3.0
     55 * @param string $text The text to transliterate.
     56 * @return string The transliterated text.
     57 */
     58function grmlt_apply_diphthongs_advanced($text) {
    3259
    3360    $diphthongs = array(
     
    5683
    5784}
     85
     86/**
     87 * sanitize_title callback - simple diphthong mode.
     88 * Accepts all 3 sanitize_title arguments to check context and skip ACF operations.
     89 *
     90 * @since 1.0.0
     91 * @since 3.3.0 Added $raw_title and $context parameters for ACF compatibility.
     92 *
     93 * @param string $text      The sanitized title.
     94 * @param string $raw_title The title prior to sanitization.
     95 * @param string $context   The context for which the title is being sanitized.
     96 * @return string The transliterated text.
     97 */
     98function grmlt_title_sanitizer_diphthongs_simple($text, $raw_title = '', $context = 'save') {
     99
     100    // Only transliterate when saving slugs
     101    if ( $context !== 'save' ) {
     102        return $text;
     103    }
     104
     105    // Skip transliteration for ACF internal operations
     106    if ( grmlt_is_acf_context() ) {
     107        return $text;
     108    }
     109
     110    return grmlt_apply_diphthongs_simple($text);
     111
     112}
     113
     114/**
     115 * sanitize_title callback - advanced diphthong mode.
     116 * Accepts all 3 sanitize_title arguments to check context and skip ACF operations.
     117 *
     118 * @since 1.0.0
     119 * @since 3.3.0 Added $raw_title and $context parameters for ACF compatibility.
     120 *
     121 * @param string $text      The sanitized title.
     122 * @param string $raw_title The title prior to sanitization.
     123 * @param string $context   The context for which the title is being sanitized.
     124 * @return string The transliterated text.
     125 */
     126function grmlt_title_sanitizer_diphthongs_advanced($text, $raw_title = '', $context = 'save') {
     127
     128    // Only transliterate when saving slugs
     129    if ( $context !== 'save' ) {
     130        return $text;
     131    }
     132
     133    // Skip transliteration for ACF internal operations
     134    if ( grmlt_is_acf_context() ) {
     135        return $text;
     136    }
     137
     138    return grmlt_apply_diphthongs_advanced($text);
     139
     140}
  • greek-multi-tool/trunk/admin/functions/translator.php

    r2812381 r3470610  
    1 <?php
    2 function grmlt_title_sanitizer($text) {
    3         $expressions = array(
    4 
    5             '/[αάΑΆ]/u'   => 'a',
    6             '/[βΒ]/u'     => 'v',
    7             '/[γΓ]/u'     => 'g',
    8             '/[δΔ]/u'     => 'd',
    9             '/[εέΕΈ]/u'   => 'e',
    10             '/[ζΖ]/u'     => 'z',
    11             '/[ηήΗΉ]/u'   => 'i',
    12             '/[θΘ]/u'     => 'th',
    13             '/[ιίϊΙΊΪ]/u' => 'i',
    14             '/[κΚ]/u'     => 'k',
    15             '/[λΛ]/u'     => 'l',
    16             '/[μΜ]/u'     => 'm',
    17             '/[νΝ]/u'     => 'n',
    18             '/[ξΞ]/u'     => 'x',
    19             '/[οόΟΌ]/u'   => 'o',
    20             '/[πΠ]/u'     => 'p',
    21             '/[ρΡ]/u'     => 'r',
    22             '/[σςΣ]/u'    => 's',
    23             '/[τΤ]/u'     => 't',
    24             '/[υύϋΥΎΫ]/u' => 'y',
    25             '/[φΦ]/iu'    => 'f',
    26             '/[χΧ]/u'     => 'ch',
    27             '/[ψΨ]/u'     => 'ps',
    28             '/[ωώ]/iu'    => 'o',
    29 
    30         );
     1<?php
     2/**
     3 * Core transliteration functions for Greek Multi Tool.
     4 *
     5 * Contains the main Greek-to-Latin character mapping, ACF context detection,
     6 * sanitize_title callback, and media file name sanitizer.
     7 *
     8 * @since    1.0.0
     9 * @since    3.3.0 Added ACF compatibility, media file name support, and shared helpers.
     10 * @package  Grmlt_Plugin
     11 */
     12
     13/**
     14 * Check if the current context is an ACF (Advanced Custom Fields) internal operation.
     15 *
     16 * ACF stores field definitions as custom post types (acf-field, acf-field-group).
     17 * When ACF generates field names from labels, it calls sanitize_title() internally.
     18 * This function detects those contexts so transliteration can be skipped, preventing
     19 * ACF field keys from being converted to Greeklish.
     20 *
     21 * @since 3.3.0
     22 * @return bool True if we're inside an ACF operation, false otherwise.
     23 */
     24function grmlt_is_acf_context() {
     25
     26    // If ACF is not active, no need to check further
     27    if ( ! class_exists( 'ACF' ) && ! function_exists( 'acf' ) ) {
     28        return false;
     29    }
     30
     31    // Check for ACF AJAX actions (field saving, field group updates, etc.)
     32    if ( wp_doing_ajax() ) {
     33        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- We're only reading, not processing
     34        $action = isset( $_POST['action'] ) ? sanitize_text_field( wp_unslash( $_POST['action'] ) ) : '';
     35        if ( strpos( $action, 'acf/' ) === 0 || strpos( $action, 'acf_' ) === 0 ) {
     36            return true;
     37        }
     38    }
     39
     40    // Check if the post being saved is an ACF internal post type
     41    // phpcs:ignore WordPress.Security.NonceVerification.Missing -- We're only reading, not processing
     42    if ( isset( $_POST['post_type'] ) ) {
     43        // phpcs:ignore WordPress.Security.NonceVerification.Missing
     44        $post_type = sanitize_text_field( wp_unslash( $_POST['post_type'] ) );
     45        if ( strpos( $post_type, 'acf-' ) === 0 ) {
     46            return true;
     47        }
     48    }
     49
     50    // Check the current admin screen for ACF post types
     51    if ( is_admin() && function_exists( 'get_current_screen' ) ) {
     52        $screen = get_current_screen();
     53        if ( $screen && ! empty( $screen->post_type ) && strpos( $screen->post_type, 'acf-' ) === 0 ) {
     54            return true;
     55        }
     56    }
     57
     58    return false;
     59
     60}
     61
     62/**
     63 * Get the Greek-to-Latin character expression map.
     64 *
     65 * @since 3.3.0
     66 * @return array Associative array of regex patterns to Latin replacements.
     67 */
     68function grmlt_get_greek_expressions() {
     69
     70    return array(
     71
     72        '/[αάΑΆ]/u'   => 'a',
     73        '/[βΒ]/u'     => 'v',
     74        '/[γΓ]/u'     => 'g',
     75        '/[δΔ]/u'     => 'd',
     76        '/[εέΕΈ]/u'   => 'e',
     77        '/[ζΖ]/u'     => 'z',
     78        '/[ηήΗΉ]/u'   => 'i',
     79        '/[θΘ]/u'     => 'th',
     80        '/[ιίϊΙΊΪ]/u' => 'i',
     81        '/[κΚ]/u'     => 'k',
     82        '/[λΛ]/u'     => 'l',
     83        '/[μΜ]/u'     => 'm',
     84        '/[νΝ]/u'     => 'n',
     85        '/[ξΞ]/u'     => 'x',
     86        '/[οόΟΌ]/u'   => 'o',
     87        '/[πΠ]/u'     => 'p',
     88        '/[ρΡ]/u'     => 'r',
     89        '/[σςΣ]/u'    => 's',
     90        '/[τΤ]/u'     => 't',
     91        '/[υύϋΥΎΫ]/u' => 'y',
     92        '/[φΦ]/iu'    => 'f',
     93        '/[χΧ]/u'     => 'ch',
     94        '/[ψΨ]/u'     => 'ps',
     95        '/[ωώ]/iu'    => 'o',
     96
     97    );
     98
     99}
     100
     101/**
     102 * Core transliteration function - converts Greek characters to Latin.
     103 * This is a pure transliteration helper without any context/stop-word checks.
     104 * Used by the file name sanitizer and can be reused by other features.
     105 *
     106 * @since 3.3.0
     107 * @param string $text The text to transliterate.
     108 * @return string The transliterated text.
     109 */
     110function grmlt_transliterate_greek($text) {
     111
     112    // Apply diphthongs first (based on settings)
     113    $diphthong_mode = get_option( 'grmlt_diphthongs' );
     114    if ( $diphthong_mode === 'simple' ) {
     115        $text = grmlt_apply_diphthongs_simple( $text );
     116    } else {
     117        $text = grmlt_apply_diphthongs_advanced( $text );
     118    }
     119
     120    // Apply individual character transliteration
     121    $expressions = grmlt_get_greek_expressions();
     122    $text = preg_replace( array_keys($expressions), array_values($expressions), $text );
     123
     124    return $text;
     125
     126}
     127
     128/**
     129 * sanitize_title callback - main Greek-to-Latin character conversion.
     130 * Processes individual Greek characters after diphthongs have been handled.
     131 *
     132 * @since 1.0.0
     133 * @since 3.3.0 Added $raw_title and $context parameters for ACF compatibility.
     134 *
     135 * @param string $text      The sanitized title.
     136 * @param string $raw_title The title prior to sanitization.
     137 * @param string $context   The context for which the title is being sanitized.
     138 * @return string The transliterated text.
     139 */
     140function grmlt_title_sanitizer($text, $raw_title = '', $context = 'save') {
     141
     142    // Only transliterate when saving slugs, not for display or query contexts
     143    if ( $context !== 'save' ) {
     144        return $text;
     145    }
     146
     147    // Skip transliteration for ACF internal operations
     148    if ( grmlt_is_acf_context() ) {
     149        return $text;
     150    }
     151
     152        $expressions = grmlt_get_greek_expressions();
    31153
    32154        // Stop Words functionality
     
    50172
    51173        return $text;
    52        
    53 }
     174
     175}
     176
     177/**
     178 * sanitize_file_name callback - converts Greek characters in uploaded media file names.
     179 * Only processes the file name portion (not the extension).
     180 *
     181 * @since 3.3.0
     182 * @param string $filename The file name to sanitize.
     183 * @return string The sanitized file name with Greek characters converted to Latin.
     184 */
     185function grmlt_file_name_sanitizer($filename) {
     186
     187    // Separate file name and extension
     188    $file_info = pathinfo( $filename );
     189    $name = isset( $file_info['filename'] ) ? $file_info['filename'] : '';
     190    $ext  = isset( $file_info['extension'] ) ? '.' . $file_info['extension'] : '';
     191
     192    // Only process if the name contains Greek characters
     193    if ( ! preg_match( '/[\x{0370}-\x{03FF}\x{1F00}-\x{1FFF}]/u', $name ) ) {
     194        return $filename;
     195    }
     196
     197    // Apply full Greek-to-Latin transliteration (diphthongs + individual characters)
     198    $name = grmlt_transliterate_greek( $name );
     199
     200    return $name . $ext;
     201
     202}
  • greek-multi-tool/trunk/admin/partials/settings-page/convert-old-permalinks.php

    r3463358 r3470610  
    44<hr>
    55<strong class="mb-0"><?php esc_html_e( 'Convert All Old Permalinks', 'greek-multi-tool' ); ?></strong>
    6 <p><?php esc_html_e( 'Press the button bellow to initialize the conversion of all old permalinks', 'greek-multi-tool' ); ?></p>
     6<p><?php esc_html_e( 'Press the button below to initialize the conversion of all old permalinks. This includes posts, pages, custom post types, media/attachment slugs, and taxonomy terms.', 'greek-multi-tool' ); ?></p>
    77<div class="mt-3">
    88    <form method="post">
  • greek-multi-tool/trunk/admin/partials/settings-page/grmlt-plugin-admin-main-settings-page.php

    r3463358 r3470610  
    5656    'grmlt_settings', // settings group name
    5757    'grmlt_redirect', // option name
     58    'sanitize_text_field' // sanitization function
     59);
     60
     61// It registers settings for Media File Name Conversion.
     62register_setting(
     63    'grmlt_settings', // settings group name
     64    'grmlt_media_file_name', // option name
    5865    'sanitize_text_field' // sanitization function
    5966);
  • greek-multi-tool/trunk/admin/partials/settings-page/permalinks-settings.php

    r2972131 r3470610  
    1717            <div class="col">
    1818                <strong class="mb-0"><?php _e('Enable Greeklish Permalinks Convert: ', 'greek-multi-tool') ?></strong>
    19                 <p class="text-muted mb-0"><?php _e('Automatically convert the greek characters to latin in all permalinks in posts, pages, custom post type and terms.', 'greek-multi-tool') ?></p>
     19                <p class="text-muted mb-0"><?php _e('Automatically convert the greek characters to latin in all permalinks in posts, pages, custom post types, media attachments and terms. Fully compatible with ACF (Advanced Custom Fields).', 'greek-multi-tool') ?></p>
    2020            </div>
    2121            <div class="col-auto">
     
    123123</div>
    124124
     125<!-- MEDIA FILE NAME CONVERSION -->
     126<?php
     127    $grmlt_media_file_name = get_option( 'grmlt_media_file_name' );
     128    if ( $grmlt_media_file_name == 'on' ){
     129        $grmlt_media_file_name = true;
     130    }
     131?>
     132
     133<hr class="my-4" />
     134<strong class="mb-0"><?php _e('Media File Name Conversion', 'greek-multi-tool'); ?></strong>
     135<p><?php _e('Convert Greek characters in media file names to Latin during upload', 'greek-multi-tool'); ?></p>
     136<div class="list-group mb-5 shadow">
     137    <div class="list-group-item">
     138        <div class="row align-items-center">
     139            <div class="col">
     140                <strong class="mb-0"><?php _e('Enable Media File Name Conversion: ', 'greek-multi-tool'); ?></strong>
     141                <p class="text-muted mb-0"><?php _e('Automatically convert Greek characters in uploaded media file names (images, documents, etc.) to clean, SEO-friendly Latin equivalents. For example "φωτογραφία.jpg" becomes "fotografia.jpg".', 'greek-multi-tool'); ?></p>
     142            </div>
     143            <div class="col-auto">
     144                <div class="custom-control custom-switch">
     145                    <label class="switch">
     146                        <input type="checkbox" class="custom-control-input" id="grmlt_media_file_name" name="grmlt_media_file_name" <?php echo checked( $grmlt_media_file_name, 1, 0 ); ?> />
     147                        <span class="slider round"></span>
     148                    </label>
     149                </div>
     150            </div>
     151        </div>
     152    </div>
     153</div>
     154
    125155<!-- STOPWORDS START -->
    126    
    127 <?php 
     156
     157<?php
    128158    $textarea_stwords = get_option( 'grmlt_stwords' );
    129159?>
  • greek-multi-tool/trunk/grmlt-plugin.php

    r3463358 r3470610  
    88 * Plugin Name:       Greek Multi Tool
    99 * Plugin URI:        https://bigdrop.gr/greek-multi-tool
    10  * Description:       This plugin provides a handful of tools and key functionalities to simplify and fix the greek language used in your webpage. For example it change the greek character urls to latin, remove the uppercase accents.
    11  * Version:           3.2.0
     10 * Description:       The comprehensive WordPress plugin for Greek websites. Converts Greek URLs and media file names to SEO-friendly Latin, removes uppercase accents, enhances search, localizes dates, and much more. Fully compatible with ACF, WooCommerce, and all major plugins.
     11 * Version:           3.3.0
    1212 * Author:            BigDrop.gr
    1313 * Author URI:        https://bigdrop.gr
     
    2929 * Currently plugin version.
    3030 */
    31 define( 'GRMLT_PLUGIN_VERSION', '3.2.0' );
     31define( 'GRMLT_PLUGIN_VERSION', '3.3.0' );
    3232
    3333/**
     
    204204// Removed: add_action('wp_ajax_nopriv_grmlt_database_301_redirect_edit_handler', 'grmlt_database_301_redirect_edit_handler');
    205205
     206// Load the Page Builder Compatibility Layer (WP Bakery, Elementor, Gutenberg, Yoast SEO)
     207require_once plugin_dir_path(__FILE__) . 'admin/functions/page-builder-compat.php';
     208
    206209// Load the Greek Text Analysis functionality
    207210if (is_admin()) {
  • greek-multi-tool/trunk/includes/class-grmlt-plugin-activator.php

    r2921021 r3470610  
    4444        add_option('grmlt_redirect', 1);
    4545
     46        // Media File Name Conversion Option
     47        add_option('grmlt_media_file_name', 'on');
     48
    4649        // flush rewrite rules
    4750        flush_rewrite_rules();
  • greek-multi-tool/trunk/readme.txt

    r3463358 r3470610  
    55Tags: greek, greeklish, permalinks, accent remover, seo
    66Requires at least: 6.2
    7 Stable tag: 3.2.0
     7Stable tag: 3.3.0
    88Tested up to: 6.9.1
    99Requires PHP: 7.4
     
    1111License URI: http://www.gnu.org/licenses/gpl-2.0.html
    1212
    13 The comprehensive WordPress plugin for Greek websites - fixes permalinks, handles accents, enhances search, localizes dates and more!
     13The comprehensive WordPress plugin for Greek websites - fixes permalinks, converts media file names, handles accents, enhances search, localizes dates and more! Fully compatible with WP Bakery, Elementor, Gutenberg, and Yoast SEO.
    1414
    1515== Description ==
    16 **Greek Multi Tool 3.0** transforms how WordPress handles the Greek language. This all-in-one solution tackles every Greek-specific challenge your website faces - from URL structure to search functionality to content optimization.
     16**Greek Multi Tool 3.3** transforms how WordPress handles the Greek language. This all-in-one solution tackles every Greek-specific challenge your website faces - from URL structure to media file names to search functionality to content optimization.
    1717
    1818Our plugin is meticulously designed for Greek website owners who need professional-grade tools that understand the unique characteristics of the Greek language. Whether you're running a blog, business site, or e-commerce store, Greek Multi Tool solves problems other plugins can't even detect.
    1919
     20= Full Page Builder & SEO Plugin Compatibility =
     21
     22Greek Multi Tool works seamlessly with the most popular WordPress page builders and SEO plugins:
     23
     24* **WP Bakery Page Builder** - Full compatibility. Text analysis, excerpt generation, uppercase accent removal, and all other features work correctly with WP Bakery content blocks (vc_column_text, vc_row, etc.). Content is properly extracted from WP Bakery shortcodes for analysis and SEO.
     25* **Elementor** - Full compatibility. The plugin reads Elementor widget data directly from post meta, ensuring text analysis and excerpt generation capture all your content - including text editors, headings, tabs, accordions, and other Elementor widgets.
     26* **WordPress Gutenberg (Block Editor)** - Full compatibility. All block types are properly parsed and their content extracted for analysis, excerpt generation, and search.
     27* **WordPress Classic Editor** - Full compatibility. Works with both TinyMCE visual and text modes.
     28* **Yoast SEO** - Full compatibility. Greek Multi Tool provides clean, rendered content to Yoast's analysis engine when page builder shortcodes are detected, ensuring Yoast can properly analyze your Greek content for SEO optimization.
     29* **Rank Math & All in One SEO** - Compatible. Uses standard WordPress hooks that work alongside all major SEO plugins.
     30* **Divi Builder, Beaver Builder, Avada/Fusion Builder** - Compatible. Page builder shortcodes are properly stripped for text analysis and excerpt generation.
     31
    2032= Why Greek Multi Tool Is Essential for Your Greek Website =
    2133
    2234* **Solve Greek URL Problems Once and For All** - Convert complicated Greek character URLs to clean, SEO-friendly Latin permalinks automatically
    23 * **Enhance Greek Content SEO** - Our specialized tools ensure search engines properly understand and index your Greek content
    24 * **Create Professional Greek Typography** - Remove unsightly uppercase accents and ensure consistent, beautiful Greek text display
     35* **Clean Up Greek Media File Names** - Automatically convert Greek file names during upload so your images and documents have proper Latin file names for maximum compatibility and SEO
     36* **Full ACF Compatibility** - Our smart context-aware transliteration knows when to convert and when to leave things alone, so Advanced Custom Fields and other plugins work perfectly alongside
     37* **Works With Any Page Builder** - Text analysis, excerpt generation, uppercase accent removal, and search all work perfectly whether you build pages with WP Bakery, Elementor, Gutenberg, or the Classic Editor
     38* **Enhance Greek Content SEO** - Our specialized tools ensure search engines properly understand and index your Greek content. Provides clean text to Yoast SEO for accurate analysis of page builder content
     39* **Create Professional Greek Typography** - Remove unsightly uppercase accents and ensure consistent, beautiful Greek text display, even on dynamically loaded page builder content
    2540* **Boost Greek Search Accuracy** - Improve internal search with accent-insensitive, diphthong-aware algorithms built specifically for Greek
    2641* **Display Proper Greek Dates** - Show dates in proper Greek format with correct month and day names
    27 * **Generate Perfect Greek Excerpts** - Create proper excerpts that respect Greek word boundaries and linguistic rules
    28 * **Analyze Greek Text Quality** - Check for proper accent usage and text readability with our Greek-specific analysis tools
     42* **Generate Perfect Greek Excerpts** - Create proper excerpts that respect Greek word boundaries and linguistic rules, with full support for extracting text from WP Bakery, Elementor, and Gutenberg content
     43* **Analyze Greek Text Quality** - Check for proper accent usage and text readability with our Greek-specific analysis tools that understand page builder content
    2944
    3045Unlike generic WordPress plugins, Greek Multi Tool was built from the ground up specifically for Greek language websites, addressing peculiarities and challenges that non-specialized tools simply can't handle.
     
    577215. **Added Toggle Control for enabling/disabling Greek Text Analysis** - Analyze your content for proper Greek accent rules with easy on/off control. Ensure linguistic correctness with just a click.
    5873
     74= New in Version 3.3.0 =
     7516. **Greek Media File Name Conversion** - Automatically convert Greek characters in uploaded media file names (images, documents, PDFs, etc.) to clean, SEO-friendly Latin equivalents during upload. No more broken image URLs or encoding headaches - "φωτογραφία-προϊόντος.jpg" becomes "fotografia-proiontos.jpg" automatically.
     7617. **ACF (Advanced Custom Fields) Compatibility Fix** - Our transliteration engine is now context-aware. It intelligently detects when Advanced Custom Fields is generating internal field names and keys, and skips transliteration to prevent ACF field corruption. Your ACF field definitions stay exactly as they should be.
     7718. **Attachment Slug Conversion** - Media attachment slugs (URLs) are now automatically converted to Latin, just like posts and pages. This applies both on new uploads and through the bulk "Convert Old Permalinks" tool which now includes attachments and media items.
     78
    5979== Compatibility ==
    60 Greek Multi Tool is compatible with:
    61 * WordPress core (tested up to 6.7.2)
    62 * WooCommerce
    63 * Major SEO plugins (Yoast SEO, Rank Math, All in One SEO)
    64 * Popular page builders (Elementor, Gutenberg, WP Bakery)
    65 * Most WordPress themes
     80
     81= Page Builders - Full Support =
     82Greek Multi Tool provides deep, tested compatibility with all major page builders. Every feature of the plugin - text analysis, excerpt generation, uppercase accent removal, search, and permalink conversion - works correctly regardless of which page builder you use:
     83
     84* **WP Bakery Page Builder (Visual Composer)** - Full support. The plugin extracts text content from all WP Bakery elements (vc_column_text, vc_row, custom text blocks, etc.) both client-side and server-side. If client-side extraction isn't possible (e.g., WP Bakery's backend editor mode), the plugin automatically falls back to server-side content extraction from the saved post. The uppercase accent remover also works on WP Bakery's dynamically rendered frontend content.
     85* **Elementor** - Full support. The plugin reads Elementor's widget data directly from post meta (_elementor_data), extracting text from all widget types including text editors, headings, tabs, accordions, testimonials, and more. Accent removal works on Elementor's frontend-rendered elements via MutationObserver.
     86* **WordPress Gutenberg (Block Editor)** - Full support. Block content is properly parsed using WordPress core functions (excerpt_remove_blocks) and the Gutenberg data API.
     87* **WordPress Classic Editor** - Full support. Works with TinyMCE visual mode and plain text mode.
     88* **Divi Builder** - Compatible. Divi shortcodes (et_*) are properly stripped for content extraction.
     89* **Beaver Builder** - Compatible. Beaver Builder shortcodes (fl_*) are properly handled.
     90* **Avada / Fusion Builder** - Compatible. Fusion shortcodes (fusion_*) are properly handled.
     91
     92= SEO Plugins =
     93* **Yoast SEO** - Full support. Greek Multi Tool filters content through Yoast's analysis hooks (wpseo_pre_analysis_post_content), providing clean rendered text when page builder shortcodes are detected. This ensures Yoast can accurately analyze your Greek content for readability and SEO, even when using WP Bakery or other shortcode-based builders.
     94* **Rank Math** - Compatible. Uses standard WordPress hooks.
     95* **All in One SEO (AIOSEO)** - Compatible. Uses standard WordPress hooks.
     96
     97= Other Plugins =
     98* **WordPress core** (tested up to 6.9.1)
     99* **WooCommerce** - Full support for product permalinks, search, and media
     100* **Advanced Custom Fields (ACF)** - Full compatibility since v3.3.0 with context-aware transliteration
    66101
    67102The plugin has been extensively tested for compatibility issues and will not conflict with other well-coded plugins.
     
    99134Absolutely! Greek Multi Tool seamlessly integrates with WooCommerce to handle Greek permalinks, accents, and all other features on your product pages.
    100135
     136= Does this plugin work with ACF (Advanced Custom Fields)? =
     137Yes! Since version 3.3.0, Greek Multi Tool is fully compatible with ACF. Our context-aware transliteration engine automatically detects ACF internal operations and skips transliteration, so your field names, keys, and definitions remain untouched.
     138
     139= Does it convert media/image file names? =
     140Yes! Since version 3.3.0, the plugin can automatically convert Greek characters in media file names during upload. Enable the "Media File Name Conversion" toggle in the Permalink Settings tab. For example, "εικόνα-προϊόντος.jpg" becomes "eikona-proiontos.jpg" automatically.
     141
     142= Does it convert attachment (media) slugs? =
     143Yes! Media attachment slugs are automatically converted to Latin, just like regular posts and pages. The bulk "Convert Old Permalinks" tool also includes existing media attachments.
     144
    101145= Will this plugin slow down my website? =
    102146No. Greek Multi Tool is built with performance in mind, using efficient code that makes minimal database queries. The impact on site speed is negligible.
    103147
    104148= How do I convert old permalinks? =
    105 Simply navigate to Greek Multi Tool → Convert Old Permalinks in your WordPress dashboard and click the "CONVERT" button. The plugin handles everything automatically, including setting up proper 301 redirects.
     149Simply navigate to Greek Multi Tool → Convert Old Permalinks in your WordPress dashboard and click the "CONVERT" button. The plugin handles everything automatically, including posts, pages, custom post types, media attachments, taxonomy terms, and setting up proper 301 redirects.
    106150
    107151= Will this break my SEO? =
     
    111155Our plugin implements specialized search algorithms that understand Greek linguistic patterns, including handling accented characters, diphthongs, and various word forms. This dramatically improves the accuracy of internal WordPress searches.
    112156
    113 = Is the Text Analysis tool compatible with Gutenberg and Classic Editor? =
    114 Yes, our Text Analysis tool works perfectly with both Gutenberg and Classic Editor.
     157= Does this plugin work with WP Bakery Page Builder? =
     158Yes! Greek Multi Tool is fully compatible with WP Bakery (Visual Composer). All features work correctly - text analysis extracts content from WP Bakery text blocks, excerpt generation properly handles vc_ shortcodes, and the uppercase accent remover works on WP Bakery's dynamically loaded frontend content. If you had issues with "No content to analyze" when using WP Bakery text blocks, this has been resolved with the page builder compatibility layer.
     159
     160= Does this plugin work with Elementor? =
     161Yes! Full Elementor support is included. The plugin reads Elementor widget data directly from post meta to extract text content from all widget types. Text analysis, excerpt generation, and all other features work perfectly with Elementor-built pages.
     162
     163= Is the Text Analysis tool compatible with page builders? =
     164Yes! The Text Analysis tool works with all major editors and page builders including WordPress Gutenberg (Block Editor), Classic Editor (TinyMCE), WP Bakery Page Builder, and Elementor. The plugin uses multiple content extraction strategies and includes a server-side fallback that reads saved post content when client-side extraction isn't possible.
     165
     166= Does this plugin work with Yoast SEO? =
     167Yes! Greek Multi Tool enhances Yoast SEO compatibility by providing clean, rendered text content to Yoast's analysis engine. When your content uses page builder shortcodes (WP Bakery, Divi, etc.), Yoast may not be able to analyze the raw shortcode content properly. Greek Multi Tool intercepts Yoast's content analysis and provides the fully rendered, clean text for accurate SEO analysis of your Greek content.
    115168
    116169= What PHP version do I need? =
     
    139192
    140193== Changelog ==
     194= 3.3.0 =
     195* **New Feature**: Greek Media File Name Conversion - Automatically convert Greek characters in uploaded media file names (images, documents, etc.) to SEO-friendly Latin equivalents during upload
     196* **New Feature**: Attachment Slug Conversion - Media attachment slugs are now converted to Latin both automatically on upload and via the bulk "Convert Old Permalinks" tool
     197* **New Feature**: Page Builder Compatibility Layer - New shared content extraction engine that properly handles content from WP Bakery, Elementor, Gutenberg, Divi, Beaver Builder, and Avada/Fusion Builder
     198* **Bug Fix**: ACF (Advanced Custom Fields) Compatibility - Transliteration engine is now context-aware and skips ACF internal operations, preventing field name/key corruption (e.g., 'acf-data-weight' no longer becomes 'acf-dedomena-varos')
     199* **Bug Fix**: Text Analysis now works with WP Bakery Page Builder - Fixed "No content to analyze" error when content is inside WP Bakery text blocks. The plugin now uses multiple content extraction strategies (WP Bakery JS API, visual editor scraping, hidden textarea) with an automatic server-side fallback
     200* **Bug Fix**: Text Analysis now works with Elementor - Content is extracted directly from Elementor's widget data stored in post meta
     201* **Improvement**: Excerpt generation now uses the page builder compatibility layer to extract clean text from any page builder content, including Elementor widget data
     202* **Improvement**: Uppercase accent remover now uses MutationObserver for dynamically loaded content from page builders (WP Bakery frontend editor, Elementor frontend rendering)
     203* **Improvement**: Uppercase accent remover listens for WP Bakery and Elementor frontend events to apply accent removal on newly rendered content
     204* **Improvement**: sanitize_title callbacks now accept all 3 WordPress filter arguments ($title, $raw_title, $context) and only run in 'save' context, preventing unintended transliteration during display and query operations
     205* **Improvement**: Bulk "Convert Old Permalinks" now includes media attachments (post_status 'inherit') alongside posts, pages, and custom post types
     206* **Improvement**: Translator functions refactored with shared helper functions (grmlt_get_greek_expressions, grmlt_transliterate_greek, grmlt_apply_diphthongs_simple/advanced) for better code reuse and maintainability
     207* **Improvement**: Smart 301 redirect creation that skips attachments (whose URLs are served from /wp-content/uploads/ and don't use slugs in the same way)
     208* **Compatibility**: Full WP Bakery Page Builder support - text analysis, excerpt generation, uppercase accent removal, and content extraction all work with WP Bakery elements
     209* **Compatibility**: Full Elementor support - reads Elementor widget data directly from post meta for comprehensive content extraction
     210* **Compatibility**: Full Gutenberg Block Editor support - proper block parsing via WordPress core functions
     211* **Compatibility**: Yoast SEO integration - provides clean rendered content to Yoast's analysis engine via wpseo_pre_analysis_post_content filter, ensuring accurate SEO analysis of page builder content
     212* **Compatibility**: Full ACF (Advanced Custom Fields) compatibility - detects ACF AJAX actions, ACF post types, and ACF admin screens
     213* **Compatibility**: Updated plugin description to reflect all current features
     214
    141215= 3.2.0 =
    142216* **Critical Fix**: Fixed 301 redirect feature not working (redirect was hooked incorrectly to `init` inside an `init` callback and never fired)
     
    199273* Global 301 Redirect Error on database record fixed.
    200274
    201 = 2.1.6 = 
     275= 2.1.6 =
    202276* Added new list for existing 301 redirections made by the plugin where you can edit/delete them.
    203277* Fixed where sometimes the plugin wouldn't automatically turn text transliteration on upon activation.
     
    217291
    218292= 2.1.2 =
    219 * Fixed the issue with the convertion of old URLs. 
     293* Fixed the issue with the convertion of old URLs.
    220294* If you are facing any error 404 with mass converted old URLs, please visit the Admin > Greek Multi Tool > Convert Old Permalinks and hit the Convert Button.
    221295
     
    250324* Minor bug fixes
    251325
    252 = 1.2.1 = 
     326= 1.2.1 =
    253327* Minor bug fixes
    254328
     
    266340
    267341= 1.0.4 =
    268 * Add the ability to choose how to save the diphthongs 
     342* Add the ability to choose how to save the diphthongs
    269343
    270344= 1.0.3 =
    271 * Minor fixes on the settings page 
     345* Minor fixes on the settings page
    272346
    273347= 1.0.2 =
    274 * Settings page redesign 
     348* Settings page redesign
    275349
    276350= 1.0.1 =
     
    279353
    280354= 1.0.0 =
    281 * Plugin released. 
     355* Plugin released.
    282356
    283357== Upgrade Notice ==
     358= 3.3.0 =
     359New features: Automatic Greek media file name conversion on upload, attachment slug conversion, and full ACF compatibility. Full page builder support: text analysis, excerpts, and accent removal now work perfectly with WP Bakery, Elementor, and Gutenberg. Yoast SEO integration provides clean content for accurate SEO analysis. Recommended update for all Greek websites!
     360
    284361= 3.2.0 =
    285362Critical security and bug fix release. Fixes 301 redirects not working, XSS vulnerabilities, SQL injection risks, and PHP 8.2+ compatibility issues. All users should update immediately.
  • greek-multi-tool/trunk/uninstall.php

    r3463358 r3470610  
    2828delete_option( 'grmlt_uar_js' );
    2929delete_option( 'grmlt_redirect' );
     30delete_option( 'grmlt_media_file_name' );
    3031delete_option( 'grmlt_enhance_search' );
    3132delete_option( 'grmlt_accent_insensitive_search' );
Note: See TracChangeset for help on using the changeset viewer.