Plugin Directory

Changeset 3416085


Ignore:
Timestamp:
12/10/2025 08:03:29 AM (4 months ago)
Author:
fantasyworld
Message:

update 1.4.8

Location:
ry-toolkit/trunk
Files:
3 added
1 deleted
26 edited

Legend:

Unmodified
Added
Removed
  • ry-toolkit/trunk/admin/admin.php

    r3413778 r3416085  
    1616    public static function instance(): RY_Toolkit_Admin
    1717    {
    18         if (null === self::$_instance) {
     18        if (self::$_instance === null) {
    1919            self::$_instance = new self();
    2020            self::$_instance->do_init();
     
    8181        $asset_info = include RY_TOOLKIT_PLUGIN_DIR . 'assets/admin/options.asset.php';
    8282        wp_register_script('ry-toolkit-options', RY_TOOLKIT_PLUGIN_URL . 'assets/admin/options.js', $asset_info['dependencies'], $asset_info['version'], true);
     83
     84        $asset_info = include RY_TOOLKIT_PLUGIN_DIR . 'assets/admin/tools.asset.php';
     85        wp_register_script('ry-toolkit-tools', RY_TOOLKIT_PLUGIN_URL . 'assets/admin/tools.js', $asset_info['dependencies'], $asset_info['version'], true);
    8386    }
    8487
     
    127130        ], admin_url('admin-post.php'));
    128131
    129         $hidden_value = array_merge($hidden_value, [
    130             'action' => 'ry-toolkit-action',
    131             'ry-toolkit-action' => $action,
    132         ]);
     132        echo '<form method="post" action="' . esc_url($post_url) . '">';
     133        foreach ($hidden_value as $name => $value) {
     134            echo '<input type="hidden" name="' . esc_attr($name) . '" value="' . esc_attr($value) . '" />';
     135        }
     136        $this->the_action_form_button($action, $submit_text);
     137        echo '</form>';
     138    }
    133139
    134         include RY_TOOLKIT_PLUGIN_DIR . 'admin/html/action-form.php';
     140    public function the_action_form_button(string $action, string $submit_text, string $type = 'submit'): void
     141    {
     142        echo '<input type="hidden" name="action" value="ry-toolkit-action" />';
     143        echo '<input type="hidden" name="ry-toolkit-action" value="' . esc_attr($action) . '" />';
     144        wp_nonce_field('ry-toolkit-action');
     145        wp_nonce_field('ry-toolkit-action/' . $action, '_ry_toolkit_nonce', false);
     146        echo '<button type="' . esc_attr($type) . '" name="submit" id="ry-' . esc_attr($action) . '" class="button" value="' . esc_attr($submit_text) . '">' . esc_html($submit_text) . '</button>';
    135147    }
    136148
  • ry-toolkit/trunk/admin/includes/cron-event-list-table.php

    r3293812 r3416085  
    4848        $this->search = sanitize_text_field(wp_unslash($_GET['s'] ?? '')); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    4949        $this->orderby = strtolower(wp_unslash($_GET['orderby'] ?? '')); // phpcs:ignore WordPress.Security.NonceVerification.Recommended , WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    50         $this->order = ('desc' === strtolower(wp_unslash($_GET['order'] ?? ''))) ? 'desc' : 'asc'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended , WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     50        $this->order = (strtolower(wp_unslash($_GET['order'] ?? '')) === 'desc') ? 'desc' : 'asc'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended , WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    5151        $this->view_type = strtolower(wp_unslash($_GET['viewtype'] ?? 'all')); // phpcs:ignore WordPress.Security.NonceVerification.Recommended , WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    5252
     
    6565            foreach ($cron as $hook => $dings) {
    6666                if (!empty($this->search)) {
    67                     if (false === strpos($hook, $this->search)) {
     67                    if (strpos($hook, $this->search) === false) {
    6868                        continue;
    6969                    }
     
    136136                number_format_i18n($count)
    137137            ),
    138             'current' => 'all' === $current_view_type,
     138            'current' => $current_view_type === 'all',
    139139        ];
    140140
    141141        $this->view_type = 'noaction';
    142142        $count = count(array_filter($this->all_events, [$this, 'filter_view_type']));
    143         if (0 < $count) {
     143        if ($count > 0) {
    144144            $url_args['viewtype'] = $this->view_type;
    145145            $links[$this->view_type] = [
     
    157157            $this->view_type = 'schedule_' . $schedule;
    158158            $count = count(array_filter($this->all_events, [$this, 'filter_view_type']));
    159             if (0 < $count) {
     159            if ($count > 0) {
    160160                $url_args['viewtype'] = $this->view_type;
    161161                $links[$this->view_type] = [
     
    183183        $utc_info = '';
    184184        if (!empty($offset)) {
    185             if (0 <= $offset) {
     185            if ($offset >= 0) {
    186186                $utc_info = '+' . (string) $offset;
    187187            } else {
     
    260260
    261261        $diff = $event->time - time();
    262         if (0 < $diff) {
     262        if ($diff > 0) {
    263263            echo '<br>' . esc_html(sprintf(
    264264                /* translators: %s: interval text */
     
    277277        }
    278278
    279         if (0 < $event->interval) {
     279        if ($event->interval > 0) {
    280280            echo '<br>' . esc_html(sprintf(
    281281                /* translators: %s: interval text */
     
    328328    {
    329329        $keep = true;
    330         if ('noaction' === $this->view_type) {
     330        if ($this->view_type === 'noaction') {
    331331            $keep = empty($event->actions);
    332332        } elseif (str_starts_with($this->view_type, 'schedule_')) {
     
    350350    {
    351351        if ($this->orderby === 'hook') {
    352             if ('asc' === $this->order) {
     352            if ($this->order === 'asc') {
    353353                return strcasecmp($a->hook, $b->hook);
    354354            } else {
     
    358358
    359359        if ($this->orderby === 'next') {
    360             if ('asc' === $this->order) {
     360            if ($this->order === 'asc') {
    361361                return $a->time <=> $b->time;
    362362            } else {
     
    443443            foreach ($time_periods as $time_period) {
    444444                $time_show = floor($time_remaining / $time_period['seconds']);
    445                 if (0 < $time_show) {
     445                if ($time_show > 0) {
    446446                    $second_text[$seconds][$period_limit][] = sprintf(
    447447                        translate_nooped_plural($time_period['names'], $time_show, 'ry-toolkit'),
  • ry-toolkit/trunk/admin/includes/post-type-list-table.php

    r3293812 r3416085  
    3535
    3636        $this->orderby = strtolower(wp_unslash($_GET['orderby'] ?? '')); // phpcs:ignore WordPress.Security.NonceVerification.Recommended , WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    37         $this->order = ('desc' === strtolower(wp_unslash($_GET['order'] ?? ''))) ? 'desc' : 'asc'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended , WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     37        $this->order = (strtolower(wp_unslash($_GET['order'] ?? '')) === 'desc') ? 'desc' : 'asc'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended , WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    3838    }
    3939
     
    135135    {
    136136        if (isset($a->{$this->orderby})) {
    137             if ('asc' === $this->order) {
     137            if ($this->order === 'asc') {
    138138                return strcasecmp($a->{$this->orderby}, $b->{$this->orderby});
    139139            } else {
  • ry-toolkit/trunk/admin/options.php

    r3413778 r3416085  
    77    public static function instance(): RY_Toolkit_Admin_Options
    88    {
    9         if (null === self::$_instance) {
     9        if (self::$_instance === null) {
    1010            self::$_instance = new self();
    1111            self::$_instance->do_init();
  • ry-toolkit/trunk/admin/page/cron.php

    r3293812 r3416085  
    116116            ksort($wp_events);
    117117            $set_cron = _set_cron_array($wp_events);
    118             if (true === $set_cron) {
     118            if ($set_cron === true) {
    119119                delete_transient('doing_cron');
    120120
  • ry-toolkit/trunk/admin/page/html/opcache.php

    r3248907 r3416085  
    1515                </td>
    1616            </tr>
    17             <?php if (0 < $opcache_status['opcache_statistics']['last_restart_time']) { ?>
     17            <?php if ($opcache_status['opcache_statistics']['last_restart_time'] > 0) { ?>
    1818            <tr>
    1919                <td><?php esc_html_e('Last restart time', 'ry-toolkit'); ?></td>
  • ry-toolkit/trunk/admin/page/html/tools.php

    r3040510 r3416085  
    66        </th>
    77        <td>
     8
    89            <div class="ry-row">
    910                <div class="ry-col-auto ry-loading">
     
    1415                </div>
    1516            </div>
     17            <?php if (current_user_can('export') && class_exists('ZipArchive')) { ?>
     18            <fieldset class="ry-row">
     19                <div class="ry-col-auto">
     20                    <?php RY_Toolkit()->admin->the_action_form_button('export-db', __('Export database', 'ry-toolkit'), 'button'); ?>
     21                </div>
     22                <div class="ry-col">
     23                    <fieldset>
     24                        <legend class="screen-reader-text"><span><?php esc_html_e('Single row', 'ry-toolkit'); ?></span></legend>
     25                        <input type="checkbox" id="single-row-1" name="single-row" value="1">
     26                        <?php esc_html_e('Insert one row at a time.', 'ry-toolkit'); ?>
     27                        <p class="description"><?php esc_html_e('Inserting data one by one would take a lot of time.', 'ry-toolkit'); ?></p>
     28                    </fieldset>
     29                </div>
     30                <div id="export-progress" class="ry-col-full">
     31                    <div class="ry-progress">
     32                        <div class="ry-progress-bar"></div>
     33                    </div>
     34                </div>
     35            </fieldset>
     36            <?php } ?>
    1637            <div class="ry-row">
    1738                <div class="ry-col-auto ry-loading">
     
    3051                </div>
    3152            </div>
     53            <?php if ($as_counts >= 0) { ?>
     54            <div class="ry-row">
     55                <div class="ry-col-auto ry-loading">
     56                    <?php RY_Toolkit()->admin->the_action_form('tools', 'clear-complete-log', __('Clear Action Scheduler complete log', 'ry-toolkit')); ?>
     57                </div>
     58                <div class="ry-col">
     59                    <p class="description">
     60                        <?php echo esc_html(sprintf(
     61                            /* translators: %: Number of complete log. */
     62                            _n('%s complete log in your database.', '%s complete logs in your database.', $as_counts, 'ry-toolkit'),
     63                            number_format_i18n($as_counts)
     64                        )); ?>
     65                    </p>
     66                </div>
     67            </div>
     68            <?php } ?>
    3269        </td>
    3370    </tr>
  • ry-toolkit/trunk/admin/page/opcache.php

    r3281849 r3416085  
    3131
    3232        $opcache_status = opcache_get_status(false);
    33         if (false === $opcache_status) {
     33        if ($opcache_status === false) {
    3434            echo esc_html__('OPcache disabled.', 'ry-toolkit');
    3535        } else {
     
    5656                if ($opcache_status && isset($opcache_status['scripts'])) {
    5757                    $check_abspath = substr(ABSPATH, 0, -1);
     58                    $start = time();
    5859                    foreach ($opcache_status['scripts'] as $script) {
    5960                        if (str_starts_with($script['full_path'], $check_abspath)) {
    6061                            opcache_invalidate($script['full_path'], true);
     62                        }
     63
     64                        if (time() - $start > 9) {
     65                            return RY_Toolkit()->admin->the_action_link('tools', 'flush-opcache', [
     66                                '_wp_http_referer' => urlencode(sanitize_url(wp_unslash($_REQUEST['_wp_http_referer'] ?? ''))), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     67                            ]);
    6168                        }
    6269                    }
  • ry-toolkit/trunk/admin/page/tools.php

    r3413778 r3416085  
    3939        }
    4040
     41        $as_counts = -1;
     42        if (class_exists('ActionScheduler')) {
     43            $store = ActionScheduler::store();
     44            if ($store instanceof ActionScheduler_DBStore) {
     45                $as_counts = $store->action_counts()['complete'] ?? 0;
     46            }
     47        }
     48
     49        wp_localize_script('ry-toolkit-tools', 'RyToolkitToolsParams', [
     50            'exportUrl' => current_user_can('export') ? RY_Toolkit()->admin->the_action_link('tools', 'export-db') : '',
     51        ]);
     52        wp_enqueue_script('ry-toolkit-tools');
     53
    4154        echo '<div class="wrap"><h1>' . esc_html__('Tools', 'ry-toolkit') . '</h1>';
    4255
     
    6073
    6174        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
    62         $tables = $wpdb->get_col($wpdb->prepare(
    63             'SHOW TABLES LIKE %s',
    64             $wpdb->esc_like($wpdb->prefix) . '%'
    65         ));
    66         foreach ($tables as $table) {
    67             if (isset($analyzed_table[$table])) {
     75        $tables = $wpdb->get_col('SHOW TABLES');
     76        sort($tables);
     77        foreach ($tables as $table_name) {
     78            if (isset($analyzed_table[$table_name])) {
    6879                continue;
    6980            }
    7081
    7182            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching , WordPress.DB.PreparedSQL.InterpolatedNotPrepared , PluginCheck.Security.DirectDB.UnescapedDBParameter
    72             $wpdb->query("ANALYZE TABLE `$table`");
    73             $analyzed_table[$table] = true;
     83            $wpdb->query("ANALYZE TABLE `$table_name`");
     84            $analyzed_table[$table_name] = true;
    7485            set_transient('ry_analyzed_table', $analyzed_table, 600);
    7586
    76             if (1 < time() - $start) {
     87            if (time() - $start > 9) {
    7788                return RY_Toolkit()->admin->the_action_link('tools', 'analyze-tables', [
    7889                    '_wp_http_referer' => urlencode(sanitize_url(wp_unslash($_REQUEST['_wp_http_referer'] ?? ''))), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     
    101112
    102113        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
    103         $tables = $wpdb->get_col($wpdb->prepare(
    104             'SHOW TABLES LIKE %s',
    105             $wpdb->esc_like($wpdb->prefix) . '%'
    106         ));
    107         foreach ($tables as $table) {
    108             if (isset($optimized_table[$table])) {
     114        $tables = $wpdb->get_col('SHOW TABLES');
     115        sort($tables);
     116        foreach ($tables as $table_name) {
     117            if (isset($optimized_table[$table_name])) {
    109118                continue;
    110119            }
    111120
    112121            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching , WordPress.DB.PreparedSQL.InterpolatedNotPrepared , PluginCheck.Security.DirectDB.UnescapedDBParameter
    113             $wpdb->query("OPTIMIZE TABLE `$table`");
    114             $optimized_table[$table] = true;
     122            $wpdb->query("OPTIMIZE TABLE `$table_name`");
     123            $optimized_table[$table_name] = true;
    115124            set_transient('ry_optimized_table', $optimized_table, 600);
    116125
    117             if (1 < time() - $start) {
     126            if (time() - $start > 9) {
    118127                return RY_Toolkit()->admin->the_action_link('tools', 'optimize-tables', [
    119128                    '_wp_http_referer' => urlencode(sanitize_url(wp_unslash($_REQUEST['_wp_http_referer'] ?? ''))), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     
    124133        delete_transient('ry_optimized_table');
    125134        RY_Toolkit()->admin->add_notice('success', __('Database tables optimized successfully.', 'ry-toolkit'));
     135
     136        return '';
     137    }
     138
     139    protected function export_db()
     140    {
     141        global $wpdb;
     142
     143        if (wp_doing_ajax()) {
     144            wp_die(-1, 403);
     145        }
     146        if (!current_user_can('export')) {
     147            wp_die(-1, 403);
     148        }
     149        if (!class_exists('ZipArchive')) {
     150            wp_die(-1, 403);
     151        }
     152
     153        check_ajax_referer('ry-toolkit-action/export-db', '_ry_toolkit_nonce');
     154
     155        $start = time();
     156
     157        $export_data = get_transient('ry_export_data');
     158        if (!is_array($export_data)) {
     159            $export_data = [];
     160
     161            $export_data['single_row'] = isset($_POST['single-row']);
     162
     163            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
     164            $export_data['table'] = $wpdb->get_col('SHOW TABLES');
     165            sort($export_data['table']);
     166            $export_data['table'] = array_fill_keys($export_data['table'], false);
     167
     168            $export_data['exported'] = 0;
     169            $export_data['total'] = 0;
     170            foreach ($export_data['table'] as $table_name => $status) {
     171                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
     172                $export_data['total'] += $wpdb->get_var("SELECT COUNT(*) FROM `{$table_name}`");
     173            }
     174            $export_data['file'] = wp_tempnam('ry-toolkit-download');
     175
     176            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
     177            $db_version = $wpdb->get_var('SELECT VERSION()');
     178            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
     179            $current_db = $wpdb->get_var('SELECT DATABASE()');
     180            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
     181            $db_charset = $wpdb->get_var('SELECT @@character_set_database');
     182            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
     183            $db_collation = $wpdb->get_var('SELECT @@collation_database');
     184
     185            $buffer = "-- ----------------------------------------\n";
     186            $buffer .= "-- WordPress database export\n";
     187            $buffer .= '-- Date: ' . date('Y-m-d H:i:s') . "\n";
     188            $buffer .= "-- Server: {$db_version}\n";
     189            $buffer .= "-- Database: {$current_db}\n";
     190            $buffer .= "-- Character Set: {$db_charset}\n";
     191            $buffer .= "-- Collation: {$db_collation}\n";
     192            $buffer .= "-- ----------------------------------------\n\n";
     193            $buffer .= "/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;\n";
     194            $buffer .= "/*!40101 SET NAMES utf8mb4 */;\n";
     195            $buffer .= "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n";
     196            $buffer .= "/*!40103 SET TIME_ZONE='+00:00' */;\n";
     197            $buffer .= "/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n";
     198            $buffer .= "/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n";
     199            $buffer .= "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n";
     200            $buffer .= "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n";
     201            file_put_contents($export_data['file'], $buffer);
     202        }
     203
     204        $batch_row_size = 5000;
     205        $batch_sql_size = $export_data['single_row'] ? 1 : 16 * KB_IN_BYTES;
     206        foreach ($export_data['table'] as $table_name => $status) {
     207            if ($status === true) {
     208                continue;
     209            }
     210
     211            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
     212            $table_rows = (int) $wpdb->get_var("SELECT COUNT(*) FROM `{$table_name}`");
     213
     214            if ($export_data['table'][$table_name] === false) {
     215                $export_data['table'][$table_name] = 0;
     216
     217                // 寫入資料表分隔符
     218                $buffer = "\n";
     219                $buffer .= "-- ----------------------------------------\n";
     220                $buffer .= "-- Schema for `{$table_name}` \n";
     221                $buffer .= "-- ----------------------------------------\n\n";
     222
     223                // 取得建立資料表的語法
     224                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
     225                $create_table = $wpdb->get_var("SHOW CREATE TABLE `{$table_name}`", 1, 0);
     226                if ($create_table) {
     227                    $buffer .= "DROP TABLE IF EXISTS `{$table_name}`;\n";
     228                    $buffer .= $create_table . ";\n\n";
     229                }
     230
     231                if ($table_rows === 0) {
     232                    $buffer .= "-- ----------------------------------------\n";
     233                    $buffer .= "-- Data for `{$table_name}` is empty \n";
     234                    $buffer .= "-- ----------------------------------------\n\n";
     235                } else {
     236                    $buffer .= "-- ----------------------------------------\n";
     237                    $buffer .= "-- Data for `{$table_name}` \n";
     238                    $buffer .= "-- ----------------------------------------\n\n";
     239                    $buffer .= "LOCK TABLES `{$table_name}` WRITE;\n";
     240                    $buffer .= "/*!40000 ALTER TABLE `{$table_name}` DISABLE KEYS */;\n";
     241                }
     242                file_put_contents($export_data['file'], $buffer, FILE_APPEND);
     243            }
     244
     245            if ($table_rows > 0) {
     246                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
     247                $columns = $wpdb->get_results("SHOW COLUMNS FROM `{$table_name}`");
     248                $column_types = [];
     249                foreach ($columns as $column) {
     250                    $type_parts = explode('(', $column->Type);
     251                    $column_types[$column->Field] = strtoupper($type_parts[0]);
     252                }
     253
     254                while (true) {
     255                    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
     256                    $rows = $wpdb->get_results($wpdb->prepare(
     257                        "SELECT * FROM `{$table_name}` LIMIT %d, %d",
     258                        $export_data['table'][$table_name],
     259                        $batch_row_size
     260                    ), ARRAY_A);
     261
     262                    if (empty($rows)) {
     263                        break;
     264                    }
     265
     266                    $buffer = '';
     267                    $insert_sql = 'INSERT INTO `' . $table_name . '` VALUES ';
     268                    foreach ($rows as $row) {
     269                        $values = [];
     270                        foreach ($row as $column_name => $value) {
     271                            if (is_null($value)) {
     272                                $values[] = 'NULL';
     273                            } elseif ($value === '') {
     274                                $values[] = "''";
     275                            } else {
     276                                switch (strtoupper($column_types[$column_name])) {
     277                                    case 'TINYINT':
     278                                    case 'SMALLINT':
     279                                    case 'MEDIUMINT':
     280                                    case 'INT':
     281                                    case 'INTEGER':
     282                                    case 'BIGINT':
     283                                    case 'FLOAT':
     284                                    case 'DOUBLE':
     285                                    case 'DECIMAL':
     286                                    case 'NUMERIC':
     287                                        $values[] = (string) $value;
     288                                        break;
     289                                    case 'BIT':
     290                                        $values[] = "b'" . decbin($value) . "'";
     291                                        break;
     292                                    case 'TINYBLOB':
     293                                    case 'BLOB':
     294                                    case 'MEDIUMBLOB':
     295                                    case 'LONGBLOB':
     296                                    case 'BINARY':
     297                                    case 'VARBINARY':
     298                                    case 'POINT':
     299                                    case 'LINESTRING':
     300                                    case 'POLYGON':
     301                                    case 'GEOMETRY':
     302                                    case 'MULTIPOINT':
     303                                    case 'MULTILINESTRING':
     304                                    case 'MULTIPOLYGON':
     305                                    case 'GEOMETRYCOLLECTION':
     306                                        $values[] = '_binary 0x' . bin2hex($value);
     307                                        break;
     308                                    default:
     309                                        $values[] = "'" . $wpdb->_real_escape($value) . "'";
     310                                        break;
     311                                }
     312                            }
     313                        }
     314                        $insert_sql .= '(' . implode(',', $values) . ')';
     315
     316                        if (strlen($insert_sql) < $batch_sql_size) {
     317                            $insert_sql .= ",\n ";
     318                            continue;
     319                        }
     320                        $buffer .= $insert_sql . ";\n";
     321                        $insert_sql = 'INSERT INTO `' . $table_name . '` VALUES ';
     322                    }
     323                    if ($insert_sql !== 'INSERT INTO `' . $table_name . '` VALUES ') {
     324                        if (str_ends_with($insert_sql, ' ')) {
     325                            $insert_sql = substr($insert_sql, 0, -3);
     326                        }
     327                        $buffer .= $insert_sql . ";\n";
     328                    }
     329
     330                    $export_data['exported'] += count($rows);
     331                    $export_data['table'][$table_name] += count($rows);
     332                    file_put_contents($export_data['file'], $buffer, FILE_APPEND);
     333
     334                    if (time() - $start >= 1) {
     335                        set_transient('ry_export_data', $export_data, 600);
     336                        wp_send_json_success([
     337                            'continue' => true,
     338                            'progress' => round($export_data['exported'] / $export_data['total'] * 100, 2),
     339                            'url' => RY_Toolkit()->admin->the_action_link('tools', 'export-db'),
     340                        ]);
     341                    }
     342                }
     343
     344                $buffer = "/*!40000 ALTER TABLE `{$table_name}` ENABLE KEYS */;\n";
     345                $buffer .= "UNLOCK TABLES;\n";
     346                file_put_contents($export_data['file'], $buffer, FILE_APPEND);
     347            }
     348
     349            $export_data['table'][$table_name] = true;
     350
     351            if (time() - $start >= 1) {
     352                set_transient('ry_export_data', $export_data, 600);
     353                wp_send_json_success([
     354                    'continue' => true,
     355                    'progress' => round($export_data['exported'] / $export_data['total'] * 100, 2),
     356                    'url' => RY_Toolkit()->admin->the_action_link('tools', 'export-db'),
     357                ]);
     358            }
     359        }
     360
     361        $buffer = "/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;\n";
     362        $buffer .= "/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;\n";
     363        $buffer .= "/*!40014 SET UNIQUE_CHECKS=IFNULL(@OLD_UNIQUE_CHECKS, 1) */;\n";
     364        $buffer .= "/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;\n";
     365        $buffer .= "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n";
     366        $buffer .= "/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;\n\n";
     367
     368        file_put_contents($export_data['file'], $buffer, FILE_APPEND);
     369
     370        wp_send_json_success([
     371            'continue' => false,
     372            'url' => RY_Toolkit()->admin->the_action_link('tools', 'export-db-zip'),
     373        ]);
     374    }
     375
     376    protected function export_db_zip()
     377    {
     378        if (current_user_can('export') && class_exists('ZipArchive')) {
     379            $export_data = get_transient('ry_export_data');
     380            if (is_array($export_data) && isset($export_data['file'])) {
     381                $tmp_zip_file = $export_data['file'] . '-zip';
     382                $zip = new ZipArchive();
     383                if ($zip->open($tmp_zip_file, ZipArchive::CREATE) === true) {
     384                    $zip->addFile($export_data['file'], 'export-db.sql');
     385                    $zip->close();
     386
     387                    delete_transient('ry_export_data');
     388
     389                    ob_end_clean();
     390                    readfile($tmp_zip_file);
     391                    wp_delete_file($export_data['file']);
     392                    wp_delete_file($tmp_zip_file);
     393                    exit;
     394                }
     395            }
     396        }
    126397
    127398        return '';
     
    142413            if ($transients) {
    143414                foreach ($transients as $transient) {
    144                     if ('_transient_' === $transient_key) {
     415                    if ($transient_key === '_transient_') {
    145416                        delete_transient(str_replace('_transient_', '', $transient));
    146417                    } else {
     
    154425        return '';
    155426    }
     427
     428    protected function clear_complete_log(): string
     429    {
     430        global $wpdb;
     431
     432        check_ajax_referer('ry-toolkit-action/clear-complete-log', '_ry_toolkit_nonce');
     433
     434        $wpdb->query("DELETE FROM {$wpdb->actionscheduler_actions} WHERE `status`='complete'");
     435        $wpdb->query("DELETE FROM {$wpdb->actionscheduler_logs} WHERE action_id NOT IN (SELECT action_id FROM {$wpdb->actionscheduler_actions})");
     436
     437        RY_Toolkit()->admin->add_notice('success', __('Clear complete log successfully.', 'ry-toolkit'));
     438
     439        return '';
     440    }
    156441}
    157442
  • ry-toolkit/trunk/admin/plugins.php

    r3293812 r3416085  
    7474        wp_delete_file($tmp_zip_file);
    7575        $zip = new ZipArchive();
    76         if (true === $zip->open($tmp_zip_file, ZipArchive::CREATE)) {
     76        if ($zip->open($tmp_zip_file, ZipArchive::CREATE) === true) {
    7777            if (strpos($plugin_file, '/') && $real_plugin_dir !== $plugins_dir) {
    7878                $plugin_name = pathinfo($real_plugin_dir, PATHINFO_BASENAME);
     
    8484            $zip->close();
    8585
    86             if (is_file($tmp_zip_file) && 0 < filesize($tmp_zip_file)) {
     86            if (is_file($tmp_zip_file) && filesize($tmp_zip_file) > 0) {
    8787                $file_name = $plugin_name . '.' . $plugin_data['Version'] . '.zip';
    8888                $file_name = strtolower($file_name);
    8989                $file_name = preg_replace('/[^a-z0-9_\-\.]/', '', $file_name);
    9090
     91                ob_end_clean();
    9192                header('Content-Description: File Transfer');
    9293                header('Content-Type: application/zip');
     
    9596                readfile($tmp_zip_file); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile
    9697                wp_delete_file($tmp_zip_file);
    97                 exit();
     98                exit;
    9899            } else {
    99100                wp_die(esc_html__('Unable to generate zip file.', 'ry-toolkit'));
  • ry-toolkit/trunk/admin/post.php

    r3413778 r3416085  
    77    public static function instance(): RY_Toolkit_Admin_Post
    88    {
    9         if (null === self::$_instance) {
     9        if (self::$_instance === null) {
    1010            self::$_instance = new self();
    1111            self::$_instance->do_init();
  • ry-toolkit/trunk/admin/site-health.php

    r3293812 r3416085  
    77    public static function instance(): RY_Toolkit_Admin_Site_Health
    88    {
    9         if (null === self::$_instance) {
     9        if (self::$_instance === null) {
    1010            self::$_instance = new self();
    1111            self::$_instance->do_init();
  • ry-toolkit/trunk/assets/admin/main-rtl.css

    r3413778 r3416085  
    1 .ry-tooltable td,.ry-tooltable th{padding:1.2rem}.ry-tooltable p.description{margin-bottom:0}.ry-row>*{margin-bottom:1rem}.ry-toolkit-options td fieldset label{display:block}.ry-row-posttypeinfo th{vertical-align:top}.ry-row-posttypeinfo td p:last-of-type{margin-bottom:0}.ry-row-posttypeinfo .info-table{width:100%}.ry-row-posttypeinfo .info-table td,.ry-row-posttypeinfo .info-table th{color:#1d2327;padding:8px 10px}.ry-row-posttypeinfo .info-table>tbody>tr>th{font-weight:600;padding-right:0;text-align:right}.fixed .column-ry-thumbnail{width:60px}@media screen and (min-width:782px){.ry-row{display:flex;flex-wrap:wrap;margin-right:-1rem;margin-left:-1rem}.ry-row,.ry-row>*{box-sizing:border-box}.ry-row>*{max-width:100%;padding-right:1rem;padding-left:1rem;width:100%}.ry-col{flex:1 0 0%}.ry-col-auto{flex:0 0 auto;width:auto}.ry-row-opcache .ry-col{flex:0 0 auto;width:50%}.ry-row-posttypeinfo .ry-col:nth-of-type(2){flex:0 0 auto;width:45%}.ry-tooltable .ry-row:last-of-type>*{margin-bottom:0}}@media screen and (min-width:1400px){.health-check-body{max-width:1000px}}@media screen and (min-width:1600px){.ry-row-opcache .ry-col{flex:0 0 auto;width:25%}}
     1.ry-tooltable td,.ry-tooltable th{padding:1.2rem}.ry-tooltable p.description{margin-bottom:0}.ry-progress{background-color:#e0e0e0;border-radius:3px;height:1rem;overflow:hidden;width:100%}.ry-progress .ry-progress-bar{background-color:#72aee6;height:100%}.ry-row>*{margin-bottom:1rem}#export-progress{display:none}.ry-toolkit-options td fieldset label{display:block}.ry-row-posttypeinfo th{vertical-align:top}.ry-row-posttypeinfo td p:last-of-type{margin-bottom:0}.ry-row-posttypeinfo .info-table{width:100%}.ry-row-posttypeinfo .info-table td,.ry-row-posttypeinfo .info-table th{color:#1d2327;padding:8px 10px}.ry-row-posttypeinfo .info-table>tbody>tr>th{font-weight:600;padding-right:0;text-align:right}.fixed .column-ry-thumbnail{width:60px}@media screen and (min-width:782px){.ry-row{display:flex;flex-wrap:wrap;margin-right:-1rem;margin-left:-1rem}.ry-row,.ry-row>*{box-sizing:border-box}.ry-row>*{max-width:100%;padding-right:1rem;padding-left:1rem;width:100%}.ry-col{flex:1 0 0%}.ry-col-auto{flex:0 0 auto;width:auto}.ry-col-full{flex:0 0 auto;width:100%}.ry-row-opcache .ry-col{flex:0 0 auto;width:50%}.ry-row-posttypeinfo .ry-col:nth-of-type(2){flex:0 0 auto;width:45%}.ry-tooltable .ry-row:last-child>*{margin-bottom:0}}@media screen and (min-width:1400px){.health-check-body{max-width:1000px}}@media screen and (min-width:1600px){.ry-row-opcache .ry-col{flex:0 0 auto;width:25%}}
  • ry-toolkit/trunk/assets/admin/main.asset.php

    r3413778 r3416085  
    1 <?php return array('dependencies' => array(), 'version' => '88d6a7b191d23fae1ec4');
     1<?php return array('dependencies' => array(), 'version' => '550f85842b8f4088d5bf');
  • ry-toolkit/trunk/assets/admin/main.css

    r3413778 r3416085  
    1 .ry-tooltable td,.ry-tooltable th{padding:1.2rem}.ry-tooltable p.description{margin-bottom:0}.ry-row>*{margin-bottom:1rem}.ry-toolkit-options td fieldset label{display:block}.ry-row-posttypeinfo th{vertical-align:top}.ry-row-posttypeinfo td p:last-of-type{margin-bottom:0}.ry-row-posttypeinfo .info-table{width:100%}.ry-row-posttypeinfo .info-table td,.ry-row-posttypeinfo .info-table th{color:#1d2327;padding:8px 10px}.ry-row-posttypeinfo .info-table>tbody>tr>th{font-weight:600;padding-left:0;text-align:left}.fixed .column-ry-thumbnail{width:60px}@media screen and (min-width:782px){.ry-row{display:flex;flex-wrap:wrap;margin-left:-1rem;margin-right:-1rem}.ry-row,.ry-row>*{box-sizing:border-box}.ry-row>*{max-width:100%;padding-left:1rem;padding-right:1rem;width:100%}.ry-col{flex:1 0 0%}.ry-col-auto{flex:0 0 auto;width:auto}.ry-row-opcache .ry-col{flex:0 0 auto;width:50%}.ry-row-posttypeinfo .ry-col:nth-of-type(2){flex:0 0 auto;width:45%}.ry-tooltable .ry-row:last-of-type>*{margin-bottom:0}}@media screen and (min-width:1400px){.health-check-body{max-width:1000px}}@media screen and (min-width:1600px){.ry-row-opcache .ry-col{flex:0 0 auto;width:25%}}
     1.ry-tooltable td,.ry-tooltable th{padding:1.2rem}.ry-tooltable p.description{margin-bottom:0}.ry-progress{background-color:#e0e0e0;border-radius:3px;height:1rem;overflow:hidden;width:100%}.ry-progress .ry-progress-bar{background-color:#72aee6;height:100%}.ry-row>*{margin-bottom:1rem}#export-progress{display:none}.ry-toolkit-options td fieldset label{display:block}.ry-row-posttypeinfo th{vertical-align:top}.ry-row-posttypeinfo td p:last-of-type{margin-bottom:0}.ry-row-posttypeinfo .info-table{width:100%}.ry-row-posttypeinfo .info-table td,.ry-row-posttypeinfo .info-table th{color:#1d2327;padding:8px 10px}.ry-row-posttypeinfo .info-table>tbody>tr>th{font-weight:600;padding-left:0;text-align:left}.fixed .column-ry-thumbnail{width:60px}@media screen and (min-width:782px){.ry-row{display:flex;flex-wrap:wrap;margin-left:-1rem;margin-right:-1rem}.ry-row,.ry-row>*{box-sizing:border-box}.ry-row>*{max-width:100%;padding-left:1rem;padding-right:1rem;width:100%}.ry-col{flex:1 0 0%}.ry-col-auto{flex:0 0 auto;width:auto}.ry-col-full{flex:0 0 auto;width:100%}.ry-row-opcache .ry-col{flex:0 0 auto;width:50%}.ry-row-posttypeinfo .ry-col:nth-of-type(2){flex:0 0 auto;width:45%}.ry-tooltable .ry-row:last-child>*{margin-bottom:0}}@media screen and (min-width:1400px){.health-check-body{max-width:1000px}}@media screen and (min-width:1600px){.ry-row-opcache .ry-col{flex:0 0 auto;width:25%}}
  • ry-toolkit/trunk/includes/cron.php

    r3293812 r3416085  
    77    public static function instance(): RY_Toolkit_Cron
    88    {
    9         if (null === self::$_instance) {
     9        if (self::$_instance === null) {
    1010            self::$_instance = new self();
    1111            self::$_instance->do_init();
     
    2222    public function limit_ready_cron_jobs($crons)
    2323    {
    24         if (null === $crons) {
     24        if ($crons === null) {
    2525            $limit_time = intval($_GET['ry-toolkit-limit-event'] ?? ''); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    26             if (0 < $limit_time) {
     26            if ($limit_time > 0) {
    2727                $wp_events = _get_cron_array();
    2828
  • ry-toolkit/trunk/includes/frontend.php

    r3015689 r3416085  
    77    public static function instance(): RY_Toolkit_Frontend
    88    {
    9         if (null === self::$_instance) {
     9        if (self::$_instance === null) {
    1010            self::$_instance = new self();
    1111            self::$_instance->do_init();
  • ry-toolkit/trunk/includes/main.php

    r3413778 r3416085  
    1818    public static function instance(): RY_Toolkit
    1919    {
    20         if (null === self::$_instance) {
     20        if (self::$_instance === null) {
    2121            self::$_instance = new self();
    2222            self::$_instance->do_init();
  • ry-toolkit/trunk/includes/plugin-wp-rocket.php

    r3151703 r3416085  
    77    public static function instance(): RY_Toolkit_Plugin_Wp_Rocket
    88    {
    9         if (null === self::$_instance) {
     9        if (self::$_instance === null) {
    1010            self::$_instance = new self();
    1111            self::$_instance->do_init();
  • ry-toolkit/trunk/includes/sitemaps.php

    r3293812 r3416085  
    77    public static function instance(): RY_Toolkit_Sitemaps
    88    {
    9         if (null === self::$_instance) {
     9        if (self::$_instance === null) {
    1010            self::$_instance = new self();
    1111            self::$_instance->do_init();
     
    4848    {
    4949        $urls = (int) RY_Toolkit::get_option('sitemap_urls_pre_file', $max_urls);
    50         if (0 < $urls) {
     50        if ($urls > 0) {
    5151            return $urls;
    5252        }
     
    7777    public function exclude_post($args, $post_type)
    7878    {
    79         if ('page' === $post_type) {
     79        if ($post_type === 'page') {
    8080            $sitemap_skip_page = RY_Toolkit::get_option('sitemap_skip_page', []);
    8181            if (class_exists('WooCommerce', false)) {
  • ry-toolkit/trunk/includes/update.php

    r3413778 r3416085  
    4141            RY_Toolkit::update_option('version', '1.4.7', true);
    4242        }
     43
     44        if (version_compare($now_version, '1.4.8', '<')) {
     45            RY_Toolkit::update_option('version', '1.4.8', true);
     46        }
    4347    }
    4448}
  • ry-toolkit/trunk/includes/upload.php

    r3151703 r3416085  
    77    public static function instance(): RY_Toolkit_Upload
    88    {
    9         if (null === self::$_instance) {
     9        if (self::$_instance === null) {
    1010            self::$_instance = new self();
    1111            self::$_instance->do_init();
     
    5656    {
    5757        $parts = explode('.', $file_name);
    58         if (1 === count($parts)) {
     58        if (count($parts) === 1) {
    5959            $extension = '';
    6060        } else {
  • ry-toolkit/trunk/includes/xmlrpc.php

    r2990386 r3416085  
    77    public static function instance(): RY_Toolkit_Xmlrpc
    88    {
    9         if (null === self::$_instance) {
     9        if (self::$_instance === null) {
    1010            self::$_instance = new self();
    1111            self::$_instance->do_init();
  • ry-toolkit/trunk/languages/ry-toolkit.pot

    r3413778 r3416085  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: RY Toolkit 1.4.7\n"
     5"Project-Id-Version: RY Toolkit 1.4.8\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/ry-toolkit\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2025-12-08T10:34:14+08:00\n"
     12"POT-Creation-Date: 2025-12-10T15:54:45+08:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.12.0\n"
     
    4040msgstr ""
    4141
    42 #: admin/admin.php:101
     42#: admin/admin.php:104
    4343msgid "RY Tool"
    4444msgstr ""
     
    464464
    465465#: admin/page/html/opcache.php:165
    466 #: admin/page/html/tools.php:36
     466#: admin/page/html/tools.php:73
    467467msgid "PHP OPcache"
    468468msgstr ""
    469469
    470470#: admin/page/html/opcache.php:171
    471 #: admin/page/html/tools.php:42
     471#: admin/page/html/tools.php:79
    472472msgid "Flush PHP OPcache"
    473473msgstr ""
    474474
    475475#: admin/page/html/opcache.php:175
    476 #: admin/page/html/tools.php:46
     476#: admin/page/html/tools.php:83
    477477msgid "Set all cached files under the WordPress root directory to be invalid."
    478478msgstr ""
    479479
    480480#: admin/page/html/opcache.php:181
    481 #: admin/page/html/tools.php:52
     481#: admin/page/html/tools.php:89
    482482msgid "Restart PHP OPcache"
    483483msgstr ""
     
    11081108msgstr ""
    11091109
    1110 #: admin/page/html/tools.php:10
     1110#: admin/page/html/tools.php:11
    11111111msgid "Analyze tables"
    11121112msgstr ""
    11131113
    1114 #: admin/page/html/tools.php:13
     1114#: admin/page/html/tools.php:14
    11151115msgid "Optimize tables"
    11161116msgstr ""
    11171117
    1118 #: admin/page/html/tools.php:18
     1118#: admin/page/html/tools.php:20
     1119msgid "Export database"
     1120msgstr ""
     1121
     1122#: admin/page/html/tools.php:24
     1123msgid "Single row"
     1124msgstr ""
     1125
     1126#: admin/page/html/tools.php:26
     1127msgid "Insert one row at a time."
     1128msgstr ""
     1129
     1130#: admin/page/html/tools.php:27
     1131msgid "Inserting data one by one would take a lot of time."
     1132msgstr ""
     1133
     1134#: admin/page/html/tools.php:39
    11191135msgid "Clear transient option"
    11201136msgstr ""
    11211137
    1122 #: admin/page/html/tools.php:22
     1138#: admin/page/html/tools.php:43
    11231139msgid "Transient option are safe to remove. They will be automatically regenerated when require it."
    11241140msgstr ""
    11251141
    11261142#. translators: %: Number of transient option.
    1127 #: admin/page/html/tools.php:26
     1143#: admin/page/html/tools.php:47
    11281144#, php-format
    11291145msgid "%s transient in your database."
     
    11321148msgstr[1] ""
    11331149
     1150#: admin/page/html/tools.php:56
     1151msgid "Clear Action Scheduler complete log"
     1152msgstr ""
     1153
     1154#. translators: %: Number of complete log.
     1155#: admin/page/html/tools.php:62
     1156#, php-format
     1157msgid "%s complete log in your database."
     1158msgid_plural "%s complete logs in your database."
     1159msgstr[0] ""
     1160msgstr[1] ""
     1161
    11341162#: admin/page/opcache.php:18
    11351163#: admin/page/opcache.php:30
     
    11411169msgstr ""
    11421170
    1143 #: admin/page/opcache.php:63
     1171#: admin/page/opcache.php:70
    11441172msgid "OPcache flushed successfully."
    11451173msgstr ""
    11461174
    1147 #: admin/page/opcache.php:66
    1148 #: admin/page/opcache.php:69
     1175#: admin/page/opcache.php:73
     1176#: admin/page/opcache.php:76
    11491177msgid "OPcache flush failed."
    11501178msgstr ""
    11511179
    1152 #: admin/page/opcache.php:80
     1180#: admin/page/opcache.php:87
    11531181msgid "OPcache restarted successfully."
    11541182msgstr ""
    11551183
    1156 #: admin/page/opcache.php:82
     1184#: admin/page/opcache.php:89
    11571185msgid "OPcache restart failed."
    11581186msgstr ""
     
    12561284
    12571285#: admin/page/tools.php:18
    1258 #: admin/page/tools.php:41
     1286#: admin/page/tools.php:54
    12591287msgid "Tools"
    12601288msgstr ""
    12611289
    1262 #: admin/page/tools.php:84
     1290#: admin/page/tools.php:95
    12631291msgid "Database tables analyzed successfully."
    12641292msgstr ""
    12651293
    1266 #: admin/page/tools.php:125
     1294#: admin/page/tools.php:134
    12671295msgid "Database tables optimized successfully."
    12681296msgstr ""
    12691297
    1270 #: admin/page/tools.php:152
     1298#: admin/page/tools.php:420
    12711299msgid "Clear transient option successfully."
     1300msgstr ""
     1301
     1302#: admin/page/tools.php:434
     1303msgid "Clear complete log successfully."
    12721304msgstr ""
    12731305
     
    12951327msgstr ""
    12961328
    1297 #: admin/plugins.php:99
     1329#: admin/plugins.php:100
    12981330msgid "Unable to generate zip file."
    12991331msgstr ""
    13001332
    1301 #: admin/plugins.php:102
     1333#: admin/plugins.php:103
    13021334msgid "Unable to open zip file for writing."
    13031335msgstr ""
  • ry-toolkit/trunk/readme.txt

    r3413780 r3416085  
    66Requires PHP: 7.4
    77Tested up to: 6.8
    8 Stable tag: 1.4.7
     8Stable tag: 1.4.8
    99License: GPLv3
    1010License URI: https://www.gnu.org/licenses/gpl-3.0.txt
     
    6363
    6464== Changelog ==
     65
     66= 1.4.8 - 2025/12/10 =
     67* Add database export tool.
    6568
    6669= 1.4.7 - 2025/12/08 =
  • ry-toolkit/trunk/ry-toolkit.php

    r3413778 r3416085  
    55 * Plugin URI: https://ry-plugin.com/ry-toolkit
    66 * Description: Useful tools for more control over you website
    7  * Version: 1.4.7
     7 * Version: 1.4.8
    88 * Requires at least: 6.0
    99 * Requires PHP: 7.4
     
    1515function_exists('plugin_dir_url') or exit('No direct script access allowed');
    1616
    17 define('RY_TOOLKIT_VERSION', '1.4.7');
     17define('RY_TOOLKIT_VERSION', '1.4.8');
    1818define('RY_TOOLKIT_PLUGIN_URL', plugin_dir_url(__FILE__));
    1919define('RY_TOOLKIT_PLUGIN_DIR', plugin_dir_path(__FILE__));
Note: See TracChangeset for help on using the changeset viewer.