Plugin Directory

Changeset 3434009


Ignore:
Timestamp:
01/07/2026 02:08:39 AM (3 months ago)
Author:
nhrrob
Message:

Update to version 1.1.9 from GitHub

Location:
nhrrob-options-table-manager
Files:
14 edited
1 copied

Legend:

Unmodified
Added
Removed
  • nhrrob-options-table-manager/tags/1.1.9/assets/css/admin.css

    r3263431 r3434009  
    427427    border: none;
    428428}
     429
     430.nhrotm-filter-group.nhrotm-bulk-action-group {
     431    position: absolute;
     432    left: 10px;
     433}
     434
     435#nhrotm-bulk-action-selector {
     436    min-width: 160px;
     437    padding: 4px 8px;
     438    border: 1px solid #ddd;
     439    border-radius: 4px;
     440}
     441
     442#nhrotm-do-bulk-action {
     443    width: 60px;
     444    padding: 4px 8px;
     445    color: #000;
     446    border: 1px solid #ddd;
     447    border-radius: 4px;
     448}
     449
     450tfoot td.manage-column.column-cb.check-column {
     451    padding: 8px 10px;
     452}
  • nhrrob-options-table-manager/tags/1.1.9/assets/js/admin.js

    r3263431 r3434009  
    4040                "data": function(d) {
    4141                    // Add column search values to the request
    42                     for (let i = 0; i < d.columns.length; i++) {                       
    43                         d.columns[i].search.value = $('#nhrotm-data-table tfoot input').eq(i).val();
     42                    // Remap inputs because Col 0 (checkbox) and Col 5 (Actions) have no inputs
     43                    // Inputs are present for Col 1, 2, 3, 4
     44                    d.columns[0].search.value = ''; // Checkbox
     45                    if ($('#nhrotm-data-table tfoot input').length >= 4) {
     46                        d.columns[1].search.value = $('#nhrotm-data-table tfoot input').eq(0).val();
     47                        d.columns[2].search.value = $('#nhrotm-data-table tfoot input').eq(1).val();
     48                        d.columns[3].search.value = $('#nhrotm-data-table tfoot input').eq(2).val();
     49                        d.columns[4].search.value = $('#nhrotm-data-table tfoot input').eq(3).val();
     50                        d.columns[5].search.value = '';
    4451                    }
    4552
     
    5158                        $('#delete-expired-transients').attr('disabled', false);
    5259
    53                         let currentSearch = d.columns[1].search.value || '';
     60                        // option_name is now at index 2 (0=cb, 1=id, 2=name)
     61                        let currentSearch = d.columns[2].search.value || '';
    5462                        if (!currentSearch.includes('transient_')) {
    55                             d.columns[1].search.value = 'transient_' + currentSearch;
     63                            d.columns[2].search.value = 'transient_' + currentSearch;
    5664                        }
    5765                    }
     
    5967            },
    6068            "columns": [
     69                {
     70                    "data": null,
     71                    "orderable": false,
     72                    "visible": true,
     73                    "searchable": false,
     74                    "render": function(data, type, row) {
     75                        return '<input type="checkbox" class="nhrotm-checkbox" value="' + row.option_name + '">';
     76                    }
     77                },
    6178                { "data": "option_id" },
    6279                { "data": "option_name" },
     
    6986            // "scrollCollapse": true,
    7087            // "paging": true,
    71             // "order": [[0, 'asc']], // Default order on the first column in ascending,
     88            "order": [[1, 'asc']], // Default order on the first column in ascending,
    7289            "initComplete": function () {
    7390                this.api()
    7491                    .columns()
    75                     .every(function () {
     92                    .every(function (index) {
     93                        // Skip checkbox column (index 0) and Actions column (index 5)
     94                        if (index === 0 || index === 5) return;
     95
    7696                        let column = this;
    7797                        let title = column.footer().textContent;
     
    638658        });
    639659       
     660        // Select All handler
     661        $('#nhrotm-select-all, #nhrotm-select-all-footer').on('click', function() {
     662            var rows = $('#nhrotm-data-table').DataTable().rows({ 'search': 'applied' }).nodes();
     663            $('input[type="checkbox"]', rows).prop('checked', this.checked);
     664            $('#nhrotm-select-all, #nhrotm-select-all-footer').prop('checked', this.checked);
     665        });
     666       
     667        // Handle individual checkbox click to update Select All state
     668        $('#nhrotm-data-table tbody').on('change', 'input[type="checkbox"]', function(){
     669            if(!this.checked){
     670                var el = $('#nhrotm-select-all, #nhrotm-select-all-footer').get(0);
     671                if(el && el.checked && ('indeterminate' in el)){
     672                    el.indeterminate = true;
     673                }
     674            }
     675        });
     676
     677        // Bulk Actions
     678        $('#nhrotm-do-bulk-action').on('click', function(e) {
     679            e.preventDefault();
     680            const action = $('#nhrotm-bulk-action-selector').val();
     681           
     682            if (action === '-1') {
     683                showToast("Please select an action.", "error");
     684                return;
     685            }
     686
     687            const selectedOptions = [];
     688            $('#nhrotm-data-table tbody input.nhrotm-checkbox:checked').each(function() {
     689                selectedOptions.push($(this).val());
     690            });
     691
     692            if (selectedOptions.length === 0) {
     693                showToast("Please select at least one option.", "warning");
     694                return;
     695            }
     696
     697            if (action === 'delete') {
     698                 if (confirm("Are you sure you want to delete selected options?")) {
     699                     bulkDeleteOptions(selectedOptions);
     700                 }
     701            }
     702        });
     703
     704        function bulkDeleteOptions(optionNames) {
     705             $.ajax({
     706                url: nhrotmOptionsTableManager.ajaxUrl,
     707                method: "POST",
     708                data: {
     709                    action: "nhrotm_bulk_delete_options",
     710                    nonce: nhrotmOptionsTableManager.nonce,
     711                    option_names: optionNames
     712                },
     713                success: function(response) {
     714                    if (response.success) {
     715                        showToast("Options deleted successfully!", "success");
     716                        table.ajax.reload(null, false);
     717                        $('#nhrotm-select-all, #nhrotm-select-all-footer').prop('checked', false);
     718                    } else {
     719                        showToast("Failed to delete options.", "error");
     720                    }
     721                }
     722            });
     723        }
     724
    640725    });
    641726})(jQuery);
  • nhrrob-options-table-manager/tags/1.1.9/includes/Ajax/AjaxHandler.php

    r3263431 r3434009  
    3333            'nhrotm_edit_option' => 'edit_option',
    3434            'nhrotm_delete_option' => 'delete_option',
     35            'nhrotm_bulk_delete_options' => 'bulk_delete_options',
    3536            'nhrotm_delete_expired_transients' => 'delete_expired_transients',
    3637            'nhrotm_option_usage_analytics' => 'option_usage_analytics',
     
    109110        }
    110111    }
     112
     113    public function bulk_delete_options() {
     114        try {
     115            $result = $this->options_manager->bulk_delete_records();
     116            if ( $result ) {
     117                wp_send_json_success('Options deleted successfully!');
     118            } else {
     119                wp_send_json_error('Failed to delete options!');
     120            }
     121        } catch (\Exception $e) {
     122            wp_send_json_error($e->getMessage());
     123        }
     124    }
    111125   
    112126    public function delete_expired_transients() {
  • nhrrob-options-table-manager/tags/1.1.9/includes/Managers/OptionsTableManager.php

    r3263180 r3434009  
    4343        // Ensure order column is valid using whitelist approach
    4444        if ($order_column_index < 0 || $order_column_index >= count($columns)) {
    45             $order_column_index = 0; // Default to first column
     45            $order_column_index = 1; // Default to 'option_id' (index 1)
    4646        }
    4747        $order_column = $columns[$order_column_index];
     48
     49        if (empty($order_column)) {
     50            $order_column = 'option_id';
     51        }
    4852
    4953        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     
    8387        // Individual column searches
    8488        if (!empty($column_search)) {
    85             // option_id column (index 0)
    86             if (!empty($column_search[0])) {
     89            // checkbox column (index 0) - Ignore/Not searchable via specific field in this implementation
     90           
     91            // option_id column (index 1)
     92            if (!empty($column_search[1])) {
    8793                // For numeric column, use exact match or range
    88                 if (is_numeric($column_search[0])) {
    89                     $where_clauses[] = $this->wpdb->prepare("option_id = %d", intval($column_search[0]));
    90                 }
    91             }
    92            
    93             // option_name column (index 1)
    94             if (!empty($column_search[1])) {
     94                if (is_numeric($column_search[1])) {
     95                    $where_clauses[] = $this->wpdb->prepare("option_id = %d", intval($column_search[1]));
     96                }
     97            }
     98           
     99            // option_name column (index 2)
     100            if (!empty($column_search[2])) {
    95101                $where_clauses[] = $this->wpdb->prepare(
    96102                    "option_name LIKE %s",
    97                     '%' . $this->wpdb->esc_like($column_search[1]) . '%'
     103                    '%' . $this->wpdb->esc_like($column_search[2]) . '%'
    98104                );
    99105            }
    100106           
    101             // option_value column (index 2)
    102             if (!empty($column_search[2])) {
     107            // option_value column (index 3)
     108            if (!empty($column_search[3])) {
    103109                $where_clauses[] = $this->wpdb->prepare(
    104110                    "option_value LIKE %s",
    105                     '%' . $this->wpdb->esc_like($column_search[2]) . '%'
     111                    '%' . $this->wpdb->esc_like($column_search[3]) . '%'
    106112                );
    107113            }
    108114           
    109             // autoload column (index 3)
    110             if (!empty($column_search[3])) {
     115            // autoload column (index 4)
     116            if (!empty($column_search[4])) {
    111117                $where_clauses[] = $this->wpdb->prepare(
    112118                    "autoload LIKE %s",
    113                     '%' . $this->wpdb->esc_like($column_search[3]) . '%'
     119                    '%' . $this->wpdb->esc_like($column_search[4]) . '%'
    114120                );
    115121            }
     
    335341
    336342    /**
     343     * Bulk delete options
     344     *
     345     * @return bool Success status
     346     */
     347    public function bulk_delete_records() {
     348        // Verify nonce
     349        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'nhrotm-admin-nonce')) {
     350            throw new \Exception('Invalid nonce');
     351        }
     352
     353        $this->validate_permissions();
     354
     355        $option_names = isset($_POST['option_names']) ? (array) $_POST['option_names'] : [];
     356
     357        if (empty($option_names)) {
     358            throw new \Exception('No options selected');
     359        }
     360
     361        foreach ($option_names as $option_name) {
     362            $option_name = sanitize_text_field(wp_unslash($option_name));
     363           
     364            if ($this->is_protected_item($option_name)) {
     365                continue; // Skip protected items
     366            }
     367
     368            delete_option($option_name);
     369        }
     370
     371        return true;
     372    }
     373
     374    /**
    337375     * Delete an expired transient
    338376     *
     
    444482     */
    445483    protected function get_searchable_columns() {
    446         return ['option_id', 'option_name', 'option_value', 'autoload'];
     484        return [null, 'option_id', 'option_name', 'option_value', 'autoload'];
    447485    }
    448486}
  • nhrrob-options-table-manager/tags/1.1.9/includes/views/admin/settings/index.php

    r3263431 r3434009  
    2828        <div class="nhrotm-filter-container">
    2929            <div class="nhrotm-filter-row">
     30                <div class="nhrotm-filter-group nhrotm-bulk-action-group">
     31                    <select id="nhrotm-bulk-action-selector">
     32                        <option value="-1"><?php esc_html_e('Bulk Actions', 'nhrrob-options-table-manager'); ?></option>
     33                        <option value="delete"><?php esc_html_e('Delete', 'nhrrob-options-table-manager'); ?></option>
     34                    </select>
     35                    <button id="nhrotm-do-bulk-action" class="button action"><?php esc_html_e('Apply', 'nhrrob-options-table-manager'); ?></button>
     36                </div>
     37
    3038                <div class="nhrotm-filter-group">
    3139                    <select id="option-type-filter">
     
    4048        </div>
    4149        <!-- Filter ends  -->
    42         
     50     
    4351        <table id="nhrotm-data-table" class="nhrotm-data-table wp-list-table widefat fixed striped">
    4452            <thead>
    4553                <tr>
     54                    <td id="cb" class="manage-column column-cb check-column"><input type="checkbox" id="nhrotm-select-all"></td>
    4655                    <th><?php esc_html_e('Option ID', 'nhrrob-options-table-manager'); ?></th>
    4756                    <th><?php esc_html_e('Option Name', 'nhrrob-options-table-manager'); ?></th>
     
    5463            <tfoot>
    5564                <tr>
     65                    <td class="manage-column column-cb check-column"><input type="checkbox" id="nhrotm-select-all-footer"></td>
    5666                    <th><?php esc_html_e('Option ID', 'nhrrob-options-table-manager'); ?></th>
    5767                    <th><?php esc_html_e('Option Name', 'nhrrob-options-table-manager'); ?></th>
  • nhrrob-options-table-manager/tags/1.1.9/nhrrob-options-table-manager.php

    r3405973 r3434009  
    66 * Author: Nazmul Hasan Robin
    77 * Author URI: https://profiles.wordpress.org/nhrrob/
    8  * Version: 1.1.8
     8 * Version: 1.1.9
    99 * Requires at least: 6.0
    1010 * Requires PHP: 7.4
     
    2828     * @var string
    2929     */
    30     const nhrotm_version = '1.1.8';
     30    const nhrotm_version = '1.1.9';
    3131
    3232    /**
  • nhrrob-options-table-manager/tags/1.1.9/readme.txt

    r3405973 r3434009  
    55Tested up to: 6.9
    66Requires PHP: 7.4 
    7 Stable tag: 1.1.8
     7Stable tag: 1.1.9
    88License: GPLv2 or later 
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html 
     
    3838We're constantly improving NHR Options Table Manager! Here's what's on the way:
    3939- **Bulk Deletion** – Quickly remove multiple options and user meta entries at once.
    40 - **WP Recipe Maker Table Support** – Manage recipe-related data efficiently.
    41 - **Expired Transient Deletion** – Automatically clean up expired transients to free up database space.
    4240- **More Exciting Features** – Stay tuned for additional enhancements!
    4341
     
    8583
    8684== Changelog ==
     85
     86= 1.1.9 - 05/01/2026 =
     87- Added: Bulk delete options feature
    8788
    8889= 1.1.8 - 30/11/2025 =
  • nhrrob-options-table-manager/trunk/assets/css/admin.css

    r3263431 r3434009  
    427427    border: none;
    428428}
     429
     430.nhrotm-filter-group.nhrotm-bulk-action-group {
     431    position: absolute;
     432    left: 10px;
     433}
     434
     435#nhrotm-bulk-action-selector {
     436    min-width: 160px;
     437    padding: 4px 8px;
     438    border: 1px solid #ddd;
     439    border-radius: 4px;
     440}
     441
     442#nhrotm-do-bulk-action {
     443    width: 60px;
     444    padding: 4px 8px;
     445    color: #000;
     446    border: 1px solid #ddd;
     447    border-radius: 4px;
     448}
     449
     450tfoot td.manage-column.column-cb.check-column {
     451    padding: 8px 10px;
     452}
  • nhrrob-options-table-manager/trunk/assets/js/admin.js

    r3263431 r3434009  
    4040                "data": function(d) {
    4141                    // Add column search values to the request
    42                     for (let i = 0; i < d.columns.length; i++) {                       
    43                         d.columns[i].search.value = $('#nhrotm-data-table tfoot input').eq(i).val();
     42                    // Remap inputs because Col 0 (checkbox) and Col 5 (Actions) have no inputs
     43                    // Inputs are present for Col 1, 2, 3, 4
     44                    d.columns[0].search.value = ''; // Checkbox
     45                    if ($('#nhrotm-data-table tfoot input').length >= 4) {
     46                        d.columns[1].search.value = $('#nhrotm-data-table tfoot input').eq(0).val();
     47                        d.columns[2].search.value = $('#nhrotm-data-table tfoot input').eq(1).val();
     48                        d.columns[3].search.value = $('#nhrotm-data-table tfoot input').eq(2).val();
     49                        d.columns[4].search.value = $('#nhrotm-data-table tfoot input').eq(3).val();
     50                        d.columns[5].search.value = '';
    4451                    }
    4552
     
    5158                        $('#delete-expired-transients').attr('disabled', false);
    5259
    53                         let currentSearch = d.columns[1].search.value || '';
     60                        // option_name is now at index 2 (0=cb, 1=id, 2=name)
     61                        let currentSearch = d.columns[2].search.value || '';
    5462                        if (!currentSearch.includes('transient_')) {
    55                             d.columns[1].search.value = 'transient_' + currentSearch;
     63                            d.columns[2].search.value = 'transient_' + currentSearch;
    5664                        }
    5765                    }
     
    5967            },
    6068            "columns": [
     69                {
     70                    "data": null,
     71                    "orderable": false,
     72                    "visible": true,
     73                    "searchable": false,
     74                    "render": function(data, type, row) {
     75                        return '<input type="checkbox" class="nhrotm-checkbox" value="' + row.option_name + '">';
     76                    }
     77                },
    6178                { "data": "option_id" },
    6279                { "data": "option_name" },
     
    6986            // "scrollCollapse": true,
    7087            // "paging": true,
    71             // "order": [[0, 'asc']], // Default order on the first column in ascending,
     88            "order": [[1, 'asc']], // Default order on the first column in ascending,
    7289            "initComplete": function () {
    7390                this.api()
    7491                    .columns()
    75                     .every(function () {
     92                    .every(function (index) {
     93                        // Skip checkbox column (index 0) and Actions column (index 5)
     94                        if (index === 0 || index === 5) return;
     95
    7696                        let column = this;
    7797                        let title = column.footer().textContent;
     
    638658        });
    639659       
     660        // Select All handler
     661        $('#nhrotm-select-all, #nhrotm-select-all-footer').on('click', function() {
     662            var rows = $('#nhrotm-data-table').DataTable().rows({ 'search': 'applied' }).nodes();
     663            $('input[type="checkbox"]', rows).prop('checked', this.checked);
     664            $('#nhrotm-select-all, #nhrotm-select-all-footer').prop('checked', this.checked);
     665        });
     666       
     667        // Handle individual checkbox click to update Select All state
     668        $('#nhrotm-data-table tbody').on('change', 'input[type="checkbox"]', function(){
     669            if(!this.checked){
     670                var el = $('#nhrotm-select-all, #nhrotm-select-all-footer').get(0);
     671                if(el && el.checked && ('indeterminate' in el)){
     672                    el.indeterminate = true;
     673                }
     674            }
     675        });
     676
     677        // Bulk Actions
     678        $('#nhrotm-do-bulk-action').on('click', function(e) {
     679            e.preventDefault();
     680            const action = $('#nhrotm-bulk-action-selector').val();
     681           
     682            if (action === '-1') {
     683                showToast("Please select an action.", "error");
     684                return;
     685            }
     686
     687            const selectedOptions = [];
     688            $('#nhrotm-data-table tbody input.nhrotm-checkbox:checked').each(function() {
     689                selectedOptions.push($(this).val());
     690            });
     691
     692            if (selectedOptions.length === 0) {
     693                showToast("Please select at least one option.", "warning");
     694                return;
     695            }
     696
     697            if (action === 'delete') {
     698                 if (confirm("Are you sure you want to delete selected options?")) {
     699                     bulkDeleteOptions(selectedOptions);
     700                 }
     701            }
     702        });
     703
     704        function bulkDeleteOptions(optionNames) {
     705             $.ajax({
     706                url: nhrotmOptionsTableManager.ajaxUrl,
     707                method: "POST",
     708                data: {
     709                    action: "nhrotm_bulk_delete_options",
     710                    nonce: nhrotmOptionsTableManager.nonce,
     711                    option_names: optionNames
     712                },
     713                success: function(response) {
     714                    if (response.success) {
     715                        showToast("Options deleted successfully!", "success");
     716                        table.ajax.reload(null, false);
     717                        $('#nhrotm-select-all, #nhrotm-select-all-footer').prop('checked', false);
     718                    } else {
     719                        showToast("Failed to delete options.", "error");
     720                    }
     721                }
     722            });
     723        }
     724
    640725    });
    641726})(jQuery);
  • nhrrob-options-table-manager/trunk/includes/Ajax/AjaxHandler.php

    r3263431 r3434009  
    3333            'nhrotm_edit_option' => 'edit_option',
    3434            'nhrotm_delete_option' => 'delete_option',
     35            'nhrotm_bulk_delete_options' => 'bulk_delete_options',
    3536            'nhrotm_delete_expired_transients' => 'delete_expired_transients',
    3637            'nhrotm_option_usage_analytics' => 'option_usage_analytics',
     
    109110        }
    110111    }
     112
     113    public function bulk_delete_options() {
     114        try {
     115            $result = $this->options_manager->bulk_delete_records();
     116            if ( $result ) {
     117                wp_send_json_success('Options deleted successfully!');
     118            } else {
     119                wp_send_json_error('Failed to delete options!');
     120            }
     121        } catch (\Exception $e) {
     122            wp_send_json_error($e->getMessage());
     123        }
     124    }
    111125   
    112126    public function delete_expired_transients() {
  • nhrrob-options-table-manager/trunk/includes/Managers/OptionsTableManager.php

    r3263180 r3434009  
    4343        // Ensure order column is valid using whitelist approach
    4444        if ($order_column_index < 0 || $order_column_index >= count($columns)) {
    45             $order_column_index = 0; // Default to first column
     45            $order_column_index = 1; // Default to 'option_id' (index 1)
    4646        }
    4747        $order_column = $columns[$order_column_index];
     48
     49        if (empty($order_column)) {
     50            $order_column = 'option_id';
     51        }
    4852
    4953        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     
    8387        // Individual column searches
    8488        if (!empty($column_search)) {
    85             // option_id column (index 0)
    86             if (!empty($column_search[0])) {
     89            // checkbox column (index 0) - Ignore/Not searchable via specific field in this implementation
     90           
     91            // option_id column (index 1)
     92            if (!empty($column_search[1])) {
    8793                // For numeric column, use exact match or range
    88                 if (is_numeric($column_search[0])) {
    89                     $where_clauses[] = $this->wpdb->prepare("option_id = %d", intval($column_search[0]));
    90                 }
    91             }
    92            
    93             // option_name column (index 1)
    94             if (!empty($column_search[1])) {
     94                if (is_numeric($column_search[1])) {
     95                    $where_clauses[] = $this->wpdb->prepare("option_id = %d", intval($column_search[1]));
     96                }
     97            }
     98           
     99            // option_name column (index 2)
     100            if (!empty($column_search[2])) {
    95101                $where_clauses[] = $this->wpdb->prepare(
    96102                    "option_name LIKE %s",
    97                     '%' . $this->wpdb->esc_like($column_search[1]) . '%'
     103                    '%' . $this->wpdb->esc_like($column_search[2]) . '%'
    98104                );
    99105            }
    100106           
    101             // option_value column (index 2)
    102             if (!empty($column_search[2])) {
     107            // option_value column (index 3)
     108            if (!empty($column_search[3])) {
    103109                $where_clauses[] = $this->wpdb->prepare(
    104110                    "option_value LIKE %s",
    105                     '%' . $this->wpdb->esc_like($column_search[2]) . '%'
     111                    '%' . $this->wpdb->esc_like($column_search[3]) . '%'
    106112                );
    107113            }
    108114           
    109             // autoload column (index 3)
    110             if (!empty($column_search[3])) {
     115            // autoload column (index 4)
     116            if (!empty($column_search[4])) {
    111117                $where_clauses[] = $this->wpdb->prepare(
    112118                    "autoload LIKE %s",
    113                     '%' . $this->wpdb->esc_like($column_search[3]) . '%'
     119                    '%' . $this->wpdb->esc_like($column_search[4]) . '%'
    114120                );
    115121            }
     
    335341
    336342    /**
     343     * Bulk delete options
     344     *
     345     * @return bool Success status
     346     */
     347    public function bulk_delete_records() {
     348        // Verify nonce
     349        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'nhrotm-admin-nonce')) {
     350            throw new \Exception('Invalid nonce');
     351        }
     352
     353        $this->validate_permissions();
     354
     355        $option_names = isset($_POST['option_names']) ? (array) $_POST['option_names'] : [];
     356
     357        if (empty($option_names)) {
     358            throw new \Exception('No options selected');
     359        }
     360
     361        foreach ($option_names as $option_name) {
     362            $option_name = sanitize_text_field(wp_unslash($option_name));
     363           
     364            if ($this->is_protected_item($option_name)) {
     365                continue; // Skip protected items
     366            }
     367
     368            delete_option($option_name);
     369        }
     370
     371        return true;
     372    }
     373
     374    /**
    337375     * Delete an expired transient
    338376     *
     
    444482     */
    445483    protected function get_searchable_columns() {
    446         return ['option_id', 'option_name', 'option_value', 'autoload'];
     484        return [null, 'option_id', 'option_name', 'option_value', 'autoload'];
    447485    }
    448486}
  • nhrrob-options-table-manager/trunk/includes/views/admin/settings/index.php

    r3263431 r3434009  
    2828        <div class="nhrotm-filter-container">
    2929            <div class="nhrotm-filter-row">
     30                <div class="nhrotm-filter-group nhrotm-bulk-action-group">
     31                    <select id="nhrotm-bulk-action-selector">
     32                        <option value="-1"><?php esc_html_e('Bulk Actions', 'nhrrob-options-table-manager'); ?></option>
     33                        <option value="delete"><?php esc_html_e('Delete', 'nhrrob-options-table-manager'); ?></option>
     34                    </select>
     35                    <button id="nhrotm-do-bulk-action" class="button action"><?php esc_html_e('Apply', 'nhrrob-options-table-manager'); ?></button>
     36                </div>
     37
    3038                <div class="nhrotm-filter-group">
    3139                    <select id="option-type-filter">
     
    4048        </div>
    4149        <!-- Filter ends  -->
    42         
     50     
    4351        <table id="nhrotm-data-table" class="nhrotm-data-table wp-list-table widefat fixed striped">
    4452            <thead>
    4553                <tr>
     54                    <td id="cb" class="manage-column column-cb check-column"><input type="checkbox" id="nhrotm-select-all"></td>
    4655                    <th><?php esc_html_e('Option ID', 'nhrrob-options-table-manager'); ?></th>
    4756                    <th><?php esc_html_e('Option Name', 'nhrrob-options-table-manager'); ?></th>
     
    5463            <tfoot>
    5564                <tr>
     65                    <td class="manage-column column-cb check-column"><input type="checkbox" id="nhrotm-select-all-footer"></td>
    5666                    <th><?php esc_html_e('Option ID', 'nhrrob-options-table-manager'); ?></th>
    5767                    <th><?php esc_html_e('Option Name', 'nhrrob-options-table-manager'); ?></th>
  • nhrrob-options-table-manager/trunk/nhrrob-options-table-manager.php

    r3405973 r3434009  
    66 * Author: Nazmul Hasan Robin
    77 * Author URI: https://profiles.wordpress.org/nhrrob/
    8  * Version: 1.1.8
     8 * Version: 1.1.9
    99 * Requires at least: 6.0
    1010 * Requires PHP: 7.4
     
    2828     * @var string
    2929     */
    30     const nhrotm_version = '1.1.8';
     30    const nhrotm_version = '1.1.9';
    3131
    3232    /**
  • nhrrob-options-table-manager/trunk/readme.txt

    r3405973 r3434009  
    55Tested up to: 6.9
    66Requires PHP: 7.4 
    7 Stable tag: 1.1.8
     7Stable tag: 1.1.9
    88License: GPLv2 or later 
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html 
     
    3838We're constantly improving NHR Options Table Manager! Here's what's on the way:
    3939- **Bulk Deletion** – Quickly remove multiple options and user meta entries at once.
    40 - **WP Recipe Maker Table Support** – Manage recipe-related data efficiently.
    41 - **Expired Transient Deletion** – Automatically clean up expired transients to free up database space.
    4240- **More Exciting Features** – Stay tuned for additional enhancements!
    4341
     
    8583
    8684== Changelog ==
     85
     86= 1.1.9 - 05/01/2026 =
     87- Added: Bulk delete options feature
    8788
    8889= 1.1.8 - 30/11/2025 =
Note: See TracChangeset for help on using the changeset viewer.