Created
August 22, 2026 15:09
-
-
Save davidfcarr/4a7dd41101ab3e4975cade91d69a6c12 to your computer and use it in GitHub Desktop.
The Advanced Editor Remover
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Plugin Name: The Advanced Editor Remover | |
| * Plugin URI: https://example.com/ | |
| * Description: Removes Advanced Editor (TinyMCE) block comments like <!-- wp:tadv/classic-paragraph --> without altering surrounding content. Includes test mode, bulk processing, undo functionality, and backup cleanup. | |
| * Version: 1.1.0 | |
| * Author: WordPress Developer | |
| * License: GPL-2.0+ | |
| */ | |
| if ( ! defined( 'ABSPATH' ) ) { | |
| exit; // Exit if accessed directly | |
| } | |
| class TADV_Remover_Plugin { | |
| private static $instance = null; | |
| private $meta_key = '_tadv_original_content'; | |
| public static function get_instance() { | |
| if ( null === self::$instance ) { | |
| self::$instance = new self(); | |
| } | |
| return self::$instance; | |
| } | |
| public function __construct() { | |
| add_action( 'admin_menu', array( $this, 'register_admin_menu' ) ); | |
| add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) ); | |
| // AJAX hooks | |
| add_action( 'wp_ajax_tadv_remover_process', array( $this, 'handle_ajax_process' ) ); | |
| add_action( 'wp_ajax_tadv_remover_undo', array( $this, 'handle_ajax_undo' ) ); | |
| add_action( 'wp_ajax_tadv_remover_delete_meta', array( $this, 'handle_ajax_delete_meta' ) ); | |
| } | |
| /** | |
| * Register Tools sub-menu page | |
| */ | |
| public function register_admin_menu() { | |
| add_submenu_page( | |
| 'tools.php', | |
| 'Advanced Editor Remover', | |
| 'Advanced Editor Remover', | |
| 'manage_options', | |
| 'tadv-remover', | |
| array( $this, 'render_admin_page' ) | |
| ); | |
| } | |
| /** | |
| * Enqueue JavaScript & Inline CSS | |
| */ | |
| public function enqueue_admin_scripts( $hook ) { | |
| if ( 'tools_page_tadv-remover' !== $hook ) { | |
| return; | |
| } | |
| wp_enqueue_script( 'jquery' ); | |
| } | |
| /** | |
| * Clean block comment tags from content | |
| */ | |
| private function strip_tadv_tags( $content ) { | |
| // Matches opening, closing, and self-closing wp:tadv tags: | |
| // - Opening: <!-- wp:tadv/... --> | |
| // - Closing: <!-- /wp:tadv/... --> | |
| // - Self-closing: <!-- wp:tadv/... /--> | |
| $pattern = '/<!--\s*\/?wp:tadv\/[a-zA-Z0-9_.-]+(?:\s+\{[\s\S]*?\})?\s*\/?-->\r?\n?/i'; | |
| return preg_replace( $pattern, '', $content ); | |
| } | |
| /** | |
| * Main Admin Interface | |
| */ | |
| public function render_admin_page() { | |
| if ( ! current_user_can( 'manage_options' ) ) { | |
| return; | |
| } | |
| // Count affected posts | |
| global $wpdb; | |
| $affected_count = $wpdb->get_var( | |
| "SELECT COUNT(ID) FROM {$wpdb->posts} | |
| WHERE post_status NOT IN ('auto-draft', 'trash') | |
| AND post_content LIKE '%wp:tadv/%'" | |
| ); | |
| // Count posts with undo meta | |
| $undo_count = $wpdb->get_var( | |
| $wpdb->prepare( | |
| "SELECT COUNT(DISTINCT post_id) FROM {$wpdb->postmeta} WHERE meta_key = %s", | |
| $this->meta_key | |
| ) | |
| ); | |
| ?> | |
| <div class="wrap"> | |
| <h1>The Advanced Editor Remover</h1> | |
| <p>Find and clean <code><!-- wp:tadv/classic-paragraph --></code> comments left over from the Advanced Editor / TinyMCE plugin, preserving your actual content.</p> | |
| <hr> | |
| <div class="card" style="max-width: 800px; padding: 20px; margin-top: 20px;"> | |
| <h2>Operation Mode</h2> | |
| <p>Found <strong><?php echo esc_html( $affected_count ); ?></strong> post(s) containing Advanced Editor code comments.</p> | |
| <form id="tadv-remover-form"> | |
| <p> | |
| <label> | |
| <input type="radio" name="mode" value="single" checked="checked"> | |
| <strong>Test Mode:</strong> Convert a single post first to verify results | |
| </label> | |
| </p> | |
| <p> | |
| <label> | |
| <input type="radio" name="mode" value="all"> | |
| <strong>Convert All Mode:</strong> Convert all remaining posts (<?php echo esc_html( $affected_count ); ?> total) | |
| </label> | |
| </p> | |
| <p style="margin-top: 20px;"> | |
| <button type="submit" id="tadv-submit-btn" class="button button-primary" <?php disabled( $affected_count, 0 ); ?>> | |
| Execute Cleanup | |
| </button> | |
| </p> | |
| </form> | |
| </div> | |
| <div class="card" style="max-width: 800px; padding: 20px; margin-top: 20px;"> | |
| <h2>Backup Maintenance & Undo Operations</h2> | |
| <p>Currently <strong><?php echo esc_html( $undo_count ); ?></strong> post(s) have backup data saved in postmeta (<code><?php echo esc_html( $this->meta_key ); ?></code>).</p> | |
| <p> | |
| <button type="button" id="tadv-undo-btn" class="button button-secondary" <?php disabled( $undo_count, 0 ); ?>> | |
| Undo All Conversions | |
| </button> | |
| <button type="button" id="tadv-purge-btn" class="button button-secondary" style="color: #b32d2e; border-color: #b32d2e;" <?php disabled( $undo_count, 0 ); ?>> | |
| Purge Backup Meta | |
| </button> | |
| </p> | |
| </div> | |
| <div id="tadv-status" style="margin-top: 20px; display: none;"> | |
| <div class="notice notice-info inline"><p id="tadv-status-text">Processing...</p></div> | |
| </div> | |
| <div id="tadv-results" style="margin-top: 20px; max-width: 1000px;"></div> | |
| </div> | |
| <script> | |
| jQuery(document).ready(function($) { | |
| $('#tadv-remover-form').on('submit', function(e) { | |
| e.preventDefault(); | |
| var mode = $('input[name="mode"]:checked').val(); | |
| $('#tadv-submit-btn').prop('disabled', true); | |
| $('#tadv-status').show(); | |
| $('#tadv-status-text').text('Processing posts, please wait...'); | |
| $.ajax({ | |
| url: ajaxurl, | |
| type: 'POST', | |
| data: { | |
| action: 'tadv_remover_process', | |
| mode: mode, | |
| nonce: '<?php echo wp_create_nonce( "tadv_remover_nonce" ); ?>' | |
| }, | |
| success: function(response) { | |
| $('#tadv-submit-btn').prop('disabled', false); | |
| $('#tadv-status').hide(); | |
| if (response.success) { | |
| renderResultsTable(response.data.posts, response.data.message); | |
| } else { | |
| alert('Error: ' + response.data); | |
| } | |
| }, | |
| error: function() { | |
| $('#tadv-submit-btn').prop('disabled', false); | |
| $('#tadv-status').hide(); | |
| alert('An unexpected AJAX error occurred.'); | |
| } | |
| }); | |
| }); | |
| $('#tadv-undo-btn').on('click', function(e) { | |
| if (!confirm('Are you sure you want to restore original content for all processed posts?')) { | |
| return; | |
| } | |
| var $btn = $(this); | |
| $btn.prop('disabled', true); | |
| $('#tadv-status').show(); | |
| $('#tadv-status-text').text('Restoring post content from meta backups...'); | |
| $.ajax({ | |
| url: ajaxurl, | |
| type: 'POST', | |
| data: { | |
| action: 'tadv_remover_undo', | |
| nonce: '<?php echo wp_create_nonce( "tadv_remover_nonce" ); ?>' | |
| }, | |
| success: function(response) { | |
| $('#tadv-status').hide(); | |
| if (response.success) { | |
| alert(response.data.message); | |
| location.reload(); | |
| } else { | |
| $btn.prop('disabled', false); | |
| alert('Error: ' + response.data); | |
| } | |
| }, | |
| error: function() { | |
| $btn.prop('disabled', false); | |
| $('#tadv-status').hide(); | |
| alert('An unexpected AJAX error occurred.'); | |
| } | |
| }); | |
| }); | |
| $('#tadv-purge-btn').on('click', function(e) { | |
| if (!confirm('Are you sure you want to permanently delete all postmeta backups? You will no longer be able to undo conversions.')) { | |
| return; | |
| } | |
| var $btn = $(this); | |
| $btn.prop('disabled', true); | |
| $('#tadv-status').show(); | |
| $('#tadv-status-text').text('Purging backup postmeta fields...'); | |
| $.ajax({ | |
| url: ajaxurl, | |
| type: 'POST', | |
| data: { | |
| action: 'tadv_remover_delete_meta', | |
| nonce: '<?php echo wp_create_nonce( "tadv_remover_nonce" ); ?>' | |
| }, | |
| success: function(response) { | |
| $('#tadv-status').hide(); | |
| if (response.success) { | |
| alert(response.data.message); | |
| location.reload(); | |
| } else { | |
| $btn.prop('disabled', false); | |
| alert('Error: ' + response.data); | |
| } | |
| }, | |
| error: function() { | |
| $btn.prop('disabled', false); | |
| $('#tadv-status').hide(); | |
| alert('An unexpected AJAX error occurred.'); | |
| } | |
| }); | |
| }); | |
| function renderResultsTable(posts, message) { | |
| if (!posts || posts.length === 0) { | |
| $('#tadv-results').html('<div class="notice notice-warning"><p>No posts were modified.</p></div>'); | |
| return; | |
| } | |
| var html = '<div class="notice notice-success"><p>' + message + '</p></div>'; | |
| html += '<table class="wp-list-table widefat fixed striped" style="margin-top:15px;">'; | |
| html += '<thead><tr><th>Title</th><th>Post Type</th><th>Actions</th></tr></thead><tbody>'; | |
| $.each(posts, function(i, post) { | |
| html += '<tr>'; | |
| html += '<td><strong>' + post.title + '</strong> (ID: ' + post.id + ')</td>'; | |
| html += '<td>' + post.type + '</td>'; | |
| html += '<td>'; | |
| html += '<a href="' + post.view_url + '" target="_blank" class="button button-small">View Post</a> '; | |
| html += '<a href="' + post.edit_url + '" target="_blank" class="button button-small">Edit Post</a>'; | |
| html += '</td>'; | |
| html += '</tr>'; | |
| }); | |
| html += '</tbody></table>'; | |
| $('#tadv-results').html(html); | |
| } | |
| }); | |
| </script> | |
| <?php | |
| } | |
| /** | |
| * AJAX Handler: Convert Posts | |
| */ | |
| public function handle_ajax_process() { | |
| check_ajax_referer( 'tadv_remover_nonce', 'nonce' ); | |
| if ( ! current_user_can( 'manage_options' ) ) { | |
| wp_send_json_error( 'Insufficient permissions.' ); | |
| } | |
| $mode = isset( $_POST['mode'] ) ? sanitize_text_field( $_POST['mode'] ) : 'single'; | |
| global $wpdb; | |
| $limit = ( 'single' === $mode ) ? 1 : -1; | |
| $query = "SELECT ID, post_title, post_type, post_content | |
| FROM {$wpdb->posts} | |
| WHERE post_status NOT IN ('auto-draft', 'trash') | |
| AND post_content LIKE '%wp:tadv/%'"; | |
| if ( $limit > 0 ) { | |
| $query .= " LIMIT " . intval( $limit ); | |
| } | |
| $posts = $wpdb->get_results( $query ); | |
| if ( empty( $posts ) ) { | |
| wp_send_json_error( 'No posts found with Advanced Editor code comments.' ); | |
| } | |
| $processed = array(); | |
| foreach ( $posts as $post ) { | |
| $original_content = $post->post_content; | |
| $cleaned_content = $this->strip_tadv_tags( $original_content ); | |
| // Save backup meta only if it hasn't been saved before | |
| if ( ! get_post_meta( $post->ID, $this->meta_key, true ) ) { | |
| update_post_meta( $post->ID, $this->meta_key, $original_content ); | |
| } | |
| // Update post content | |
| $wpdb->update( | |
| $wpdb->posts, | |
| array( 'post_content' => $cleaned_content ), | |
| array( 'ID' => $post->ID ), | |
| array( '%s' ), | |
| array( '%d' ) | |
| ); | |
| clean_post_cache( $post->ID ); | |
| $processed[] = array( | |
| 'id' => $post->ID, | |
| 'title' => esc_html( $post->post_title ? $post->post_title : '(No Title)' ), | |
| 'type' => esc_html( $post->post_type ), | |
| 'view_url' => esc_url( get_permalink( $post->ID ) ), | |
| 'edit_url' => esc_url( get_edit_post_link( $post->ID, 'raw' ) ), | |
| ); | |
| } | |
| $message = sprintf( 'Successfully processed %d post(s).', count( $processed ) ); | |
| wp_send_json_success( array( | |
| 'message' => $message, | |
| 'posts' => $processed, | |
| ) ); | |
| } | |
| /** | |
| * AJAX Handler: Undo All Conversions | |
| */ | |
| public function handle_ajax_undo() { | |
| check_ajax_referer( 'tadv_remover_nonce', 'nonce' ); | |
| if ( ! current_user_can( 'manage_options' ) ) { | |
| wp_send_json_error( 'Insufficient permissions.' ); | |
| } | |
| global $wpdb; | |
| $meta_records = $wpdb->get_results( | |
| $wpdb->prepare( | |
| "SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s", | |
| $this->meta_key | |
| ) | |
| ); | |
| if ( empty( $meta_records ) ) { | |
| wp_send_json_error( 'No backup content found to restore.' ); | |
| } | |
| $restored_count = 0; | |
| foreach ( $meta_records as $record ) { | |
| $post_id = intval( $record->post_id ); | |
| $original_content = $record->meta_value; | |
| $wpdb->update( | |
| $wpdb->posts, | |
| array( 'post_content' => $original_content ), | |
| array( 'ID' => $post_id ), | |
| array( '%s' ), | |
| array( '%d' ) | |
| ); | |
| delete_post_meta( $post_id, $this->meta_key ); | |
| clean_post_cache( $post_id ); | |
| $restored_count++; | |
| } | |
| wp_send_json_success( array( | |
| 'message' => sprintf( 'Successfully restored %d post(s) to their original state.', $restored_count ), | |
| ) ); | |
| } | |
| /** | |
| * AJAX Handler: Delete Backup Postmeta | |
| */ | |
| public function handle_ajax_delete_meta() { | |
| check_ajax_referer( 'tadv_remover_nonce', 'nonce' ); | |
| if ( ! current_user_can( 'manage_options' ) ) { | |
| wp_send_json_error( 'Insufficient permissions.' ); | |
| } | |
| global $wpdb; | |
| $deleted = $wpdb->delete( | |
| $wpdb->postmeta, | |
| array( 'meta_key' => $this->meta_key ), | |
| array( '%s' ) | |
| ); | |
| if ( false === $deleted ) { | |
| wp_send_json_error( 'Failed to remove backup meta from the database.' ); | |
| } | |
| wp_send_json_success( array( | |
| 'message' => sprintf( 'Successfully purged %d backup meta record(s).', $deleted ), | |
| ) ); | |
| } | |
| } | |
| // Initialize the plugin | |
| add_action( 'plugins_loaded', array( 'TADV_Remover_Plugin', 'get_instance' ) ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment