Plugin Directory

Changeset 3798362


Ignore:
Timestamp:
11/12/2026 01:05:22 PM (39 hours ago)
Author:
winningsolutions
Message:

1.3.2: fix WPCS mistakes and add faster clearing logic

Location:
ws-action-scheduler-cleaner/trunk
Files:
9 added
23 edited

Legend:

Unmodified
Added
Removed
  • ws-action-scheduler-cleaner/trunk/.distignore

    r3544086 r3798362  
    22wsacsc-populate-test-data.php
    33.distignore
     4phpcs.xml.dist
  • ws-action-scheduler-cleaner/trunk/assets/js/ws-as-cleaner.js

    r3559324 r3798362  
    55    const scheduleFieldSelector = '#actions-schedule-interval, #actions-schedule-time, #actions-retention, #logs-schedule-interval, #logs-schedule-time, #logs-retention';
    66    const destructiveButtonSelector = '#clear-actions, #clear-logs, #optimize-actions, #optimize-logs';
    7     const POLL_INTERVAL_MS = 650;
     7    const POLL_INTERVAL_MS = 250;
    88    const POLL_RETRY_MAX_MS = 8000;
    99
  • ws-action-scheduler-cleaner/trunk/includes/class-activation.php

    r3750500 r3798362  
    3636
    3737                if ( in_array( 'scheduled_date_gmt', $columns ) && in_array( 'status', $columns ) ) {
    38                         $wpdb->query(
    39                                 $wpdb->prepare(
    40                                         'CREATE INDEX IF NOT EXISTS as_status_scheduled ON %i (status, scheduled_date_gmt)',
    41                                         $actions_table
    42                                 )
    43                         );
     38                        WSACSC_Database::create_index_if_missing( $actions_table, 'as_status_scheduled', array( 'status', 'scheduled_date_gmt' ) );
    4439                }
    4540
    4641                if ( in_array( 'completed_date_gmt', $columns ) && in_array( 'status', $columns ) ) {
    47                         $wpdb->query(
    48                                 $wpdb->prepare(
    49                                         'CREATE INDEX IF NOT EXISTS as_status_completed ON %i (status, completed_date_gmt)',
    50                                         $actions_table
    51                                 )
    52                         );
     42                        WSACSC_Database::create_index_if_missing( $actions_table, 'as_status_completed', array( 'status', 'completed_date_gmt' ) );
    5343                }
    5444
    … …  
    7666                $actions_table = $wpdb->prefix . 'actionscheduler_actions';
    7767                if ( WSACSC_Database::check_tables_exist() ) {
    78                         // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
    79                         $wpdb->query( "DROP INDEX IF EXISTS as_status_scheduled ON `{$actions_table}`" );
    80                         // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
    81                         $wpdb->query( "DROP INDEX IF EXISTS as_status_completed ON `{$actions_table}`" );
     68                        WSACSC_Database::drop_index_if_exists( $actions_table, 'as_status_scheduled' );
     69                        WSACSC_Database::drop_index_if_exists( $actions_table, 'as_status_completed' );
    8270                }
    8371
  • ws-action-scheduler-cleaner/trunk/includes/class-database.php

    r3559324 r3798362  
    4747
    4848                return $result;
     49        }
     50
     51        /**
     52         * Check whether an index exists on a table.
     53         *
     54         * Uses SHOW INDEX because MySQL does not support IF [NOT] EXISTS on CREATE INDEX or DROP INDEX.
     55         * Only MariaDB supports that syntax.
     56         *
     57         * @param string $table      Full table name, including the prefix.
     58         * @param string $index_name Index name.
     59         * @return bool True if the index exists. False if it does not exist or the query fails.
     60         */
     61        public static function index_exists( string $table, string $index_name ): bool {
     62                global $wpdb;
     63
     64                $query  = $wpdb->prepare( 'SHOW INDEX FROM %i WHERE Key_name = %s', $table, $index_name );
     65                $result = $wpdb->get_results( $query );
     66
     67                return ! empty( $result );
     68        }
     69
     70        /**
     71         * Create an index if it does not exist yet.
     72         *
     73         * Works on MySQL and MariaDB. A concurrent request can create the same index between
     74         * the check and the CREATE INDEX statement. In that case the query fails and returns false.
     75         *
     76         * @param string   $table      Full table name, including the prefix.
     77         * @param string   $index_name Index name.
     78         * @param string[] $columns    Column names in index order.
     79         * @return bool True if the index exists after the call.
     80         */
     81        public static function create_index_if_missing( string $table, string $index_name, array $columns ): bool {
     82                global $wpdb;
     83
     84                if ( empty( $columns ) ) {
     85                        return false;
     86                }
     87
     88                if ( self::index_exists( $table, $index_name ) ) {
     89                        return true;
     90                }
     91
     92                $column_placeholders = implode( ', ', array_fill( 0, count( $columns ), '%i' ) );
     93                // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Only %i placeholders are interpolated.
     94                $query = $wpdb->prepare( "CREATE INDEX %i ON %i ({$column_placeholders})", $index_name, $table, ...array_values( $columns ) );
     95
     96                return false !== $wpdb->query( $query );
     97        }
     98
     99        /**
     100         * Drop an index if it exists.
     101         *
     102         * Works on MySQL and MariaDB.
     103         *
     104         * @param string $table      Full table name, including the prefix.
     105         * @param string $index_name Index name.
     106         * @return bool True if the index does not exist after the call.
     107         */
     108        public static function drop_index_if_exists( string $table, string $index_name ): bool {
     109                global $wpdb;
     110
     111                if ( ! self::index_exists( $table, $index_name ) ) {
     112                        return true;
     113                }
     114
     115                $query = $wpdb->prepare( 'DROP INDEX %i ON %i', $index_name, $table );
     116
     117                return false !== $wpdb->query( $query );
    49118        }
    50119
  • ws-action-scheduler-cleaner/trunk/includes/filters.php

    r3750500 r3798362  
    1818        add_filter( 'action_scheduler_retention_period', 'wsacsc_change_retention_period' );
    1919        add_filter( 'action_scheduler_default_cleaner_statuses', 'wsacsc_set_cleaner_statuses' );
     20        add_filter( 'action_scheduler_enable_failed_action_cleanup', 'wsacsc_filter_failed_action_cleanup' );
    2021}
    2122
    2223/**
    23  * Increase cleanup batch size
     24 * Increase cleanup batch size to at least 50.
    2425 *
    25  * @param int $batch_size Default batch size
     26 * @param int $batch_size Batch size from Action Scheduler or other code.
    2627 * @return int
    2728 */
    2829function wsacsc_increase_cleanup_batch_size( $batch_size ): int {
    29         return 50;
     30        return max( (int) $batch_size, 50 );
    3031}
    3132
    3233/**
    33  * Increase queue runner time limit
     34 * Increase queue runner time limit to at least 60 seconds.
    3435 *
    35  * @param int $time_limit Default time limit
     36 * @param int $time_limit Time limit from Action Scheduler or other code.
    3637 * @return int
    3738 */
    3839function wsacsc_increase_queue_runner_time_limit( $time_limit ): int {
    39         return 60;
     40        return max( (int) $time_limit, 60 );
    4041}
    4142
    … …  
    5960
    6061/**
    61  * Change retention period
     62 * Retention period in seconds that keeps all actions from the Action Scheduler cleaner.
    6263 *
    63  * @param int $default_retention_period Default retention period
    64  * @return int
     64 * Action Scheduler builds its cutoff with "<seconds> seconds ago". PHP_INT_MAX overflows
     65 * to a future date, so the cleaner deleted all finished actions in 1.3.1. 50 years stays
     66 * below the 32-bit integer limit and gives a cutoff before any Action Scheduler data.
     67 */
     68const WSACSC_DISABLED_RETENTION_PERIOD = 50 * YEAR_IN_SECONDS;
     69
     70/**
     71 * Pass the actions retention period to Action Scheduler.
     72 *
     73 * When the plugin schedule is active, the Action Scheduler cleaner must delete nothing.
     74 * wsacsc_set_cleaner_statuses() returns an empty status list for this. Action Scheduler
     75 * before 3.6 has no status filter, and 3.6 to 3.9 replace an empty list with their
     76 * default statuses. So this function also returns a retention period that matches no action.
     77 *
     78 * @param int $default_retention_period Default retention period in seconds.
     79 * @return int Retention period in seconds.
    6580 */
    6681function wsacsc_change_retention_period( $default_retention_period ): int {
    6782        if ( wsacsc_is_plugin_schedule_active() ) {
    68                 return PHP_INT_MAX;
     83                return WSACSC_DISABLED_RETENTION_PERIOD;
    6984        }
    7085
    7186        $retention_days_option = get_option( 'wsacsc_actions_retention', '30' );
    72         if ( $retention_days_option === '' || ! ctype_digit( (string) $retention_days_option ) ) {
    73                 return $default_retention_period;
     87        if ( '' === $retention_days_option || ! ctype_digit( (string) $retention_days_option ) ) {
     88                return (int) $default_retention_period;
    7489        }
    75         $retention_days = absint( $retention_days_option );
    76         if ( 0 === $retention_days ) {
    77                 return 0;
    78         }
    79         return $retention_days * DAY_IN_SECONDS;
     90
     91        return absint( $retention_days_option ) * DAY_IN_SECONDS;
    8092}
    8193
    8294/**
    83  * Set cleaner statuses
     95 * Set cleaner statuses.
    8496 *
    85  * @param array $default_statuses Default statuses
     97 * An empty array turns off the Action Scheduler cleaner in Action Scheduler 4.0 and later.
     98 * Versions 3.6 to 3.9 use their default statuses instead, and earlier versions have no
     99 * status filter. For these, wsacsc_change_retention_period() returns a retention period
     100 * that matches no action.
     101 *
     102 * @param array $default_statuses Default statuses.
    86103 * @return array
    87104 */
    88105function wsacsc_set_cleaner_statuses( $default_statuses ): array {
     106        if ( wsacsc_is_plugin_schedule_active() ) {
     107                return array();
     108        }
     109
    89110        $selected_statuses_option = get_option( 'wsacsc_selected_statuses', array( 'complete', 'failed', 'canceled' ) );
    90111        if ( ! is_array( $selected_statuses_option ) ) {
    … …  
    95116        $selected_statuses = array_intersect( $selected_statuses, wsacsc_get_allowed_action_statuses() );
    96117
    97         return ! empty( $selected_statuses ) ? $selected_statuses : $default_statuses;
     118        return ! empty( $selected_statuses ) ? array_values( $selected_statuses ) : (array) $default_statuses;
    98119}
     120
     121/**
     122 * Turn off the separate failed-action cleanup of Action Scheduler 4.0 and later
     123 * while the plugin schedule is active.
     124 *
     125 * @param bool $enabled Whether Action Scheduler purges failed actions.
     126 * @return bool
     127 */
     128function wsacsc_filter_failed_action_cleanup( $enabled ): bool {
     129        return wsacsc_is_plugin_schedule_active() ? false : (bool) $enabled;
     130}
  • ws-action-scheduler-cleaner/trunk/includes/helpers.php

    r3559324 r3798362  
    2424
    2525/**
     26 * Write a diagnostic message to the PHP error log when logging is on.
     27 *
     28 * @param string $message Message without the plugin name prefix.
     29 */
     30function wsacsc_log( string $message ): void {
     31        if ( ! wsacsc_should_log() ) {
     32                return;
     33        }
     34
     35        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Diagnostic output only when WP_DEBUG or plugin development mode is on.
     36        error_log( 'WS Action Scheduler Cleaner: ' . $message );
     37}
     38
     39/**
     40 * Set the PHP time limit when the host allows it.
     41 *
     42 * @param int $seconds Seconds. 0 means no limit.
     43 */
     44function wsacsc_set_time_limit( int $seconds ): void {
     45        if ( ! function_exists( 'set_time_limit' ) ) {
     46                return;
     47        }
     48
     49        $disabled_functions = array_map( 'trim', explode( ',', (string) ini_get( 'disable_functions' ) ) );
     50        if ( in_array( 'set_time_limit', $disabled_functions, true ) ) {
     51                return;
     52        }
     53
     54        set_time_limit( max( 0, $seconds ) );
     55}
     56
     57/**
     58 * Cutoff in UTC for a retention period.
     59 *
     60 * The cutoff is calculated in PHP so that it does not depend on the time zone of the
     61 * database session, and so that it stays the same for all chunks of one job.
     62 *
     63 * @param int $retention_days Retention in days (1 to 365).
     64 * @return string Date and time in the format Y-m-d H:i:s (UTC).
     65 */
     66function wsacsc_get_retention_cutoff_gmt( int $retention_days ): string {
     67        return gmdate( 'Y-m-d H:i:s', time() - ( $retention_days * DAY_IN_SECONDS ) );
     68}
     69
     70/**
     71 * Whether a value is a valid retention cutoff.
     72 *
     73 * @param mixed $value Value from stored progress data.
     74 * @return bool True for a UTC date in the format Y-m-d H:i:s that is not in the future and not older than 366 days.
     75 */
     76function wsacsc_is_valid_retention_cutoff( $value ): bool {
     77        if ( ! is_string( $value ) ) {
     78                return false;
     79        }
     80
     81        $date = DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', $value, new DateTimeZone( 'UTC' ) );
     82        if ( false === $date || $date->format( 'Y-m-d H:i:s' ) !== $value ) {
     83                return false;
     84        }
     85
     86        $timestamp = $date->getTimestamp();
     87
     88        return $timestamp <= time() && $timestamp >= time() - ( 366 * DAY_IN_SECONDS );
     89}
     90
     91/**
    2692 * Action statuses allowed for cleanup operations.
    2793 *
    … …  
    64130        global $wpdb;
    65131
    66         $actions_table   = $wpdb->prefix . 'actionscheduler_actions';
    67         $columns_query   = $wpdb->prepare( 'DESC %i', $actions_table );
    68         $columns_result  = $wpdb->get_results( $columns_query );
     132        $actions_table = $wpdb->prefix . 'actionscheduler_actions';
     133        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Table structure of Action Scheduler. The result is cached in a static variable.
     134        $columns_result  = $wpdb->get_results( $wpdb->prepare( 'DESC %i', $actions_table ) );
    69135        $columns         = is_array( $columns_result ) ? wp_list_pluck( $columns_result, 'Field' ) : array();
    70136        $allowed_columns = wsacsc_get_allowed_actions_retention_date_columns();
    … …  
    110176
    111177        return array(
    112                 'where_clause' => 'status IN (' . $placeholders . ') AND `' . $date_column . '` < DATE_SUB(NOW(), INTERVAL %d DAY)',
    113                 'where_params' => array_merge( $selected_statuses, array( $retention_days ) ),
     178                'where_clause' => 'status IN (' . $placeholders . ') AND `' . $date_column . '` < %s',
     179                'where_params' => array_merge( $selected_statuses, array( wsacsc_get_retention_cutoff_gmt( $retention_days ) ) ),
     180        );
     181}
     182
     183/**
     184 * Build WHERE clause and parameters for scheduled logs retention cleanup.
     185 *
     186 * @param int $retention_days Retention in days (0 = all log entries).
     187 * @return array{where_clause: string, where_params: array}
     188 */
     189function wsacsc_build_logs_retention_where( int $retention_days ): array {
     190        if ( 0 === $retention_days ) {
     191                return array(
     192                        'where_clause' => '1=1',
     193                        'where_params' => array(),
     194                );
     195        }
     196
     197        return array(
     198                'where_clause' => '`log_date_gmt` < %s',
     199                'where_params' => array( wsacsc_get_retention_cutoff_gmt( $retention_days ) ),
    114200        );
    115201}
    … …  
    159245                        return false;
    160246                }
    161         } elseif ( '`log_date_gmt` < DATE_SUB(NOW(), INTERVAL %d DAY)' === $where_clause ) {
     247        } elseif ( '`log_date_gmt` < %s' === $where_clause ) {
    162248                if ( $logs_table !== $table || 1 !== count( $where_params ) ) {
    163249                        return false;
    164250                }
    165                 $retention_days = (int) $where_params[0];
    166                 if ( $retention_days < 1 || $retention_days > 365 ) {
     251                if ( ! wsacsc_is_valid_retention_cutoff( $where_params[0] ) ) {
    167252                        return false;
    168253                }
    … …  
    182267                        }
    183268                }
    184         } elseif ( preg_match( '/^status IN \((%s(?:,\s*%s)*)\) AND `(completed_date_gmt|last_attempt_gmt|scheduled_date_gmt)` < DATE_SUB\(NOW\(\), INTERVAL %d DAY\)$/', $where_clause, $matches ) ) {
     269        } elseif ( preg_match( '/^status IN \((%s(?:,\s*%s)*)\) AND `(completed_date_gmt|last_attempt_gmt|scheduled_date_gmt)` < %s$/', $where_clause, $matches ) ) {
    185270                if ( $actions_table !== $table ) {
    186271                        return false;
    … …  
    196281                }
    197282
    198                 $retention_days = (int) $where_params[ count( $where_params ) - 1 ];
    199                 if ( $retention_days < 1 || $retention_days > 365 ) {
     283                if ( ! wsacsc_is_valid_retention_cutoff( $where_params[ count( $where_params ) - 1 ] ) ) {
    200284                        return false;
    201285                }
    … …  
    221305        }
    222306
     307        if ( isset( $progress['total_to_delete'] ) ) {
     308                $progress['total_to_delete'] = max( 0, (int) $progress['total_to_delete'] );
     309        }
     310
    223311        if ( isset( $progress['context'] ) && ! in_array( $progress['context'], array( 'ajax', 'cron' ), true ) ) {
    224312                return false;
    … …  
    231319 * Format in-progress cleanup message with rows deleted.
    232320 *
    233  * @param int $total_deleted Rows deleted so far.
     321 * @param int $total_deleted   Rows deleted so far.
     322 * @param int $total_to_delete Rows the job counted at its start, or 0 if unknown.
    234323 * @return string
    235324 */
    236 function wsacsc_format_cleanup_progress_message( int $total_deleted ): string {
     325function wsacsc_format_cleanup_progress_message( int $total_deleted, int $total_to_delete = 0 ): string {
     326        if ( $total_to_delete > 0 && $total_deleted < $total_to_delete ) {
     327                return sprintf(
     328                        /* translators: 1: rows deleted so far, 2: rows to delete in total, 3: percentage done. */
     329                        __( 'Clearing in progress… %1$s of %2$s rows deleted (%3$d%%).', 'ws-action-scheduler-cleaner' ),
     330                        number_format_i18n( $total_deleted ),
     331                        number_format_i18n( $total_to_delete ),
     332                        (int) floor( $total_deleted / $total_to_delete * 100 )
     333                );
     334        }
     335
    237336        if ( $total_deleted <= 0 ) {
    238337                return __( 'Clearing in progress...', 'ws-action-scheduler-cleaner' );
  • ws-action-scheduler-cleaner/trunk/languages/ws-action-scheduler-cleaner-de_AT.po

    r3750500 r3798362  
     1#
    12msgid ""
    23msgstr ""
    34"Project-Id-Version: WS Action Scheduler Cleaner\n"
    4 "Report-Msgid-Bugs-To: \n"
    5 "POT-Creation-Date: 2024-10-10 12:00+0000\n"
    6 "PO-Revision-Date: 2025-11-24 18:00+0100\n"
     5"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/ws-action-scheduler-cleaner\n"
     6"POT-Creation-Date: 2026-11-10T20:25:22+00:00\n"
     7"PO-Revision-Date: 2026-11-10 12:00+0000\n"
    78"Last-Translator: Marco Brack <mbrack@winning-solutions.de>\n"
    89"Language-Team: \n"
    … …  
    1415"X-Generator: Poedit 3.8\n"
    1516
     17#. Plugin Name of the plugin
     18#: ws-action-scheduler-cleaner.php includes/class-wsacsc-admin.php:70 includes/class-wsacsc-admin.php:149 includes/class-wsacsc-admin.php:156
    1619msgid "WS Action Scheduler Cleaner"
    1720msgstr "WS Action Scheduler Cleaner"
    1821
     22#. Description of the plugin
     23#: ws-action-scheduler-cleaner.php
     24msgid "Suffering from database bloat? Try cleaning up the Action Scheduler tables through an easy-to-understand GUI."
     25msgstr "Leidet Ihre Datenbank unter aufgeblähten Tabellen? Bereinigen Sie die Action-Scheduler-Tabellen über eine leicht verständliche Oberfläche."
     26
     27#. Author of the plugin
     28#: ws-action-scheduler-cleaner.php
     29msgid "Winning Solutions - Nagel & Mäder GbR"
     30msgstr "Winning Solutions - Nagel & Mäder GbR"
     31
     32#. Author URI of the plugin
     33#: ws-action-scheduler-cleaner.php
     34msgid "https://www.winning-solutions.de"
     35msgstr "https://www.winning-solutions.de"
     36
     37#: includes/class-wsacsc-admin.php:40
     38msgid "Settings"
     39msgstr "Einstellungen"
     40
     41#: includes/class-wsacsc-admin.php:71
     42msgid "WS AS Cleaner"
     43msgstr "WS AS Cleaner"
     44
     45#: includes/class-wsacsc-admin.php:118 includes/class-wsacsc-ajax.php:108 includes/class-wsacsc-ajax.php:314
     46msgid "Please select at least one status to clear."
     47msgstr "Bitte wählen Sie mindestens einen Status zum Bereinigen aus."
     48
     49#: includes/class-wsacsc-admin.php:119 includes/helpers.php:337
     50msgid "Clearing in progress..."
     51msgstr "Bereinigung läuft..."
     52
     53#: includes/class-wsacsc-admin.php:120
     54msgid "Please wait..."
     55msgstr "Bitte warten Sie..."
     56
     57#: includes/class-wsacsc-admin.php:121
     58msgid "An error occurred. Please try again."
     59msgstr "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
     60
     61#: includes/class-wsacsc-admin.php:122 includes/class-wsacsc-ajax.php:138
     62msgid "Selected actions cleared successfully!"
     63msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
     64
     65#: includes/class-wsacsc-admin.php:123 includes/class-wsacsc-ajax.php:180 includes/class-wsacsc-ajax.php:197
     66msgid "Logs cleared successfully!"
     67msgstr "Protokolle erfolgreich bereinigt!"
     68
     69#: includes/class-wsacsc-admin.php:124 includes/class-wsacsc-ajax.php:295
     70msgid "Schedule saved successfully!"
     71msgstr "Zeitplan erfolgreich gespeichert!"
     72
     73#: includes/class-wsacsc-admin.php:125 includes/class-wsacsc-ajax.php:319
     74msgid "Statuses saved successfully!"
     75msgstr "Status erfolgreich gespeichert!"
     76
     77#: includes/class-wsacsc-admin.php:126
     78msgid "Optimizing table..."
     79msgstr "Tabelle wird optimiert..."
     80
     81#: includes/class-wsacsc-admin.php:127 includes/class-wsacsc-admin.php:189 includes/class-wsacsc-admin.php:191 includes/class-wsacsc-admin.php:197 includes/class-wsacsc-admin.php:199
     82msgid "Loading..."
     83msgstr "Wird geladen..."
     84
     85#: includes/class-wsacsc-admin.php:128 includes/class-wsacsc-ajax.php:382
     86msgid "Table optimization failed."
     87msgstr "Tabellenoptimierung fehlgeschlagen."
     88
     89#: includes/class-wsacsc-admin.php:129
     90msgid "Please fix the highlighted fields before saving."
     91msgstr "Bitte korrigieren Sie die markierten Felder vor dem Speichern."
     92
     93#: includes/class-wsacsc-admin.php:130 includes/class-wsacsc-admin.php:192
     94msgid "Refresh actions table size"
     95msgstr "Größe der Aktionstabelle aktualisieren"
     96
     97#: includes/class-wsacsc-admin.php:131 includes/class-wsacsc-admin.php:200
     98msgid "Refresh logs table size"
     99msgstr "Größe der Protokolltabelle aktualisieren"
     100
     101#: includes/class-wsacsc-admin.php:132
     102msgid "Retrying…"
     103msgstr "Erneuter Versuch…"
     104
     105#: includes/class-wsacsc-admin.php:150
     106msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
     107msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stellen Sie sicher, dass Action Scheduler ordnungsgemäß installiert und aktiviert ist."
     108
     109#: includes/class-wsacsc-admin.php:159
    19110msgid "This tool allows you to clean up the Action Scheduler tables in your WordPress database. Action Scheduler is a library used by many plugins to schedule background tasks."
    20111msgstr "Dieses Tool ermöglicht es Ihnen, die Action Scheduler-Tabellen in Ihrer WordPress-Datenbank zu bereinigen. Action Scheduler ist eine Bibliothek, die von vielen Plugins zur Planung von Hintergrundaufgaben verwendet wird."
    21112
    22 msgid "Please wait..."
    23 msgstr "Bitte warten Sie..."
    24 
    25 msgid "Loading..."
    26 msgstr "Wird geladen..."
    27 
     113#: includes/class-wsacsc-admin.php:160
    28114msgid "The Action Scheduler uses two main tables:"
    29115msgstr "Der Action Scheduler verwendet zwei Haupttabellen:"
    30116
     117#: includes/class-wsacsc-admin.php:162
    31118msgid "Actions Table: Stores scheduled actions and their statuses."
    32119msgstr "Aktionstabelle: Speichert geplante Aktionen und deren Status."
    33120
     121#: includes/class-wsacsc-admin.php:163
    34122msgid "Logs Table: Stores logs of action executions."
    35123msgstr "Protokolltabelle: Speichert Protokolle von Aktionsausführungen."
    36124
     125#: includes/class-wsacsc-admin.php:165
    37126msgid "Clearing these tables is generally safe and can improve database performance. However, please note:"
    38127msgstr "Das Bereinigen dieser Tabellen ist im Allgemeinen sicher und kann die Datenbankleistung verbessern. Bitte beachten Sie jedoch:"
    39128
     129#: includes/class-wsacsc-admin.php:167
    40130msgid "Clearing can take a while depending on the size of the tables."
    41131msgstr "Die Bereinigung kann je nach Größe der Tabellen eine Weile dauern."
    42132
     133#: includes/class-wsacsc-admin.php:168
    43134msgid "Cleared data will be permanently deleted."
    44135msgstr "Bereinigte Daten werden dauerhaft gelöscht."
    45136
     137#: includes/class-wsacsc-admin.php:169
    46138msgid "It's recommended to <strong>make a backup</strong> before proceeding."
    47139msgstr "Es wird empfohlen, vor dem Fortfahren ein <strong>Backup zu erstellen</strong>."
    48140
     141#: includes/class-wsacsc-admin.php:170
    49142msgid "Clearing completed, failed, or canceled actions usually doesn't affect WordPress functionality."
    50143msgstr "Das Bereinigen von abgeschlossenen, fehlgeschlagenen oder abgebrochenen Aktionen beeinträchtigt normalerweise nicht die WordPress-Funktionalität."
    51144
     145#. translators: %s: URL to Action Scheduler admin page
     146#: includes/class-wsacsc-admin.php:177
     147#, php-format
    52148msgid "For more information, visit the <a href=\"%s\">Action Scheduler admin page</a>."
    53149msgstr "Weitere Informationen finden Sie auf der <a href=\"%s\">Action Scheduler-Administrationsseite</a>."
    54150
     151#: includes/class-wsacsc-admin.php:186
    55152msgid "Current Table Sizes:"
    56153msgstr "Aktuelle Tabellengrößen:"
    57154
     155#: includes/class-wsacsc-admin.php:188
    58156msgid "Actions table:"
    59157msgstr "Aktionstabelle:"
    60158
     159#: includes/class-wsacsc-admin.php:190 includes/class-wsacsc-admin.php:198
    61160msgid "rows"
    62161msgstr "Zeilen"
    63162
     163#: includes/class-wsacsc-admin.php:196
    64164msgid "Logs table:"
    65165msgstr "Protokolltabelle:"
    66166
     167#: includes/class-wsacsc-admin.php:207
    67168msgid "Clear Action Statuses"
    68169msgstr "Aktionsstatus bereinigen"
    69170
    70 msgid "Select which action statuses to clear:"
    71 msgstr "Wählen Sie aus, welche Aktionsstatus bereinigt werden sollen:"
    72 
     171#: includes/class-wsacsc-admin.php:209
     172msgid "Action statuses to clear"
     173msgstr "Zu bereinigende Aktionsstatus"
     174
     175#: includes/class-wsacsc-admin.php:210
    73176msgid "Select which statuses to remove when clearing manually, when this plugin runs scheduled action cleanup, and (if this plugin’s action cleanup schedule is disabled) which statuses Action Scheduler may delete in the background:"
    74177msgstr "Wählen Sie aus, welche Status bei manueller Bereinigung, bei der geplanten Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) bei der Hintergrundbereinigung von Action Scheduler entfernt werden sollen:"
    75178
     179#: includes/class-wsacsc-admin.php:217
    76180msgid "Complete"
    77181msgstr "Abgeschlossen"
    78182
     183#: includes/class-wsacsc-admin.php:218
    79184msgid "Failed"
    80185msgstr "Fehlgeschlagen"
    81186
     187#: includes/class-wsacsc-admin.php:219
    82188msgid "Canceled"
    83189msgstr "Abgebrochen"
    84190
     191#: includes/class-wsacsc-admin.php:221
    85192msgid "Clear Selected Actions"
    86193msgstr "Ausgewählte Aktionen bereinigen"
    87194
     195#: includes/class-wsacsc-admin.php:226
    88196msgid "Clear Logs Table"
    89197msgstr "Protokolltabelle bereinigen"
    90198
     199#: includes/class-wsacsc-admin.php:227
    91200msgid "This will clear all entries in the logs table."
    92201msgstr "Dies wird alle Einträge in der Protokolltabelle löschen."
    93202
     203#: includes/class-wsacsc-admin.php:228
    94204msgid "Clear Logs"
    95205msgstr "Protokolle bereinigen"
    96206
     207#: includes/class-wsacsc-admin.php:232
     208msgid "Optimize Tables"
     209msgstr "Tabellen optimieren"
     210
     211#: includes/class-wsacsc-admin.php:233
     212msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
     213msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
     214
     215#: includes/class-wsacsc-admin.php:235
     216msgid "Optimize Actions Table"
     217msgstr "Aktionstabelle optimieren"
     218
     219#: includes/class-wsacsc-admin.php:236
     220msgid "Optimize Logs Table"
     221msgstr "Protokolltabelle optimieren"
     222
     223#: includes/class-wsacsc-admin.php:241
    97224msgid "Scheduling Options"
    98225msgstr "Planungsoptionen"
    99226
    100 msgid "Set up automatic clearing schedules for selected statuses (set to 0 to clean fully; leave empty to disable automatic clearing):"
    101 msgstr "Richten Sie automatische Bereinigungspläne für ausgewählte Status ein (auf 0 setzen, um vollständig zu bereinigen; leer lassen, um die automatische Bereinigung zu deaktivieren):"
    102 
    103 msgid "Clear logs older than:"
    104 msgstr "Protokolle bereinigen, die älter sind als:"
    105 
     227#: includes/class-wsacsc-admin.php:242
     228msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
     229msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
     230
     231#: includes/class-wsacsc-admin.php:243
     232msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
     233msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
     234
     235#: includes/class-wsacsc-admin.php:244
     236msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
     237msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
     238
     239#: includes/class-wsacsc-admin.php:245
     240msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
     241msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
     242
     243#: includes/class-wsacsc-admin.php:246
     244msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
     245msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr großem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
     246
     247#: includes/class-wsacsc-admin.php:249
     248msgid "Action Statuses"
     249msgstr "Aktionsstatus"
     250
     251#: includes/class-wsacsc-admin.php:251 includes/class-wsacsc-admin.php:277
     252msgid "Cleanup Schedule:"
     253msgstr "Bereinigungszeitplan:"
     254
     255#: includes/class-wsacsc-admin.php:254 includes/class-wsacsc-admin.php:269 includes/class-wsacsc-admin.php:280 includes/class-wsacsc-admin.php:295
    106256msgid "days"
    107257msgstr "Tage"
    108258
    109 msgid "Clear action statuses older than:"
    110 msgstr "Aktionsstatus bereinigen, die älter sind als:"
    111 
     259#: includes/class-wsacsc-admin.php:256
     260msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
     261msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
     262
     263#: includes/class-wsacsc-admin.php:259 includes/class-wsacsc-admin.php:285
     264msgid "Schedule Time:"
     265msgstr "Zeitplan:"
     266
     267#: includes/class-wsacsc-admin.php:263
     268msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
     269msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
     270
     271#: includes/class-wsacsc-admin.php:266 includes/class-wsacsc-admin.php:292
     272msgid "Retention Period:"
     273msgstr "Aufbewahrungsfrist:"
     274
     275#: includes/class-wsacsc-admin.php:271
     276msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
     277msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
     278
     279#: includes/class-wsacsc-admin.php:275
     280msgid "Logs"
     281msgstr "Protokolle"
     282
     283#: includes/class-wsacsc-admin.php:282
     284msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
     285msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
     286
     287#: includes/class-wsacsc-admin.php:289
     288msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
     289msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
     290
     291#: includes/class-wsacsc-admin.php:297
     292msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
     293msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
     294
     295#: includes/class-wsacsc-admin.php:301
    112296msgid "Save Schedule"
    113297msgstr "Zeitplan speichern"
    114298
     299#: includes/class-wsacsc-admin.php:307
    115300msgid "Powered by Winning Solutions"
    116301msgstr "Powered by Winning Solutions"
    117302
    118 msgid "Selected actions cleared successfully!"
    119 msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
    120 
    121 msgid "Logs cleared successfully!"
    122 msgstr "Protokolle erfolgreich bereinigt!"
    123 
    124 msgid "Schedule saved successfully!"
    125 msgstr "Zeitplan erfolgreich gespeichert!"
    126 
     303#: includes/class-wsacsc-ajax.php:37
     304msgid "Another cleanup or optimization is already running. Please wait until it finishes."
     305msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warten Sie, bis sie abgeschlossen ist."
     306
     307#: includes/class-wsacsc-ajax.php:81 includes/class-wsacsc-ajax.php:96 includes/class-wsacsc-ajax.php:150 includes/class-wsacsc-ajax.php:209 includes/class-wsacsc-ajax.php:305 includes/class-wsacsc-ajax.php:329 includes/class-wsacsc-ajax.php:356 includes/class-wsacsc-ajax.php:404
     308msgid "Insufficient permissions."
     309msgstr "Unzureichende Berechtigungen."
     310
     311#: includes/class-wsacsc-ajax.php:112 includes/class-wsacsc-ajax.php:156
     312msgid "Action Scheduler tables do not exist."
     313msgstr "Die Action-Scheduler-Tabellen existieren nicht."
     314
     315#: includes/class-wsacsc-ajax.php:131
     316msgid "An error occurred while clearing actions."
     317msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
     318
     319#: includes/class-wsacsc-ajax.php:190
     320msgid "An error occurred while clearing logs."
     321msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
     322
     323#: includes/class-wsacsc-ajax.php:230
     324msgid "Actions schedule interval must be empty or between 1 and 365 days."
     325msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     326
     327#: includes/class-wsacsc-ajax.php:234
     328msgid "Logs schedule interval must be empty or between 1 and 365 days."
     329msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     330
     331#: includes/class-wsacsc-ajax.php:238
     332msgid "Actions schedule time must be in HH:MM format."
     333msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
     334
     335#: includes/class-wsacsc-ajax.php:242
     336msgid "Logs schedule time must be in HH:MM format."
     337msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
     338
     339#: includes/class-wsacsc-ajax.php:246
     340msgid "Actions retention period is required and must be between 0 and 365 days."
     341msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     342
     343#: includes/class-wsacsc-ajax.php:250
     344msgid "Logs retention period is required and must be between 0 and 365 days."
     345msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     346
     347#: includes/class-wsacsc-ajax.php:288
     348msgid "Failed to save schedule. Please try again."
     349msgstr "Der Zeitplan konnte nicht gespeichert werden. Bitte versuchen Sie es erneut."
     350
     351#: includes/class-wsacsc-ajax.php:292
    127352msgid "The settings were saved, but the cleanup schedule could not be updated yet. The plugin will retry automatically."
    128353msgstr "Die Einstellungen wurden gespeichert, aber der Bereinigungszeitplan konnte noch nicht aktualisiert werden. Das Plugin versucht es automatisch erneut."
    129354
    130 msgid "Statuses saved successfully!"
    131 msgstr "Status erfolgreich gespeichert!"
    132 
    133 msgid "Settings"
    134 msgstr "Einstellungen"
    135 
    136 msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
    137 msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stellen Sie sicher, dass Action Scheduler ordnungsgemäß installiert und aktiviert ist."
    138 
    139 msgid "Please select at least one status to clear."
    140 msgstr "Bitte wählen Sie mindestens einen Status zum Bereinigen aus."
    141 
    142 msgid "Clearing in progress..."
    143 msgstr "Bereinigung läuft..."
    144 
    145 msgid "An error occurred. Please try again."
    146 msgstr "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
    147 
    148 msgid "Optimize Tables"
    149 msgstr "Tabellen optimieren"
    150 
    151 msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
    152 msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
    153 
    154 msgid "Optimize Actions Table"
    155 msgstr "Aktionstabelle optimieren"
    156 
    157 msgid "Optimize Logs Table"
    158 msgstr "Protokolltabelle optimieren"
    159 
    160 msgid "Optimizing table..."
    161 msgstr "Tabelle wird optimiert..."
    162 
     355#: includes/class-wsacsc-ajax.php:336 includes/class-wsacsc-ajax.php:363
     356msgid "Invalid table type."
     357msgstr "Ungültiger Tabellentyp."
     358
     359#. translators: %s: table type (actions or logs).
     360#: includes/class-wsacsc-ajax.php:390
     361#, php-format
    163362msgid "%s table optimized successfully!"
    164363msgstr "%s-Tabelle erfolgreich optimiert!"
    165364
    166 msgid "Table optimization failed."
    167 msgstr "Tabellenoptimierung fehlgeschlagen."
    168 
    169 msgid "Table does not exist."
    170 msgstr "Tabelle existiert nicht."
    171 
    172 msgid "Invalid table type."
    173 msgstr "Ungültiger Tabellentyp."
    174 
    175 msgid "Insufficient permissions."
    176 msgstr "Unzureichende Berechtigungen."
    177 
    178 msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
    179 msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
    180 
    181 msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
    182 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
    183 
    184 msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
    185 msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
    186 
    187 msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
    188 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
    189 
    190 msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
    191 msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr großem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
    192 
    193 msgid "Action Statuses"
    194 msgstr "Aktionsstatus"
    195 
    196 msgid "Cleanup Schedule:"
    197 msgstr "Bereinigungszeitplan:"
    198 
    199 msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
    200 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
    201 
    202 msgid "Schedule Time:"
    203 msgstr "Zeitplan:"
    204 
    205 msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
    206 msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
    207 
    208 msgid "Retention Period:"
    209 msgstr "Aufbewahrungsfrist:"
    210 
    211 msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
    212 msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
    213 
    214 msgid "Logs"
    215 msgstr "Protokolle"
    216 
    217 msgid "How often to run cleanup (empty or 0 = disabled, 1-365 days)."
    218 msgstr "Wie oft die Bereinigung ausgeführt wird (leer oder 0 = deaktiviert, 1–365 Tage)."
    219 
    220 msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
    221 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
    222 
    223 msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
    224 msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
    225 
    226 msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
    227 msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
    228 
    229 msgid "Actions schedule interval must be empty or between 1 and 365 days."
    230 msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    231 
    232 msgid "Logs schedule interval must be empty or between 1 and 365 days."
    233 msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    234 
    235 msgid "Actions schedule time must be in HH:MM format."
    236 msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
    237 
    238 msgid "Logs schedule time must be in HH:MM format."
    239 msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
    240 
    241 msgid "Actions retention period is required and must be between 0 and 365 days."
    242 msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    243 
    244 msgid "Logs retention period is required and must be between 0 and 365 days."
    245 msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    246 
     365#: includes/class-wsacsc-ajax.php:411
     366msgid "Invalid cleanup ID."
     367msgstr "Ungültige Bereinigungs-ID."
     368
     369#: includes/class-wsacsc-ajax.php:427
     370msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
     371msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Laden Sie die Seite neu, um die Tabellengrößen zu prüfen."
     372
     373#: includes/class-wsacsc-ajax.php:435
     374msgid "Invalid cleanup progress data."
     375msgstr "Ungültige Fortschrittsdaten der Bereinigung."
     376
     377#: includes/class-wsacsc-ajax.php:441
     378msgid "An error occurred during cleanup."
     379msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
     380
     381#: includes/class-wsacsc-ajax.php:453
     382msgid "Cleanup completed successfully!"
     383msgstr "Bereinigung erfolgreich abgeschlossen!"
     384
     385#. translators: %d: number of days.
     386#: includes/class-wsacsc-scheduler.php:245
     387#, php-format
     388msgid "Every %d day"
     389msgid_plural "Every %d days"
     390msgstr[0] "Jeden Tag"
     391msgstr[1] "Alle %d Tage"
     392
     393#. translators: 1: rows deleted so far, 2: rows to delete in total, 3: percentage done.
     394#: includes/helpers.php:329
     395#, php-format
     396msgid "Clearing in progress… %1$s of %2$s rows deleted (%3$d%%)."
     397msgstr "Bereinigung läuft… %1$s von %2$s Zeilen gelöscht (%3$d %%)."
     398
     399#. translators: %s: number of rows deleted so far.
     400#: includes/helpers.php:342
     401#, php-format
    247402msgid "Clearing in progress… %s rows deleted so far."
    248403msgstr "Bereinigung läuft… bisher %s Zeilen gelöscht."
    249 
    250 msgid "Cleanup completed successfully!"
    251 msgstr "Bereinigung erfolgreich abgeschlossen!"
    252 
    253 msgid "Another cleanup or optimization is already running. Please wait until it finishes."
    254 msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warten Sie, bis sie abgeschlossen ist."
    255 
    256 msgid "An error occurred while clearing actions."
    257 msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
    258 
    259 msgid "An error occurred while clearing logs."
    260 msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
    261 
    262 msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
    263 msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Laden Sie die Seite neu, um die Tabellengrößen zu prüfen."
    264 
    265 msgid "An error occurred during cleanup."
    266 msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
    267 
    268 msgid "Retrying…"
    269 msgstr "Erneuter Versuch…"
  • ws-action-scheduler-cleaner/trunk/languages/ws-action-scheduler-cleaner-de_AT_informal.po

    r3750500 r3798362  
     1#
    12msgid ""
    23msgstr ""
    34"Project-Id-Version: WS Action Scheduler Cleaner\n"
    4 "Report-Msgid-Bugs-To: \n"
    5 "POT-Creation-Date: 2024-10-10 12:00+0000\n"
    6 "PO-Revision-Date: 2025-11-24 18:00+0100\n"
     5"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/ws-action-scheduler-cleaner\n"
     6"POT-Creation-Date: 2026-11-10T20:25:22+00:00\n"
     7"PO-Revision-Date: 2026-11-10 12:00+0000\n"
    78"Last-Translator: Marco Brack <mbrack@winning-solutions.de>\n"
    89"Language-Team: \n"
    … …  
    1415"X-Generator: Poedit 3.8\n"
    1516
     17#. Plugin Name of the plugin
     18#: ws-action-scheduler-cleaner.php includes/class-wsacsc-admin.php:70 includes/class-wsacsc-admin.php:149 includes/class-wsacsc-admin.php:156
    1619msgid "WS Action Scheduler Cleaner"
    1720msgstr "WS Action Scheduler Cleaner"
    1821
     22#. Description of the plugin
     23#: ws-action-scheduler-cleaner.php
     24msgid "Suffering from database bloat? Try cleaning up the Action Scheduler tables through an easy-to-understand GUI."
     25msgstr "Leidet deine Datenbank unter aufgeblähten Tabellen? Bereinige die Action-Scheduler-Tabellen über eine leicht verständliche Oberfläche."
     26
     27#. Author of the plugin
     28#: ws-action-scheduler-cleaner.php
     29msgid "Winning Solutions - Nagel & Mäder GbR"
     30msgstr "Winning Solutions - Nagel & Mäder GbR"
     31
     32#. Author URI of the plugin
     33#: ws-action-scheduler-cleaner.php
     34msgid "https://www.winning-solutions.de"
     35msgstr "https://www.winning-solutions.de"
     36
     37#: includes/class-wsacsc-admin.php:40
     38msgid "Settings"
     39msgstr "Einstellungen"
     40
     41#: includes/class-wsacsc-admin.php:71
     42msgid "WS AS Cleaner"
     43msgstr "WS AS Cleaner"
     44
     45#: includes/class-wsacsc-admin.php:118 includes/class-wsacsc-ajax.php:108 includes/class-wsacsc-ajax.php:314
     46msgid "Please select at least one status to clear."
     47msgstr "Bitte wähle mindestens einen Status zum Bereinigen aus."
     48
     49#: includes/class-wsacsc-admin.php:119 includes/helpers.php:337
     50msgid "Clearing in progress..."
     51msgstr "Bereinigung läuft..."
     52
     53#: includes/class-wsacsc-admin.php:120
     54msgid "Please wait..."
     55msgstr "Bitte warte..."
     56
     57#: includes/class-wsacsc-admin.php:121
     58msgid "An error occurred. Please try again."
     59msgstr "Ein Fehler ist aufgetreten. Bitte versuche es erneut."
     60
     61#: includes/class-wsacsc-admin.php:122 includes/class-wsacsc-ajax.php:138
     62msgid "Selected actions cleared successfully!"
     63msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
     64
     65#: includes/class-wsacsc-admin.php:123 includes/class-wsacsc-ajax.php:180 includes/class-wsacsc-ajax.php:197
     66msgid "Logs cleared successfully!"
     67msgstr "Protokolle erfolgreich bereinigt!"
     68
     69#: includes/class-wsacsc-admin.php:124 includes/class-wsacsc-ajax.php:295
     70msgid "Schedule saved successfully!"
     71msgstr "Zeitplan erfolgreich gespeichert!"
     72
     73#: includes/class-wsacsc-admin.php:125 includes/class-wsacsc-ajax.php:319
     74msgid "Statuses saved successfully!"
     75msgstr "Status erfolgreich gespeichert!"
     76
     77#: includes/class-wsacsc-admin.php:126
     78msgid "Optimizing table..."
     79msgstr "Tabelle wird optimiert..."
     80
     81#: includes/class-wsacsc-admin.php:127 includes/class-wsacsc-admin.php:189 includes/class-wsacsc-admin.php:191 includes/class-wsacsc-admin.php:197 includes/class-wsacsc-admin.php:199
     82msgid "Loading..."
     83msgstr "Wird geladen..."
     84
     85#: includes/class-wsacsc-admin.php:128 includes/class-wsacsc-ajax.php:382
     86msgid "Table optimization failed."
     87msgstr "Tabellenoptimierung fehlgeschlagen."
     88
     89#: includes/class-wsacsc-admin.php:129
     90msgid "Please fix the highlighted fields before saving."
     91msgstr "Bitte korrigiere die markierten Felder vor dem Speichern."
     92
     93#: includes/class-wsacsc-admin.php:130 includes/class-wsacsc-admin.php:192
     94msgid "Refresh actions table size"
     95msgstr "Größe der Aktionstabelle aktualisieren"
     96
     97#: includes/class-wsacsc-admin.php:131 includes/class-wsacsc-admin.php:200
     98msgid "Refresh logs table size"
     99msgstr "Größe der Protokolltabelle aktualisieren"
     100
     101#: includes/class-wsacsc-admin.php:132
     102msgid "Retrying…"
     103msgstr "Erneuter Versuch…"
     104
     105#: includes/class-wsacsc-admin.php:150
     106msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
     107msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stelle sicher, dass Action Scheduler ordnungsgemäß installiert und aktiviert ist."
     108
     109#: includes/class-wsacsc-admin.php:159
    19110msgid "This tool allows you to clean up the Action Scheduler tables in your WordPress database. Action Scheduler is a library used by many plugins to schedule background tasks."
    20111msgstr "Dieses Tool ermöglicht es dir, die Action Scheduler-Tabellen in deiner WordPress-Datenbank zu bereinigen. Action Scheduler ist eine Bibliothek, die von vielen Plugins zur Planung von Hintergrundaufgaben verwendet wird."
    21112
    22 msgid "Please wait..."
    23 msgstr "Bitte warte..."
    24 
    25 msgid "Loading..."
    26 msgstr "Wird geladen..."
    27 
     113#: includes/class-wsacsc-admin.php:160
    28114msgid "The Action Scheduler uses two main tables:"
    29115msgstr "Der Action Scheduler verwendet zwei Haupttabellen:"
    30116
     117#: includes/class-wsacsc-admin.php:162
    31118msgid "Actions Table: Stores scheduled actions and their statuses."
    32119msgstr "Aktionstabelle: Speichert geplante Aktionen und deren Status."
    33120
     121#: includes/class-wsacsc-admin.php:163
    34122msgid "Logs Table: Stores logs of action executions."
    35123msgstr "Protokolltabelle: Speichert Protokolle von Aktionsausführungen."
    36124
     125#: includes/class-wsacsc-admin.php:165
    37126msgid "Clearing these tables is generally safe and can improve database performance. However, please note:"
    38127msgstr "Das Bereinigen dieser Tabellen ist im Allgemeinen sicher und kann die Datenbankleistung verbessern. Bitte beachte jedoch:"
    39128
     129#: includes/class-wsacsc-admin.php:167
    40130msgid "Clearing can take a while depending on the size of the tables."
    41131msgstr "Die Bereinigung kann je nach Größe der Tabellen eine Weile dauern."
    42132
     133#: includes/class-wsacsc-admin.php:168
    43134msgid "Cleared data will be permanently deleted."
    44135msgstr "Bereinigte Daten werden dauerhaft gelöscht."
    45136
     137#: includes/class-wsacsc-admin.php:169
    46138msgid "It's recommended to <strong>make a backup</strong> before proceeding."
    47139msgstr "Es wird empfohlen, vor dem Fortfahren ein <strong>Backup zu erstellen</strong>."
    48140
     141#: includes/class-wsacsc-admin.php:170
    49142msgid "Clearing completed, failed, or canceled actions usually doesn't affect WordPress functionality."
    50143msgstr "Das Bereinigen von abgeschlossenen, fehlgeschlagenen oder abgebrochenen Aktionen beeinträchtigt normalerweise nicht die WordPress-Funktionalität."
    51144
     145#. translators: %s: URL to Action Scheduler admin page
     146#: includes/class-wsacsc-admin.php:177
     147#, php-format
    52148msgid "For more information, visit the <a href=\"%s\">Action Scheduler admin page</a>."
    53149msgstr "Weitere Informationen findest du auf der <a href=\"%s\">Action Scheduler-Administrationsseite</a>."
    54150
     151#: includes/class-wsacsc-admin.php:186
    55152msgid "Current Table Sizes:"
    56153msgstr "Aktuelle Tabellengrößen:"
    57154
     155#: includes/class-wsacsc-admin.php:188
    58156msgid "Actions table:"
    59157msgstr "Aktionstabelle:"
    60158
     159#: includes/class-wsacsc-admin.php:190 includes/class-wsacsc-admin.php:198
    61160msgid "rows"
    62161msgstr "Zeilen"
    63162
     163#: includes/class-wsacsc-admin.php:196
    64164msgid "Logs table:"
    65165msgstr "Protokolltabelle:"
    66166
     167#: includes/class-wsacsc-admin.php:207
    67168msgid "Clear Action Statuses"
    68169msgstr "Aktionsstatus bereinigen"
    69170
    70 msgid "Select which action statuses to clear:"
    71 msgstr "Wähle aus, welche Aktionsstatus bereinigt werden sollen:"
    72 
     171#: includes/class-wsacsc-admin.php:209
     172msgid "Action statuses to clear"
     173msgstr "Zu bereinigende Aktionsstatus"
     174
     175#: includes/class-wsacsc-admin.php:210
    73176msgid "Select which statuses to remove when clearing manually, when this plugin runs scheduled action cleanup, and (if this plugin’s action cleanup schedule is disabled) which statuses Action Scheduler may delete in the background:"
    74177msgstr "Wähle aus, welche Status bei manueller Bereinigung, bei der geplanten Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) bei der Hintergrundbereinigung von Action Scheduler entfernt werden sollen:"
    75178
     179#: includes/class-wsacsc-admin.php:217
    76180msgid "Complete"
    77181msgstr "Abgeschlossen"
    78182
     183#: includes/class-wsacsc-admin.php:218
    79184msgid "Failed"
    80185msgstr "Fehlgeschlagen"
    81186
     187#: includes/class-wsacsc-admin.php:219
    82188msgid "Canceled"
    83189msgstr "Abgebrochen"
    84190
     191#: includes/class-wsacsc-admin.php:221
    85192msgid "Clear Selected Actions"
    86193msgstr "Ausgewählte Aktionen bereinigen"
    87194
     195#: includes/class-wsacsc-admin.php:226
    88196msgid "Clear Logs Table"
    89197msgstr "Protokolltabelle bereinigen"
    90198
     199#: includes/class-wsacsc-admin.php:227
    91200msgid "This will clear all entries in the logs table."
    92201msgstr "Dies wird alle Einträge in der Protokolltabelle löschen."
    93202
     203#: includes/class-wsacsc-admin.php:228
    94204msgid "Clear Logs"
    95205msgstr "Protokolle bereinigen"
    96206
     207#: includes/class-wsacsc-admin.php:232
     208msgid "Optimize Tables"
     209msgstr "Tabellen optimieren"
     210
     211#: includes/class-wsacsc-admin.php:233
     212msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
     213msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
     214
     215#: includes/class-wsacsc-admin.php:235
     216msgid "Optimize Actions Table"
     217msgstr "Aktionstabelle optimieren"
     218
     219#: includes/class-wsacsc-admin.php:236
     220msgid "Optimize Logs Table"
     221msgstr "Protokolltabelle optimieren"
     222
     223#: includes/class-wsacsc-admin.php:241
    97224msgid "Scheduling Options"
    98225msgstr "Planungsoptionen"
    99226
    100 msgid "Set up automatic clearing schedules for selected statuses (set to 0 to clean fully; leave empty to disable automatic clearing):"
    101 msgstr "Richte automatische Bereinigungspläne für ausgewählte Status ein (auf 0 setzen, um vollständig zu bereinigen; leer lassen, um die automatische Bereinigung zu deaktivieren):"
    102 
    103 msgid "Clear logs older than:"
    104 msgstr "Protokolle bereinigen, die älter sind als:"
    105 
     227#: includes/class-wsacsc-admin.php:242
     228msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
     229msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
     230
     231#: includes/class-wsacsc-admin.php:243
     232msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
     233msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
     234
     235#: includes/class-wsacsc-admin.php:244
     236msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
     237msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
     238
     239#: includes/class-wsacsc-admin.php:245
     240msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
     241msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
     242
     243#: includes/class-wsacsc-admin.php:246
     244msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
     245msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr großem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
     246
     247#: includes/class-wsacsc-admin.php:249
     248msgid "Action Statuses"
     249msgstr "Aktionsstatus"
     250
     251#: includes/class-wsacsc-admin.php:251 includes/class-wsacsc-admin.php:277
     252msgid "Cleanup Schedule:"
     253msgstr "Bereinigungszeitplan:"
     254
     255#: includes/class-wsacsc-admin.php:254 includes/class-wsacsc-admin.php:269 includes/class-wsacsc-admin.php:280 includes/class-wsacsc-admin.php:295
    106256msgid "days"
    107257msgstr "Tage"
    108258
    109 msgid "Clear action statuses older than:"
    110 msgstr "Aktionsstatus bereinigen, die älter sind als:"
    111 
     259#: includes/class-wsacsc-admin.php:256
     260msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
     261msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
     262
     263#: includes/class-wsacsc-admin.php:259 includes/class-wsacsc-admin.php:285
     264msgid "Schedule Time:"
     265msgstr "Zeitplan:"
     266
     267#: includes/class-wsacsc-admin.php:263
     268msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
     269msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
     270
     271#: includes/class-wsacsc-admin.php:266 includes/class-wsacsc-admin.php:292
     272msgid "Retention Period:"
     273msgstr "Aufbewahrungsfrist:"
     274
     275#: includes/class-wsacsc-admin.php:271
     276msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
     277msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
     278
     279#: includes/class-wsacsc-admin.php:275
     280msgid "Logs"
     281msgstr "Protokolle"
     282
     283#: includes/class-wsacsc-admin.php:282
     284msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
     285msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
     286
     287#: includes/class-wsacsc-admin.php:289
     288msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
     289msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
     290
     291#: includes/class-wsacsc-admin.php:297
     292msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
     293msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
     294
     295#: includes/class-wsacsc-admin.php:301
    112296msgid "Save Schedule"
    113297msgstr "Zeitplan speichern"
    114298
     299#: includes/class-wsacsc-admin.php:307
    115300msgid "Powered by Winning Solutions"
    116301msgstr "Powered by Winning Solutions"
    117302
    118 msgid "Selected actions cleared successfully!"
    119 msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
    120 
    121 msgid "Logs cleared successfully!"
    122 msgstr "Protokolle erfolgreich bereinigt!"
    123 
    124 msgid "Schedule saved successfully!"
    125 msgstr "Zeitplan erfolgreich gespeichert!"
    126 
     303#: includes/class-wsacsc-ajax.php:37
     304msgid "Another cleanup or optimization is already running. Please wait until it finishes."
     305msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warte, bis sie abgeschlossen ist."
     306
     307#: includes/class-wsacsc-ajax.php:81 includes/class-wsacsc-ajax.php:96 includes/class-wsacsc-ajax.php:150 includes/class-wsacsc-ajax.php:209 includes/class-wsacsc-ajax.php:305 includes/class-wsacsc-ajax.php:329 includes/class-wsacsc-ajax.php:356 includes/class-wsacsc-ajax.php:404
     308msgid "Insufficient permissions."
     309msgstr "Unzureichende Berechtigungen."
     310
     311#: includes/class-wsacsc-ajax.php:112 includes/class-wsacsc-ajax.php:156
     312msgid "Action Scheduler tables do not exist."
     313msgstr "Die Action-Scheduler-Tabellen existieren nicht."
     314
     315#: includes/class-wsacsc-ajax.php:131
     316msgid "An error occurred while clearing actions."
     317msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
     318
     319#: includes/class-wsacsc-ajax.php:190
     320msgid "An error occurred while clearing logs."
     321msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
     322
     323#: includes/class-wsacsc-ajax.php:230
     324msgid "Actions schedule interval must be empty or between 1 and 365 days."
     325msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     326
     327#: includes/class-wsacsc-ajax.php:234
     328msgid "Logs schedule interval must be empty or between 1 and 365 days."
     329msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     330
     331#: includes/class-wsacsc-ajax.php:238
     332msgid "Actions schedule time must be in HH:MM format."
     333msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
     334
     335#: includes/class-wsacsc-ajax.php:242
     336msgid "Logs schedule time must be in HH:MM format."
     337msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
     338
     339#: includes/class-wsacsc-ajax.php:246
     340msgid "Actions retention period is required and must be between 0 and 365 days."
     341msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     342
     343#: includes/class-wsacsc-ajax.php:250
     344msgid "Logs retention period is required and must be between 0 and 365 days."
     345msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     346
     347#: includes/class-wsacsc-ajax.php:288
     348msgid "Failed to save schedule. Please try again."
     349msgstr "Der Zeitplan konnte nicht gespeichert werden. Bitte versuche es erneut."
     350
     351#: includes/class-wsacsc-ajax.php:292
    127352msgid "The settings were saved, but the cleanup schedule could not be updated yet. The plugin will retry automatically."
    128353msgstr "Die Einstellungen wurden gespeichert, aber der Bereinigungszeitplan konnte noch nicht aktualisiert werden. Das Plugin versucht es automatisch erneut."
    129354
    130 msgid "Statuses saved successfully!"
    131 msgstr "Status erfolgreich gespeichert!"
    132 
    133 msgid "Settings"
    134 msgstr "Einstellungen"
    135 
    136 msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
    137 msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stelle sicher, dass Action Scheduler ordnungsgemäß installiert und aktiviert ist."
    138 
    139 msgid "Please select at least one status to clear."
    140 msgstr "Bitte wähle mindestens einen Status zum Bereinigen aus."
    141 
    142 msgid "Clearing in progress..."
    143 msgstr "Bereinigung läuft..."
    144 
    145 msgid "An error occurred. Please try again."
    146 msgstr "Ein Fehler ist aufgetreten. Bitte versuche es erneut."
    147 
    148 msgid "Optimize Tables"
    149 msgstr "Tabellen optimieren"
    150 
    151 msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
    152 msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
    153 
    154 msgid "Optimize Actions Table"
    155 msgstr "Aktionstabelle optimieren"
    156 
    157 msgid "Optimize Logs Table"
    158 msgstr "Protokolltabelle optimieren"
    159 
    160 msgid "Optimizing table..."
    161 msgstr "Tabelle wird optimiert..."
    162 
     355#: includes/class-wsacsc-ajax.php:336 includes/class-wsacsc-ajax.php:363
     356msgid "Invalid table type."
     357msgstr "Ungültiger Tabellentyp."
     358
     359#. translators: %s: table type (actions or logs).
     360#: includes/class-wsacsc-ajax.php:390
     361#, php-format
    163362msgid "%s table optimized successfully!"
    164363msgstr "%s-Tabelle erfolgreich optimiert!"
    165364
    166 msgid "Table optimization failed."
    167 msgstr "Tabellenoptimierung fehlgeschlagen."
    168 
    169 msgid "Table does not exist."
    170 msgstr "Tabelle existiert nicht."
    171 
    172 msgid "Invalid table type."
    173 msgstr "Ungültiger Tabellentyp."
    174 
    175 msgid "Insufficient permissions."
    176 msgstr "Unzureichende Berechtigungen."
    177 
    178 msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
    179 msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
    180 
    181 msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
    182 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
    183 
    184 msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
    185 msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
    186 
    187 msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
    188 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
    189 
    190 msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
    191 msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr großem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
    192 
    193 msgid "Action Statuses"
    194 msgstr "Aktionsstatus"
    195 
    196 msgid "Cleanup Schedule:"
    197 msgstr "Bereinigungszeitplan:"
    198 
    199 msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
    200 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
    201 
    202 msgid "Schedule Time:"
    203 msgstr "Zeitplan:"
    204 
    205 msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
    206 msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
    207 
    208 msgid "Retention Period:"
    209 msgstr "Aufbewahrungsfrist:"
    210 
    211 msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
    212 msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
    213 
    214 msgid "Logs"
    215 msgstr "Protokolle"
    216 
    217 msgid "How often to run cleanup (empty or 0 = disabled, 1-365 days)."
    218 msgstr "Wie oft die Bereinigung ausgeführt wird (leer oder 0 = deaktiviert, 1–365 Tage)."
    219 
    220 msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
    221 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
    222 
    223 msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
    224 msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
    225 
    226 msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
    227 msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
    228 
    229 msgid "Actions schedule interval must be empty or between 1 and 365 days."
    230 msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    231 
    232 msgid "Logs schedule interval must be empty or between 1 and 365 days."
    233 msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    234 
    235 msgid "Actions schedule time must be in HH:MM format."
    236 msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
    237 
    238 msgid "Logs schedule time must be in HH:MM format."
    239 msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
    240 
    241 msgid "Actions retention period is required and must be between 0 and 365 days."
    242 msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    243 
    244 msgid "Logs retention period is required and must be between 0 and 365 days."
    245 msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    246 
     365#: includes/class-wsacsc-ajax.php:411
     366msgid "Invalid cleanup ID."
     367msgstr "Ungültige Bereinigungs-ID."
     368
     369#: includes/class-wsacsc-ajax.php:427
     370msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
     371msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Lade die Seite neu, um die Tabellengrößen zu prüfen."
     372
     373#: includes/class-wsacsc-ajax.php:435
     374msgid "Invalid cleanup progress data."
     375msgstr "Ungültige Fortschrittsdaten der Bereinigung."
     376
     377#: includes/class-wsacsc-ajax.php:441
     378msgid "An error occurred during cleanup."
     379msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
     380
     381#: includes/class-wsacsc-ajax.php:453
     382msgid "Cleanup completed successfully!"
     383msgstr "Bereinigung erfolgreich abgeschlossen!"
     384
     385#. translators: %d: number of days.
     386#: includes/class-wsacsc-scheduler.php:245
     387#, php-format
     388msgid "Every %d day"
     389msgid_plural "Every %d days"
     390msgstr[0] "Jeden Tag"
     391msgstr[1] "Alle %d Tage"
     392
     393#. translators: 1: rows deleted so far, 2: rows to delete in total, 3: percentage done.
     394#: includes/helpers.php:329
     395#, php-format
     396msgid "Clearing in progress… %1$s of %2$s rows deleted (%3$d%%)."
     397msgstr "Bereinigung läuft… %1$s von %2$s Zeilen gelöscht (%3$d %%)."
     398
     399#. translators: %s: number of rows deleted so far.
     400#: includes/helpers.php:342
     401#, php-format
    247402msgid "Clearing in progress… %s rows deleted so far."
    248403msgstr "Bereinigung läuft… bisher %s Zeilen gelöscht."
    249 
    250 msgid "Cleanup completed successfully!"
    251 msgstr "Bereinigung erfolgreich abgeschlossen!"
    252 
    253 msgid "Another cleanup or optimization is already running. Please wait until it finishes."
    254 msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warte, bis sie abgeschlossen ist."
    255 
    256 msgid "An error occurred while clearing actions."
    257 msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
    258 
    259 msgid "An error occurred while clearing logs."
    260 msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
    261 
    262 msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
    263 msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Lade die Seite neu, um die Tabellengrößen zu prüfen."
    264 
    265 msgid "An error occurred during cleanup."
    266 msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
    267 
    268 msgid "Retrying…"
    269 msgstr "Erneuter Versuch…"
  • ws-action-scheduler-cleaner/trunk/languages/ws-action-scheduler-cleaner-de_CH.po

    r3750500 r3798362  
     1#
    12msgid ""
    23msgstr ""
    34"Project-Id-Version: WS Action Scheduler Cleaner\n"
    4 "Report-Msgid-Bugs-To: \n"
    5 "POT-Creation-Date: 2024-10-10 12:00+0000\n"
    6 "PO-Revision-Date: 2025-11-24 18:00+0100\n"
     5"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/ws-action-scheduler-cleaner\n"
     6"POT-Creation-Date: 2026-11-10T20:25:22+00:00\n"
     7"PO-Revision-Date: 2026-11-10 12:00+0000\n"
    78"Last-Translator: Marco Brack <mbrack@winning-solutions.de>\n"
    89"Language-Team: \n"
    … …  
    1415"X-Generator: Poedit 3.8\n"
    1516
     17#. Plugin Name of the plugin
     18#: ws-action-scheduler-cleaner.php includes/class-wsacsc-admin.php:70 includes/class-wsacsc-admin.php:149 includes/class-wsacsc-admin.php:156
    1619msgid "WS Action Scheduler Cleaner"
    1720msgstr "WS Action Scheduler Cleaner"
    1821
     22#. Description of the plugin
     23#: ws-action-scheduler-cleaner.php
     24msgid "Suffering from database bloat? Try cleaning up the Action Scheduler tables through an easy-to-understand GUI."
     25msgstr "Leidet Ihre Datenbank unter aufgeblähten Tabellen? Bereinigen Sie die Action-Scheduler-Tabellen über eine leicht verständliche Oberfläche."
     26
     27#. Author of the plugin
     28#: ws-action-scheduler-cleaner.php
     29msgid "Winning Solutions - Nagel & Mäder GbR"
     30msgstr "Winning Solutions - Nagel & Mäder GbR"
     31
     32#. Author URI of the plugin
     33#: ws-action-scheduler-cleaner.php
     34msgid "https://www.winning-solutions.de"
     35msgstr "https://www.winning-solutions.de"
     36
     37#: includes/class-wsacsc-admin.php:40
     38msgid "Settings"
     39msgstr "Einstellungen"
     40
     41#: includes/class-wsacsc-admin.php:71
     42msgid "WS AS Cleaner"
     43msgstr "WS AS Cleaner"
     44
     45#: includes/class-wsacsc-admin.php:118 includes/class-wsacsc-ajax.php:108 includes/class-wsacsc-ajax.php:314
     46msgid "Please select at least one status to clear."
     47msgstr "Bitte wählen Sie mindestens einen Status zum Bereinigen aus."
     48
     49#: includes/class-wsacsc-admin.php:119 includes/helpers.php:337
     50msgid "Clearing in progress..."
     51msgstr "Bereinigung läuft..."
     52
     53#: includes/class-wsacsc-admin.php:120
     54msgid "Please wait..."
     55msgstr "Bitte warten Sie..."
     56
     57#: includes/class-wsacsc-admin.php:121
     58msgid "An error occurred. Please try again."
     59msgstr "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
     60
     61#: includes/class-wsacsc-admin.php:122 includes/class-wsacsc-ajax.php:138
     62msgid "Selected actions cleared successfully!"
     63msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
     64
     65#: includes/class-wsacsc-admin.php:123 includes/class-wsacsc-ajax.php:180 includes/class-wsacsc-ajax.php:197
     66msgid "Logs cleared successfully!"
     67msgstr "Protokolle erfolgreich bereinigt!"
     68
     69#: includes/class-wsacsc-admin.php:124 includes/class-wsacsc-ajax.php:295
     70msgid "Schedule saved successfully!"
     71msgstr "Zeitplan erfolgreich gespeichert!"
     72
     73#: includes/class-wsacsc-admin.php:125 includes/class-wsacsc-ajax.php:319
     74msgid "Statuses saved successfully!"
     75msgstr "Status erfolgreich gespeichert!"
     76
     77#: includes/class-wsacsc-admin.php:126
     78msgid "Optimizing table..."
     79msgstr "Tabelle wird optimiert..."
     80
     81#: includes/class-wsacsc-admin.php:127 includes/class-wsacsc-admin.php:189 includes/class-wsacsc-admin.php:191 includes/class-wsacsc-admin.php:197 includes/class-wsacsc-admin.php:199
     82msgid "Loading..."
     83msgstr "Wird geladen..."
     84
     85#: includes/class-wsacsc-admin.php:128 includes/class-wsacsc-ajax.php:382
     86msgid "Table optimization failed."
     87msgstr "Tabellenoptimierung fehlgeschlagen."
     88
     89#: includes/class-wsacsc-admin.php:129
     90msgid "Please fix the highlighted fields before saving."
     91msgstr "Bitte korrigieren Sie die markierten Felder vor dem Speichern."
     92
     93#: includes/class-wsacsc-admin.php:130 includes/class-wsacsc-admin.php:192
     94msgid "Refresh actions table size"
     95msgstr "Grösse der Aktionstabelle aktualisieren"
     96
     97#: includes/class-wsacsc-admin.php:131 includes/class-wsacsc-admin.php:200
     98msgid "Refresh logs table size"
     99msgstr "Grösse der Protokolltabelle aktualisieren"
     100
     101#: includes/class-wsacsc-admin.php:132
     102msgid "Retrying…"
     103msgstr "Erneuter Versuch…"
     104
     105#: includes/class-wsacsc-admin.php:150
     106msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
     107msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stellen Sie sicher, dass Action Scheduler ordnungsgemäss installiert und aktiviert ist."
     108
     109#: includes/class-wsacsc-admin.php:159
    19110msgid "This tool allows you to clean up the Action Scheduler tables in your WordPress database. Action Scheduler is a library used by many plugins to schedule background tasks."
    20111msgstr "Dieses Tool ermöglicht es Ihnen, die Action Scheduler-Tabellen in Ihrer WordPress-Datenbank zu bereinigen. Action Scheduler ist eine Bibliothek, die von vielen Plugins zur Planung von Hintergrundaufgaben verwendet wird."
    21112
    22 msgid "Please wait..."
    23 msgstr "Bitte warten Sie..."
    24 
    25 msgid "Loading..."
    26 msgstr "Wird geladen..."
    27 
     113#: includes/class-wsacsc-admin.php:160
    28114msgid "The Action Scheduler uses two main tables:"
    29115msgstr "Der Action Scheduler verwendet zwei Haupttabellen:"
    30116
     117#: includes/class-wsacsc-admin.php:162
    31118msgid "Actions Table: Stores scheduled actions and their statuses."
    32119msgstr "Aktionstabelle: Speichert geplante Aktionen und deren Status."
    33120
     121#: includes/class-wsacsc-admin.php:163
    34122msgid "Logs Table: Stores logs of action executions."
    35123msgstr "Protokolltabelle: Speichert Protokolle von Aktionsausführungen."
    36124
     125#: includes/class-wsacsc-admin.php:165
    37126msgid "Clearing these tables is generally safe and can improve database performance. However, please note:"
    38127msgstr "Das Bereinigen dieser Tabellen ist im Allgemeinen sicher und kann die Datenbankleistung verbessern. Bitte beachten Sie jedoch:"
    39128
     129#: includes/class-wsacsc-admin.php:167
    40130msgid "Clearing can take a while depending on the size of the tables."
    41131msgstr "Die Bereinigung kann je nach Grösse der Tabellen eine Weile dauern."
    42132
     133#: includes/class-wsacsc-admin.php:168
    43134msgid "Cleared data will be permanently deleted."
    44135msgstr "Bereinigte Daten werden dauerhaft gelöscht."
    45136
     137#: includes/class-wsacsc-admin.php:169
    46138msgid "It's recommended to <strong>make a backup</strong> before proceeding."
    47139msgstr "Es wird empfohlen, vor dem Fortfahren ein <strong>Backup zu erstellen</strong>."
    48140
     141#: includes/class-wsacsc-admin.php:170
    49142msgid "Clearing completed, failed, or canceled actions usually doesn't affect WordPress functionality."
    50143msgstr "Das Bereinigen von abgeschlossenen, fehlgeschlagenen oder abgebrochenen Aktionen beeinträchtigt normalerweise nicht die WordPress-Funktionalität."
    51144
     145#. translators: %s: URL to Action Scheduler admin page
     146#: includes/class-wsacsc-admin.php:177
     147#, php-format
    52148msgid "For more information, visit the <a href=\"%s\">Action Scheduler admin page</a>."
    53149msgstr "Weitere Informationen finden Sie auf der <a href=\"%s\">Action Scheduler-Administrationsseite</a>."
    54150
     151#: includes/class-wsacsc-admin.php:186
    55152msgid "Current Table Sizes:"
    56153msgstr "Aktuelle Tabellengrössen:"
    57154
     155#: includes/class-wsacsc-admin.php:188
    58156msgid "Actions table:"
    59157msgstr "Aktionstabelle:"
    60158
     159#: includes/class-wsacsc-admin.php:190 includes/class-wsacsc-admin.php:198
    61160msgid "rows"
    62161msgstr "Zeilen"
    63162
     163#: includes/class-wsacsc-admin.php:196
    64164msgid "Logs table:"
    65165msgstr "Protokolltabelle:"
    66166
     167#: includes/class-wsacsc-admin.php:207
    67168msgid "Clear Action Statuses"
    68169msgstr "Aktionsstatus bereinigen"
    69170
    70 msgid "Select which action statuses to clear:"
    71 msgstr "Wählen Sie aus, welche Aktionsstatus bereinigt werden sollen:"
    72 
     171#: includes/class-wsacsc-admin.php:209
     172msgid "Action statuses to clear"
     173msgstr "Zu bereinigende Aktionsstatus"
     174
     175#: includes/class-wsacsc-admin.php:210
    73176msgid "Select which statuses to remove when clearing manually, when this plugin runs scheduled action cleanup, and (if this plugin’s action cleanup schedule is disabled) which statuses Action Scheduler may delete in the background:"
    74177msgstr "Wählen Sie aus, welche Status bei manueller Bereinigung, bei der geplanten Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) bei der Hintergrundbereinigung von Action Scheduler entfernt werden sollen:"
    75178
     179#: includes/class-wsacsc-admin.php:217
    76180msgid "Complete"
    77181msgstr "Abgeschlossen"
    78182
     183#: includes/class-wsacsc-admin.php:218
    79184msgid "Failed"
    80185msgstr "Fehlgeschlagen"
    81186
     187#: includes/class-wsacsc-admin.php:219
    82188msgid "Canceled"
    83189msgstr "Abgebrochen"
    84190
     191#: includes/class-wsacsc-admin.php:221
    85192msgid "Clear Selected Actions"
    86193msgstr "Ausgewählte Aktionen bereinigen"
    87194
     195#: includes/class-wsacsc-admin.php:226
    88196msgid "Clear Logs Table"
    89197msgstr "Protokolltabelle bereinigen"
    90198
     199#: includes/class-wsacsc-admin.php:227
    91200msgid "This will clear all entries in the logs table."
    92201msgstr "Dies wird alle Einträge in der Protokolltabelle löschen."
    93202
     203#: includes/class-wsacsc-admin.php:228
    94204msgid "Clear Logs"
    95205msgstr "Protokolle bereinigen"
    96206
     207#: includes/class-wsacsc-admin.php:232
     208msgid "Optimize Tables"
     209msgstr "Tabellen optimieren"
     210
     211#: includes/class-wsacsc-admin.php:233
     212msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
     213msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
     214
     215#: includes/class-wsacsc-admin.php:235
     216msgid "Optimize Actions Table"
     217msgstr "Aktionstabelle optimieren"
     218
     219#: includes/class-wsacsc-admin.php:236
     220msgid "Optimize Logs Table"
     221msgstr "Protokolltabelle optimieren"
     222
     223#: includes/class-wsacsc-admin.php:241
    97224msgid "Scheduling Options"
    98225msgstr "Planungsoptionen"
    99226
    100 msgid "Set up automatic clearing schedules for selected statuses (set to 0 to clean fully; leave empty to disable automatic clearing):"
    101 msgstr "Richten Sie automatische Bereinigungspläne für ausgewählte Status ein (auf 0 setzen, um vollständig zu bereinigen; leer lassen, um die automatische Bereinigung zu deaktivieren):"
    102 
    103 msgid "Clear logs older than:"
    104 msgstr "Protokolle bereinigen, die älter sind als:"
    105 
     227#: includes/class-wsacsc-admin.php:242
     228msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
     229msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
     230
     231#: includes/class-wsacsc-admin.php:243
     232msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
     233msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
     234
     235#: includes/class-wsacsc-admin.php:244
     236msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
     237msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
     238
     239#: includes/class-wsacsc-admin.php:245
     240msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
     241msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
     242
     243#: includes/class-wsacsc-admin.php:246
     244msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
     245msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr grossem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
     246
     247#: includes/class-wsacsc-admin.php:249
     248msgid "Action Statuses"
     249msgstr "Aktionsstatus"
     250
     251#: includes/class-wsacsc-admin.php:251 includes/class-wsacsc-admin.php:277
     252msgid "Cleanup Schedule:"
     253msgstr "Bereinigungszeitplan:"
     254
     255#: includes/class-wsacsc-admin.php:254 includes/class-wsacsc-admin.php:269 includes/class-wsacsc-admin.php:280 includes/class-wsacsc-admin.php:295
    106256msgid "days"
    107257msgstr "Tage"
    108258
    109 msgid "Clear action statuses older than:"
    110 msgstr "Aktionsstatus bereinigen, die älter sind als:"
    111 
     259#: includes/class-wsacsc-admin.php:256
     260msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
     261msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
     262
     263#: includes/class-wsacsc-admin.php:259 includes/class-wsacsc-admin.php:285
     264msgid "Schedule Time:"
     265msgstr "Zeitplan:"
     266
     267#: includes/class-wsacsc-admin.php:263
     268msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
     269msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
     270
     271#: includes/class-wsacsc-admin.php:266 includes/class-wsacsc-admin.php:292
     272msgid "Retention Period:"
     273msgstr "Aufbewahrungsfrist:"
     274
     275#: includes/class-wsacsc-admin.php:271
     276msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
     277msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
     278
     279#: includes/class-wsacsc-admin.php:275
     280msgid "Logs"
     281msgstr "Protokolle"
     282
     283#: includes/class-wsacsc-admin.php:282
     284msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
     285msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
     286
     287#: includes/class-wsacsc-admin.php:289
     288msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
     289msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
     290
     291#: includes/class-wsacsc-admin.php:297
     292msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
     293msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
     294
     295#: includes/class-wsacsc-admin.php:301
    112296msgid "Save Schedule"
    113297msgstr "Zeitplan speichern"
    114298
     299#: includes/class-wsacsc-admin.php:307
    115300msgid "Powered by Winning Solutions"
    116301msgstr "Powered by Winning Solutions"
    117302
    118 msgid "Selected actions cleared successfully!"
    119 msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
    120 
    121 msgid "Logs cleared successfully!"
    122 msgstr "Protokolle erfolgreich bereinigt!"
    123 
    124 msgid "Schedule saved successfully!"
    125 msgstr "Zeitplan erfolgreich gespeichert!"
    126 
     303#: includes/class-wsacsc-ajax.php:37
     304msgid "Another cleanup or optimization is already running. Please wait until it finishes."
     305msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warten Sie, bis sie abgeschlossen ist."
     306
     307#: includes/class-wsacsc-ajax.php:81 includes/class-wsacsc-ajax.php:96 includes/class-wsacsc-ajax.php:150 includes/class-wsacsc-ajax.php:209 includes/class-wsacsc-ajax.php:305 includes/class-wsacsc-ajax.php:329 includes/class-wsacsc-ajax.php:356 includes/class-wsacsc-ajax.php:404
     308msgid "Insufficient permissions."
     309msgstr "Unzureichende Berechtigungen."
     310
     311#: includes/class-wsacsc-ajax.php:112 includes/class-wsacsc-ajax.php:156
     312msgid "Action Scheduler tables do not exist."
     313msgstr "Die Action-Scheduler-Tabellen existieren nicht."
     314
     315#: includes/class-wsacsc-ajax.php:131
     316msgid "An error occurred while clearing actions."
     317msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
     318
     319#: includes/class-wsacsc-ajax.php:190
     320msgid "An error occurred while clearing logs."
     321msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
     322
     323#: includes/class-wsacsc-ajax.php:230
     324msgid "Actions schedule interval must be empty or between 1 and 365 days."
     325msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     326
     327#: includes/class-wsacsc-ajax.php:234
     328msgid "Logs schedule interval must be empty or between 1 and 365 days."
     329msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     330
     331#: includes/class-wsacsc-ajax.php:238
     332msgid "Actions schedule time must be in HH:MM format."
     333msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
     334
     335#: includes/class-wsacsc-ajax.php:242
     336msgid "Logs schedule time must be in HH:MM format."
     337msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
     338
     339#: includes/class-wsacsc-ajax.php:246
     340msgid "Actions retention period is required and must be between 0 and 365 days."
     341msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     342
     343#: includes/class-wsacsc-ajax.php:250
     344msgid "Logs retention period is required and must be between 0 and 365 days."
     345msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     346
     347#: includes/class-wsacsc-ajax.php:288
     348msgid "Failed to save schedule. Please try again."
     349msgstr "Der Zeitplan konnte nicht gespeichert werden. Bitte versuchen Sie es erneut."
     350
     351#: includes/class-wsacsc-ajax.php:292
    127352msgid "The settings were saved, but the cleanup schedule could not be updated yet. The plugin will retry automatically."
    128353msgstr "Die Einstellungen wurden gespeichert, aber der Bereinigungszeitplan konnte noch nicht aktualisiert werden. Das Plugin versucht es automatisch erneut."
    129354
    130 msgid "Statuses saved successfully!"
    131 msgstr "Status erfolgreich gespeichert!"
    132 
    133 msgid "Settings"
    134 msgstr "Einstellungen"
    135 
    136 msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
    137 msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stellen Sie sicher, dass Action Scheduler ordnungsgemäss installiert und aktiviert ist."
    138 
    139 msgid "Please select at least one status to clear."
    140 msgstr "Bitte wählen Sie mindestens einen Status zum Bereinigen aus."
    141 
    142 msgid "Clearing in progress..."
    143 msgstr "Bereinigung läuft..."
    144 
    145 msgid "An error occurred. Please try again."
    146 msgstr "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
    147 
    148 msgid "Optimize Tables"
    149 msgstr "Tabellen optimieren"
    150 
    151 msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
    152 msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
    153 
    154 msgid "Optimize Actions Table"
    155 msgstr "Aktionstabelle optimieren"
    156 
    157 msgid "Optimize Logs Table"
    158 msgstr "Protokolltabelle optimieren"
    159 
    160 msgid "Optimizing table..."
    161 msgstr "Tabelle wird optimiert..."
    162 
     355#: includes/class-wsacsc-ajax.php:336 includes/class-wsacsc-ajax.php:363
     356msgid "Invalid table type."
     357msgstr "Ungültiger Tabellentyp."
     358
     359#. translators: %s: table type (actions or logs).
     360#: includes/class-wsacsc-ajax.php:390
     361#, php-format
    163362msgid "%s table optimized successfully!"
    164363msgstr "%s-Tabelle erfolgreich optimiert!"
    165364
    166 msgid "Table optimization failed."
    167 msgstr "Tabellenoptimierung fehlgeschlagen."
    168 
    169 msgid "Table does not exist."
    170 msgstr "Tabelle existiert nicht."
    171 
    172 msgid "Invalid table type."
    173 msgstr "Ungültiger Tabellentyp."
    174 
    175 msgid "Insufficient permissions."
    176 msgstr "Unzureichende Berechtigungen."
    177 
    178 msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
    179 msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
    180 
    181 msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
    182 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
    183 
    184 msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
    185 msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
    186 
    187 msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
    188 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
    189 
    190 msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
    191 msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr großem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
    192 
    193 msgid "Action Statuses"
    194 msgstr "Aktionsstatus"
    195 
    196 msgid "Cleanup Schedule:"
    197 msgstr "Bereinigungszeitplan:"
    198 
    199 msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
    200 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
    201 
    202 msgid "Schedule Time:"
    203 msgstr "Zeitplan:"
    204 
    205 msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
    206 msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
    207 
    208 msgid "Retention Period:"
    209 msgstr "Aufbewahrungsfrist:"
    210 
    211 msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
    212 msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
    213 
    214 msgid "Logs"
    215 msgstr "Protokolle"
    216 
    217 msgid "How often to run cleanup (empty or 0 = disabled, 1-365 days)."
    218 msgstr "Wie oft die Bereinigung ausgeführt wird (leer oder 0 = deaktiviert, 1–365 Tage)."
    219 
    220 msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
    221 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
    222 
    223 msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
    224 msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
    225 
    226 msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
    227 msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
    228 
    229 msgid "Actions schedule interval must be empty or between 1 and 365 days."
    230 msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    231 
    232 msgid "Logs schedule interval must be empty or between 1 and 365 days."
    233 msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    234 
    235 msgid "Actions schedule time must be in HH:MM format."
    236 msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
    237 
    238 msgid "Logs schedule time must be in HH:MM format."
    239 msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
    240 
    241 msgid "Actions retention period is required and must be between 0 and 365 days."
    242 msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    243 
    244 msgid "Logs retention period is required and must be between 0 and 365 days."
    245 msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    246 
     365#: includes/class-wsacsc-ajax.php:411
     366msgid "Invalid cleanup ID."
     367msgstr "Ungültige Bereinigungs-ID."
     368
     369#: includes/class-wsacsc-ajax.php:427
     370msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
     371msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Laden Sie die Seite neu, um die Tabellengrössen zu prüfen."
     372
     373#: includes/class-wsacsc-ajax.php:435
     374msgid "Invalid cleanup progress data."
     375msgstr "Ungültige Fortschrittsdaten der Bereinigung."
     376
     377#: includes/class-wsacsc-ajax.php:441
     378msgid "An error occurred during cleanup."
     379msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
     380
     381#: includes/class-wsacsc-ajax.php:453
     382msgid "Cleanup completed successfully!"
     383msgstr "Bereinigung erfolgreich abgeschlossen!"
     384
     385#. translators: %d: number of days.
     386#: includes/class-wsacsc-scheduler.php:245
     387#, php-format
     388msgid "Every %d day"
     389msgid_plural "Every %d days"
     390msgstr[0] "Jeden Tag"
     391msgstr[1] "Alle %d Tage"
     392
     393#. translators: 1: rows deleted so far, 2: rows to delete in total, 3: percentage done.
     394#: includes/helpers.php:329
     395#, php-format
     396msgid "Clearing in progress… %1$s of %2$s rows deleted (%3$d%%)."
     397msgstr "Bereinigung läuft… %1$s von %2$s Zeilen gelöscht (%3$d %%)."
     398
     399#. translators: %s: number of rows deleted so far.
     400#: includes/helpers.php:342
     401#, php-format
    247402msgid "Clearing in progress… %s rows deleted so far."
    248403msgstr "Bereinigung läuft… bisher %s Zeilen gelöscht."
    249 
    250 msgid "Cleanup completed successfully!"
    251 msgstr "Bereinigung erfolgreich abgeschlossen!"
    252 
    253 msgid "Another cleanup or optimization is already running. Please wait until it finishes."
    254 msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warten Sie, bis sie abgeschlossen ist."
    255 
    256 msgid "An error occurred while clearing actions."
    257 msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
    258 
    259 msgid "An error occurred while clearing logs."
    260 msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
    261 
    262 msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
    263 msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Laden Sie die Seite neu, um die Tabellengrößen zu prüfen."
    264 
    265 msgid "An error occurred during cleanup."
    266 msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
    267 
    268 msgid "Retrying…"
    269 msgstr "Erneuter Versuch…"
  • ws-action-scheduler-cleaner/trunk/languages/ws-action-scheduler-cleaner-de_CH_informal.po

    r3750500 r3798362  
     1#
    12msgid ""
    23msgstr ""
    34"Project-Id-Version: WS Action Scheduler Cleaner\n"
    4 "Report-Msgid-Bugs-To: \n"
    5 "POT-Creation-Date: 2024-10-10 12:00+0000\n"
    6 "PO-Revision-Date: 2025-11-24 18:00+0100\n"
     5"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/ws-action-scheduler-cleaner\n"
     6"POT-Creation-Date: 2026-11-10T20:25:22+00:00\n"
     7"PO-Revision-Date: 2026-11-10 12:00+0000\n"
    78"Last-Translator: Marco Brack <mbrack@winning-solutions.de>\n"
    89"Language-Team: \n"
    … …  
    1415"X-Generator: Poedit 3.8\n"
    1516
     17#. Plugin Name of the plugin
     18#: ws-action-scheduler-cleaner.php includes/class-wsacsc-admin.php:70 includes/class-wsacsc-admin.php:149 includes/class-wsacsc-admin.php:156
    1619msgid "WS Action Scheduler Cleaner"
    1720msgstr "WS Action Scheduler Cleaner"
    1821
     22#. Description of the plugin
     23#: ws-action-scheduler-cleaner.php
     24msgid "Suffering from database bloat? Try cleaning up the Action Scheduler tables through an easy-to-understand GUI."
     25msgstr "Leidet deine Datenbank unter aufgeblähten Tabellen? Bereinige die Action-Scheduler-Tabellen über eine leicht verständliche Oberfläche."
     26
     27#. Author of the plugin
     28#: ws-action-scheduler-cleaner.php
     29msgid "Winning Solutions - Nagel & Mäder GbR"
     30msgstr "Winning Solutions - Nagel & Mäder GbR"
     31
     32#. Author URI of the plugin
     33#: ws-action-scheduler-cleaner.php
     34msgid "https://www.winning-solutions.de"
     35msgstr "https://www.winning-solutions.de"
     36
     37#: includes/class-wsacsc-admin.php:40
     38msgid "Settings"
     39msgstr "Einstellungen"
     40
     41#: includes/class-wsacsc-admin.php:71
     42msgid "WS AS Cleaner"
     43msgstr "WS AS Cleaner"
     44
     45#: includes/class-wsacsc-admin.php:118 includes/class-wsacsc-ajax.php:108 includes/class-wsacsc-ajax.php:314
     46msgid "Please select at least one status to clear."
     47msgstr "Bitte wähle mindestens einen Status zum Bereinigen aus."
     48
     49#: includes/class-wsacsc-admin.php:119 includes/helpers.php:337
     50msgid "Clearing in progress..."
     51msgstr "Bereinigung läuft..."
     52
     53#: includes/class-wsacsc-admin.php:120
     54msgid "Please wait..."
     55msgstr "Bitte warte..."
     56
     57#: includes/class-wsacsc-admin.php:121
     58msgid "An error occurred. Please try again."
     59msgstr "Ein Fehler ist aufgetreten. Bitte versuche es erneut."
     60
     61#: includes/class-wsacsc-admin.php:122 includes/class-wsacsc-ajax.php:138
     62msgid "Selected actions cleared successfully!"
     63msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
     64
     65#: includes/class-wsacsc-admin.php:123 includes/class-wsacsc-ajax.php:180 includes/class-wsacsc-ajax.php:197
     66msgid "Logs cleared successfully!"
     67msgstr "Protokolle erfolgreich bereinigt!"
     68
     69#: includes/class-wsacsc-admin.php:124 includes/class-wsacsc-ajax.php:295
     70msgid "Schedule saved successfully!"
     71msgstr "Zeitplan erfolgreich gespeichert!"
     72
     73#: includes/class-wsacsc-admin.php:125 includes/class-wsacsc-ajax.php:319
     74msgid "Statuses saved successfully!"
     75msgstr "Status erfolgreich gespeichert!"
     76
     77#: includes/class-wsacsc-admin.php:126
     78msgid "Optimizing table..."
     79msgstr "Tabelle wird optimiert..."
     80
     81#: includes/class-wsacsc-admin.php:127 includes/class-wsacsc-admin.php:189 includes/class-wsacsc-admin.php:191 includes/class-wsacsc-admin.php:197 includes/class-wsacsc-admin.php:199
     82msgid "Loading..."
     83msgstr "Wird geladen..."
     84
     85#: includes/class-wsacsc-admin.php:128 includes/class-wsacsc-ajax.php:382
     86msgid "Table optimization failed."
     87msgstr "Tabellenoptimierung fehlgeschlagen."
     88
     89#: includes/class-wsacsc-admin.php:129
     90msgid "Please fix the highlighted fields before saving."
     91msgstr "Bitte korrigiere die markierten Felder vor dem Speichern."
     92
     93#: includes/class-wsacsc-admin.php:130 includes/class-wsacsc-admin.php:192
     94msgid "Refresh actions table size"
     95msgstr "Grösse der Aktionstabelle aktualisieren"
     96
     97#: includes/class-wsacsc-admin.php:131 includes/class-wsacsc-admin.php:200
     98msgid "Refresh logs table size"
     99msgstr "Grösse der Protokolltabelle aktualisieren"
     100
     101#: includes/class-wsacsc-admin.php:132
     102msgid "Retrying…"
     103msgstr "Erneuter Versuch…"
     104
     105#: includes/class-wsacsc-admin.php:150
     106msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
     107msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stelle sicher, dass Action Scheduler ordnungsgemäss installiert und aktiviert ist."
     108
     109#: includes/class-wsacsc-admin.php:159
    19110msgid "This tool allows you to clean up the Action Scheduler tables in your WordPress database. Action Scheduler is a library used by many plugins to schedule background tasks."
    20111msgstr "Dieses Tool ermöglicht es dir, die Action Scheduler-Tabellen in deiner WordPress-Datenbank zu bereinigen. Action Scheduler ist eine Bibliothek, die von vielen Plugins zur Planung von Hintergrundaufgaben verwendet wird."
    21112
    22 msgid "Please wait..."
    23 msgstr "Bitte warte..."
    24 
    25 msgid "Loading..."
    26 msgstr "Wird geladen..."
    27 
     113#: includes/class-wsacsc-admin.php:160
    28114msgid "The Action Scheduler uses two main tables:"
    29115msgstr "Der Action Scheduler verwendet zwei Haupttabellen:"
    30116
     117#: includes/class-wsacsc-admin.php:162
    31118msgid "Actions Table: Stores scheduled actions and their statuses."
    32119msgstr "Aktionstabelle: Speichert geplante Aktionen und deren Status."
    33120
     121#: includes/class-wsacsc-admin.php:163
    34122msgid "Logs Table: Stores logs of action executions."
    35123msgstr "Protokolltabelle: Speichert Protokolle von Aktionsausführungen."
    36124
     125#: includes/class-wsacsc-admin.php:165
    37126msgid "Clearing these tables is generally safe and can improve database performance. However, please note:"
    38127msgstr "Das Bereinigen dieser Tabellen ist im Allgemeinen sicher und kann die Datenbankleistung verbessern. Bitte beachte jedoch:"
    39128
     129#: includes/class-wsacsc-admin.php:167
    40130msgid "Clearing can take a while depending on the size of the tables."
    41131msgstr "Die Bereinigung kann je nach Grösse der Tabellen eine Weile dauern."
    42132
     133#: includes/class-wsacsc-admin.php:168
    43134msgid "Cleared data will be permanently deleted."
    44135msgstr "Bereinigte Daten werden dauerhaft gelöscht."
    45136
     137#: includes/class-wsacsc-admin.php:169
    46138msgid "It's recommended to <strong>make a backup</strong> before proceeding."
    47139msgstr "Es wird empfohlen, vor dem Fortfahren ein <strong>Backup zu erstellen</strong>."
    48140
     141#: includes/class-wsacsc-admin.php:170
    49142msgid "Clearing completed, failed, or canceled actions usually doesn't affect WordPress functionality."
    50143msgstr "Das Bereinigen von abgeschlossenen, fehlgeschlagenen oder abgebrochenen Aktionen beeinträchtigt normalerweise nicht die WordPress-Funktionalität."
    51144
     145#. translators: %s: URL to Action Scheduler admin page
     146#: includes/class-wsacsc-admin.php:177
     147#, php-format
    52148msgid "For more information, visit the <a href=\"%s\">Action Scheduler admin page</a>."
    53149msgstr "Weitere Informationen findest du auf der <a href=\"%s\">Action Scheduler-Administrationsseite</a>."
    54150
     151#: includes/class-wsacsc-admin.php:186
    55152msgid "Current Table Sizes:"
    56153msgstr "Aktuelle Tabellengrössen:"
    57154
     155#: includes/class-wsacsc-admin.php:188
    58156msgid "Actions table:"
    59157msgstr "Aktionstabelle:"
    60158
     159#: includes/class-wsacsc-admin.php:190 includes/class-wsacsc-admin.php:198
    61160msgid "rows"
    62161msgstr "Zeilen"
    63162
     163#: includes/class-wsacsc-admin.php:196
    64164msgid "Logs table:"
    65165msgstr "Protokolltabelle:"
    66166
     167#: includes/class-wsacsc-admin.php:207
    67168msgid "Clear Action Statuses"
    68169msgstr "Aktionsstatus bereinigen"
    69170
    70 msgid "Select which action statuses to clear:"
    71 msgstr "Wähle aus, welche Aktionsstatus bereinigt werden sollen:"
    72 
     171#: includes/class-wsacsc-admin.php:209
     172msgid "Action statuses to clear"
     173msgstr "Zu bereinigende Aktionsstatus"
     174
     175#: includes/class-wsacsc-admin.php:210
    73176msgid "Select which statuses to remove when clearing manually, when this plugin runs scheduled action cleanup, and (if this plugin’s action cleanup schedule is disabled) which statuses Action Scheduler may delete in the background:"
    74177msgstr "Wähle aus, welche Status bei manueller Bereinigung, bei der geplanten Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) bei der Hintergrundbereinigung von Action Scheduler entfernt werden sollen:"
    75178
     179#: includes/class-wsacsc-admin.php:217
    76180msgid "Complete"
    77181msgstr "Abgeschlossen"
    78182
     183#: includes/class-wsacsc-admin.php:218
    79184msgid "Failed"
    80185msgstr "Fehlgeschlagen"
    81186
     187#: includes/class-wsacsc-admin.php:219
    82188msgid "Canceled"
    83189msgstr "Abgebrochen"
    84190
     191#: includes/class-wsacsc-admin.php:221
    85192msgid "Clear Selected Actions"
    86193msgstr "Ausgewählte Aktionen bereinigen"
    87194
     195#: includes/class-wsacsc-admin.php:226
    88196msgid "Clear Logs Table"
    89197msgstr "Protokolltabelle bereinigen"
    90198
     199#: includes/class-wsacsc-admin.php:227
    91200msgid "This will clear all entries in the logs table."
    92201msgstr "Dies wird alle Einträge in der Protokolltabelle löschen."
    93202
     203#: includes/class-wsacsc-admin.php:228
    94204msgid "Clear Logs"
    95205msgstr "Protokolle bereinigen"
    96206
     207#: includes/class-wsacsc-admin.php:232
     208msgid "Optimize Tables"
     209msgstr "Tabellen optimieren"
     210
     211#: includes/class-wsacsc-admin.php:233
     212msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
     213msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
     214
     215#: includes/class-wsacsc-admin.php:235
     216msgid "Optimize Actions Table"
     217msgstr "Aktionstabelle optimieren"
     218
     219#: includes/class-wsacsc-admin.php:236
     220msgid "Optimize Logs Table"
     221msgstr "Protokolltabelle optimieren"
     222
     223#: includes/class-wsacsc-admin.php:241
    97224msgid "Scheduling Options"
    98225msgstr "Planungsoptionen"
    99226
    100 msgid "Set up automatic clearing schedules for selected statuses (set to 0 to clean fully; leave empty to disable automatic clearing):"
    101 msgstr "Richte automatische Bereinigungspläne für ausgewählte Status ein (auf 0 setzen, um vollständig zu bereinigen; leer lassen, um die automatische Bereinigung zu deaktivieren):"
    102 
    103 msgid "Clear logs older than:"
    104 msgstr "Protokolle bereinigen, die älter sind als:"
    105 
     227#: includes/class-wsacsc-admin.php:242
     228msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
     229msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
     230
     231#: includes/class-wsacsc-admin.php:243
     232msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
     233msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
     234
     235#: includes/class-wsacsc-admin.php:244
     236msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
     237msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
     238
     239#: includes/class-wsacsc-admin.php:245
     240msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
     241msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
     242
     243#: includes/class-wsacsc-admin.php:246
     244msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
     245msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr grossem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
     246
     247#: includes/class-wsacsc-admin.php:249
     248msgid "Action Statuses"
     249msgstr "Aktionsstatus"
     250
     251#: includes/class-wsacsc-admin.php:251 includes/class-wsacsc-admin.php:277
     252msgid "Cleanup Schedule:"
     253msgstr "Bereinigungszeitplan:"
     254
     255#: includes/class-wsacsc-admin.php:254 includes/class-wsacsc-admin.php:269 includes/class-wsacsc-admin.php:280 includes/class-wsacsc-admin.php:295
    106256msgid "days"
    107257msgstr "Tage"
    108258
    109 msgid "Clear action statuses older than:"
    110 msgstr "Aktionsstatus bereinigen, die älter sind als:"
    111 
     259#: includes/class-wsacsc-admin.php:256
     260msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
     261msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
     262
     263#: includes/class-wsacsc-admin.php:259 includes/class-wsacsc-admin.php:285
     264msgid "Schedule Time:"
     265msgstr "Zeitplan:"
     266
     267#: includes/class-wsacsc-admin.php:263
     268msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
     269msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
     270
     271#: includes/class-wsacsc-admin.php:266 includes/class-wsacsc-admin.php:292
     272msgid "Retention Period:"
     273msgstr "Aufbewahrungsfrist:"
     274
     275#: includes/class-wsacsc-admin.php:271
     276msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
     277msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
     278
     279#: includes/class-wsacsc-admin.php:275
     280msgid "Logs"
     281msgstr "Protokolle"
     282
     283#: includes/class-wsacsc-admin.php:282
     284msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
     285msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
     286
     287#: includes/class-wsacsc-admin.php:289
     288msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
     289msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
     290
     291#: includes/class-wsacsc-admin.php:297
     292msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
     293msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
     294
     295#: includes/class-wsacsc-admin.php:301
    112296msgid "Save Schedule"
    113297msgstr "Zeitplan speichern"
    114298
     299#: includes/class-wsacsc-admin.php:307
    115300msgid "Powered by Winning Solutions"
    116301msgstr "Powered by Winning Solutions"
    117302
    118 msgid "Selected actions cleared successfully!"
    119 msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
    120 
    121 msgid "Logs cleared successfully!"
    122 msgstr "Protokolle erfolgreich bereinigt!"
    123 
    124 msgid "Schedule saved successfully!"
    125 msgstr "Zeitplan erfolgreich gespeichert!"
    126 
     303#: includes/class-wsacsc-ajax.php:37
     304msgid "Another cleanup or optimization is already running. Please wait until it finishes."
     305msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warte, bis sie abgeschlossen ist."
     306
     307#: includes/class-wsacsc-ajax.php:81 includes/class-wsacsc-ajax.php:96 includes/class-wsacsc-ajax.php:150 includes/class-wsacsc-ajax.php:209 includes/class-wsacsc-ajax.php:305 includes/class-wsacsc-ajax.php:329 includes/class-wsacsc-ajax.php:356 includes/class-wsacsc-ajax.php:404
     308msgid "Insufficient permissions."
     309msgstr "Unzureichende Berechtigungen."
     310
     311#: includes/class-wsacsc-ajax.php:112 includes/class-wsacsc-ajax.php:156
     312msgid "Action Scheduler tables do not exist."
     313msgstr "Die Action-Scheduler-Tabellen existieren nicht."
     314
     315#: includes/class-wsacsc-ajax.php:131
     316msgid "An error occurred while clearing actions."
     317msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
     318
     319#: includes/class-wsacsc-ajax.php:190
     320msgid "An error occurred while clearing logs."
     321msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
     322
     323#: includes/class-wsacsc-ajax.php:230
     324msgid "Actions schedule interval must be empty or between 1 and 365 days."
     325msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     326
     327#: includes/class-wsacsc-ajax.php:234
     328msgid "Logs schedule interval must be empty or between 1 and 365 days."
     329msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     330
     331#: includes/class-wsacsc-ajax.php:238
     332msgid "Actions schedule time must be in HH:MM format."
     333msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
     334
     335#: includes/class-wsacsc-ajax.php:242
     336msgid "Logs schedule time must be in HH:MM format."
     337msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
     338
     339#: includes/class-wsacsc-ajax.php:246
     340msgid "Actions retention period is required and must be between 0 and 365 days."
     341msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     342
     343#: includes/class-wsacsc-ajax.php:250
     344msgid "Logs retention period is required and must be between 0 and 365 days."
     345msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     346
     347#: includes/class-wsacsc-ajax.php:288
     348msgid "Failed to save schedule. Please try again."
     349msgstr "Der Zeitplan konnte nicht gespeichert werden. Bitte versuche es erneut."
     350
     351#: includes/class-wsacsc-ajax.php:292
    127352msgid "The settings were saved, but the cleanup schedule could not be updated yet. The plugin will retry automatically."
    128353msgstr "Die Einstellungen wurden gespeichert, aber der Bereinigungszeitplan konnte noch nicht aktualisiert werden. Das Plugin versucht es automatisch erneut."
    129354
    130 msgid "Statuses saved successfully!"
    131 msgstr "Status erfolgreich gespeichert!"
    132 
    133 msgid "Settings"
    134 msgstr "Einstellungen"
    135 
    136 msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
    137 msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stelle sicher, dass Action Scheduler ordnungsgemäß installiert und aktiviert ist."
    138 
    139 msgid "Please select at least one status to clear."
    140 msgstr "Bitte wähle mindestens einen Status zum Bereinigen aus."
    141 
    142 msgid "Clearing in progress..."
    143 msgstr "Bereinigung läuft..."
    144 
    145 msgid "An error occurred. Please try again."
    146 msgstr "Ein Fehler ist aufgetreten. Bitte versuche es erneut."
    147 
    148 msgid "Optimize Tables"
    149 msgstr "Tabellen optimieren"
    150 
    151 msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
    152 msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
    153 
    154 msgid "Optimize Actions Table"
    155 msgstr "Aktionstabelle optimieren"
    156 
    157 msgid "Optimize Logs Table"
    158 msgstr "Protokolltabelle optimieren"
    159 
    160 msgid "Optimizing table..."
    161 msgstr "Tabelle wird optimiert..."
    162 
     355#: includes/class-wsacsc-ajax.php:336 includes/class-wsacsc-ajax.php:363
     356msgid "Invalid table type."
     357msgstr "Ungültiger Tabellentyp."
     358
     359#. translators: %s: table type (actions or logs).
     360#: includes/class-wsacsc-ajax.php:390
     361#, php-format
    163362msgid "%s table optimized successfully!"
    164363msgstr "%s-Tabelle erfolgreich optimiert!"
    165364
    166 msgid "Table optimization failed."
    167 msgstr "Tabellenoptimierung fehlgeschlagen."
    168 
    169 msgid "Table does not exist."
    170 msgstr "Tabelle existiert nicht."
    171 
    172 msgid "Invalid table type."
    173 msgstr "Ungültiger Tabellentyp."
    174 
    175 msgid "Insufficient permissions."
    176 msgstr "Unzureichende Berechtigungen."
    177 
    178 msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
    179 msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
    180 
    181 msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
    182 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
    183 
    184 msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
    185 msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
    186 
    187 msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
    188 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
    189 
    190 msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
    191 msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr großem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
    192 
    193 msgid "Action Statuses"
    194 msgstr "Aktionsstatus"
    195 
    196 msgid "Cleanup Schedule:"
    197 msgstr "Bereinigungszeitplan:"
    198 
    199 msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
    200 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
    201 
    202 msgid "Schedule Time:"
    203 msgstr "Zeitplan:"
    204 
    205 msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
    206 msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
    207 
    208 msgid "Retention Period:"
    209 msgstr "Aufbewahrungsfrist:"
    210 
    211 msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
    212 msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
    213 
    214 msgid "Logs"
    215 msgstr "Protokolle"
    216 
    217 msgid "How often to run cleanup (empty or 0 = disabled, 1-365 days)."
    218 msgstr "Wie oft die Bereinigung ausgeführt wird (leer oder 0 = deaktiviert, 1–365 Tage)."
    219 
    220 msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
    221 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
    222 
    223 msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
    224 msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
    225 
    226 msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
    227 msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
    228 
    229 msgid "Actions schedule interval must be empty or between 1 and 365 days."
    230 msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    231 
    232 msgid "Logs schedule interval must be empty or between 1 and 365 days."
    233 msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    234 
    235 msgid "Actions schedule time must be in HH:MM format."
    236 msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
    237 
    238 msgid "Logs schedule time must be in HH:MM format."
    239 msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
    240 
    241 msgid "Actions retention period is required and must be between 0 and 365 days."
    242 msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    243 
    244 msgid "Logs retention period is required and must be between 0 and 365 days."
    245 msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    246 
     365#: includes/class-wsacsc-ajax.php:411
     366msgid "Invalid cleanup ID."
     367msgstr "Ungültige Bereinigungs-ID."
     368
     369#: includes/class-wsacsc-ajax.php:427
     370msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
     371msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Lade die Seite neu, um die Tabellengrössen zu prüfen."
     372
     373#: includes/class-wsacsc-ajax.php:435
     374msgid "Invalid cleanup progress data."
     375msgstr "Ungültige Fortschrittsdaten der Bereinigung."
     376
     377#: includes/class-wsacsc-ajax.php:441
     378msgid "An error occurred during cleanup."
     379msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
     380
     381#: includes/class-wsacsc-ajax.php:453
     382msgid "Cleanup completed successfully!"
     383msgstr "Bereinigung erfolgreich abgeschlossen!"
     384
     385#. translators: %d: number of days.
     386#: includes/class-wsacsc-scheduler.php:245
     387#, php-format
     388msgid "Every %d day"
     389msgid_plural "Every %d days"
     390msgstr[0] "Jeden Tag"
     391msgstr[1] "Alle %d Tage"
     392
     393#. translators: 1: rows deleted so far, 2: rows to delete in total, 3: percentage done.
     394#: includes/helpers.php:329
     395#, php-format
     396msgid "Clearing in progress… %1$s of %2$s rows deleted (%3$d%%)."
     397msgstr "Bereinigung läuft… %1$s von %2$s Zeilen gelöscht (%3$d %%)."
     398
     399#. translators: %s: number of rows deleted so far.
     400#: includes/helpers.php:342
     401#, php-format
    247402msgid "Clearing in progress… %s rows deleted so far."
    248403msgstr "Bereinigung läuft… bisher %s Zeilen gelöscht."
    249 
    250 msgid "Cleanup completed successfully!"
    251 msgstr "Bereinigung erfolgreich abgeschlossen!"
    252 
    253 msgid "Another cleanup or optimization is already running. Please wait until it finishes."
    254 msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warte, bis sie abgeschlossen ist."
    255 
    256 msgid "An error occurred while clearing actions."
    257 msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
    258 
    259 msgid "An error occurred while clearing logs."
    260 msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
    261 
    262 msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
    263 msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Lade die Seite neu, um die Tabellengrößen zu prüfen."
    264 
    265 msgid "An error occurred during cleanup."
    266 msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
    267 
    268 msgid "Retrying…"
    269 msgstr "Erneuter Versuch…"
  • ws-action-scheduler-cleaner/trunk/languages/ws-action-scheduler-cleaner-de_DE.po

    r3750500 r3798362  
     1#
    12msgid ""
    23msgstr ""
    34"Project-Id-Version: WS Action Scheduler Cleaner\n"
    4 "Report-Msgid-Bugs-To: \n"
    5 "POT-Creation-Date: 2024-10-10 12:00+0000\n"
    6 "PO-Revision-Date: 2025-11-24 18:00+0100\n"
     5"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/ws-action-scheduler-cleaner\n"
     6"POT-Creation-Date: 2026-11-10T20:25:22+00:00\n"
     7"PO-Revision-Date: 2026-11-10 12:00+0000\n"
    78"Last-Translator: Marco Brack <mbrack@winning-solutions.de>\n"
    89"Language-Team: \n"
    … …  
    1415"X-Generator: Poedit 3.8\n"
    1516
     17#. Plugin Name of the plugin
     18#: ws-action-scheduler-cleaner.php includes/class-wsacsc-admin.php:70 includes/class-wsacsc-admin.php:149 includes/class-wsacsc-admin.php:156
    1619msgid "WS Action Scheduler Cleaner"
    1720msgstr "WS Action Scheduler Cleaner"
    1821
     22#. Description of the plugin
     23#: ws-action-scheduler-cleaner.php
     24msgid "Suffering from database bloat? Try cleaning up the Action Scheduler tables through an easy-to-understand GUI."
     25msgstr "Leidet deine Datenbank unter aufgeblähten Tabellen? Bereinige die Action-Scheduler-Tabellen über eine leicht verständliche Oberfläche."
     26
     27#. Author of the plugin
     28#: ws-action-scheduler-cleaner.php
     29msgid "Winning Solutions - Nagel & Mäder GbR"
     30msgstr "Winning Solutions - Nagel & Mäder GbR"
     31
     32#. Author URI of the plugin
     33#: ws-action-scheduler-cleaner.php
     34msgid "https://www.winning-solutions.de"
     35msgstr "https://www.winning-solutions.de"
     36
     37#: includes/class-wsacsc-admin.php:40
     38msgid "Settings"
     39msgstr "Einstellungen"
     40
     41#: includes/class-wsacsc-admin.php:71
     42msgid "WS AS Cleaner"
     43msgstr "WS AS Cleaner"
     44
     45#: includes/class-wsacsc-admin.php:118 includes/class-wsacsc-ajax.php:108 includes/class-wsacsc-ajax.php:314
     46msgid "Please select at least one status to clear."
     47msgstr "Bitte wähle mindestens einen Status zum Bereinigen aus."
     48
     49#: includes/class-wsacsc-admin.php:119 includes/helpers.php:337
     50msgid "Clearing in progress..."
     51msgstr "Bereinigung läuft..."
     52
     53#: includes/class-wsacsc-admin.php:120
     54msgid "Please wait..."
     55msgstr "Bitte warte..."
     56
     57#: includes/class-wsacsc-admin.php:121
     58msgid "An error occurred. Please try again."
     59msgstr "Ein Fehler ist aufgetreten. Bitte versuche es erneut."
     60
     61#: includes/class-wsacsc-admin.php:122 includes/class-wsacsc-ajax.php:138
     62msgid "Selected actions cleared successfully!"
     63msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
     64
     65#: includes/class-wsacsc-admin.php:123 includes/class-wsacsc-ajax.php:180 includes/class-wsacsc-ajax.php:197
     66msgid "Logs cleared successfully!"
     67msgstr "Protokolle erfolgreich bereinigt!"
     68
     69#: includes/class-wsacsc-admin.php:124 includes/class-wsacsc-ajax.php:295
     70msgid "Schedule saved successfully!"
     71msgstr "Zeitplan erfolgreich gespeichert!"
     72
     73#: includes/class-wsacsc-admin.php:125 includes/class-wsacsc-ajax.php:319
     74msgid "Statuses saved successfully!"
     75msgstr "Status erfolgreich gespeichert!"
     76
     77#: includes/class-wsacsc-admin.php:126
     78msgid "Optimizing table..."
     79msgstr "Tabelle wird optimiert..."
     80
     81#: includes/class-wsacsc-admin.php:127 includes/class-wsacsc-admin.php:189 includes/class-wsacsc-admin.php:191 includes/class-wsacsc-admin.php:197 includes/class-wsacsc-admin.php:199
     82msgid "Loading..."
     83msgstr "Wird geladen..."
     84
     85#: includes/class-wsacsc-admin.php:128 includes/class-wsacsc-ajax.php:382
     86msgid "Table optimization failed."
     87msgstr "Tabellenoptimierung fehlgeschlagen."
     88
     89#: includes/class-wsacsc-admin.php:129
     90msgid "Please fix the highlighted fields before saving."
     91msgstr "Bitte korrigiere die markierten Felder vor dem Speichern."
     92
     93#: includes/class-wsacsc-admin.php:130 includes/class-wsacsc-admin.php:192
     94msgid "Refresh actions table size"
     95msgstr "Größe der Aktionstabelle aktualisieren"
     96
     97#: includes/class-wsacsc-admin.php:131 includes/class-wsacsc-admin.php:200
     98msgid "Refresh logs table size"
     99msgstr "Größe der Protokolltabelle aktualisieren"
     100
     101#: includes/class-wsacsc-admin.php:132
     102msgid "Retrying…"
     103msgstr "Erneuter Versuch…"
     104
     105#: includes/class-wsacsc-admin.php:150
     106msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
     107msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stelle sicher, dass Action Scheduler ordnungsgemäß installiert und aktiviert ist."
     108
     109#: includes/class-wsacsc-admin.php:159
    19110msgid "This tool allows you to clean up the Action Scheduler tables in your WordPress database. Action Scheduler is a library used by many plugins to schedule background tasks."
    20111msgstr "Dieses Tool ermöglicht es dir, die Action Scheduler-Tabellen in deiner WordPress-Datenbank zu bereinigen. Action Scheduler ist eine Bibliothek, die von vielen Plugins zur Planung von Hintergrundaufgaben verwendet wird."
    21112
    22 msgid "Please wait..."
    23 msgstr "Bitte warte..."
    24 
    25 msgid "Loading..."
    26 msgstr "Wird geladen..."
    27 
     113#: includes/class-wsacsc-admin.php:160
    28114msgid "The Action Scheduler uses two main tables:"
    29115msgstr "Der Action Scheduler verwendet zwei Haupttabellen:"
    30116
     117#: includes/class-wsacsc-admin.php:162
    31118msgid "Actions Table: Stores scheduled actions and their statuses."
    32119msgstr "Aktionstabelle: Speichert geplante Aktionen und deren Status."
    33120
     121#: includes/class-wsacsc-admin.php:163
    34122msgid "Logs Table: Stores logs of action executions."
    35123msgstr "Protokolltabelle: Speichert Protokolle von Aktionsausführungen."
    36124
     125#: includes/class-wsacsc-admin.php:165
    37126msgid "Clearing these tables is generally safe and can improve database performance. However, please note:"
    38127msgstr "Das Bereinigen dieser Tabellen ist im Allgemeinen sicher und kann die Datenbankleistung verbessern. Bitte beachte jedoch:"
    39128
     129#: includes/class-wsacsc-admin.php:167
    40130msgid "Clearing can take a while depending on the size of the tables."
    41131msgstr "Die Bereinigung kann je nach Größe der Tabellen eine Weile dauern."
    42132
     133#: includes/class-wsacsc-admin.php:168
    43134msgid "Cleared data will be permanently deleted."
    44135msgstr "Bereinigte Daten werden dauerhaft gelöscht."
    45136
     137#: includes/class-wsacsc-admin.php:169
    46138msgid "It's recommended to <strong>make a backup</strong> before proceeding."
    47139msgstr "Es wird empfohlen, vor dem Fortfahren ein <strong>Backup zu erstellen</strong>."
    48140
     141#: includes/class-wsacsc-admin.php:170
    49142msgid "Clearing completed, failed, or canceled actions usually doesn't affect WordPress functionality."
    50143msgstr "Das Bereinigen von abgeschlossenen, fehlgeschlagenen oder abgebrochenen Aktionen beeinträchtigt normalerweise nicht die WordPress-Funktionalität."
    51144
     145#. translators: %s: URL to Action Scheduler admin page
     146#: includes/class-wsacsc-admin.php:177
     147#, php-format
    52148msgid "For more information, visit the <a href=\"%s\">Action Scheduler admin page</a>."
    53149msgstr "Weitere Informationen findest du auf der <a href=\"%s\">Action Scheduler-Administrationsseite</a>."
    54150
     151#: includes/class-wsacsc-admin.php:186
    55152msgid "Current Table Sizes:"
    56153msgstr "Aktuelle Tabellengrößen:"
    57154
     155#: includes/class-wsacsc-admin.php:188
    58156msgid "Actions table:"
    59157msgstr "Aktionstabelle:"
    60158
     159#: includes/class-wsacsc-admin.php:190 includes/class-wsacsc-admin.php:198
    61160msgid "rows"
    62161msgstr "Zeilen"
    63162
     163#: includes/class-wsacsc-admin.php:196
    64164msgid "Logs table:"
    65165msgstr "Protokolltabelle:"
    66166
     167#: includes/class-wsacsc-admin.php:207
    67168msgid "Clear Action Statuses"
    68169msgstr "Aktionsstatus bereinigen"
    69170
    70 msgid "Select which action statuses to clear:"
    71 msgstr "Wähle aus, welche Aktionsstatus bereinigt werden sollen:"
    72 
     171#: includes/class-wsacsc-admin.php:209
     172msgid "Action statuses to clear"
     173msgstr "Zu bereinigende Aktionsstatus"
     174
     175#: includes/class-wsacsc-admin.php:210
    73176msgid "Select which statuses to remove when clearing manually, when this plugin runs scheduled action cleanup, and (if this plugin’s action cleanup schedule is disabled) which statuses Action Scheduler may delete in the background:"
    74177msgstr "Wähle aus, welche Status bei manueller Bereinigung, bei der geplanten Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) bei der Hintergrundbereinigung von Action Scheduler entfernt werden sollen:"
    75178
     179#: includes/class-wsacsc-admin.php:217
    76180msgid "Complete"
    77181msgstr "Abgeschlossen"
    78182
     183#: includes/class-wsacsc-admin.php:218
    79184msgid "Failed"
    80185msgstr "Fehlgeschlagen"
    81186
     187#: includes/class-wsacsc-admin.php:219
    82188msgid "Canceled"
    83189msgstr "Abgebrochen"
    84190
     191#: includes/class-wsacsc-admin.php:221
    85192msgid "Clear Selected Actions"
    86193msgstr "Ausgewählte Aktionen bereinigen"
    87194
     195#: includes/class-wsacsc-admin.php:226
    88196msgid "Clear Logs Table"
    89197msgstr "Protokolltabelle bereinigen"
    90198
     199#: includes/class-wsacsc-admin.php:227
    91200msgid "This will clear all entries in the logs table."
    92201msgstr "Dies wird alle Einträge in der Protokolltabelle löschen."
    93202
     203#: includes/class-wsacsc-admin.php:228
    94204msgid "Clear Logs"
    95205msgstr "Protokolle bereinigen"
    96206
     207#: includes/class-wsacsc-admin.php:232
     208msgid "Optimize Tables"
     209msgstr "Tabellen optimieren"
     210
     211#: includes/class-wsacsc-admin.php:233
     212msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
     213msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
     214
     215#: includes/class-wsacsc-admin.php:235
     216msgid "Optimize Actions Table"
     217msgstr "Aktionstabelle optimieren"
     218
     219#: includes/class-wsacsc-admin.php:236
     220msgid "Optimize Logs Table"
     221msgstr "Protokolltabelle optimieren"
     222
     223#: includes/class-wsacsc-admin.php:241
    97224msgid "Scheduling Options"
    98225msgstr "Planungsoptionen"
    99226
    100 msgid "Set up automatic clearing schedules for selected statuses (set to 0 to clean fully; leave empty to disable automatic clearing):"
    101 msgstr "Richte automatische Bereinigungspläne für ausgewählte Status ein (auf 0 setzen, um vollständig zu bereinigen; leer lassen, um die automatische Bereinigung zu deaktivieren):"
    102 
    103 msgid "Clear logs older than:"
    104 msgstr "Protokolle bereinigen, die älter sind als:"
    105 
     227#: includes/class-wsacsc-admin.php:242
     228msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
     229msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
     230
     231#: includes/class-wsacsc-admin.php:243
     232msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
     233msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
     234
     235#: includes/class-wsacsc-admin.php:244
     236msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
     237msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
     238
     239#: includes/class-wsacsc-admin.php:245
     240msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
     241msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
     242
     243#: includes/class-wsacsc-admin.php:246
     244msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
     245msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr großem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
     246
     247#: includes/class-wsacsc-admin.php:249
     248msgid "Action Statuses"
     249msgstr "Aktionsstatus"
     250
     251#: includes/class-wsacsc-admin.php:251 includes/class-wsacsc-admin.php:277
     252msgid "Cleanup Schedule:"
     253msgstr "Bereinigungszeitplan:"
     254
     255#: includes/class-wsacsc-admin.php:254 includes/class-wsacsc-admin.php:269 includes/class-wsacsc-admin.php:280 includes/class-wsacsc-admin.php:295
    106256msgid "days"
    107257msgstr "Tage"
    108258
    109 msgid "Clear action statuses older than:"
    110 msgstr "Aktionsstatus bereinigen, die älter sind als:"
    111 
     259#: includes/class-wsacsc-admin.php:256
     260msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
     261msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
     262
     263#: includes/class-wsacsc-admin.php:259 includes/class-wsacsc-admin.php:285
     264msgid "Schedule Time:"
     265msgstr "Zeitplan:"
     266
     267#: includes/class-wsacsc-admin.php:263
     268msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
     269msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
     270
     271#: includes/class-wsacsc-admin.php:266 includes/class-wsacsc-admin.php:292
     272msgid "Retention Period:"
     273msgstr "Aufbewahrungsfrist:"
     274
     275#: includes/class-wsacsc-admin.php:271
     276msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
     277msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
     278
     279#: includes/class-wsacsc-admin.php:275
     280msgid "Logs"
     281msgstr "Protokolle"
     282
     283#: includes/class-wsacsc-admin.php:282
     284msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
     285msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
     286
     287#: includes/class-wsacsc-admin.php:289
     288msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
     289msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
     290
     291#: includes/class-wsacsc-admin.php:297
     292msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
     293msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
     294
     295#: includes/class-wsacsc-admin.php:301
    112296msgid "Save Schedule"
    113297msgstr "Zeitplan speichern"
    114298
     299#: includes/class-wsacsc-admin.php:307
    115300msgid "Powered by Winning Solutions"
    116301msgstr "Powered by Winning Solutions"
    117302
    118 msgid "Selected actions cleared successfully!"
    119 msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
    120 
    121 msgid "Logs cleared successfully!"
    122 msgstr "Protokolle erfolgreich bereinigt!"
    123 
    124 msgid "Schedule saved successfully!"
    125 msgstr "Zeitplan erfolgreich gespeichert!"
    126 
     303#: includes/class-wsacsc-ajax.php:37
     304msgid "Another cleanup or optimization is already running. Please wait until it finishes."
     305msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warte, bis sie abgeschlossen ist."
     306
     307#: includes/class-wsacsc-ajax.php:81 includes/class-wsacsc-ajax.php:96 includes/class-wsacsc-ajax.php:150 includes/class-wsacsc-ajax.php:209 includes/class-wsacsc-ajax.php:305 includes/class-wsacsc-ajax.php:329 includes/class-wsacsc-ajax.php:356 includes/class-wsacsc-ajax.php:404
     308msgid "Insufficient permissions."
     309msgstr "Unzureichende Berechtigungen."
     310
     311#: includes/class-wsacsc-ajax.php:112 includes/class-wsacsc-ajax.php:156
     312msgid "Action Scheduler tables do not exist."
     313msgstr "Die Action-Scheduler-Tabellen existieren nicht."
     314
     315#: includes/class-wsacsc-ajax.php:131
     316msgid "An error occurred while clearing actions."
     317msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
     318
     319#: includes/class-wsacsc-ajax.php:190
     320msgid "An error occurred while clearing logs."
     321msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
     322
     323#: includes/class-wsacsc-ajax.php:230
     324msgid "Actions schedule interval must be empty or between 1 and 365 days."
     325msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     326
     327#: includes/class-wsacsc-ajax.php:234
     328msgid "Logs schedule interval must be empty or between 1 and 365 days."
     329msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     330
     331#: includes/class-wsacsc-ajax.php:238
     332msgid "Actions schedule time must be in HH:MM format."
     333msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
     334
     335#: includes/class-wsacsc-ajax.php:242
     336msgid "Logs schedule time must be in HH:MM format."
     337msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
     338
     339#: includes/class-wsacsc-ajax.php:246
     340msgid "Actions retention period is required and must be between 0 and 365 days."
     341msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     342
     343#: includes/class-wsacsc-ajax.php:250
     344msgid "Logs retention period is required and must be between 0 and 365 days."
     345msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     346
     347#: includes/class-wsacsc-ajax.php:288
     348msgid "Failed to save schedule. Please try again."
     349msgstr "Der Zeitplan konnte nicht gespeichert werden. Bitte versuche es erneut."
     350
     351#: includes/class-wsacsc-ajax.php:292
    127352msgid "The settings were saved, but the cleanup schedule could not be updated yet. The plugin will retry automatically."
    128353msgstr "Die Einstellungen wurden gespeichert, aber der Bereinigungszeitplan konnte noch nicht aktualisiert werden. Das Plugin versucht es automatisch erneut."
    129354
    130 msgid "Statuses saved successfully!"
    131 msgstr "Status erfolgreich gespeichert!"
    132 
    133 msgid "Settings"
    134 msgstr "Einstellungen"
    135 
    136 msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
    137 msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stelle sicher, dass Action Scheduler ordnungsgemäß installiert und aktiviert ist."
    138 
    139 msgid "Please select at least one status to clear."
    140 msgstr "Bitte wähle mindestens einen Status zum Bereinigen aus."
    141 
    142 msgid "Clearing in progress..."
    143 msgstr "Bereinigung läuft..."
    144 
    145 msgid "An error occurred. Please try again."
    146 msgstr "Ein Fehler ist aufgetreten. Bitte versuche es erneut."
    147 
    148 msgid "Optimize Tables"
    149 msgstr "Tabellen optimieren"
    150 
    151 msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
    152 msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
    153 
    154 msgid "Optimize Actions Table"
    155 msgstr "Aktionstabelle optimieren"
    156 
    157 msgid "Optimize Logs Table"
    158 msgstr "Protokolltabelle optimieren"
    159 
    160 msgid "Optimizing table..."
    161 msgstr "Tabelle wird optimiert..."
    162 
     355#: includes/class-wsacsc-ajax.php:336 includes/class-wsacsc-ajax.php:363
     356msgid "Invalid table type."
     357msgstr "Ungültiger Tabellentyp."
     358
     359#. translators: %s: table type (actions or logs).
     360#: includes/class-wsacsc-ajax.php:390
     361#, php-format
    163362msgid "%s table optimized successfully!"
    164363msgstr "%s-Tabelle erfolgreich optimiert!"
    165364
    166 msgid "Table optimization failed."
    167 msgstr "Tabellenoptimierung fehlgeschlagen."
    168 
    169 msgid "Table does not exist."
    170 msgstr "Tabelle existiert nicht."
    171 
    172 msgid "Invalid table type."
    173 msgstr "Ungültiger Tabellentyp."
    174 
    175 msgid "Insufficient permissions."
    176 msgstr "Unzureichende Berechtigungen."
    177 
    178 msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
    179 msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
    180 
    181 msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
    182 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
    183 
    184 msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
    185 msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
    186 
    187 msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
    188 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
    189 
    190 msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
    191 msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr großem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
    192 
    193 msgid "Action Statuses"
    194 msgstr "Aktionsstatus"
    195 
    196 msgid "Cleanup Schedule:"
    197 msgstr "Bereinigungszeitplan:"
    198 
    199 msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
    200 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
    201 
    202 msgid "Schedule Time:"
    203 msgstr "Zeitplan:"
    204 
    205 msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
    206 msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
    207 
    208 msgid "Retention Period:"
    209 msgstr "Aufbewahrungsfrist:"
    210 
    211 msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
    212 msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
    213 
    214 msgid "Logs"
    215 msgstr "Protokolle"
    216 
    217 msgid "How often to run cleanup (empty or 0 = disabled, 1-365 days)."
    218 msgstr "Wie oft die Bereinigung ausgeführt wird (leer oder 0 = deaktiviert, 1–365 Tage)."
    219 
    220 msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
    221 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
    222 
    223 msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
    224 msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
    225 
    226 msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
    227 msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
    228 
    229 msgid "Actions schedule interval must be empty or between 1 and 365 days."
    230 msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    231 
    232 msgid "Logs schedule interval must be empty or between 1 and 365 days."
    233 msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    234 
    235 msgid "Actions schedule time must be in HH:MM format."
    236 msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
    237 
    238 msgid "Logs schedule time must be in HH:MM format."
    239 msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
    240 
    241 msgid "Actions retention period is required and must be between 0 and 365 days."
    242 msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    243 
    244 msgid "Logs retention period is required and must be between 0 and 365 days."
    245 msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    246 
     365#: includes/class-wsacsc-ajax.php:411
     366msgid "Invalid cleanup ID."
     367msgstr "Ungültige Bereinigungs-ID."
     368
     369#: includes/class-wsacsc-ajax.php:427
     370msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
     371msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Lade die Seite neu, um die Tabellengrößen zu prüfen."
     372
     373#: includes/class-wsacsc-ajax.php:435
     374msgid "Invalid cleanup progress data."
     375msgstr "Ungültige Fortschrittsdaten der Bereinigung."
     376
     377#: includes/class-wsacsc-ajax.php:441
     378msgid "An error occurred during cleanup."
     379msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
     380
     381#: includes/class-wsacsc-ajax.php:453
     382msgid "Cleanup completed successfully!"
     383msgstr "Bereinigung erfolgreich abgeschlossen!"
     384
     385#. translators: %d: number of days.
     386#: includes/class-wsacsc-scheduler.php:245
     387#, php-format
     388msgid "Every %d day"
     389msgid_plural "Every %d days"
     390msgstr[0] "Jeden Tag"
     391msgstr[1] "Alle %d Tage"
     392
     393#. translators: 1: rows deleted so far, 2: rows to delete in total, 3: percentage done.
     394#: includes/helpers.php:329
     395#, php-format
     396msgid "Clearing in progress… %1$s of %2$s rows deleted (%3$d%%)."
     397msgstr "Bereinigung läuft… %1$s von %2$s Zeilen gelöscht (%3$d %%)."
     398
     399#. translators: %s: number of rows deleted so far.
     400#: includes/helpers.php:342
     401#, php-format
    247402msgid "Clearing in progress… %s rows deleted so far."
    248403msgstr "Bereinigung läuft… bisher %s Zeilen gelöscht."
    249 
    250 msgid "Cleanup completed successfully!"
    251 msgstr "Bereinigung erfolgreich abgeschlossen!"
    252 
    253 msgid "Another cleanup or optimization is already running. Please wait until it finishes."
    254 msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warte, bis sie abgeschlossen ist."
    255 
    256 msgid "An error occurred while clearing actions."
    257 msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
    258 
    259 msgid "An error occurred while clearing logs."
    260 msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
    261 
    262 msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
    263 msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Lade die Seite neu, um die Tabellengrößen zu prüfen."
    264 
    265 msgid "An error occurred during cleanup."
    266 msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
    267 
    268 msgid "Retrying…"
    269 msgstr "Erneuter Versuch…"
  • ws-action-scheduler-cleaner/trunk/languages/ws-action-scheduler-cleaner-de_DE_formal.po

    r3750500 r3798362  
     1#
    12msgid ""
    23msgstr ""
    34"Project-Id-Version: WS Action Scheduler Cleaner\n"
    4 "Report-Msgid-Bugs-To: \n"
    5 "POT-Creation-Date: 2024-10-10 12:00+0000\n"
    6 "PO-Revision-Date: 2025-11-24 18:00+0100\n"
     5"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/ws-action-scheduler-cleaner\n"
     6"POT-Creation-Date: 2026-11-10T20:25:22+00:00\n"
     7"PO-Revision-Date: 2026-11-10 12:00+0000\n"
    78"Last-Translator: Marco Brack <mbrack@winning-solutions.de>\n"
    89"Language-Team: \n"
    … …  
    1415"X-Generator: Poedit 3.8\n"
    1516
     17#. Plugin Name of the plugin
     18#: ws-action-scheduler-cleaner.php includes/class-wsacsc-admin.php:70 includes/class-wsacsc-admin.php:149 includes/class-wsacsc-admin.php:156
    1619msgid "WS Action Scheduler Cleaner"
    1720msgstr "WS Action Scheduler Cleaner"
    1821
     22#. Description of the plugin
     23#: ws-action-scheduler-cleaner.php
     24msgid "Suffering from database bloat? Try cleaning up the Action Scheduler tables through an easy-to-understand GUI."
     25msgstr "Leidet Ihre Datenbank unter aufgeblähten Tabellen? Bereinigen Sie die Action-Scheduler-Tabellen über eine leicht verständliche Oberfläche."
     26
     27#. Author of the plugin
     28#: ws-action-scheduler-cleaner.php
     29msgid "Winning Solutions - Nagel & Mäder GbR"
     30msgstr "Winning Solutions - Nagel & Mäder GbR"
     31
     32#. Author URI of the plugin
     33#: ws-action-scheduler-cleaner.php
     34msgid "https://www.winning-solutions.de"
     35msgstr "https://www.winning-solutions.de"
     36
     37#: includes/class-wsacsc-admin.php:40
     38msgid "Settings"
     39msgstr "Einstellungen"
     40
     41#: includes/class-wsacsc-admin.php:71
     42msgid "WS AS Cleaner"
     43msgstr "WS AS Cleaner"
     44
     45#: includes/class-wsacsc-admin.php:118 includes/class-wsacsc-ajax.php:108 includes/class-wsacsc-ajax.php:314
     46msgid "Please select at least one status to clear."
     47msgstr "Bitte wählen Sie mindestens einen Status zum Bereinigen aus."
     48
     49#: includes/class-wsacsc-admin.php:119 includes/helpers.php:337
     50msgid "Clearing in progress..."
     51msgstr "Bereinigung läuft..."
     52
     53#: includes/class-wsacsc-admin.php:120
     54msgid "Please wait..."
     55msgstr "Bitte warten Sie..."
     56
     57#: includes/class-wsacsc-admin.php:121
     58msgid "An error occurred. Please try again."
     59msgstr "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
     60
     61#: includes/class-wsacsc-admin.php:122 includes/class-wsacsc-ajax.php:138
     62msgid "Selected actions cleared successfully!"
     63msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
     64
     65#: includes/class-wsacsc-admin.php:123 includes/class-wsacsc-ajax.php:180 includes/class-wsacsc-ajax.php:197
     66msgid "Logs cleared successfully!"
     67msgstr "Protokolle erfolgreich bereinigt!"
     68
     69#: includes/class-wsacsc-admin.php:124 includes/class-wsacsc-ajax.php:295
     70msgid "Schedule saved successfully!"
     71msgstr "Zeitplan erfolgreich gespeichert!"
     72
     73#: includes/class-wsacsc-admin.php:125 includes/class-wsacsc-ajax.php:319
     74msgid "Statuses saved successfully!"
     75msgstr "Status erfolgreich gespeichert!"
     76
     77#: includes/class-wsacsc-admin.php:126
     78msgid "Optimizing table..."
     79msgstr "Tabelle wird optimiert..."
     80
     81#: includes/class-wsacsc-admin.php:127 includes/class-wsacsc-admin.php:189 includes/class-wsacsc-admin.php:191 includes/class-wsacsc-admin.php:197 includes/class-wsacsc-admin.php:199
     82msgid "Loading..."
     83msgstr "Wird geladen..."
     84
     85#: includes/class-wsacsc-admin.php:128 includes/class-wsacsc-ajax.php:382
     86msgid "Table optimization failed."
     87msgstr "Tabellenoptimierung fehlgeschlagen."
     88
     89#: includes/class-wsacsc-admin.php:129
     90msgid "Please fix the highlighted fields before saving."
     91msgstr "Bitte korrigieren Sie die markierten Felder vor dem Speichern."
     92
     93#: includes/class-wsacsc-admin.php:130 includes/class-wsacsc-admin.php:192
     94msgid "Refresh actions table size"
     95msgstr "Größe der Aktionstabelle aktualisieren"
     96
     97#: includes/class-wsacsc-admin.php:131 includes/class-wsacsc-admin.php:200
     98msgid "Refresh logs table size"
     99msgstr "Größe der Protokolltabelle aktualisieren"
     100
     101#: includes/class-wsacsc-admin.php:132
     102msgid "Retrying…"
     103msgstr "Erneuter Versuch…"
     104
     105#: includes/class-wsacsc-admin.php:150
     106msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
     107msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stellen Sie sicher, dass Action Scheduler ordnungsgemäß installiert und aktiviert ist."
     108
     109#: includes/class-wsacsc-admin.php:159
    19110msgid "This tool allows you to clean up the Action Scheduler tables in your WordPress database. Action Scheduler is a library used by many plugins to schedule background tasks."
    20111msgstr "Dieses Tool ermöglicht es Ihnen, die Action Scheduler-Tabellen in Ihrer WordPress-Datenbank zu bereinigen. Action Scheduler ist eine Bibliothek, die von vielen Plugins zur Planung von Hintergrundaufgaben verwendet wird."
    21112
    22 msgid "Please wait..."
    23 msgstr "Bitte warten Sie..."
    24 
    25 msgid "Loading..."
    26 msgstr "Wird geladen..."
    27 
     113#: includes/class-wsacsc-admin.php:160
    28114msgid "The Action Scheduler uses two main tables:"
    29115msgstr "Der Action Scheduler verwendet zwei Haupttabellen:"
    30116
     117#: includes/class-wsacsc-admin.php:162
    31118msgid "Actions Table: Stores scheduled actions and their statuses."
    32119msgstr "Aktionstabelle: Speichert geplante Aktionen und deren Status."
    33120
     121#: includes/class-wsacsc-admin.php:163
    34122msgid "Logs Table: Stores logs of action executions."
    35123msgstr "Protokolltabelle: Speichert Protokolle von Aktionsausführungen."
    36124
     125#: includes/class-wsacsc-admin.php:165
    37126msgid "Clearing these tables is generally safe and can improve database performance. However, please note:"
    38127msgstr "Das Bereinigen dieser Tabellen ist im Allgemeinen sicher und kann die Datenbankleistung verbessern. Bitte beachten Sie jedoch:"
    39128
     129#: includes/class-wsacsc-admin.php:167
    40130msgid "Clearing can take a while depending on the size of the tables."
    41131msgstr "Die Bereinigung kann je nach Größe der Tabellen eine Weile dauern."
    42132
     133#: includes/class-wsacsc-admin.php:168
    43134msgid "Cleared data will be permanently deleted."
    44135msgstr "Bereinigte Daten werden dauerhaft gelöscht."
    45136
     137#: includes/class-wsacsc-admin.php:169
    46138msgid "It's recommended to <strong>make a backup</strong> before proceeding."
    47139msgstr "Es wird empfohlen, vor dem Fortfahren ein <strong>Backup zu erstellen</strong>."
    48140
     141#: includes/class-wsacsc-admin.php:170
    49142msgid "Clearing completed, failed, or canceled actions usually doesn't affect WordPress functionality."
    50143msgstr "Das Bereinigen von abgeschlossenen, fehlgeschlagenen oder abgebrochenen Aktionen beeinträchtigt normalerweise nicht die WordPress-Funktionalität."
    51144
     145#. translators: %s: URL to Action Scheduler admin page
     146#: includes/class-wsacsc-admin.php:177
     147#, php-format
    52148msgid "For more information, visit the <a href=\"%s\">Action Scheduler admin page</a>."
    53149msgstr "Weitere Informationen finden Sie auf der <a href=\"%s\">Action Scheduler-Administrationsseite</a>."
    54150
     151#: includes/class-wsacsc-admin.php:186
    55152msgid "Current Table Sizes:"
    56153msgstr "Aktuelle Tabellengrößen:"
    57154
     155#: includes/class-wsacsc-admin.php:188
    58156msgid "Actions table:"
    59157msgstr "Aktionstabelle:"
    60158
     159#: includes/class-wsacsc-admin.php:190 includes/class-wsacsc-admin.php:198
    61160msgid "rows"
    62161msgstr "Zeilen"
    63162
     163#: includes/class-wsacsc-admin.php:196
    64164msgid "Logs table:"
    65165msgstr "Protokolltabelle:"
    66166
     167#: includes/class-wsacsc-admin.php:207
    67168msgid "Clear Action Statuses"
    68169msgstr "Aktionsstatus bereinigen"
    69170
    70 msgid "Select which action statuses to clear:"
    71 msgstr "Wählen Sie aus, welche Aktionsstatus bereinigt werden sollen:"
    72 
     171#: includes/class-wsacsc-admin.php:209
     172msgid "Action statuses to clear"
     173msgstr "Zu bereinigende Aktionsstatus"
     174
     175#: includes/class-wsacsc-admin.php:210
    73176msgid "Select which statuses to remove when clearing manually, when this plugin runs scheduled action cleanup, and (if this plugin’s action cleanup schedule is disabled) which statuses Action Scheduler may delete in the background:"
    74177msgstr "Wählen Sie aus, welche Status bei manueller Bereinigung, bei der geplanten Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) bei der Hintergrundbereinigung von Action Scheduler entfernt werden sollen:"
    75178
     179#: includes/class-wsacsc-admin.php:217
    76180msgid "Complete"
    77181msgstr "Abgeschlossen"
    78182
     183#: includes/class-wsacsc-admin.php:218
    79184msgid "Failed"
    80185msgstr "Fehlgeschlagen"
    81186
     187#: includes/class-wsacsc-admin.php:219
    82188msgid "Canceled"
    83189msgstr "Abgebrochen"
    84190
     191#: includes/class-wsacsc-admin.php:221
    85192msgid "Clear Selected Actions"
    86193msgstr "Ausgewählte Aktionen bereinigen"
    87194
     195#: includes/class-wsacsc-admin.php:226
    88196msgid "Clear Logs Table"
    89197msgstr "Protokolltabelle bereinigen"
    90198
     199#: includes/class-wsacsc-admin.php:227
    91200msgid "This will clear all entries in the logs table."
    92201msgstr "Dies wird alle Einträge in der Protokolltabelle löschen."
    93202
     203#: includes/class-wsacsc-admin.php:228
    94204msgid "Clear Logs"
    95205msgstr "Protokolle bereinigen"
    96206
     207#: includes/class-wsacsc-admin.php:232
     208msgid "Optimize Tables"
     209msgstr "Tabellen optimieren"
     210
     211#: includes/class-wsacsc-admin.php:233
     212msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
     213msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
     214
     215#: includes/class-wsacsc-admin.php:235
     216msgid "Optimize Actions Table"
     217msgstr "Aktionstabelle optimieren"
     218
     219#: includes/class-wsacsc-admin.php:236
     220msgid "Optimize Logs Table"
     221msgstr "Protokolltabelle optimieren"
     222
     223#: includes/class-wsacsc-admin.php:241
    97224msgid "Scheduling Options"
    98225msgstr "Planungsoptionen"
    99226
    100 msgid "Set up automatic clearing schedules for selected statuses (set to 0 to clean fully; leave empty to disable automatic clearing):"
    101 msgstr "Richten Sie automatische Bereinigungspläne für ausgewählte Status ein (auf 0 setzen, um vollständig zu bereinigen; leer lassen, um die automatische Bereinigung zu deaktivieren):"
    102 
    103 msgid "Clear logs older than:"
    104 msgstr "Protokolle bereinigen, die älter sind als:"
    105 
     227#: includes/class-wsacsc-admin.php:242
     228msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
     229msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
     230
     231#: includes/class-wsacsc-admin.php:243
     232msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
     233msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
     234
     235#: includes/class-wsacsc-admin.php:244
     236msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
     237msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
     238
     239#: includes/class-wsacsc-admin.php:245
     240msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
     241msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
     242
     243#: includes/class-wsacsc-admin.php:246
     244msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
     245msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr großem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
     246
     247#: includes/class-wsacsc-admin.php:249
     248msgid "Action Statuses"
     249msgstr "Aktionsstatus"
     250
     251#: includes/class-wsacsc-admin.php:251 includes/class-wsacsc-admin.php:277
     252msgid "Cleanup Schedule:"
     253msgstr "Bereinigungszeitplan:"
     254
     255#: includes/class-wsacsc-admin.php:254 includes/class-wsacsc-admin.php:269 includes/class-wsacsc-admin.php:280 includes/class-wsacsc-admin.php:295
    106256msgid "days"
    107257msgstr "Tage"
    108258
    109 msgid "Clear action statuses older than:"
    110 msgstr "Aktionsstatus bereinigen, die älter sind als:"
    111 
     259#: includes/class-wsacsc-admin.php:256
     260msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
     261msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
     262
     263#: includes/class-wsacsc-admin.php:259 includes/class-wsacsc-admin.php:285
     264msgid "Schedule Time:"
     265msgstr "Zeitplan:"
     266
     267#: includes/class-wsacsc-admin.php:263
     268msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
     269msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
     270
     271#: includes/class-wsacsc-admin.php:266 includes/class-wsacsc-admin.php:292
     272msgid "Retention Period:"
     273msgstr "Aufbewahrungsfrist:"
     274
     275#: includes/class-wsacsc-admin.php:271
     276msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
     277msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
     278
     279#: includes/class-wsacsc-admin.php:275
     280msgid "Logs"
     281msgstr "Protokolle"
     282
     283#: includes/class-wsacsc-admin.php:282
     284msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
     285msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
     286
     287#: includes/class-wsacsc-admin.php:289
     288msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
     289msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
     290
     291#: includes/class-wsacsc-admin.php:297
     292msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
     293msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
     294
     295#: includes/class-wsacsc-admin.php:301
    112296msgid "Save Schedule"
    113297msgstr "Zeitplan speichern"
    114298
     299#: includes/class-wsacsc-admin.php:307
    115300msgid "Powered by Winning Solutions"
    116301msgstr "Powered by Winning Solutions"
    117302
    118 msgid "Selected actions cleared successfully!"
    119 msgstr "Ausgewählte Aktionen erfolgreich bereinigt!"
    120 
    121 msgid "Logs cleared successfully!"
    122 msgstr "Protokolle erfolgreich bereinigt!"
    123 
    124 msgid "Schedule saved successfully!"
    125 msgstr "Zeitplan erfolgreich gespeichert!"
    126 
     303#: includes/class-wsacsc-ajax.php:37
     304msgid "Another cleanup or optimization is already running. Please wait until it finishes."
     305msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warten Sie, bis sie abgeschlossen ist."
     306
     307#: includes/class-wsacsc-ajax.php:81 includes/class-wsacsc-ajax.php:96 includes/class-wsacsc-ajax.php:150 includes/class-wsacsc-ajax.php:209 includes/class-wsacsc-ajax.php:305 includes/class-wsacsc-ajax.php:329 includes/class-wsacsc-ajax.php:356 includes/class-wsacsc-ajax.php:404
     308msgid "Insufficient permissions."
     309msgstr "Unzureichende Berechtigungen."
     310
     311#: includes/class-wsacsc-ajax.php:112 includes/class-wsacsc-ajax.php:156
     312msgid "Action Scheduler tables do not exist."
     313msgstr "Die Action-Scheduler-Tabellen existieren nicht."
     314
     315#: includes/class-wsacsc-ajax.php:131
     316msgid "An error occurred while clearing actions."
     317msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
     318
     319#: includes/class-wsacsc-ajax.php:190
     320msgid "An error occurred while clearing logs."
     321msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
     322
     323#: includes/class-wsacsc-ajax.php:230
     324msgid "Actions schedule interval must be empty or between 1 and 365 days."
     325msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     326
     327#: includes/class-wsacsc-ajax.php:234
     328msgid "Logs schedule interval must be empty or between 1 and 365 days."
     329msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
     330
     331#: includes/class-wsacsc-ajax.php:238
     332msgid "Actions schedule time must be in HH:MM format."
     333msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
     334
     335#: includes/class-wsacsc-ajax.php:242
     336msgid "Logs schedule time must be in HH:MM format."
     337msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
     338
     339#: includes/class-wsacsc-ajax.php:246
     340msgid "Actions retention period is required and must be between 0 and 365 days."
     341msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     342
     343#: includes/class-wsacsc-ajax.php:250
     344msgid "Logs retention period is required and must be between 0 and 365 days."
     345msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
     346
     347#: includes/class-wsacsc-ajax.php:288
     348msgid "Failed to save schedule. Please try again."
     349msgstr "Der Zeitplan konnte nicht gespeichert werden. Bitte versuchen Sie es erneut."
     350
     351#: includes/class-wsacsc-ajax.php:292
    127352msgid "The settings were saved, but the cleanup schedule could not be updated yet. The plugin will retry automatically."
    128353msgstr "Die Einstellungen wurden gespeichert, aber der Bereinigungszeitplan konnte noch nicht aktualisiert werden. Das Plugin versucht es automatisch erneut."
    129354
    130 msgid "Statuses saved successfully!"
    131 msgstr "Status erfolgreich gespeichert!"
    132 
    133 msgid "Settings"
    134 msgstr "Einstellungen"
    135 
    136 msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
    137 msgstr "Die Action-Scheduler-Tabellen existieren nicht. Bitte stellen Sie sicher, dass Action Scheduler ordnungsgemäß installiert und aktiviert ist."
    138 
    139 msgid "Please select at least one status to clear."
    140 msgstr "Bitte wählen Sie mindestens einen Status zum Bereinigen aus."
    141 
    142 msgid "Clearing in progress..."
    143 msgstr "Bereinigung läuft..."
    144 
    145 msgid "An error occurred. Please try again."
    146 msgstr "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
    147 
    148 msgid "Optimize Tables"
    149 msgstr "Tabellen optimieren"
    150 
    151 msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
    152 msgstr "Optimiere die Datenbanktabellen, um ungenutzten Speicherplatz freizugeben und möglicherweise die Leistung zu verbessern."
    153 
    154 msgid "Optimize Actions Table"
    155 msgstr "Aktionstabelle optimieren"
    156 
    157 msgid "Optimize Logs Table"
    158 msgstr "Protokolltabelle optimieren"
    159 
    160 msgid "Optimizing table..."
    161 msgstr "Tabelle wird optimiert..."
    162 
     355#: includes/class-wsacsc-ajax.php:336 includes/class-wsacsc-ajax.php:363
     356msgid "Invalid table type."
     357msgstr "Ungültiger Tabellentyp."
     358
     359#. translators: %s: table type (actions or logs).
     360#: includes/class-wsacsc-ajax.php:390
     361#, php-format
    163362msgid "%s table optimized successfully!"
    164363msgstr "%s-Tabelle erfolgreich optimiert!"
    165364
    166 msgid "Table optimization failed."
    167 msgstr "Tabellenoptimierung fehlgeschlagen."
    168 
    169 msgid "Table does not exist."
    170 msgstr "Tabelle existiert nicht."
    171 
    172 msgid "Invalid table type."
    173 msgstr "Ungültiger Tabellentyp."
    174 
    175 msgid "Insufficient permissions."
    176 msgstr "Unzureichende Berechtigungen."
    177 
    178 msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
    179 msgstr "Abgeschlossene Aktionen können auf zwei Arten automatisch entfernt werden: über die geplante Bereinigung dieses Plugins (Einstellungen unten) und über die eingebaute Hintergrundbereinigung von Action Scheduler für die Aktionstabelle. Die Status-Kontrollkästchen unter „Aktionsstatus bereinigen“ legen fest, welche Status betroffen sind – manuelle Bereinigung, die geplante Aktionsbereinigung dieses Plugins und (wenn der Aktions-Bereinigungszeitplan dieses Plugins deaktiviert ist) die Hintergrundlöschungen von Action Scheduler."
    180 
    181 msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
    182 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist sind getrennte Einstellungen. Der Bereinigungszeitplan legt fest, wie oft dieses Plugin seine eigenen WordPress-Cronjobs ausführt (1–365 Tage, oder leer/0 zum Deaktivieren). Die Aufbewahrungsfrist legt fest, wie alt Einträge sein müssen, bevor sie gelöscht werden. Bei Aktionen wird das Alter am Abschluss- oder letzten Ausführungszeitpunkt gemessen – nicht am ursprünglichen Planungsdatum."
    183 
    184 msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
    185 msgstr "Ist ein Bereinigungszeitplan für Aktionen aktiviert, löscht nur der Cronjob dieses Plugins alte Aktionen (mit den oben gewählten Status); die eingebaute Aktionsbereinigung von Action Scheduler wird deaktiviert, um doppelte Löschungen zu vermeiden. Ist dieser Zeitplan deaktiviert, führt dieses Plugin keine geplante Aktionsbereinigung aus – die Aufbewahrungsfrist für Aktionen wird stattdessen an Action Scheduler übergeben, das Aktionen in den gewählten Status löscht, wenn sie älter als die angegebene Anzahl Tage sind."
    186 
    187 msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
    188 msgstr "Bereinigungszeitplan und Aufbewahrungsfrist für Protokolle gelten nur für dieses Plugin; Action Scheduler bereinigt die Protokolltabelle nicht von sich aus."
    189 
    190 msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
    191 msgstr "Dieses Plugin blendet keine Statusfilter auf der Action-Scheduler-Verwaltungsseite aus. Registerkarten wie „Abgeschlossen“ oder „Fehlgeschlagen“ erscheinen nur, wenn Aktionen mit diesen Status in der Datenbank existieren. Bei sehr großem Pending-Rückstau werden wenige Aktionen abgeschlossen; bleiben die Zähler bei null, werden diese Registerkarten nicht angezeigt."
    192 
    193 msgid "Action Statuses"
    194 msgstr "Aktionsstatus"
    195 
    196 msgid "Cleanup Schedule:"
    197 msgstr "Bereinigungszeitplan:"
    198 
    199 msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
    200 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Aktionen löscht (leer oder 0 = deaktiviert, 1–365 Tage). Wenn aktiviert, ist die eingebaute Aktionsbereinigung von Action Scheduler deaktiviert. Das ist nicht die Aufbewahrungsfrist."
    201 
    202 msgid "Schedule Time:"
    203 msgstr "Zeitplan:"
    204 
    205 msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
    206 msgstr "Nur dieses Plugin: Tageszeit für den Aktions-Bereinigungsjob (WordPress-Zeitzone)."
    207 
    208 msgid "Retention Period:"
    209 msgstr "Aufbewahrungsfrist:"
    210 
    211 msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
    212 msgstr "Wie lange Aktionen vor dem Löschen aufbewahrt werden (Abschluss- oder letzter Ausführungszeitpunkt, nicht Planungsdatum), für die oben gewählten Status. Mit aktiviertem Aktions-Bereinigungszeitplan: nur für den Cronjob dieses Plugins. Ohne diesen Zeitplan: wird an die Hintergrundbereinigung von Action Scheduler für dieselben Status übergeben. 0 = bei jedem Bereinigungslauf alle passenden Aktionen löschen. Pflichtfeld."
    213 
    214 msgid "Logs"
    215 msgstr "Protokolle"
    216 
    217 msgid "How often to run cleanup (empty or 0 = disabled, 1-365 days)."
    218 msgstr "Wie oft die Bereinigung ausgeführt wird (leer oder 0 = deaktiviert, 1–365 Tage)."
    219 
    220 msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
    221 msgstr "Nur dieses Plugin: Wie oft sein WordPress-Cronjob alte Protokolleinträge löscht (leer oder 0 = deaktiviert, 1–365 Tage). Action Scheduler bereinigt Protokolle nicht automatisch. Das ist nicht die Aufbewahrungsfrist."
    222 
    223 msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
    224 msgstr "Nur dieses Plugin: Tageszeit für den Protokoll-Bereinigungsjob (WordPress-Zeitzone)."
    225 
    226 msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
    227 msgstr "Nur dieses Plugin: Protokolleinträge löschen, die älter sind als diese Anzahl Tage (0 = bei jedem Bereinigungslauf alle Protokolle löschen). Pflichtfeld."
    228 
    229 msgid "Actions schedule interval must be empty or between 1 and 365 days."
    230 msgstr "Das Intervall für den Aktionszeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    231 
    232 msgid "Logs schedule interval must be empty or between 1 and 365 days."
    233 msgstr "Das Intervall für den Protokollzeitplan muss leer sein oder zwischen 1 und 365 Tagen liegen."
    234 
    235 msgid "Actions schedule time must be in HH:MM format."
    236 msgstr "Die Zeit für den Aktionszeitplan muss im Format HH:MM angegeben werden."
    237 
    238 msgid "Logs schedule time must be in HH:MM format."
    239 msgstr "Die Zeit für den Protokollzeitplan muss im Format HH:MM angegeben werden."
    240 
    241 msgid "Actions retention period is required and must be between 0 and 365 days."
    242 msgstr "Die Aufbewahrungsfrist für Aktionen ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    243 
    244 msgid "Logs retention period is required and must be between 0 and 365 days."
    245 msgstr "Die Aufbewahrungsfrist für Protokolle ist erforderlich und muss zwischen 0 und 365 Tagen liegen."
    246 
     365#: includes/class-wsacsc-ajax.php:411
     366msgid "Invalid cleanup ID."
     367msgstr "Ungültige Bereinigungs-ID."
     368
     369#: includes/class-wsacsc-ajax.php:427
     370msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
     371msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Laden Sie die Seite neu, um die Tabellengrößen zu prüfen."
     372
     373#: includes/class-wsacsc-ajax.php:435
     374msgid "Invalid cleanup progress data."
     375msgstr "Ungültige Fortschrittsdaten der Bereinigung."
     376
     377#: includes/class-wsacsc-ajax.php:441
     378msgid "An error occurred during cleanup."
     379msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
     380
     381#: includes/class-wsacsc-ajax.php:453
     382msgid "Cleanup completed successfully!"
     383msgstr "Bereinigung erfolgreich abgeschlossen!"
     384
     385#. translators: %d: number of days.
     386#: includes/class-wsacsc-scheduler.php:245
     387#, php-format
     388msgid "Every %d day"
     389msgid_plural "Every %d days"
     390msgstr[0] "Jeden Tag"
     391msgstr[1] "Alle %d Tage"
     392
     393#. translators: 1: rows deleted so far, 2: rows to delete in total, 3: percentage done.
     394#: includes/helpers.php:329
     395#, php-format
     396msgid "Clearing in progress… %1$s of %2$s rows deleted (%3$d%%)."
     397msgstr "Bereinigung läuft… %1$s von %2$s Zeilen gelöscht (%3$d %%)."
     398
     399#. translators: %s: number of rows deleted so far.
     400#: includes/helpers.php:342
     401#, php-format
    247402msgid "Clearing in progress… %s rows deleted so far."
    248403msgstr "Bereinigung läuft… bisher %s Zeilen gelöscht."
    249 
    250 msgid "Cleanup completed successfully!"
    251 msgstr "Bereinigung erfolgreich abgeschlossen!"
    252 
    253 msgid "Another cleanup or optimization is already running. Please wait until it finishes."
    254 msgstr "Eine andere Bereinigung oder Optimierung läuft bereits. Bitte warten Sie, bis sie abgeschlossen ist."
    255 
    256 msgid "An error occurred while clearing actions."
    257 msgstr "Beim Bereinigen der Aktionen ist ein Fehler aufgetreten."
    258 
    259 msgid "An error occurred while clearing logs."
    260 msgstr "Beim Bereinigen der Protokolle ist ein Fehler aufgetreten."
    261 
    262 msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
    263 msgstr "Der Bereinigungsfortschritt ging verloren oder die Bereinigung läuft im Hintergrund weiter. Laden Sie die Seite neu, um die Tabellengrößen zu prüfen."
    264 
    265 msgid "An error occurred during cleanup."
    266 msgstr "Während der Bereinigung ist ein Fehler aufgetreten."
    267 
    268 msgid "Retrying…"
    269 msgstr "Erneuter Versuch…"
  • ws-action-scheduler-cleaner/trunk/languages/ws-action-scheduler-cleaner.pot

    r3750500 r3798362  
    1 #, fuzzy
     1# Copyright (C) 2026 Winning Solutions - Nagel & Mäder GbR
     2# This file is distributed under the GPLv2 or later.
    23msgid ""
    34msgstr ""
    4 "Project-Id-Version: WS Action Scheduler Cleaner\n"
    5 "Report-Msgid-Bugs-To: \n"
    6 "POT-Creation-Date: 2024-10-10 12:00+0000\n"
    7 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
     5"Project-Id-Version: WS Action Scheduler Cleaner 1.3.2\n"
     6"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/ws-action-scheduler-cleaner\n"
    87"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
    98"Language-Team: LANGUAGE <LL@li.org>\n"
    10 "Language: \n"
    119"MIME-Version: 1.0\n"
    1210"Content-Type: text/plain; charset=UTF-8\n"
    1311"Content-Transfer-Encoding: 8bit\n"
    14 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
    15 
    16 #: ws-action-scheduler-cleaner.php:3
    17 #: ws-action-scheduler-cleaner.php:156
     12"POT-Creation-Date: 2026-11-10T20:25:22+00:00\n"
     13"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
     14"X-Generator: WP-CLI 2.12.0\n"
     15"X-Domain: ws-action-scheduler-cleaner\n"
     16
     17#. Plugin Name of the plugin
     18#: ws-action-scheduler-cleaner.php
     19#: includes/class-wsacsc-admin.php:70
     20#: includes/class-wsacsc-admin.php:149
     21#: includes/class-wsacsc-admin.php:156
    1822msgid "WS Action Scheduler Cleaner"
    1923msgstr ""
    2024
    21 #: ws-action-scheduler-cleaner.php:4
     25#. Description of the plugin
     26#: ws-action-scheduler-cleaner.php
    2227msgid "Suffering from database bloat? Try cleaning up the Action Scheduler tables through an easy-to-understand GUI."
    2328msgstr ""
    2429
    25 #: ws-action-scheduler-cleaner.php:69
     30#. Author of the plugin
     31#: ws-action-scheduler-cleaner.php
     32msgid "Winning Solutions - Nagel & Mäder GbR"
     33msgstr ""
     34
     35#. Author URI of the plugin
     36#: ws-action-scheduler-cleaner.php
     37msgid "https://www.winning-solutions.de"
     38msgstr ""
     39
     40#: includes/class-wsacsc-admin.php:40
     41msgid "Settings"
     42msgstr ""
     43
     44#: includes/class-wsacsc-admin.php:71
     45msgid "WS AS Cleaner"
     46msgstr ""
     47
     48#: includes/class-wsacsc-admin.php:118
     49#: includes/class-wsacsc-ajax.php:108
     50#: includes/class-wsacsc-ajax.php:314
     51msgid "Please select at least one status to clear."
     52msgstr ""
     53
     54#: includes/class-wsacsc-admin.php:119
     55#: includes/helpers.php:337
     56msgid "Clearing in progress..."
     57msgstr ""
     58
     59#: includes/class-wsacsc-admin.php:120
    2660msgid "Please wait..."
    2761msgstr ""
    2862
    29 #: ws-action-scheduler-cleaner.php:70
     63#: includes/class-wsacsc-admin.php:121
     64msgid "An error occurred. Please try again."
     65msgstr ""
     66
     67#: includes/class-wsacsc-admin.php:122
     68#: includes/class-wsacsc-ajax.php:138
     69msgid "Selected actions cleared successfully!"
     70msgstr ""
     71
     72#: includes/class-wsacsc-admin.php:123
     73#: includes/class-wsacsc-ajax.php:180
     74#: includes/class-wsacsc-ajax.php:197
     75msgid "Logs cleared successfully!"
     76msgstr ""
     77
     78#: includes/class-wsacsc-admin.php:124
     79#: includes/class-wsacsc-ajax.php:295
     80msgid "Schedule saved successfully!"
     81msgstr ""
     82
     83#: includes/class-wsacsc-admin.php:125
     84#: includes/class-wsacsc-ajax.php:319
     85msgid "Statuses saved successfully!"
     86msgstr ""
     87
     88#: includes/class-wsacsc-admin.php:126
     89msgid "Optimizing table..."
     90msgstr ""
     91
     92#: includes/class-wsacsc-admin.php:127
     93#: includes/class-wsacsc-admin.php:189
     94#: includes/class-wsacsc-admin.php:191
     95#: includes/class-wsacsc-admin.php:197
     96#: includes/class-wsacsc-admin.php:199
    3097msgid "Loading..."
    3198msgstr ""
    3299
    33 #: ws-action-scheduler-cleaner.php:164
     100#: includes/class-wsacsc-admin.php:128
     101#: includes/class-wsacsc-ajax.php:382
     102msgid "Table optimization failed."
     103msgstr ""
     104
     105#: includes/class-wsacsc-admin.php:129
     106msgid "Please fix the highlighted fields before saving."
     107msgstr ""
     108
     109#: includes/class-wsacsc-admin.php:130
     110#: includes/class-wsacsc-admin.php:192
     111msgid "Refresh actions table size"
     112msgstr ""
     113
     114#: includes/class-wsacsc-admin.php:131
     115#: includes/class-wsacsc-admin.php:200
     116msgid "Refresh logs table size"
     117msgstr ""
     118
     119#: includes/class-wsacsc-admin.php:132
     120msgid "Retrying…"
     121msgstr ""
     122
     123#: includes/class-wsacsc-admin.php:150
     124msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
     125msgstr ""
     126
     127#: includes/class-wsacsc-admin.php:159
    34128msgid "This tool allows you to clean up the Action Scheduler tables in your WordPress database. Action Scheduler is a library used by many plugins to schedule background tasks."
    35129msgstr ""
    36130
    37 #: ws-action-scheduler-cleaner.php:165
     131#: includes/class-wsacsc-admin.php:160
    38132msgid "The Action Scheduler uses two main tables:"
    39133msgstr ""
    40134
    41 #: ws-action-scheduler-cleaner.php:167
     135#: includes/class-wsacsc-admin.php:162
    42136msgid "Actions Table: Stores scheduled actions and their statuses."
    43137msgstr ""
    44138
    45 #: ws-action-scheduler-cleaner.php:168
     139#: includes/class-wsacsc-admin.php:163
    46140msgid "Logs Table: Stores logs of action executions."
    47141msgstr ""
    48142
    49 #: ws-action-scheduler-cleaner.php:170
     143#: includes/class-wsacsc-admin.php:165
    50144msgid "Clearing these tables is generally safe and can improve database performance. However, please note:"
    51145msgstr ""
    52146
    53 #: ws-action-scheduler-cleaner.php:172
     147#: includes/class-wsacsc-admin.php:167
    54148msgid "Clearing can take a while depending on the size of the tables."
    55149msgstr ""
    56150
    57 #: ws-action-scheduler-cleaner.php:173
     151#: includes/class-wsacsc-admin.php:168
    58152msgid "Cleared data will be permanently deleted."
    59153msgstr ""
    60154
    61 #: ws-action-scheduler-cleaner.php:174
     155#: includes/class-wsacsc-admin.php:169
    62156msgid "It's recommended to <strong>make a backup</strong> before proceeding."
    63157msgstr ""
    64158
    65 #: ws-action-scheduler-cleaner.php:175
     159#: includes/class-wsacsc-admin.php:170
    66160msgid "Clearing completed, failed, or canceled actions usually doesn't affect WordPress functionality."
    67161msgstr ""
    68162
    69 #: ws-action-scheduler-cleaner.php:177
     163#. translators: %s: URL to Action Scheduler admin page
     164#: includes/class-wsacsc-admin.php:177
     165#, php-format
    70166msgid "For more information, visit the <a href=\"%s\">Action Scheduler admin page</a>."
    71167msgstr ""
    72168
    73 #: ws-action-scheduler-cleaner.php:143
     169#: includes/class-wsacsc-admin.php:186
    74170msgid "Current Table Sizes:"
    75171msgstr ""
    76172
    77 #: ws-action-scheduler-cleaner.php:151
     173#: includes/class-wsacsc-admin.php:188
     174msgid "Actions table:"
     175msgstr ""
     176
     177#: includes/class-wsacsc-admin.php:190
     178#: includes/class-wsacsc-admin.php:198
     179msgid "rows"
     180msgstr ""
     181
     182#: includes/class-wsacsc-admin.php:196
     183msgid "Logs table:"
     184msgstr ""
     185
     186#: includes/class-wsacsc-admin.php:207
    78187msgid "Clear Action Statuses"
    79188msgstr ""
    80189
    81 #: ws-action-scheduler-cleaner.php:153
    82 msgid "Select which action statuses to clear:"
    83 msgstr ""
    84 
    85 #: ws-action-scheduler-cleaner.php:158
     190#: includes/class-wsacsc-admin.php:209
     191msgid "Action statuses to clear"
     192msgstr ""
     193
     194#: includes/class-wsacsc-admin.php:210
     195msgid "Select which statuses to remove when clearing manually, when this plugin runs scheduled action cleanup, and (if this plugin’s action cleanup schedule is disabled) which statuses Action Scheduler may delete in the background:"
     196msgstr ""
     197
     198#: includes/class-wsacsc-admin.php:217
    86199msgid "Complete"
    87200msgstr ""
    88201
    89 #: ws-action-scheduler-cleaner.php:159
     202#: includes/class-wsacsc-admin.php:218
    90203msgid "Failed"
    91204msgstr ""
    92205
    93 #: ws-action-scheduler-cleaner.php:160
     206#: includes/class-wsacsc-admin.php:219
    94207msgid "Canceled"
    95208msgstr ""
    96209
    97 #: ws-action-scheduler-cleaner.php:163
     210#: includes/class-wsacsc-admin.php:221
    98211msgid "Clear Selected Actions"
    99212msgstr ""
    100213
    101 #: ws-action-scheduler-cleaner.php:169
     214#: includes/class-wsacsc-admin.php:226
    102215msgid "Clear Logs Table"
    103216msgstr ""
    104217
    105 #: ws-action-scheduler-cleaner.php:170
     218#: includes/class-wsacsc-admin.php:227
    106219msgid "This will clear all entries in the logs table."
    107220msgstr ""
    108221
    109 #: ws-action-scheduler-cleaner.php:171
     222#: includes/class-wsacsc-admin.php:228
    110223msgid "Clear Logs"
    111224msgstr ""
    112225
    113 #: ws-action-scheduler-cleaner.php:177
     226#: includes/class-wsacsc-admin.php:232
     227msgid "Optimize Tables"
     228msgstr ""
     229
     230#: includes/class-wsacsc-admin.php:233
     231msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
     232msgstr ""
     233
     234#: includes/class-wsacsc-admin.php:235
     235msgid "Optimize Actions Table"
     236msgstr ""
     237
     238#: includes/class-wsacsc-admin.php:236
     239msgid "Optimize Logs Table"
     240msgstr ""
     241
     242#: includes/class-wsacsc-admin.php:241
    114243msgid "Scheduling Options"
    115244msgstr ""
    116245
    117 #: ws-action-scheduler-cleaner.php:178
    118 msgid "Set up automatic clearing schedules for selected statuses (set to 0 to clean fully; leave empty to disable automatic clearing):"
    119 msgstr ""
    120 
    121 #: ws-action-scheduler-cleaner.php:181
    122 msgid "Clear logs older than:"
    123 msgstr ""
    124 
    125 #: ws-action-scheduler-cleaner.php:185
    126 #: ws-action-scheduler-cleaner.php:193
     246#: includes/class-wsacsc-admin.php:242
     247msgid "Finished actions can be removed automatically in two ways: this plugin’s scheduled cleanup (settings below) and Action Scheduler’s own built-in background cleanup for the actions table. The status checkboxes in “Clear Action Statuses” above define which statuses are affected—manual clearing, this plugin’s scheduled action cleanup, and (when this plugin’s action cleanup schedule is disabled) Action Scheduler’s background deletions."
     248msgstr ""
     249
     250#: includes/class-wsacsc-admin.php:243
     251msgid "Cleanup schedule and retention period are separate. Cleanup schedule controls how often this plugin runs its own WordPress cron jobs (1–365 days, or empty/0 to disable). Retention period controls how old entries must be before they are deleted. For actions, age is measured by completion or last attempt time—not the original scheduled date."
     252msgstr ""
     253
     254#: includes/class-wsacsc-admin.php:244
     255msgid "If an actions cleanup schedule is enabled, only this plugin’s cron job deletes old actions (using the selected statuses above); Action Scheduler’s built-in action cleanup is turned off to avoid duplicate deletions. If that schedule is disabled, this plugin does not run scheduled action cleanup—the actions retention period is passed to Action Scheduler instead, which deletes actions in the selected statuses when they are older than that many days."
     256msgstr ""
     257
     258#: includes/class-wsacsc-admin.php:245
     259msgid "Logs cleanup schedule and logs retention apply only to this plugin; Action Scheduler does not clean the logs table on its own."
     260msgstr ""
     261
     262#: includes/class-wsacsc-admin.php:246
     263msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
     264msgstr ""
     265
     266#: includes/class-wsacsc-admin.php:249
     267msgid "Action Statuses"
     268msgstr ""
     269
     270#: includes/class-wsacsc-admin.php:251
     271#: includes/class-wsacsc-admin.php:277
     272msgid "Cleanup Schedule:"
     273msgstr ""
     274
     275#: includes/class-wsacsc-admin.php:254
     276#: includes/class-wsacsc-admin.php:269
     277#: includes/class-wsacsc-admin.php:280
     278#: includes/class-wsacsc-admin.php:295
    127279msgid "days"
    128280msgstr ""
    129281
    130 #: ws-action-scheduler-cleaner.php:189
    131 msgid "Clear action statuses older than:"
    132 msgstr ""
    133 
    134 #: ws-action-scheduler-cleaner.php:197
     282#: includes/class-wsacsc-admin.php:256
     283msgid "This plugin only: how often its WordPress cron job deletes old actions (empty or 0 = disabled, 1–365 days). When enabled, Action Scheduler’s built-in action cleanup is disabled. This is not the retention period."
     284msgstr ""
     285
     286#: includes/class-wsacsc-admin.php:259
     287#: includes/class-wsacsc-admin.php:285
     288msgid "Schedule Time:"
     289msgstr ""
     290
     291#: includes/class-wsacsc-admin.php:263
     292msgid "This plugin only: time of day for its action cleanup job (WordPress timezone)."
     293msgstr ""
     294
     295#: includes/class-wsacsc-admin.php:266
     296#: includes/class-wsacsc-admin.php:292
     297msgid "Retention Period:"
     298msgstr ""
     299
     300#: includes/class-wsacsc-admin.php:271
     301msgid "How long to keep actions before deletion (by completion or last attempt time, not scheduled date), for the statuses selected above. With a plugin action cleanup schedule enabled: used only by this plugin’s cron job. With that schedule disabled: passed to Action Scheduler’s background cleanup for the same selected statuses. 0 = delete all matching actions on every cleanup run. Required."
     302msgstr ""
     303
     304#: includes/class-wsacsc-admin.php:275
     305msgid "Logs"
     306msgstr ""
     307
     308#: includes/class-wsacsc-admin.php:282
     309msgid "This plugin only: how often its WordPress cron job deletes old log entries (empty or 0 = disabled, 1–365 days). Action Scheduler does not clean logs automatically. This is not the retention period."
     310msgstr ""
     311
     312#: includes/class-wsacsc-admin.php:289
     313msgid "This plugin only: time of day for its log cleanup job (WordPress timezone)."
     314msgstr ""
     315
     316#: includes/class-wsacsc-admin.php:297
     317msgid "This plugin only: delete log entries older than this many days (0 = delete all logs on each cleanup run). Required."
     318msgstr ""
     319
     320#: includes/class-wsacsc-admin.php:301
    135321msgid "Save Schedule"
    136322msgstr ""
    137323
    138 #: ws-action-scheduler-cleaner.php:203
     324#: includes/class-wsacsc-admin.php:307
    139325msgid "Powered by Winning Solutions"
    140326msgstr ""
    141327
    142 #: ws-action-scheduler-cleaner.php:252
    143 msgid "Selected actions cleared successfully!"
    144 msgstr ""
    145 
    146 #: ws-action-scheduler-cleaner.php:270
    147 msgid "Logs cleared successfully!"
    148 msgstr ""
    149 
    150 #: ws-action-scheduler-cleaner.php:288
    151 msgid "Schedule saved successfully!"
    152 msgstr ""
    153 
    154 #: includes/class-ajax.php:278
     328#: includes/class-wsacsc-ajax.php:37
     329msgid "Another cleanup or optimization is already running. Please wait until it finishes."
     330msgstr ""
     331
     332#: includes/class-wsacsc-ajax.php:81
     333#: includes/class-wsacsc-ajax.php:96
     334#: includes/class-wsacsc-ajax.php:150
     335#: includes/class-wsacsc-ajax.php:209
     336#: includes/class-wsacsc-ajax.php:305
     337#: includes/class-wsacsc-ajax.php:329
     338#: includes/class-wsacsc-ajax.php:356
     339#: includes/class-wsacsc-ajax.php:404
     340msgid "Insufficient permissions."
     341msgstr ""
     342
     343#: includes/class-wsacsc-ajax.php:112
     344#: includes/class-wsacsc-ajax.php:156
     345msgid "Action Scheduler tables do not exist."
     346msgstr ""
     347
     348#: includes/class-wsacsc-ajax.php:131
     349msgid "An error occurred while clearing actions."
     350msgstr ""
     351
     352#: includes/class-wsacsc-ajax.php:190
     353msgid "An error occurred while clearing logs."
     354msgstr ""
     355
     356#: includes/class-wsacsc-ajax.php:230
     357msgid "Actions schedule interval must be empty or between 1 and 365 days."
     358msgstr ""
     359
     360#: includes/class-wsacsc-ajax.php:234
     361msgid "Logs schedule interval must be empty or between 1 and 365 days."
     362msgstr ""
     363
     364#: includes/class-wsacsc-ajax.php:238
     365msgid "Actions schedule time must be in HH:MM format."
     366msgstr ""
     367
     368#: includes/class-wsacsc-ajax.php:242
     369msgid "Logs schedule time must be in HH:MM format."
     370msgstr ""
     371
     372#: includes/class-wsacsc-ajax.php:246
     373msgid "Actions retention period is required and must be between 0 and 365 days."
     374msgstr ""
     375
     376#: includes/class-wsacsc-ajax.php:250
     377msgid "Logs retention period is required and must be between 0 and 365 days."
     378msgstr ""
     379
     380#: includes/class-wsacsc-ajax.php:288
     381msgid "Failed to save schedule. Please try again."
     382msgstr ""
     383
     384#: includes/class-wsacsc-ajax.php:292
    155385msgid "The settings were saved, but the cleanup schedule could not be updated yet. The plugin will retry automatically."
    156386msgstr ""
    157387
    158 #: ws-action-scheduler-cleaner.php:302
    159 msgid "Statuses saved successfully!"
    160 msgstr ""
    161 
    162 #: ws-action-scheduler-cleaner.php:420
    163 msgid "Action Scheduler tables do not exist. Please ensure Action Scheduler is properly installed and activated."
    164 msgstr ""
    165 
    166 #: ws-action-scheduler-cleaner.php:445
    167 msgid "Please select at least one status to clear."
    168 msgstr ""
    169 
    170 #: ws-action-scheduler-cleaner.php:446
    171 msgid "Clearing in progress..."
    172 msgstr ""
    173 
    174 #: ws-action-scheduler-cleaner.php:480
    175 msgid "Optimize Tables"
    176 msgstr ""
    177 
    178 #: ws-action-scheduler-cleaner.php:481
    179 msgid "Optimize the database tables to reclaim unused space and potentially improve performance."
    180 msgstr ""
    181 
    182 #: ws-action-scheduler-cleaner.php:482
    183 msgid "Optimize Actions Table"
    184 msgstr ""
    185 
    186 #: ws-action-scheduler-cleaner.php:483
    187 msgid "Optimize Logs Table"
    188 msgstr ""
    189 
    190 #: ws-action-scheduler-cleaner.php:484
    191 msgid "Optimizing table..."
    192 msgstr ""
    193 
    194 #: ws-action-scheduler-cleaner.php:485
     388#: includes/class-wsacsc-ajax.php:336
     389#: includes/class-wsacsc-ajax.php:363
     390msgid "Invalid table type."
     391msgstr ""
     392
     393#. translators: %s: table type (actions or logs).
     394#: includes/class-wsacsc-ajax.php:390
     395#, php-format
    195396msgid "%s table optimized successfully!"
    196397msgstr ""
    197398
    198 #: ws-action-scheduler-cleaner.php:486
    199 msgid "Table optimization failed."
    200 msgstr ""
    201 
    202 #: ws-action-scheduler-cleaner.php:487
    203 msgid "An error occurred. Please try again."
    204 msgstr ""
    205 
    206 #: ws-action-scheduler-cleaner.php:488
    207 msgid "Table does not exist."
    208 msgstr ""
    209 
    210 #: ws-action-scheduler-cleaner.php:489
    211 msgid "Invalid table type."
    212 msgstr ""
    213 
    214 #: ws-action-scheduler-cleaner.php:490
    215 msgid "Insufficient permissions."
    216 msgstr ""
    217 
    218 #: includes/class-admin.php:221
    219 msgid "Cleanup Schedule and Retention Period are separate settings. Cleanup Schedule controls how often this plugin runs its own cleanup job (when set to 1–365 days). Retention Period controls how old finished actions must be before they are deleted, based on completion or last attempt time—the same basis Action Scheduler uses—not the original scheduled date."
    220 msgstr ""
    221 
    222 #: includes/class-admin.php:222
    223 msgid "When a cleanup schedule is enabled, Action Scheduler's built-in continuous cleanup is disabled to avoid duplicate deletions; only this plugin's scheduled job removes old finished actions until you clear the schedule. Without a cleanup schedule, Retention Period still applies to Action Scheduler's background cleanup. Logs retention applies only to this plugin's log cleanup."
    224 msgstr ""
    225 
    226 #: includes/class-admin.php:223
    227 msgid "This plugin does not hide status filters on the Action Scheduler admin screen. Tabs such as Complete or Failed only appear when actions with those statuses exist in the database. On sites with a very large pending backlog, few actions may finish; if counts stay at zero, those tabs will not show."
    228 msgstr ""
    229 
    230 #: includes/class-admin.php:225
    231 msgid "Action Statuses"
    232 msgstr ""
    233 
    234 #: includes/class-admin.php:227
    235 msgid "Cleanup Schedule:"
    236 msgstr ""
    237 
    238 #: includes/class-admin.php:232
    239 msgid "How often this plugin runs its cleanup job (empty or 0 = disabled, 1–365 days). This is not the retention period."
    240 msgstr ""
    241 
    242 #: includes/class-admin.php:229
    243 msgid "Schedule Time:"
    244 msgstr ""
    245 
    246 #: includes/class-admin.php:233
    247 msgid "Time of day to run cleanup (uses WordPress timezone)."
    248 msgstr ""
    249 
    250 #: includes/class-admin.php:236
    251 msgid "Retention Period:"
    252 msgstr ""
    253 
    254 #: includes/class-admin.php:247
    255 msgid "Delete selected finished statuses whose completion or last attempt is older than this many days (0 = delete all matching statuses on each cleanup run, required field)."
    256 msgstr ""
    257 
    258 #: includes/class-admin.php:245
    259 msgid "Logs"
    260 msgstr ""
    261 
    262 #: includes/class-admin.php:267
    263 msgid "Delete logs older than this (0 = delete all logs, required field)."
    264 msgstr ""
    265 
    266 #: includes/class-ajax.php:139
    267 msgid "Actions schedule interval must be empty or between 1 and 365 days."
    268 msgstr ""
    269 
    270 #: includes/class-ajax.php:144
    271 msgid "Logs schedule interval must be empty or between 1 and 365 days."
    272 msgstr ""
    273 
    274 #: includes/class-ajax.php:149
    275 msgid "Actions schedule time must be in HH:MM format."
    276 msgstr ""
    277 
    278 #: includes/class-ajax.php:154
    279 msgid "Logs schedule time must be in HH:MM format."
    280 msgstr ""
    281 
    282 #: includes/class-ajax.php:159
    283 msgid "Actions retention period is required and must be between 0 and 365 days."
    284 msgstr ""
    285 
    286 #: includes/class-ajax.php:164
    287 msgid "Logs retention period is required and must be between 0 and 365 days."
    288 msgstr ""
    289 
    290 #: includes/helpers.php:243
     399#: includes/class-wsacsc-ajax.php:411
     400msgid "Invalid cleanup ID."
     401msgstr ""
     402
     403#: includes/class-wsacsc-ajax.php:427
     404msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
     405msgstr ""
     406
     407#: includes/class-wsacsc-ajax.php:435
     408msgid "Invalid cleanup progress data."
     409msgstr ""
     410
     411#: includes/class-wsacsc-ajax.php:441
     412msgid "An error occurred during cleanup."
     413msgstr ""
     414
     415#: includes/class-wsacsc-ajax.php:453
     416msgid "Cleanup completed successfully!"
     417msgstr ""
     418
     419#. translators: %d: number of days.
     420#: includes/class-wsacsc-scheduler.php:245
     421#, php-format
     422msgid "Every %d day"
     423msgid_plural "Every %d days"
     424msgstr[0] ""
     425msgstr[1] ""
     426
     427#. translators: 1: rows deleted so far, 2: rows to delete in total, 3: percentage done.
     428#: includes/helpers.php:329
     429#, php-format
     430msgid "Clearing in progress… %1$s of %2$s rows deleted (%3$d%%)."
     431msgstr ""
     432
     433#. translators: %s: number of rows deleted so far.
     434#: includes/helpers.php:342
     435#, php-format
    291436msgid "Clearing in progress… %s rows deleted so far."
    292437msgstr ""
    293 
    294 #: includes/class-ajax.php:504
    295 msgid "Cleanup completed successfully!"
    296 msgstr ""
    297 
    298 #: includes/class-ajax.php:37
    299 msgid "Another cleanup or optimization is already running. Please wait until it finishes."
    300 msgstr ""
    301 
    302 #: includes/class-ajax.php:132
    303 msgid "An error occurred while clearing actions."
    304 msgstr ""
    305 
    306 #: includes/class-ajax.php:176
    307 msgid "An error occurred while clearing logs."
    308 msgstr ""
    309 
    310 #: includes/class-ajax.php:476
    311 msgid "Cleanup progress was lost or is continuing in the background. Refresh the page to check table sizes."
    312 msgstr ""
    313 
    314 #: includes/class-ajax.php:491
    315 msgid "An error occurred during cleanup."
    316 msgstr ""
    317 
    318 #: includes/class-admin.php:131
    319 msgid "Retrying…"
    320 msgstr ""
  • ws-action-scheduler-cleaner/trunk/readme.txt

    r3750500 r3798362  
    44Requires at least: 6.3
    55Tested up to: 7.1
    6 Stable tag: 1.3.1
     6Stable tag: 1.3.2
    77Requires PHP: 7.4
    88License: GPLv2 or later
    … …  
    8080
    8181== Changelog ==
     82
     83= 2026-11-10: 1.3.2 =
     84* Fixed: With a cleanup schedule turned on, Action Scheduler deleted all finished actions at once. It now keeps them for your retention period.
     85* Fixed: Activation and deactivation no longer cause database errors on MySQL. Table sizes now show correctly on MySQL 8.
     86* Fixed: Clearing old actions now also removes their log entries. Retention now uses UTC time.
     87* Improved: Clearing millions of finished actions or logs now takes seconds instead of minutes. Other clears show their progress as rows deleted of the total and no longer run twice at the same time or stop early.
     88* Improved: Faster table statistics, no duplicate database index, complete German translations, and code that follows the WordPress Coding Standards.
    8289
    8390= 2026-10-15: 1.3.1 =
    … …  
    117124* **Improved AJAX cleanup performance**: AJAX-based cleanup now uses batch processing with larger batches (5000 rows per batch, so still a low enough number that shouldn't cause DB server issues) for faster cleanup of large tables.
    118125* **Enhanced user feedback**: Added modern loading spinner animation and italic styling to progress messages. Buttons remain disabled and progress messages stay visible during cleanup operations.
    119 * **Prevented timeouts on large tables**: Both AJAX-based and scheduled cleanup operations now temporarily increase PHP execution time and memory limits during cleanup to handle very large tables (multiple gigabytes) without timing out. Original PHP settings are automatically restored after cleanup completes.
     126* **Prevented timeouts on large tables**: Both AJAX-based and scheduled cleanup operations now temporarily increase PHP execution time and memory limits during cleanup to handle very large tables (multiple gigabytes) without timing out. Original PHP settings are automatically restored after cleanup completes. (Since 1.3.2, the memory limit is only raised and not lowered again.)
    120127* **Added cron health checking for version migration**: We now handle edge cases for crons after version migration better and fixed some uninstall behavior issues.
    121128
    … …  
    142149== Upgrade Notice ==
    143150
     151= 1.3.2 =
     152* Fixes early deletion of finished actions when a cleanup schedule is turned on. Recommended for all users.
     153
    144154= 1.3.1 =
    145155* Fixes very high Redis CPU load caused by repeated cache group flushes, and scheduled cleanups that never ran when no time of day was set. Recommended for all users, especially sites with a persistent object cache.
    … …  
    171181= Manual cleanup (admin UI / AJAX) =
    172182
    173 * `wsacsc_ajax_cleanup_batch_size` (default: `10000`) — Maximum rows deleted per `DELETE` statement during manual clear operations initiated from the admin screen. Higher values can speed up very large tables but increase load per query.
    174 * `wsacsc_ajax_cleanup_max_seconds` (default: `18`) — Seconds of work per AJAX request before the plugin saves progress and returns. The admin UI polls for the next chunk while you keep the page open. Increase on slow hosts if chunks finish too quickly; decrease if requests time out.
     183* `wsacsc_ajax_cleanup_batch_size` (default: `10000`) — Maximum rows deleted per `DELETE` statement during manual clear operations initiated from the admin screen. Since 1.3.2, each job starts with smaller batches and adapts the size to the target time below, so this is an upper limit.
     184* `wsacsc_ajax_cleanup_target_batch_seconds` (default: `1.0`) — Target duration in seconds of one `DELETE` statement during manual clear operations. The batch size doubles while statements are faster than half this value and halves when they take more than twice this value.
     185* `wsacsc_ajax_cleanup_sleep_us` (default: `5000`) — Microseconds to pause between two `DELETE` statements during manual clear operations.
     186* `wsacsc_ajax_cleanup_max_seconds` (default: `5`) — Seconds of work per AJAX request before the plugin saves progress and returns. The admin UI polls for the next chunk while you keep the page open, so a lower value updates the progress text more often. Decrease if requests time out.
    175187
    176188= Scheduled cleanup (WP-Cron) =
    177189
    178 * `wsacsc_cron_cleanup_batch_size` (default: `2000`) — Same as the AJAX batch size, but for automatic retention cleanup run on a schedule. Defaults are lower than manual cleanup to reduce impact on live traffic.
     190* `wsacsc_cron_cleanup_batch_size` (default: `1000`) — Same as the AJAX batch size, but for automatic retention cleanup run on a schedule. Defaults are lower than manual cleanup to reduce impact on live traffic.
     191* `wsacsc_cron_cleanup_target_batch_seconds` (default: `0.5`) — Same as the AJAX target time, but for scheduled cleanup.
     192* `wsacsc_cron_cleanup_sleep_us` (default: `25000`) — Microseconds to pause between two `DELETE` statements during scheduled cleanup.
    179193* `wsacsc_cron_cleanup_max_seconds` (default: `45`) — Seconds of work per cron run before the job pauses and schedules continuation (see below).
    180194
    181195= Background continuation =
    182196
    183 * `wsacsc_cleanup_use_background_continuation` (default: `true`) — When a chunk ends before deletion is finished, schedule a single WP-Cron event to resume the job in the background. This is important for scheduled cleanup on large tables and when no admin session is polling progress. Manual cleanup in the browser also continues via AJAX polling; setting this filter to `false` disables cron-based resumption only (unfinished scheduled jobs may stall unless something else triggers the next chunk).
     197* `wsacsc_cleanup_use_background_continuation` (default: `true`) — When a chunk ends before deletion is finished, schedule a single WP-Cron event to resume the job in the background. This is important for scheduled cleanup on large tables and when no admin session is polling progress. Manual cleanup in the browser also continues via AJAX polling; setting this filter to `false` disables cron-based resumption only (unfinished scheduled jobs may stall unless something else triggers the next chunk). Since 1.3.2, only one process works on a job at a time: while the admin page polls a manual job, the background continuation waits, and it takes over about 25 seconds after the page stops polling.
     198* `wsacsc_cleanup_continuation_delay` (default: `30`) — Seconds until the background continuation runs. Clamped between `15` and `120`.
     199* `wsacsc_cron_cleanup_cli_max_seconds` (default: `600`) — When WP-Cron runs through WP-CLI (for example `wp cron event run --due-now` from a system cron job), a scheduled cleanup keeps running its next chunks in the same process, with the normal pause between chunks, instead of waiting for the next system cron run. After this many seconds, it starts no new chunk and leaves the rest to the next run.
    184200
    185201= Scheduled auto-optimize =
    … …  
    189205* `wsacsc_scheduled_auto_optimize_max_rows` (default: `100000`) — Run auto-optimize only if the table's total row count is at or below this value after cleanup. Prevents long, blocking optimize operations on tables that are still huge. Values below `1000` are raised to `1000`.
    190206* `wsacsc_scheduled_auto_optimize_delay_seconds` (default: `5`) — Seconds to wait after the last delete batch before running `OPTIMIZE TABLE`, giving the database a short breather. Clamped between `0` and `60`.
     207
     208= Resources and statistics =
     209
     210* `wsacsc_clear_actions_use_rebuild` (default: `true`) — When "Clear Selected Actions" deletes almost all rows of a large table, the plugin copies the few rows to keep, empties the actions and logs tables with `TRUNCATE TABLE`, and copies the kept rows back with their original IDs. This takes seconds instead of minutes and frees the disk space at once. The tables are locked during the rebuild, so Action Scheduler waits briefly and loses nothing. The plugin falls back to deleting in batches when the conditions below are not met, when the database user lacks the `CREATE`, `DROP`, `ALTER` or `LOCK TABLES` privilege, or when the tables are busy for more than 5 seconds. If a rebuild stops halfway, the plugin restores the kept rows on the next admin page load. Scheduled cleanup never uses the rebuild.
     211* `wsacsc_rebuild_min_rows` (default: `100000`) — Smallest number of rows to delete for which the rebuild is used.
     212* `wsacsc_rebuild_max_kept_actions` (default: `10000`) — Largest number of kept actions (for example pending actions) for which the rebuild is used. The lock time grows with this number.
     213* `wsacsc_rebuild_max_kept_logs` (default: `40000`) — Largest number of kept log entries for which the rebuild is used.
     214* `wsacsc_clear_logs_use_truncate` (default: `true`) — "Clear Logs" and a logs retention of 0 days empty the logs table with `TRUNCATE TABLE`, which takes under a second and frees the disk space at once. This needs the database `DROP` privilege. Without it, or when this filter returns `false`, the plugin deletes the log entries in batches.
     215* `wsacsc_cleanup_memory_limit` (default: `512M`) — Memory limit for cleanup and optimize requests. The plugin only raises the limit through `wp_raise_memory_limit()` and never lowers it.
     216* `wsacsc_exact_count_max_rows` (default: `1000000`) — Row counts on the admin screen are exact up to this value. For a larger table, the screen shows the estimate of the database server with a `~` prefix. Values below `1000` are raised to `1000`.
    191217
    192218Example (gentler cron, no background continuation):
  • ws-action-scheduler-cleaner/trunk/uninstall.php

    r3750500 r3798362  
    1313}
    1414
    15 $plugin_file = __FILE__;
    16 $plugin_dir  = plugin_dir_path( $plugin_file );
     15/**
     16 * Remove all plugin data: indexes, cron events, jobs, locks, options, and cache entries.
     17 *
     18 * The code runs in a function so that it defines no global variables.
     19 */
     20function wsacsc_uninstall(): void {
     21        $plugin_dir = plugin_dir_path( __FILE__ );
    1722
    18 if ( file_exists( $plugin_dir . 'includes/helpers.php' ) ) {
    19         require_once $plugin_dir . 'includes/helpers.php';
    20 }
    21 if ( file_exists( $plugin_dir . 'includes/class-database.php' ) ) {
    22         require_once $plugin_dir . 'includes/class-database.php';
    23 }
    24 if ( file_exists( $plugin_dir . 'includes/class-scheduler.php' ) ) {
    25         require_once $plugin_dir . 'includes/class-scheduler.php';
     23        foreach ( array( 'helpers.php', 'class-wsacsc-database.php', 'class-wsacsc-job-lock.php', 'class-wsacsc-rebuild.php', 'class-wsacsc-cleanup.php', 'class-wsacsc-scheduler.php' ) as $file ) {
     24                if ( file_exists( $plugin_dir . 'includes/' . $file ) ) {
     25                        require_once $plugin_dir . 'includes/' . $file;
     26                }
     27        }
     28
     29        // Put back the kept rows of an interrupted fast clear before anything else.
     30        if ( class_exists( 'WSACSC_Rebuild' ) && WSACSC_Rebuild::recover() ) {
     31                WSACSC_Rebuild::drop_work_tables();
     32        }
     33
     34        if ( class_exists( 'WSACSC_Database' ) ) {
     35                WSACSC_Database::drop_plugin_indexes();
     36        }
     37
     38        $hook_names = array( 'wsacsc_cleanup_logs', 'wsacsc_cleanup_actions' );
     39
     40        if ( class_exists( 'WSACSC_Scheduler' ) ) {
     41                WSACSC_Scheduler::winningsolutions_force_clear_cron_hooks( $hook_names );
     42        } else {
     43                foreach ( $hook_names as $hook_name ) {
     44                        wp_unschedule_hook( $hook_name );
     45                }
     46        }
     47
     48        foreach ( $hook_names as $hook_name ) {
     49                if ( false !== wp_next_scheduled( $hook_name ) && function_exists( 'wsacsc_log' ) ) {
     50                        wsacsc_log( sprintf( 'Warning - Hook %s still exists after cleanup attempt', $hook_name ) );
     51                }
     52        }
     53
     54        wp_unschedule_hook( 'wsacsc_maintain_indexes' );
     55
     56        if ( class_exists( 'WSACSC_Cleanup' ) ) {
     57                WSACSC_Cleanup::delete_all_jobs();
     58        }
     59
     60        $plugin_options = array(
     61                'wsacsc_logs_retention',
     62                'wsacsc_actions_retention',
     63                'wsacsc_selected_statuses',
     64                'wsacsc_actions_schedule_interval',
     65                'wsacsc_logs_schedule_interval',
     66                'wsacsc_actions_schedule_time',
     67                'wsacsc_logs_schedule_time',
     68                'wsacsc_migration_v2_done',
     69                'wsacsc_db_version',
     70                'wsacsc_schedule_state',
     71                'wsacsc_schedule_lock',
     72                'wsacsc_schedule_revision',
     73        );
     74
     75        foreach ( $plugin_options as $option ) {
     76                delete_option( $option );
     77        }
     78
     79        wp_cache_delete( 'wsacsc_tables_exist', 'wsacsc' );
     80        wp_cache_delete( 'wsacsc_table_sizes', 'wsacsc' );
    2681}
    2782
    28 global $wpdb;
    29 
    30 $actions_table = $wpdb->prefix . 'actionscheduler_actions';
    31 if ( class_exists( 'WSACSC_Database' ) && WSACSC_Database::check_tables_exist() ) {
    32         // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
    33         $wpdb->query( "DROP INDEX IF EXISTS as_status_scheduled ON `{$actions_table}`" );
    34         // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
    35         $wpdb->query( "DROP INDEX IF EXISTS as_status_completed ON `{$actions_table}`" );
    36 }
    37 
    38 $hook_names = array( 'wsacsc_cleanup_logs', 'wsacsc_cleanup_actions' );
    39 
    40 if ( class_exists( 'WSACSC_Scheduler' ) ) {
    41         WSACSC_Scheduler::winningsolutions_force_clear_cron_hooks( $hook_names );
    42 } else {
    43         foreach ( $hook_names as $hook_name ) {
    44                 wp_unschedule_hook( $hook_name );
    45         }
    46 }
    47 
    48 foreach ( $hook_names as $hook_name ) {
    49         $still_exists = wp_next_scheduled( $hook_name );
    50         if ( false !== $still_exists && function_exists( 'wsacsc_should_log' ) && wsacsc_should_log() ) {
    51                 error_log( sprintf( 'WS Action Scheduler Cleaner: Warning - Hook %s still exists after cleanup attempt', $hook_name ) );
    52         }
    53 }
    54 
    55 $plugin_options = array(
    56         'wsacsc_logs_retention',
    57         'wsacsc_actions_retention',
    58         'wsacsc_selected_statuses',
    59         'wsacsc_actions_schedule_interval',
    60         'wsacsc_logs_schedule_interval',
    61         'wsacsc_actions_schedule_time',
    62         'wsacsc_logs_schedule_time',
    63         'wsacsc_migration_v2_done',
    64         'wsacsc_schedule_state',
    65         'wsacsc_schedule_lock',
    66         'wsacsc_schedule_revision',
    67 );
    68 
    69 foreach ( $plugin_options as $option ) {
    70         delete_option( $option );
    71 }
    72 
    73 wp_cache_delete( 'wsacsc_tables_exist', 'wsacsc' );
    74 wp_cache_delete( 'wsacsc_table_sizes', 'wsacsc' );
     83wsacsc_uninstall();
  • ws-action-scheduler-cleaner/trunk/ws-action-scheduler-cleaner.php

    r3750500 r3798362  
    33 * Plugin Name: WS Action Scheduler Cleaner
    44 * Description: Suffering from database bloat? Try cleaning up the Action Scheduler tables through an easy-to-understand GUI.
    5  * Version: 1.3.1
     5 * Version: 1.3.2
    66 * Author: Winning Solutions - Nagel & Mäder GbR
    77 * Author URI: https://www.winning-solutions.de
    … …  
    1313 * License: GPLv2 or later
    1414 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
     15 *
     16 * @package WS_Action_Scheduler_Cleaner
    1517 */
    1618
    … …  
    2325define( 'WSACSC_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
    2426
    25 $wsacsc_plugin_data = get_file_data(
    26         __FILE__,
    27         array(
    28                 'Version' => 'Version',
    29         ),
    30         'plugin'
    31 );
    32 define( 'WSACSC_VERSION', ! empty( $wsacsc_plugin_data['Version'] ) ? $wsacsc_plugin_data['Version'] : '1.3.1' );
     27// Keep equal to the Version header and to the Stable tag in readme.txt.
     28define( 'WSACSC_VERSION', '1.3.2' );
    3329
    3430require_once WSACSC_PLUGIN_DIR . 'includes/helpers.php';
    35 require_once WSACSC_PLUGIN_DIR . 'includes/class-database.php';
    36 require_once WSACSC_PLUGIN_DIR . 'includes/class-activation.php';
    37 require_once WSACSC_PLUGIN_DIR . 'includes/class-admin.php';
    38 require_once WSACSC_PLUGIN_DIR . 'includes/class-ajax.php';
    39 require_once WSACSC_PLUGIN_DIR . 'includes/class-cleanup.php';
    40 require_once WSACSC_PLUGIN_DIR . 'includes/class-scheduler.php';
     31require_once WSACSC_PLUGIN_DIR . 'includes/class-wsacsc-database.php';
     32require_once WSACSC_PLUGIN_DIR . 'includes/class-wsacsc-job-lock.php';
     33require_once WSACSC_PLUGIN_DIR . 'includes/class-wsacsc-rebuild.php';
     34require_once WSACSC_PLUGIN_DIR . 'includes/class-wsacsc-activation.php';
     35require_once WSACSC_PLUGIN_DIR . 'includes/class-wsacsc-admin.php';
     36require_once WSACSC_PLUGIN_DIR . 'includes/class-wsacsc-ajax.php';
     37require_once WSACSC_PLUGIN_DIR . 'includes/class-wsacsc-cleanup.php';
     38require_once WSACSC_PLUGIN_DIR . 'includes/class-wsacsc-scheduler.php';
    4139require_once WSACSC_PLUGIN_DIR . 'includes/filters.php';
    4240
    … …  
    5149
    5250add_action( 'admin_init', array( 'WSACSC_Activation', 'migrate_existing_settings' ) );
     51add_action( 'admin_init', array( 'WSACSC_Activation', 'maybe_upgrade' ) );
     52add_action( 'admin_init', array( 'WSACSC_Rebuild', 'recover' ) );
     53add_action( WSACSC_Database::INDEX_HOOK, array( 'WSACSC_Database', 'run_index_maintenance' ) );
  • ws-action-scheduler-cleaner/trunk/wsacsc-populate-test-data.php

    r3559324 r3798362  
    55 * WARNING: TESTING ONLY. Do not run on production.
    66 *
    7  * Usage: Open this file via browser from the plugin directory (must be logged in as admin, WP_DEBUG on).
    8  * WP-CLI: wp eval-file path/to/wsacsc-populate-test-data.php -- --table=actions --target-mb=100
    9  * WP-CLI: wp eval-file path/to/wsacsc-populate-test-data.php -- --table=logs --target-rows=50000
    10  * WP-CLI: wp eval-file path/to/wsacsc-populate-test-data.php -- --table=actions --target-rows=10000 --include-pending-pct=5
    11  *
    12  * Realistic row shapes require Action Scheduler (e.g. via WooCommerce) so schedule classes load.
     7 * Generates Action Scheduler rows that resemble a real WooCommerce site:
     8 * - Action IDs follow time: older actions have lower IDs, as on a real site.
     9 * - Most finished actions are "complete". "failed" and "canceled" are rare.
     10 * - Every action gets the log entries that Action Scheduler writes for it
     11 *   ("action created", "action started via …", "action complete via …").
     12 * - Hooks, arguments, groups and schedules follow common WooCommerce patterns.
     13 *
     14 * Usage (browser): open this file from the plugin directory while logged in as an
     15 * administrator, with WP_DEBUG on.
     16 *
     17 * Usage (WP-CLI): pass options as key=value arguments and run as an administrator:
     18 *   wp --user=admin eval-file wsacsc-populate-test-data.php table=actions target-mb=500
     19 *   wp --user=admin eval-file wsacsc-populate-test-data.php table=actions target-rows=100000 days=180 pending-pct=2
     20 *   wp --user=admin eval-file wsacsc-populate-test-data.php table=actions target-rows=50000 logs=0
     21 *   wp --user=admin eval-file wsacsc-populate-test-data.php table=logs target-rows=200000
     22 *
     23 * The actions mode fills the actions table to the target and adds the matching log
     24 * entries to the logs table (logs=0 turns this off). The logs mode adds log entries
     25 * for existing actions, oldest first, and needs actions in the table.
     26 *
     27 * Realistic row shapes need Action Scheduler classes (for example from WooCommerce),
     28 * so that schedules are serialized like Action Scheduler does.
    1329 *
    1430 * @package WS_Action_Scheduler_Cleaner
    … …  
    2743        }
    2844
    29         while ( $dir && $dir !== dirname( $dir ) ) {
     45        while ( $dir && dirname( $dir ) !== $dir ) {
    3046                $candidate = $dir . DIRECTORY_SEPARATOR . 'wp-load.php';
    3147                if ( is_readable( $candidate ) ) {
    … …  
    3955
    4056if ( ! defined( 'ABSPATH' ) ) {
    41         $wp_load = wsacsc_populate_locate_wp_load( __DIR__ );
    42         if ( ! $wp_load ) {
     57        $wsacsc_populate_wp_load = wsacsc_populate_locate_wp_load( __DIR__ );
     58        if ( ! $wsacsc_populate_wp_load ) {
    4359                header( 'Content-Type: text/plain; charset=utf-8', true, 500 );
    4460                echo 'Could not locate wp-load.php. Place this file inside a WordPress installation.';
    4561                exit;
    4662        }
    47         require_once $wp_load;
     63        require_once $wsacsc_populate_wp_load;
    4864}
    4965
    … …  
    5773
    5874if ( 'cli' === PHP_SAPI && defined( 'WP_CLI' ) && WP_CLI ) {
    59         wsacsc_populate_run_cli();
     75        // WP-CLI eval-file passes positional arguments in $args.
     76        wsacsc_populate_run_cli( isset( $args ) && is_array( $args ) ? $args : array() );
    6077        exit;
    6178}
    … …  
    7592 */
    7693function wsacsc_populate_is_ajax_request() {
    77         if ( isset( $_POST['wsacsc_populate_ajax'] ) && '1' === (string) $_POST['wsacsc_populate_ajax'] ) {
     94        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Routing only. The handler verifies the nonce.
     95        if ( isset( $_POST['wsacsc_populate_ajax'] ) && '1' === sanitize_text_field( wp_unslash( $_POST['wsacsc_populate_ajax'] ) ) ) {
    7896                return true;
    7997        }
    8098
    81         $method = isset( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( (string) $_SERVER['REQUEST_METHOD'] ) : '';
     99        $method = isset( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ) : '';
    82100        if ( 'POST' !== $method ) {
    83101                return false;
    84102        }
    85103
    86         $content_type = isset( $_SERVER['CONTENT_TYPE'] ) ? (string) $_SERVER['CONTENT_TYPE'] : '';
    87         return str_contains( $content_type, 'application/json' );
     104        $content_type = isset( $_SERVER['CONTENT_TYPE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['CONTENT_TYPE'] ) ) : '';
     105        return false !== strpos( $content_type, 'application/json' );
    88106}
    89107
    … …  
    94112 */
    95113function wsacsc_populate_get_request_payload() {
    96         $content_type = isset( $_SERVER['CONTENT_TYPE'] ) ? (string) $_SERVER['CONTENT_TYPE'] : '';
    97         if ( str_contains( $content_type, 'application/json' ) ) {
    98                 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- raw JSON body.
    99                 $raw  = file_get_contents( 'php://input' );
    100                 $data = json_decode( $raw, true );
     114        $content_type = isset( $_SERVER['CONTENT_TYPE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['CONTENT_TYPE'] ) ) : '';
     115        if ( false !== strpos( $content_type, 'application/json' ) ) {
     116                // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Raw JSON body.
     117                $data = json_decode( (string) file_get_contents( 'php://input' ), true );
    101118                return is_array( $data ) ? $data : array();
    102119        }
    103120
    104121        $payload = array();
     122        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- The handler verifies the nonce in the payload.
    105123        foreach ( $_POST as $key => $value ) {
    106124                $payload[ $key ] = is_string( $value ) ? wp_unslash( $value ) : $value;
    … …  
    118136function wsacsc_populate_json_response( $success, array $data ) {
    119137        nocache_headers();
    120         header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
    121138        wp_send_json( array_merge( array( 'success' => $success ), $data ) );
    122139}
    … …  
    154171}
    155172
     173/*
     174 * -------------------------------------------------------------------------
     175 * Limits and tuning
     176 * -------------------------------------------------------------------------
     177 */
     178
    156179/**
    157180 * Transient key for a populate job.
    … …  
    188211 */
    189212function wsacsc_populate_max_rows_per_table() {
    190         return (int) apply_filters( 'wsacsc_populate_max_rows_per_table', 1000000 );
    191 }
    192 
    193 /**
    194  * Rows inserted per batch.
     213        return (int) apply_filters( 'wsacsc_populate_max_rows_per_table', 5000000 );
     214}
     215
     216/**
     217 * Actions inserted per batch. Each action also gets 2 to 3 log rows.
    195218 *
    196219 * @return int
    197220 */
    198221function wsacsc_populate_batch_row_count() {
    199         return (int) apply_filters( 'wsacsc_populate_batch_row_count', 600 );
     222        return max( 1, (int) apply_filters( 'wsacsc_populate_batch_row_count', 600 ) );
    200223}
    201224
    … …  
    206229 */
    207230function wsacsc_populate_bulk_chunk_size() {
    208         return (int) apply_filters( 'wsacsc_populate_bulk_chunk_size', 250 );
     231        return max( 1, (int) apply_filters( 'wsacsc_populate_bulk_chunk_size', 250 ) );
    209232}
    210233
    … …  
    215238 */
    216239function wsacsc_populate_max_seconds_per_batch() {
    217         return (int) apply_filters( 'wsacsc_populate_max_seconds_per_batch', 25 );
     240        return max( 1, (int) apply_filters( 'wsacsc_populate_max_seconds_per_batch', 20 ) );
    218241}
    219242
    … …  
    224247 */
    225248function wsacsc_populate_size_check_interval() {
    226         return (int) apply_filters( 'wsacsc_populate_size_check_interval', 40 );
    227 }
    228 
    229 /**
    230  * Estimated bytes per action row until recalibrated from information_schema.
    231  *
     249        return max( 1, (int) apply_filters( 'wsacsc_populate_size_check_interval', 20 ) );
     250}
     251
     252/**
     253 * Estimated bytes per row (data and indexes) until recalibrated from information_schema.
     254 *
     255 * Measured on Action Scheduler 4.2: about 770 bytes per action row with its 10 secondary
     256 * indexes, and about 140 bytes per log row.
     257 *
     258 * @param string $table actions or logs.
    232259 * @return int
    233260 */
    234 function wsacsc_populate_default_estimated_action_bytes() {
    235         return (int) apply_filters( 'wsacsc_populate_default_estimated_action_bytes', 450 );
    236 }
    237 
    238 /**
    239  * Estimated bytes per log row until recalibrated.
     261function wsacsc_populate_default_estimated_row_bytes( $table ) {
     262        if ( 'actions' === $table ) {
     263                return (int) apply_filters( 'wsacsc_populate_default_estimated_action_bytes', 770 );
     264        }
     265
     266        return (int) apply_filters( 'wsacsc_populate_default_estimated_log_bytes', 140 );
     267}
     268
     269/**
     270 * Default time span of generated history in days.
    240271 *
    241272 * @return int
    242273 */
    243 function wsacsc_populate_default_estimated_log_bytes() {
    244         return (int) apply_filters( 'wsacsc_populate_default_estimated_log_bytes', 180 );
    245 }
    246 
    247 /**
    248  * Realistic WooCommerce / WordPress hooks.
    249  *
    250  * @return string[]
    251  */
    252 function wsacsc_populate_realistic_hooks() {
     274function wsacsc_populate_default_span_days() {
     275        return 90;
     276}
     277
     278/*
     279 * -------------------------------------------------------------------------
     280 * Realistic data model
     281 * -------------------------------------------------------------------------
     282 */
     283
     284/**
     285 * Status weights of finished actions, in percent.
     286 *
     287 * On a typical store almost all finished actions are complete. Canceled actions come
     288 * mostly from unscheduled recurring actions, and failed actions are rare.
     289 *
     290 * @return array<string, int>
     291 */
     292function wsacsc_populate_status_weights() {
     293        return (array) apply_filters(
     294                'wsacsc_populate_status_weights',
     295                array(
     296                        'complete' => 94,
     297                        'canceled' => 4,
     298                        'failed'   => 2,
     299                )
     300        );
     301}
     302
     303/**
     304 * Typical Action Scheduler hooks with relative weights.
     305 *
     306 * The names come from WooCommerce, WooCommerce Subscriptions and common extensions.
     307 * The weights are estimates for a busy store, not measured values.
     308 *
     309 * Keys of each entry:
     310 * - weight:    Relative frequency.
     311 * - group:     Action Scheduler group slug, or an empty string for no group.
     312 * - args:      Argument pattern (see wsacsc_populate_build_action_args()).
     313 * - recurring: Interval in seconds for recurring actions, or 0 for single actions.
     314 * - async:     Whether the action normally runs through an async request.
     315 *
     316 * @return array<string, array{weight: int, group: string, args: string, recurring: int, async: bool}>
     317 */
     318function wsacsc_populate_hook_profiles() {
     319        return (array) apply_filters(
     320                'wsacsc_populate_hook_profiles',
     321                array(
     322                        'woocommerce_deliver_webhook_async'            => array(
     323                                'weight'    => 22,
     324                                'group'     => 'woocommerce-webhooks',
     325                                'args'      => 'webhook',
     326                                'recurring' => 0,
     327                                'async'     => true,
     328                        ),
     329                        'wc-admin_import_orders'                       => array(
     330                                'weight'    => 20,
     331                                'group'     => 'wc-admin-data',
     332                                'args'      => 'id',
     333                                'recurring' => 0,
     334                                'async'     => true,
     335                        ),
     336                        'woocommerce_run_product_attribute_lookup_update_callback' => array(
     337                                'weight'    => 14,
     338                                'group'     => 'woocommerce-db-updates',
     339                                'args'      => 'product_lookup',
     340                                'recurring' => 0,
     341                                'async'     => true,
     342                        ),
     343                        'wc-admin_import_customers'                    => array(
     344                                'weight'    => 8,
     345                                'group'     => 'wc-admin-data',
     346                                'args'      => 'id',
     347                                'recurring' => 0,
     348                                'async'     => true,
     349                        ),
     350                        'woocommerce_scheduled_subscription_payment'   => array(
     351                                'weight'    => 10,
     352                                'group'     => '',
     353                                'args'      => 'subscription',
     354                                'recurring' => 0,
     355                                'async'     => false,
     356                        ),
     357                        'woocommerce_scheduled_subscription_expiration' => array(
     358                                'weight'    => 3,
     359                                'group'     => '',
     360                                'args'      => 'subscription',
     361                                'recurring' => 0,
     362                                'async'     => false,
     363                        ),
     364                        'woocommerce_scheduled_subscription_trial_end' => array(
     365                                'weight'    => 2,
     366                                'group'     => '',
     367                                'args'      => 'subscription',
     368                                'recurring' => 0,
     369                                'async'     => false,
     370                        ),
     371                        'woocommerce_cleanup_draft_orders'             => array(
     372                                'weight'    => 4,
     373                                'group'     => '',
     374                                'args'      => 'none',
     375                                'recurring' => DAY_IN_SECONDS,
     376                                'async'     => false,
     377                        ),
     378                        'wc_admin_unsnooze_admin_notes'                => array(
     379                                'weight'    => 6,
     380                                'group'     => 'wc-admin-notes',
     381                                'args'      => 'none',
     382                                'recurring' => HOUR_IN_SECONDS,
     383                                'async'     => false,
     384                        ),
     385                        'action_scheduler/migration_hook'              => array(
     386                                'weight'    => 3,
     387                                'group'     => 'action-scheduler-migration',
     388                                'args'      => 'none',
     389                                'recurring' => MINUTE_IN_SECONDS,
     390                                'async'     => false,
     391                        ),
     392                        'mailpoet/cron/daemon-trigger'                 => array(
     393                                'weight'    => 8,
     394                                'group'     => 'mailpoet-cron',
     395                                'args'      => 'none',
     396                                'recurring' => MINUTE_IN_SECONDS,
     397                                'async'     => false,
     398                        ),
     399                )
     400        );
     401}
     402
     403/**
     404 * Pick a key from a weight map.
     405 *
     406 * @param array<string, int> $weights Key => weight.
     407 * @return string
     408 */
     409function wsacsc_populate_pick_weighted( array $weights ) {
     410        $total = array_sum( $weights );
     411        $roll  = wp_rand( 1, max( 1, (int) $total ) );
     412
     413        foreach ( $weights as $key => $weight ) {
     414                $roll -= (int) $weight;
     415                if ( $roll <= 0 ) {
     416                        return (string) $key;
     417                }
     418        }
     419
     420        return (string) array_key_first( $weights );
     421}
     422
     423/**
     424 * Max indexed args length (matches Action Scheduler DB store).
     425 *
     426 * @return int
     427 */
     428function wsacsc_populate_max_args_index_length() {
     429        return (int) apply_filters( 'wsacsc_populate_max_args_index_length', 191 );
     430}
     431
     432/**
     433 * Build args and optional extended_args for an action row.
     434 *
     435 * About 1% of actions carry a long payload, which Action Scheduler stores in
     436 * extended_args with an md5 hash in args.
     437 *
     438 * @param string $pattern Argument pattern of the hook profile.
     439 * @param bool   $has_extended_args Whether the table has the extended_args column.
     440 * @return array{args: string, extended_args: string|null}
     441 */
     442function wsacsc_populate_build_action_args( $pattern, $has_extended_args ) {
     443        switch ( $pattern ) {
     444                case 'webhook':
     445                        $args_array = array( wp_rand( 1, 12 ), wp_rand( 1000, 250000 ) );
     446                        break;
     447                case 'product_lookup':
     448                        $args_array = array( wp_rand( 10, 60000 ), wp_rand( 1, 2 ) );
     449                        break;
     450                case 'subscription':
     451                        $args_array = array( 'subscription_id' => wp_rand( 1000, 250000 ) );
     452                        break;
     453                case 'id':
     454                        $args_array = array( wp_rand( 1000, 250000 ) );
     455                        break;
     456                default:
     457                        $args_array = array();
     458        }
     459
     460        if ( wp_rand( 1, 100 ) === 1 ) {
     461                $args_array = array(
     462                        'order_id' => wp_rand( 1000, 250000 ),
     463                        'payload'  => wp_generate_password( 220, false ),
     464                        'meta'     => array_fill( 0, 8, wp_rand( 1, 9999 ) ),
     465                );
     466        }
     467
     468        $json = wp_json_encode( $args_array );
     469        if ( false === $json ) {
     470                $json = '[]';
     471        }
     472
     473        if ( strlen( $json ) <= wsacsc_populate_max_args_index_length() ) {
     474                return array(
     475                        'args'          => $json,
     476                        'extended_args' => null,
     477                );
     478        }
     479
     480        if ( ! $has_extended_args ) {
     481                return array(
     482                        'args'          => substr( $json, 0, wsacsc_populate_max_args_index_length() ),
     483                        'extended_args' => null,
     484                );
     485        }
     486
    253487        return array(
    254                 'woocommerce_scheduled_subscription_payment',
    255                 'woocommerce_scheduled_subscription_trial_end',
    256                 'woocommerce_cleanup_sessions',
    257                 'woocommerce_update_product_lookup_tables',
    258                 'woocommerce_run_update_callback',
    259                 'woocommerce_cleanup_logs',
    260                 'woocommerce_cleanup_personal_data',
    261                 'woocommerce_scheduled_sales',
    262                 'woocommerce_scheduled_downloads',
    263                 'woocommerce_cleanup_expired_transients',
    264                 'action_scheduler/migration_hook',
    265                 'wp_scheduled_auto_draft_delete',
    266                 'wp_scheduled_delete',
    267                 'wp_update_plugins',
    268                 'wp_update_themes',
    269                 'wp_version_check',
    270                 'wp_update_core',
    271                 'recovery_mode_clean_expired_keys',
    272                 'wp_privacy_delete_old_export_files',
    273                 'delete_expired_transients',
    274                 'wp_scheduled_delete_revisions',
     488                'args'          => md5( $json ),
     489                'extended_args' => $json,
    275490        );
    276491}
    277492
    278493/**
    279  * Allowed action statuses for test data.
    280  *
    281  * @return string[]
    282  */
    283 function wsacsc_populate_statuses() {
    284         return array( 'complete', 'failed', 'canceled' );
    285 }
    286 
    287 /**
    288  * Get table byte size from information_schema.
     494 * Serialized schedule for an action row, as Action Scheduler stores it.
     495 *
     496 * @param string $status    Action status.
     497 * @param int    $timestamp Scheduled time (Unix, UTC).
     498 * @param int    $recurring Recurrence interval in seconds, or 0.
     499 * @return string
     500 */
     501function wsacsc_populate_build_action_schedule( $status, $timestamp, $recurring ) {
     502        $fallback = 'O:28:"ActionScheduler_NullSchedule":0:{}';
     503
     504        if ( ! class_exists( 'ActionScheduler_SimpleSchedule' ) ) {
     505                return $fallback;
     506        }
     507
     508        try {
     509                $date = new DateTime( '@' . (int) $timestamp );
     510                $date->setTimezone( new DateTimeZone( 'UTC' ) );
     511
     512                // phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize -- Same storage format as Action Scheduler.
     513                if ( 'canceled' === $status && class_exists( 'ActionScheduler_CanceledSchedule' ) ) {
     514                        return serialize( new ActionScheduler_CanceledSchedule( $date ) );
     515                }
     516
     517                if ( $recurring > 0 && class_exists( 'ActionScheduler_IntervalSchedule' ) ) {
     518                        return serialize( new ActionScheduler_IntervalSchedule( $date, $recurring ) );
     519                }
     520
     521                return serialize( new ActionScheduler_SimpleSchedule( $date ) );
     522                // phpcs:enable
     523        } catch ( Exception $e ) {
     524                return $fallback;
     525        }
     526}
     527
     528/**
     529 * Convert a Unix timestamp to MySQL datetime strings in UTC and site time.
     530 *
     531 * @param int $timestamp Unix timestamp.
     532 * @return array{gmt: string, local: string}
     533 */
     534function wsacsc_populate_mysql_dates( $timestamp ) {
     535        return array(
     536                'gmt'   => gmdate( 'Y-m-d H:i:s', (int) $timestamp ),
     537                'local' => wp_date( 'Y-m-d H:i:s', (int) $timestamp ),
     538        );
     539}
     540
     541/*
     542 * -------------------------------------------------------------------------
     543 * Schema helpers
     544 * -------------------------------------------------------------------------
     545 */
     546
     547/**
     548 * Optional columns and tables of the Action Scheduler schema (cached per request).
     549 *
     550 * @return array{has_priority: bool, has_extended_args: bool, has_groups_table: bool}
     551 */
     552function wsacsc_populate_get_actions_schema() {
     553        static $schema = null;
     554
     555        if ( null !== $schema ) {
     556                return $schema;
     557        }
     558
     559        global $wpdb;
     560
     561        $actions_table = $wpdb->prefix . 'actionscheduler_actions';
     562        $groups_table  = $wpdb->prefix . 'actionscheduler_groups';
     563
     564        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dev utility, cached in a static variable.
     565        $columns_result = $wpdb->get_results( $wpdb->prepare( 'DESC %i', $actions_table ) );
     566        $columns        = is_array( $columns_result ) ? wp_list_pluck( $columns_result, 'Field' ) : array();
     567
     568        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dev utility, cached in a static variable.
     569        $groups_exist = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $groups_table ) ) ) === $groups_table;
     570
     571        $schema = array(
     572                'has_priority'      => in_array( 'priority', $columns, true ),
     573                'has_extended_args' => in_array( 'extended_args', $columns, true ),
     574                'has_groups_table'  => $groups_exist,
     575        );
     576
     577        return $schema;
     578}
     579
     580/**
     581 * Group slug => group_id map for all groups of the hook profiles (cached per request).
     582 *
     583 * @return array<string, int>
     584 */
     585function wsacsc_populate_group_ids() {
     586        static $map = null;
     587
     588        if ( null !== $map ) {
     589                return $map;
     590        }
     591
     592        $map = array();
     593        if ( ! wsacsc_populate_get_actions_schema()['has_groups_table'] ) {
     594                return $map;
     595        }
     596
     597        global $wpdb;
     598        $groups_table = $wpdb->prefix . 'actionscheduler_groups';
     599
     600        foreach ( wsacsc_populate_hook_profiles() as $profile ) {
     601                $slug = (string) $profile['group'];
     602                if ( '' === $slug || isset( $map[ $slug ] ) ) {
     603                        continue;
     604                }
     605
     606                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dev utility.
     607                $existing = $wpdb->get_var( $wpdb->prepare( 'SELECT group_id FROM %i WHERE slug = %s LIMIT 1', $groups_table, $slug ) );
     608                if ( $existing ) {
     609                        $map[ $slug ] = (int) $existing;
     610                        continue;
     611                }
     612
     613                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Dev utility.
     614                $wpdb->insert( $groups_table, array( 'slug' => $slug ), array( '%s' ) );
     615                if ( $wpdb->insert_id ) {
     616                        $map[ $slug ] = (int) $wpdb->insert_id;
     617                }
     618        }
     619
     620        return $map;
     621}
     622
     623/**
     624 * Get table byte size (data and indexes) from information_schema.
    289625 *
    290626 * @param string $table_name Full table name.
    … …  
    294630        global $wpdb;
    295631
     632        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Size must be current.
    296633        $size = $wpdb->get_var(
    297634                $wpdb->prepare(
    298                         'SELECT ROUND((DATA_LENGTH + INDEX_LENGTH)) AS size
    299                         FROM information_schema.TABLES
    300                         WHERE TABLE_SCHEMA = %s
    301                         AND TABLE_NAME = %s',
    302                         DB_NAME,
     635                        'SELECT (data_length + index_length) AS wsacsc_size FROM information_schema.TABLES WHERE table_schema = DATABASE() AND table_name = %s',
    303636                        $table_name
    304637                )
    … …  
    309642
    310643/**
     644 * Row count of a table.
     645 *
     646 * @param string $table_name Full table name.
     647 * @return int
     648 */
     649function wsacsc_populate_get_table_row_count( $table_name ) {
     650        global $wpdb;
     651
     652        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Count must be current.
     653        return max( 0, (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i', $table_name ) ) );
     654}
     655
     656/**
    311657 * Format bytes for display.
    312658 *
    … …  
    318664        $units = array( 'B', 'KB', 'MB', 'GB', 'TB' );
    319665        $bytes = max( 0, (int) $bytes );
    320 
    321         for ( $i = 0; $bytes > 1024 && $i < count( $units ) - 1; $i++ ) {
     666        $count = count( $units );
     667
     668        for ( $i = 0; $bytes > 1024 && $i < $count - 1; $i++ ) {
    322669                $bytes /= 1024;
    323670        }
    324671
    325672        return round( $bytes, $precision ) . ' ' . $units[ $i ];
    326 }
    327 
    328 /**
    329  * Detect optional columns on the actions table (cached per request).
    330  *
    331  * @return array{columns: string[], has_completed_date: bool, has_priority: bool, has_extended_args: bool, has_groups_table: bool}
    332  */
    333 function wsacsc_populate_get_actions_schema() {
    334         static $schema = null;
    335 
    336         if ( null !== $schema ) {
    337                 return $schema;
    338         }
    339 
    340         global $wpdb;
    341 
    342         $actions_table  = $wpdb->prefix . 'actionscheduler_actions';
    343         $groups_table   = $wpdb->prefix . 'actionscheduler_groups';
    344         $columns_query  = $wpdb->prepare( 'DESC %i', $actions_table );
    345         $columns_result = $wpdb->get_results( $columns_query );
    346         $columns        = is_array( $columns_result ) ? wp_list_pluck( $columns_result, 'Field' ) : array();
    347 
    348         $groups_exist = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $groups_table ) ) === $groups_table;
    349 
    350         $schema = array(
    351                 'columns'            => $columns,
    352                 'has_completed_date' => in_array( 'completed_date_gmt', $columns, true ) && in_array( 'completed_date_local', $columns, true ),
    353                 'has_priority'       => in_array( 'priority', $columns, true ),
    354                 'has_extended_args'  => in_array( 'extended_args', $columns, true ),
    355                 'has_groups_table'   => $groups_exist,
    356         );
    357 
    358         return $schema;
    359 }
    360 
    361 /**
    362  * Max indexed args length (matches Action Scheduler DB store).
    363  *
    364  * @return int
    365  */
    366 function wsacsc_populate_max_args_index_length() {
    367         return (int) apply_filters( 'wsacsc_populate_max_args_index_length', 191 );
    368 }
    369 
    370 /**
    371  * Whether Action Scheduler schedule classes are available.
    372  *
    373  * @return bool
    374  */
    375 function wsacsc_populate_can_use_as_classes() {
    376         return class_exists( 'ActionScheduler_SimpleSchedule' ) && class_exists( 'ActionScheduler_Action' );
    377 }
    378 
    379 /**
    380  * Convert a GMT mysql datetime string to site-local mysql format.
    381  *
    382  * @param string $gmt_mysql Datetime in GMT (Y-m-d H:i:s).
    383  * @return string
    384  */
    385 function wsacsc_populate_gmt_to_local_mysql( $gmt_mysql ) {
    386         if ( function_exists( 'as_get_datetime_object' ) && class_exists( 'ActionScheduler_TimezoneHelper' ) ) {
    387                 $date = as_get_datetime_object( $gmt_mysql );
    388                 ActionScheduler_TimezoneHelper::set_local_timezone( $date );
    389                 return $date->format( 'Y-m-d H:i:s' );
    390         }
    391 
    392         return wp_date( 'Y-m-d H:i:s', strtotime( $gmt_mysql . ' UTC' ) );
    393 }
    394 
    395 /**
    396  * Hash JSON args for indexed column when payload exceeds max length (AS-compatible).
    397  *
    398  * @param string $json_args JSON-encoded args.
    399  * @return string
    400  */
    401 function wsacsc_populate_hash_args( $json_args ) {
    402         return md5( $json_args );
    403 }
    404 
    405 /**
    406  * Build args + optional extended_args for an action row.
    407  *
    408  * @param string $hook              Action hook.
    409  * @param bool   $force_long_args   Force extended_args pattern (~5% of rows).
    410  * @return array{args: string, extended_args?: string}
    411  */
    412 function wsacsc_populate_build_action_args( $hook, $force_long_args = false ) {
    413         $schema = wsacsc_populate_get_actions_schema();
    414         $max    = wsacsc_populate_max_args_index_length();
    415 
    416         $empty_hooks = array(
    417                 'woocommerce_cleanup_sessions',
    418                 'woocommerce_cleanup_logs',
    419                 'woocommerce_cleanup_personal_data',
    420                 'woocommerce_cleanup_expired_transients',
    421                 'wp_scheduled_auto_draft_delete',
    422                 'wp_scheduled_delete',
    423                 'wp_update_plugins',
    424                 'wp_update_themes',
    425                 'wp_version_check',
    426                 'wp_update_core',
    427                 'recovery_mode_clean_expired_keys',
    428                 'wp_privacy_delete_old_export_files',
    429                 'delete_expired_transients',
    430                 'wp_scheduled_delete_revisions',
    431                 'action_scheduler/migration_hook',
    432         );
    433 
    434         if ( in_array( $hook, $empty_hooks, true ) ) {
    435                 $args_array = array();
    436         } elseif ( str_contains( $hook, 'subscription' ) ) {
    437                 $args_array = array( wp_rand( 1, 99999 ), wp_rand( 1, 9999 ) );
    438         } elseif ( str_contains( $hook, 'woocommerce' ) ) {
    439                 $args_array = array( wp_rand( 1, 99999 ) );
    440         } else {
    441                 $args_array = array( wp_rand( 1, 99999 ) );
    442                 if ( wp_rand( 0, 1 ) ) {
    443                         $args_array[] = (string) wp_rand( 1, 1000 );
    444                 }
    445         }
    446 
    447         if ( $force_long_args ) {
    448                 $args_array = array(
    449                         'order_id'    => wp_rand( 1, 99999 ),
    450                         'payload'     => wp_generate_password( 220, false ),
    451                         'meta'        => array_fill( 0, 8, wp_rand( 1, 9999 ) ),
    452                         'description' => 'WS AS Cleaner populate extended args test row',
    453                 );
    454         }
    455 
    456         $json = wp_json_encode( $args_array );
    457         if ( false === $json ) {
    458                 $json = '[]';
    459         }
    460 
    461         $result = array( 'args' => $json );
    462 
    463         if ( strlen( $json ) <= $max ) {
    464                 return $result;
    465         }
    466 
    467         if ( ! $schema['has_extended_args'] ) {
    468                 $result['args'] = substr( $json, 0, $max );
    469                 return $result;
    470         }
    471 
    472         $result['args']          = wsacsc_populate_hash_args( $json );
    473         $result['extended_args'] = $json;
    474 
    475         return $result;
    476 }
    477 
    478 /**
    479  * Serialized schedule fallback when AS classes are unavailable.
    480  *
    481  * @return string
    482  */
    483 function wsacsc_populate_fallback_schedule_serialized() {
    484         // Minimal ActionScheduler_NullSchedule-like serialized blob (schedule only; dev fallback).
    485         return 'O:32:"ActionScheduler_NullSchedule":0:{}';
    486 }
    487 
    488 /**
    489  * Build serialized schedule column value for an action row.
    490  *
    491  * @param string $status         Action status slug.
    492  * @param string $scheduled_gmt  Scheduled datetime GMT (Y-m-d H:i:s).
    493  * @return string
    494  */
    495 function wsacsc_populate_build_action_schedule( $status, $scheduled_gmt ) {
    496         if ( ! wsacsc_populate_can_use_as_classes() ) {
    497                 return wsacsc_populate_fallback_schedule_serialized();
    498         }
    499 
    500         try {
    501                 $timestamp = strtotime( $scheduled_gmt . ' UTC' );
    502                 if ( false === $timestamp ) {
    503                         return wsacsc_populate_fallback_schedule_serialized();
    504                 }
    505 
    506                 $date = new DateTime( '@' . $timestamp );
    507                 $date->setTimezone( new DateTimeZone( 'UTC' ) );
    508 
    509                 if ( 'canceled' === $status && class_exists( 'ActionScheduler_CanceledSchedule' ) ) {
    510                         return serialize( new ActionScheduler_CanceledSchedule( $date ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
    511                 }
    512 
    513                 if ( wp_rand( 0, 100 ) < 12 && class_exists( 'ActionScheduler_IntervalSchedule' ) ) {
    514                         return serialize( new ActionScheduler_IntervalSchedule( $date, HOUR_IN_SECONDS ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
    515                 }
    516 
    517                 if ( wp_rand( 0, 100 ) < 5 && class_exists( 'ActionScheduler_CronSchedule' ) ) {
    518                         return serialize( new ActionScheduler_CronSchedule( $date, '0 0 * * *' ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
    519                 }
    520 
    521                 return serialize( new ActionScheduler_SimpleSchedule( $date ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
    522         } catch ( Exception $e ) {
    523                 return wsacsc_populate_fallback_schedule_serialized();
    524         }
    525 }
    526 
    527 /**
    528  * Ensure common Action Scheduler groups exist; return slug => group_id map.
    529  *
    530  * @return array<string, int>
    531  */
    532 function wsacsc_populate_ensure_test_groups() {
    533         static $map = null;
    534 
    535         if ( null !== $map ) {
    536                 return $map;
    537         }
    538 
    539         $map    = array();
    540         $schema = wsacsc_populate_get_actions_schema();
    541 
    542         if ( ! $schema['has_groups_table'] ) {
    543                 return $map;
    544         }
    545 
    546         global $wpdb;
    547 
    548         $groups_table = $wpdb->prefix . 'actionscheduler_groups';
    549         $slugs        = array( 'woocommerce', 'action-scheduler', '' );
    550 
    551         foreach ( $slugs as $slug ) {
    552                 if ( '' === $slug ) {
    553                         continue;
    554                 }
    555 
    556                 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    557                 $existing = $wpdb->get_var(
    558                         $wpdb->prepare(
    559                                 'SELECT group_id FROM %i WHERE slug = %s LIMIT 1',
    560                                 $groups_table,
    561                                 $slug
    562                         )
    563                 );
    564 
    565                 if ( $existing ) {
    566                         $map[ $slug ] = (int) $existing;
    567                         continue;
    568                 }
    569 
    570                 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
    571                 $wpdb->insert(
    572                         $groups_table,
    573                         array( 'slug' => $slug ),
    574                         array( '%s' )
    575                 );
    576 
    577                 if ( $wpdb->insert_id ) {
    578                         $map[ $slug ] = (int) $wpdb->insert_id;
    579                 }
    580         }
    581 
    582         return $map;
    583 }
    584 
    585 /**
    586  * Pick a group_id for a new action row.
    587  *
    588  * @param array<string, int> $group_map Slug => group_id.
    589  * @return int
    590  */
    591 function wsacsc_populate_pick_group_id( array $group_map ) {
    592         if ( empty( $group_map ) || wp_rand( 0, 100 ) > 70 ) {
    593                 return 0;
    594         }
    595 
    596         $ids = array_values( $group_map );
    597         return $ids[ wp_rand( 0, count( $ids ) - 1 ) ];
    598 }
    599 
    600 /**
    601  * Pick action priority (weighted toward default 10).
    602  *
    603  * @return int
    604  */
    605 function wsacsc_populate_pick_priority() {
    606         $choices = array( 10, 10, 10, 10, 0, 20 );
    607         return $choices[ wp_rand( 0, count( $choices ) - 1 ) ];
    608 }
    609 
    610 /**
    611  * Build coherent GMT/local datetimes for a finished or pending action.
    612  *
    613  * @param array<string, mixed> $ctx         Generation context.
    614  * @param string               $status      Action status.
    615  * @param bool                 $is_pending  Whether row is pending (future scheduled).
    616  * @return array<string, string>
    617  */
    618 function wsacsc_populate_build_action_dates( array $ctx, $status, $is_pending = false ) {
    619         $default_date = '0000-00-00 00:00:00';
    620 
    621         if ( $is_pending ) {
    622                 $days_ahead    = wp_rand( 1, 14 );
    623                 $scheduled_ts  = $ctx['now_gmt_ts'] + ( $days_ahead * DAY_IN_SECONDS );
    624                 $scheduled_gmt = gmdate( 'Y-m-d H:i:s', $scheduled_ts );
    625 
    626                 return array(
    627                         'scheduled_date_gmt'   => $scheduled_gmt,
    628                         'scheduled_date_local' => wsacsc_populate_gmt_to_local_mysql( $scheduled_gmt ),
    629                         'last_attempt_gmt'     => $default_date,
    630                         'last_attempt_local'   => $default_date,
    631                         'completed_date_gmt'   => '',
    632                         'completed_date_local' => '',
    633                 );
    634         }
    635 
    636         $days_ago      = wp_rand( 0, 90 );
    637         $scheduled_ts  = $ctx['now_gmt_ts'] - ( $days_ago * DAY_IN_SECONDS );
    638         $offset_sec    = wp_rand( 60, 7200 );
    639         $last_ts       = min( $ctx['now_gmt_ts'] - wp_rand( 0, 3600 ), $scheduled_ts + $offset_sec );
    640         $scheduled_gmt = gmdate( 'Y-m-d H:i:s', $scheduled_ts );
    641         $last_gmt      = gmdate( 'Y-m-d H:i:s', $last_ts );
    642 
    643         $dates = array(
    644                 'scheduled_date_gmt'   => $scheduled_gmt,
    645                 'scheduled_date_local' => wsacsc_populate_gmt_to_local_mysql( $scheduled_gmt ),
    646                 'last_attempt_gmt'     => $last_gmt,
    647                 'last_attempt_local'   => wsacsc_populate_gmt_to_local_mysql( $last_gmt ),
    648                 'completed_date_gmt'   => '',
    649                 'completed_date_local' => '',
    650         );
    651 
    652         if ( in_array( $status, array( 'complete', 'failed' ), true ) ) {
    653                 $dates['completed_date_gmt']   = $last_gmt;
    654                 $dates['completed_date_local'] = $dates['last_attempt_local'];
    655         }
    656 
    657         return $dates;
    658 }
    659 
    660 /**
    661  * Sanitize pending-backlog percentage for actions population.
    662  *
    663  * @param mixed $pct Raw value.
    664  * @return int 0-30
    665  */
    666 function wsacsc_populate_sanitize_pending_pct( $pct ) {
    667         if ( ! is_numeric( $pct ) ) {
    668                 return 0;
    669         }
    670 
    671         $pct = (int) $pct;
    672         return max( 0, min( 30, $pct ) );
    673673}
    674674
    … …  
    681681        global $wpdb;
    682682
    683         $actions_table = $wpdb->prefix . 'actionscheduler_actions';
    684         $logs_table    = $wpdb->prefix . 'actionscheduler_logs';
    685 
    686         $actions_exist = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $actions_table ) ) === $actions_table;
    687         $logs_exist    = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $logs_table ) ) === $logs_table;
    688 
    689         return $actions_exist && $logs_exist;
    690 }
    691 
    692 /**
    693  * Sanitize and validate target MB from user input.
    694  *
    695  * @param mixed $target_mb Raw value.
     683        foreach ( array( 'actionscheduler_actions', 'actionscheduler_logs' ) as $suffix ) {
     684                $table = $wpdb->prefix . $suffix;
     685                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dev utility.
     686                if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table ) ) ) !== $table ) {
     687                        return false;
     688                }
     689        }
     690
     691        return true;
     692}
     693
     694/*
     695 * -------------------------------------------------------------------------
     696 * Options and jobs
     697 * -------------------------------------------------------------------------
     698 */
     699
     700/**
     701 * Parse an integer option within a range.
     702 *
     703 * @param mixed $value Raw value.
     704 * @param int   $min   Minimum.
     705 * @param int   $max   Maximum.
    696706 * @return int|false
    697707 */
    698 function wsacsc_populate_sanitize_target_mb( $target_mb ) {
    699         if ( ! is_numeric( $target_mb ) ) {
     708function wsacsc_populate_parse_int( $value, $min, $max ) {
     709        if ( ! is_numeric( $value ) ) {
    700710                return false;
    701711        }
    702712
    703         $mb = (int) $target_mb;
    704         if ( $mb < 1 || $mb > wsacsc_populate_max_target_mb() ) {
    705                 return false;
    706         }
    707 
    708         return $mb;
    709 }
    710 
    711 /**
    712  * Sanitize populate table target (actions or logs).
    713  *
    714  * @param mixed $table Raw value.
    715  * @return string|false
    716  */
    717 function wsacsc_populate_sanitize_table( $table ) {
    718         $table = sanitize_key( (string) $table );
    719         if ( ! in_array( $table, array( 'actions', 'logs' ), true ) ) {
    720                 return false;
    721         }
    722 
    723         return $table;
    724 }
    725 
    726 /**
    727  * Sanitize target mode (size in MB or row count).
    728  *
    729  * @param mixed $mode Raw value.
    730  * @return string|false
    731  */
    732 function wsacsc_populate_sanitize_target_mode( $mode ) {
    733         $mode = sanitize_key( (string) $mode );
    734         if ( ! in_array( $mode, array( 'size', 'rows' ), true ) ) {
    735                 return false;
    736         }
    737 
    738         return $mode;
    739 }
    740 
    741 /**
    742  * Sanitize target row count (total rows desired in the table).
    743  *
    744  * @param mixed $target_rows Raw value.
    745  * @return int|false
    746  */
    747 function wsacsc_populate_sanitize_target_rows( $target_rows ) {
    748         if ( ! is_numeric( $target_rows ) ) {
    749                 return false;
    750         }
    751 
    752         $rows = (int) $target_rows;
    753         if ( $rows < 1 || $rows > wsacsc_populate_max_rows_per_table() ) {
    754                 return false;
    755         }
    756 
    757         return $rows;
    758 }
    759 
    760 /**
    761  * Row count for an Action Scheduler table.
    762  *
    763  * @param string $table_name Full table name.
    764  * @return int
    765  */
    766 function wsacsc_populate_get_table_row_count( $table_name ) {
    767         global $wpdb;
    768 
    769         // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    770         $count = $wpdb->get_var(
    771                 $wpdb->prepare(
    772                         'SELECT COUNT(*) FROM %i',
    773                         $table_name
    774                 )
    775         );
    776 
    777         return max( 0, (int) $count );
    778 }
    779 
    780 /**
    781  * Parse and validate start-request options for one table.
     713        $value = (int) $value;
     714        return ( $value < $min || $value > $max ) ? false : $value;
     715}
     716
     717/**
     718 * Parse and validate start options.
    782719 *
    783720 * @param array<string, mixed> $payload Request payload.
    … …  
    785722 */
    786723function wsacsc_populate_parse_start_options( array $payload ) {
    787         $table = isset( $payload['table'] ) ? wsacsc_populate_sanitize_table( $payload['table'] ) : false;
    788         if ( false === $table ) {
     724        $table = isset( $payload['table'] ) ? sanitize_key( (string) $payload['table'] ) : '';
     725        if ( ! in_array( $table, array( 'actions', 'logs' ), true ) ) {
    789726                return new WP_Error( 'invalid_table', __( 'Invalid table. Use actions or logs.', 'ws-action-scheduler-cleaner' ) );
    790727        }
    791728
    792         $target_mode = isset( $payload['target_mode'] ) ? wsacsc_populate_sanitize_target_mode( $payload['target_mode'] ) : false;
    793         if ( false === $target_mode ) {
     729        $target_mode = isset( $payload['target_mode'] ) ? sanitize_key( (string) $payload['target_mode'] ) : '';
     730        if ( ! in_array( $target_mode, array( 'size', 'rows' ), true ) ) {
    794731                return new WP_Error( 'invalid_mode', __( 'Invalid target mode. Use size or rows.', 'ws-action-scheduler-cleaner' ) );
    795732        }
    796733
     734        $options = array(
     735                'table'       => $table,
     736                'target_mode' => $target_mode,
     737                'target_mb'   => 0,
     738                'target_rows' => 0,
     739                'span_days'   => wsacsc_populate_default_span_days(),
     740                'pending_pct' => 0,
     741                'with_logs'   => true,
     742        );
     743
    797744        if ( 'size' === $target_mode ) {
    798                 $target_mb = isset( $payload['target_mb'] ) ? wsacsc_populate_sanitize_target_mb( $payload['target_mb'] ) : false;
    799                 if ( false === $target_mb ) {
     745                $options['target_mb'] = wsacsc_populate_parse_int( $payload['target_mb'] ?? null, 1, wsacsc_populate_max_target_mb() );
     746                if ( false === $options['target_mb'] ) {
    800747                        return new WP_Error(
    801748                                'invalid_mb',
    802                                 sprintf(
    803                                         /* translators: %d: maximum megabytes allowed. */
    804                                         __( 'Target size must be between 1 and %d MB.', 'ws-action-scheduler-cleaner' ),
    805                                         wsacsc_populate_max_target_mb()
    806                                 )
     749                                /* translators: %d: maximum megabytes allowed. */
     750                                sprintf( __( 'Target size must be between 1 and %d MB.', 'ws-action-scheduler-cleaner' ), wsacsc_populate_max_target_mb() )
    807751                        );
    808752                }
    809 
    810                 $result = array(
    811                         'table'       => $table,
    812                         'target_mode' => 'size',
    813                         'target_mb'   => $target_mb,
    814                 );
    815                 if ( 'actions' === $table ) {
    816                         $result['include_pending_pct'] = wsacsc_populate_sanitize_pending_pct( $payload['include_pending_pct'] ?? 0 );
    817                 }
    818                 return $result;
    819         }
    820 
    821         $target_rows = isset( $payload['target_rows'] ) ? wsacsc_populate_sanitize_target_rows( $payload['target_rows'] ) : false;
    822         if ( false === $target_rows ) {
    823                 return new WP_Error(
    824                         'invalid_rows',
    825                         sprintf(
     753        } else {
     754                $options['target_rows'] = wsacsc_populate_parse_int( $payload['target_rows'] ?? null, 1, wsacsc_populate_max_rows_per_table() );
     755                if ( false === $options['target_rows'] ) {
     756                        return new WP_Error(
     757                                'invalid_rows',
    826758                                /* translators: %d: maximum row count allowed. */
    827                                 __( 'Target row count must be between 1 and %d.', 'ws-action-scheduler-cleaner' ),
    828                                 wsacsc_populate_max_rows_per_table()
    829                         )
    830                 );
    831         }
    832 
    833         $result = array(
    834                 'table'       => $table,
    835                 'target_mode' => 'rows',
    836                 'target_rows' => $target_rows,
    837         );
     759                                sprintf( __( 'Target row count must be between 1 and %d.', 'ws-action-scheduler-cleaner' ), wsacsc_populate_max_rows_per_table() )
     760                        );
     761                }
     762        }
     763
    838764        if ( 'actions' === $table ) {
    839                 $result['include_pending_pct'] = wsacsc_populate_sanitize_pending_pct( $payload['include_pending_pct'] ?? 0 );
    840         }
    841         return $result;
    842 }
    843 
    844 /**
    845  * Create a new populate job for one table.
    846  *
    847  * @param array<string, mixed> $options Parsed start options from wsacsc_populate_parse_start_options().
     765                if ( isset( $payload['span_days'] ) && '' !== $payload['span_days'] ) {
     766                        $options['span_days'] = wsacsc_populate_parse_int( $payload['span_days'], 1, 730 );
     767                        if ( false === $options['span_days'] ) {
     768                                return new WP_Error( 'invalid_days', __( 'History span must be between 1 and 730 days.', 'ws-action-scheduler-cleaner' ) );
     769                        }
     770                }
     771
     772                $pending = wsacsc_populate_parse_int( $payload['pending_pct'] ?? 0, 0, 30 );
     773                if ( false === $pending ) {
     774                        return new WP_Error( 'invalid_pending', __( 'Pending share must be between 0 and 30 percent.', 'ws-action-scheduler-cleaner' ) );
     775                }
     776                $options['pending_pct'] = $pending;
     777                $options['with_logs']   = ! isset( $payload['with_logs'] ) || ! in_array( (string) $payload['with_logs'], array( '0', 'false', 'no', '' ), true );
     778        }
     779
     780        return $options;
     781}
     782
     783/**
     784 * Full table name for a job table key.
     785 *
     786 * @param string $table actions or logs.
     787 * @return string
     788 */
     789function wsacsc_populate_table_name( $table ) {
     790        global $wpdb;
     791
     792        return $wpdb->prefix . ( 'actions' === $table ? 'actionscheduler_actions' : 'actionscheduler_logs' );
     793}
     794
     795/**
     796 * Number of rows the job still plans to insert, for the timeline.
     797 *
     798 * @param array<string, mixed> $job Job.
     799 * @return int Planned total rows of this job (inserted and remaining).
     800 */
     801function wsacsc_populate_planned_rows( array $job ) {
     802        if ( 'rows' === $job['target_mode'] ) {
     803                return max( 1, (int) $job['rows_to_add'] );
     804        }
     805
     806        $remaining_bytes = max( 0, (int) $job['target_bytes'] - (int) $job['size_bytes'] );
     807        $remaining_rows  = (int) ceil( $remaining_bytes / max( 1, (int) $job['est_row_bytes'] ) );
     808
     809        return max( 1, (int) $job['rows_inserted'] + $remaining_rows );
     810}
     811
     812/**
     813 * Create a new populate job.
     814 *
     815 * @param array<string, mixed> $options Parsed start options.
    848816 * @return array<string, mixed>
    849817 */
    850818function wsacsc_populate_create_job( array $options ) {
    851         global $wpdb;
    852 
    853         $table         = (string) $options['table'];
    854         $target_mode   = (string) $options['target_mode'];
    855         $populate_id   = 'pop_' . wp_generate_password( 12, false, false );
    856         $actions_table = $wpdb->prefix . 'actionscheduler_actions';
    857         $logs_table    = $wpdb->prefix . 'actionscheduler_logs';
    858         $db_table      = 'actions' === $table ? $actions_table : $logs_table;
    859 
    860         $size_bytes    = wsacsc_populate_get_table_size_bytes( $db_table );
    861         $baseline_rows = wsacsc_populate_get_table_row_count( $db_table );
     819        $table    = (string) $options['table'];
     820        $db_table = wsacsc_populate_table_name( $table );
     821        $size     = wsacsc_populate_get_table_size_bytes( $db_table );
     822        $baseline = wsacsc_populate_get_table_row_count( $db_table );
     823        $now      = time();
    862824
    863825        $job = array(
    864                 'populate_id'         => $populate_id,
     826                'populate_id'         => 'pop_' . wp_generate_password( 12, false, false ),
    865827                'table'               => $table,
    866                 'target_mode'         => $target_mode,
    867                 'target_mb'           => 0,
    868                 'target_bytes'        => 0,
    869                 'target_rows'         => 0,
    870                 'baseline_rows'       => $baseline_rows,
     828                'target_mode'         => (string) $options['target_mode'],
     829                'target_mb'           => (int) $options['target_mb'],
     830                'target_bytes'        => (int) $options['target_mb'] * 1024 * 1024,
     831                'target_rows'         => (int) $options['target_rows'],
     832                'baseline_rows'       => $baseline,
    871833                'rows_to_add'         => 0,
     834                'rows_inserted'       => 0,
     835                'logs_inserted'       => 0,
     836                'size_bytes'          => $size,
     837                'baseline_size_bytes' => $size,
     838                'est_row_bytes'       => wsacsc_populate_default_estimated_row_bytes( $table ),
     839                'batch_count'         => 0,
     840                'span_days'           => (int) $options['span_days'],
     841                'pending_pct'         => (int) $options['pending_pct'],
     842                'with_logs'           => (bool) $options['with_logs'],
     843                'timeline_start_ts'   => $now - ( (int) $options['span_days'] * DAY_IN_SECONDS ),
     844                'timeline_end_ts'     => $now - MINUTE_IN_SECONDS,
     845                'log_cursor_id'       => 0,
    872846                'status'              => 'running',
    873                 'rows_inserted'       => 0,
    874                 'size_bytes'          => $size_bytes,
    875                 'baseline_size_bytes' => $size_bytes,
    876                 'est_row_bytes'       => 'actions' === $table
    877                         ? wsacsc_populate_default_estimated_action_bytes()
    878                         : wsacsc_populate_default_estimated_log_bytes(),
    879                 'batch_count'         => 0,
    880                 'action_id_pool'      => array(),
    881                 'last_action_id'      => 0,
    882847                'message'             => 'actions' === $table
    883848                        ? __( 'Populating actions…', 'ws-action-scheduler-cleaner' )
    884849                        : __( 'Populating logs…', 'ws-action-scheduler-cleaner' ),
    885850                'error'               => '',
    886                 'started_at'          => time(),
    887                 'last_activity'       => time(),
     851                'started_at'          => $now,
     852                'last_activity'       => $now,
    888853        );
    889854
    890         $job['include_pending_pct'] = 0;
     855        if ( 'rows' === $job['target_mode'] ) {
     856                $job['rows_to_add'] = max( 0, (int) $options['target_rows'] - $baseline );
     857        }
     858
     859        wsacsc_populate_maybe_finish_job( $job );
     860
    891861        if ( 'actions' === $table ) {
    892                 $job['include_pending_pct'] = isset( $options['include_pending_pct'] )
    893                         ? wsacsc_populate_sanitize_pending_pct( $options['include_pending_pct'] )
    894                         : 0;
    895                 wsacsc_populate_ensure_test_groups();
    896         }
    897 
    898         if ( 'size' === $target_mode ) {
    899                 $job['target_mb']    = (int) $options['target_mb'];
    900                 $job['target_bytes'] = (int) $options['target_mb'] * 1024 * 1024;
    901         } else {
    902                 $job['target_rows'] = (int) $options['target_rows'];
    903                 $job['rows_to_add'] = max( 0, (int) $options['target_rows'] - $baseline_rows );
    904                 if ( 0 === $job['rows_to_add'] ) {
    905                         $job['status']  = 'complete';
    906                         $job['message'] = __( 'Population complete.', 'ws-action-scheduler-cleaner' );
    907                 }
    908         }
    909 
    910         set_transient( wsacsc_populate_transient_key( $populate_id ), $job, wsacsc_populate_transient_ttl() );
     862                wsacsc_populate_group_ids();
     863        }
     864
     865        set_transient( wsacsc_populate_transient_key( $job['populate_id'] ), $job, wsacsc_populate_transient_ttl() );
    911866
    912867        return $job;
    … …  
    926881
    927882        $job = get_transient( wsacsc_populate_transient_key( $populate_id ) );
    928         return is_array( $job ) ? $job : false;
     883        return ( is_array( $job ) && isset( $job['timeline_start_ts'] ) ) ? $job : false;
    929884}
    930885
    … …  
    936891 */
    937892function wsacsc_populate_save_job( array $job ) {
    938         if ( empty( $job['populate_id'] ) ) {
    939                 return;
    940         }
    941 
    942893        $job['last_activity'] = time();
    943894        set_transient( wsacsc_populate_transient_key( $job['populate_id'] ), $job, wsacsc_populate_transient_ttl() );
    … …  
    955906
    956907/**
     908 * Whether the job has reached its target (size or row count).
     909 *
     910 * @param array<string, mixed> $job Job.
     911 * @return bool
     912 */
     913function wsacsc_populate_job_target_met( array $job ) {
     914        if ( 'rows' === $job['target_mode'] ) {
     915                return (int) $job['rows_inserted'] >= (int) $job['rows_to_add'];
     916        }
     917
     918        return (int) $job['size_bytes'] >= (int) $job['target_bytes'];
     919}
     920
     921/**
     922 * Mark job complete when its target is met.
     923 *
     924 * @param array<string, mixed> $job Job (by reference).
     925 * @return void
     926 */
     927function wsacsc_populate_maybe_finish_job( array &$job ) {
     928        if ( 'running' === $job['status'] && wsacsc_populate_job_target_met( $job ) ) {
     929                $job['status']  = 'complete';
     930                $job['message'] = __( 'Population complete.', 'ws-action-scheduler-cleaner' );
     931        }
     932}
     933
     934/**
     935 * Mark job as failed.
     936 *
     937 * @param array<string, mixed> $job     Job (by reference).
     938 * @param string               $message Error message.
     939 * @return void
     940 */
     941function wsacsc_populate_fail_job( array &$job, $message ) {
     942        $job['status']  = 'error';
     943        $job['error']   = (string) $message;
     944        $job['message'] = (string) $message;
     945}
     946
     947/**
     948 * Update the table size of the job (from information_schema only periodically).
     949 *
     950 * @param array<string, mixed> $job   Job (by reference).
     951 * @param bool                 $force Force a size query.
     952 * @return void
     953 */
     954function wsacsc_populate_update_size_estimates( array &$job, $force = false ) {
     955        if ( $force || 0 === ( (int) $job['batch_count'] % wsacsc_populate_size_check_interval() ) ) {
     956                global $wpdb;
     957
     958                $table = wsacsc_populate_table_name( $job['table'] );
     959
     960                // information_schema sizes lag behind inserts (MySQL 8 caches them for up to 24 hours).
     961                // ANALYZE TABLE refreshes them. It samples a few pages and is fast.
     962                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dev utility.
     963                $wpdb->query( $wpdb->prepare( 'ANALYZE TABLE %i', $table ) );
     964
     965                $job['size_bytes'] = wsacsc_populate_get_table_size_bytes( $table );
     966
     967                $growth = (int) $job['size_bytes'] - (int) $job['baseline_size_bytes'];
     968                // InnoDB grows in extents, so only recalibrate after real growth.
     969                if ( (int) $job['rows_inserted'] > 0 && $growth > 4 * 1024 * 1024 ) {
     970                        $job['est_row_bytes'] = max( 60, (int) round( $growth / (int) $job['rows_inserted'] ) );
     971                }
     972                return;
     973        }
     974
     975        $job['size_bytes'] = (int) $job['baseline_size_bytes'] + ( (int) $job['rows_inserted'] * (int) $job['est_row_bytes'] );
     976}
     977
     978/**
    957979 * Build progress payload for JSON responses.
    958980 *
    … …  
    961983 */
    962984function wsacsc_populate_job_progress( array $job ) {
    963         wsacsc_populate_normalize_job( $job );
    964 
    965         $percent = 0;
    966985        if ( 'complete' === $job['status'] ) {
    967986                $percent = 100;
    968987        } elseif ( 'rows' === $job['target_mode'] ) {
    969                 $rows_to_add = (int) $job['rows_to_add'];
    970                 $percent     = $rows_to_add > 0
    971                         ? min( 100, (int) round( ( (int) $job['rows_inserted'] / $rows_to_add ) * 100 ) )
    972                         : 100;
     988                $percent = (int) $job['rows_to_add'] > 0 ? min( 100, (int) round( (int) $job['rows_inserted'] / (int) $job['rows_to_add'] * 100 ) ) : 100;
    973989        } else {
    974                 $target_bytes = (int) $job['target_bytes'];
    975                 $percent      = $target_bytes > 0
    976                         ? min( 100, (int) round( ( (int) $job['size_bytes'] / $target_bytes ) * 100 ) )
    977                         : 0;
     990                $percent = (int) $job['target_bytes'] > 0 ? min( 100, (int) round( (int) $job['size_bytes'] / (int) $job['target_bytes'] * 100 ) ) : 0;
    978991        }
    979992
    … …  
    986999                'target_rows'   => (int) $job['target_rows'],
    9871000                'rows_inserted' => (int) $job['rows_inserted'],
     1001                'logs_inserted' => (int) $job['logs_inserted'],
    9881002                'rows_to_add'   => (int) $job['rows_to_add'],
    9891003                'baseline_rows' => (int) $job['baseline_rows'],
    … …  
    9981012}
    9991013
    1000 /**
    1001  * Cached context for fast row generation within a request.
    1002  *
    1003  * @return array<string, mixed>
    1004  */
    1005 function wsacsc_populate_get_generation_context() {
    1006         static $ctx = null;
    1007 
    1008         if ( null !== $ctx ) {
    1009                 return $ctx;
    1010         }
    1011 
    1012         $schema = wsacsc_populate_get_actions_schema();
    1013 
    1014         $ctx = array(
    1015                 'hooks'              => wsacsc_populate_realistic_hooks(),
    1016                 'statuses'           => wsacsc_populate_statuses(),
    1017                 'group_map'          => wsacsc_populate_ensure_test_groups(),
    1018                 'has_completed_date' => $schema['has_completed_date'],
    1019                 'has_priority'       => $schema['has_priority'],
    1020                 'has_extended_args'  => $schema['has_extended_args'],
    1021                 'as_classes'         => wsacsc_populate_can_use_as_classes(),
    1022                 'now_gmt'            => current_time( 'mysql', true ),
    1023                 'now_local'          => current_time( 'mysql', false ),
    1024                 'now_gmt_ts'         => strtotime( current_time( 'mysql', true ) ),
    1025                 'now_local_ts'       => strtotime( current_time( 'mysql', false ) ),
    1026         );
    1027 
    1028         return $ctx;
    1029 }
    1030 
    1031 /**
    1032  * Column list for bulk action inserts (stable order).
    1033  *
    1034  * @return string[]
    1035  */
    1036 function wsacsc_populate_get_action_insert_columns() {
    1037         static $columns = null;
    1038 
    1039         if ( null !== $columns ) {
    1040                 return $columns;
    1041         }
    1042 
    1043         $columns = array(
    1044                 'hook',
    1045                 'status',
    1046                 'scheduled_date_gmt',
    1047                 'scheduled_date_local',
    1048                 'args',
    1049                 'schedule',
    1050                 'group_id',
    1051                 'attempts',
    1052                 'last_attempt_gmt',
    1053                 'last_attempt_local',
    1054                 'claim_id',
    1055         );
    1056 
    1057         $schema = wsacsc_populate_get_actions_schema();
    1058         if ( $schema['has_extended_args'] ) {
    1059                 $args_index = array_search( 'args', $columns, true );
    1060                 if ( false !== $args_index ) {
    1061                         array_splice( $columns, $args_index + 1, 0, array( 'extended_args' ) );
    1062                 }
    1063         }
    1064         if ( $schema['has_completed_date'] ) {
    1065                 $columns[] = 'completed_date_gmt';
    1066                 $columns[] = 'completed_date_local';
    1067         }
    1068         if ( $schema['has_priority'] ) {
    1069                 $columns[] = 'priority';
    1070         }
    1071 
    1072         return $columns;
    1073 }
    1074 
    1075 /**
    1076  * Integer columns in bulk action inserts.
    1077  *
    1078  * @return string[]
    1079  */
    1080 function wsacsc_populate_get_action_int_columns() {
    1081         $ints = array( 'group_id', 'attempts', 'claim_id' );
    1082         if ( wsacsc_populate_get_actions_schema()['has_priority'] ) {
    1083                 $ints[] = 'priority';
    1084         }
    1085         return $ints;
    1086 }
    1087 
    1088 /**
    1089  * Build multiple action rows using shared context.
    1090  *
     1014/*
     1015 * -------------------------------------------------------------------------
     1016 * Row generation
     1017 * -------------------------------------------------------------------------
     1018 */
     1019
     1020/**
     1021 * Timestamp on the job timeline for the n-th row of the job.
     1022 *
     1023 * Rows are spread evenly over the history span in insert order, with a small jitter,
     1024 * so that action IDs and dates grow together as on a real site.
     1025 *
     1026 * @param array<string, mixed> $job     Job.
     1027 * @param int                  $n       Zero-based row number within the job.
     1028 * @param int                  $planned Planned total rows of the job.
     1029 * @return int
     1030 */
     1031function wsacsc_populate_timeline_ts( array $job, $n, $planned ) {
     1032        $start = (int) $job['timeline_start_ts'];
     1033        $span  = max( 1, (int) $job['timeline_end_ts'] - $start );
     1034        $step  = $span / max( 1, $planned );
     1035        $base  = $start + (int) ( min( 1, ( $n + 0.5 ) / max( 1, $planned ) ) * $span );
     1036        $half  = (int) max( 0, $step / 2 );
     1037
     1038        return min( (int) $job['timeline_end_ts'], max( $start, $base + wp_rand( -$half, $half ) ) );
     1039}
     1040
     1041/**
     1042 * Build action rows for one batch.
     1043 *
     1044 * @param array<string, mixed> $job   Job.
    10911045 * @param int                  $count Row count.
    1092  * @param array<string, mixed> $job   Populate job (for pending %).
    10931046 * @return array<int, array<string, mixed>>
    10941047 */
    1095 function wsacsc_populate_build_action_rows( $count, array $job = array() ) {
    1096         $ctx         = wsacsc_populate_get_generation_context();
    1097         $hooks       = $ctx['hooks'];
    1098         $statuses    = $ctx['statuses'];
    1099         $pending_pct = isset( $job['include_pending_pct'] ) ? (int) $job['include_pending_pct'] : 0;
    1100         $rows        = array();
     1048function wsacsc_populate_build_action_rows( array $job, $count ) {
     1049        $schema   = wsacsc_populate_get_actions_schema();
     1050        $profiles = wsacsc_populate_hook_profiles();
     1051        $weights  = wp_list_pluck( $profiles, 'weight' );
     1052        $statuses = wsacsc_populate_status_weights();
     1053        $groups   = wsacsc_populate_group_ids();
     1054        $planned  = wsacsc_populate_planned_rows( $job );
     1055        $pending  = (int) $job['pending_pct'];
     1056        $empty    = '0000-00-00 00:00:00';
     1057        $now      = time();
     1058        $rows     = array();
    11011059
    11021060        for ( $i = 0; $i < $count; $i++ ) {
    1103                 $hook        = $hooks[ wp_rand( 0, count( $hooks ) - 1 ) ];
    1104                 $is_pending  = $pending_pct > 0 && wp_rand( 1, 100 ) <= $pending_pct;
    1105                 $status      = $is_pending ? 'pending' : $statuses[ wp_rand( 0, count( $statuses ) - 1 ) ];
    1106                 $dates       = wsacsc_populate_build_action_dates( $ctx, $status, $is_pending );
    1107                 $args_fields = wsacsc_populate_build_action_args( $hook, wp_rand( 1, 100 ) <= 5 );
     1061                $n       = (int) $job['rows_inserted'] + $i;
     1062                $hook    = wsacsc_populate_pick_weighted( $weights );
     1063                $profile = $profiles[ $hook ];
     1064                $created = wsacsc_populate_timeline_ts( $job, $n, $planned );
     1065
     1066                // Pending actions are the newest rows, as on a real site with a backlog.
     1067                $is_pending = $pending > 0 && ( $n + 0.5 ) / $planned >= 1 - ( $pending / 100 );
     1068                $status     = $is_pending ? 'pending' : wsacsc_populate_pick_weighted( $statuses );
    11081069
    11091070                if ( $is_pending ) {
    1110                         $attempts = 0;
    1111                 } elseif ( 'failed' === $status ) {
    1112                         $attempts = wp_rand( 1, 5 );
    1113                 } elseif ( 'canceled' === $status ) {
    1114                         $attempts = 0;
     1071                        $scheduled_ts = $now + wp_rand( MINUTE_IN_SECONDS, 14 * DAY_IN_SECONDS );
     1072                } elseif ( $profile['async'] ) {
     1073                        $scheduled_ts = $created;
    11151074                } else {
     1075                        $scheduled_ts = $created + wp_rand( 0, $profile['recurring'] > 0 ? (int) $profile['recurring'] : HOUR_IN_SECONDS );
     1076                }
     1077
     1078                $scheduled = wsacsc_populate_mysql_dates( $scheduled_ts );
     1079                $attempt   = array(
     1080                        'gmt'   => $empty,
     1081                        'local' => $empty,
     1082                );
     1083                $attempts  = 0;
     1084
     1085                // Canceled and pending actions never ran, so Action Scheduler keeps the default last attempt date.
     1086                if ( in_array( $status, array( 'complete', 'failed' ), true ) ) {
     1087                        $lag      = $profile['async'] ? wp_rand( 1, 30 ) : wp_rand( 5, 300 );
     1088                        $attempt  = wsacsc_populate_mysql_dates( min( $now, $scheduled_ts + $lag ) );
    11161089                        $attempts = 1;
    11171090                }
     1091
     1092                $args = wsacsc_populate_build_action_args( $profile['args'], $schema['has_extended_args'] );
    11181093
    11191094                $row = array(
    11201095                        'hook'                 => $hook,
    11211096                        'status'               => $status,
    1122                         'scheduled_date_gmt'   => $dates['scheduled_date_gmt'],
    1123                         'scheduled_date_local' => $dates['scheduled_date_local'],
    1124                         'args'                 => $args_fields['args'],
    1125                         'schedule'             => wsacsc_populate_build_action_schedule( $status, $dates['scheduled_date_gmt'] ),
    1126                         'group_id'             => wsacsc_populate_pick_group_id( $ctx['group_map'] ),
     1097                        'scheduled_date_gmt'   => $scheduled['gmt'],
     1098                        'scheduled_date_local' => $scheduled['local'],
     1099                        'args'                 => $args['args'],
     1100                        'schedule'             => wsacsc_populate_build_action_schedule( $status, $scheduled_ts, (int) $profile['recurring'] ),
     1101                        'group_id'             => ( '' !== $profile['group'] && isset( $groups[ $profile['group'] ] ) ) ? $groups[ $profile['group'] ] : 0,
    11271102                        'attempts'             => $attempts,
    1128                         'last_attempt_gmt'     => $dates['last_attempt_gmt'],
    1129                         'last_attempt_local'   => $dates['last_attempt_local'],
     1103                        'last_attempt_gmt'     => $attempt['gmt'],
     1104                        'last_attempt_local'   => $attempt['local'],
    11301105                        'claim_id'             => 0,
    1131                         '_populate_meta'       => array(
    1132                                 'status'             => $status,
    1133                                 'last_attempt_gmt'   => $dates['last_attempt_gmt'],
    1134                                 'scheduled_date_gmt' => $dates['scheduled_date_gmt'],
    1135                         ),
    11361106                );
    11371107
    1138                 if ( $ctx['has_extended_args'] ) {
    1139                         $row['extended_args'] = isset( $args_fields['extended_args'] ) ? $args_fields['extended_args'] : null;
    1140                 }
    1141 
    1142                 if ( $ctx['has_completed_date'] && ! empty( $dates['completed_date_gmt'] ) ) {
    1143                         $row['completed_date_gmt']   = $dates['completed_date_gmt'];
    1144                         $row['completed_date_local'] = $dates['completed_date_local'];
    1145                 }
    1146                 if ( $ctx['has_priority'] ) {
    1147                         $row['priority'] = wsacsc_populate_pick_priority();
     1108                if ( $schema['has_extended_args'] ) {
     1109                        $row['extended_args'] = $args['extended_args'];
     1110                }
     1111                if ( $schema['has_priority'] ) {
     1112                        $row['priority'] = 10;
    11481113                }
    11491114
    … …  
    11551120
    11561121/**
    1157  * Build log entry rows for one action (AS-style message sequence).
    1158  *
    1159  * @param int                  $action_id Action ID.
    1160  * @param array<string, mixed> $meta      status, last_attempt_gmt, scheduled_date_gmt.
     1122 * Log rows that Action Scheduler writes for one action.
     1123 *
     1124 * The created time comes from the stored schedule, with a short lead time.
     1125 *
     1126 * @param array<string, string> $action Action row with action_id, hook, status, scheduled_date_gmt, last_attempt_gmt.
    11611127 * @return array<int, array<string, mixed>>
    11621128 */
    1163 function wsacsc_populate_build_log_rows_for_action( $action_id, array $meta ) {
    1164         $status           = isset( $meta['status'] ) ? (string) $meta['status'] : 'complete';
    1165         $last_attempt_gmt = isset( $meta['last_attempt_gmt'] ) ? (string) $meta['last_attempt_gmt'] : '';
    1166         $scheduled_gmt    = isset( $meta['scheduled_date_gmt'] ) ? (string) $meta['scheduled_date_gmt'] : $last_attempt_gmt;
    1167 
    1168         $last_ts = strtotime( $last_attempt_gmt . ' UTC' );
    1169         if ( false === $last_ts || '0000-00-00 00:00:00' === $last_attempt_gmt ) {
    1170                 $last_ts = strtotime( $scheduled_gmt . ' UTC' );
    1171         }
    1172         if ( false === $last_ts ) {
    1173                 $last_ts = time();
    1174         }
    1175 
    1176         $started_ts = max( strtotime( $scheduled_gmt . ' UTC' ) ?: $last_ts, $last_ts - wp_rand( 120, 900 ) );
    1177 
    1178         $entries = array();
     1129function wsacsc_populate_build_log_rows_for_action( array $action ) {
     1130        $profiles  = wsacsc_populate_hook_profiles();
     1131        $hook      = (string) $action['hook'];
     1132        $async     = isset( $profiles[ $hook ] ) ? (bool) $profiles[ $hook ]['async'] : false;
     1133        $context   = $async ? 'Async Request' : 'WP Cron';
     1134        $status    = (string) $action['status'];
     1135        $scheduled = strtotime( $action['scheduled_date_gmt'] . ' UTC' );
     1136        $attempt   = '0000-00-00 00:00:00' === $action['last_attempt_gmt'] ? false : strtotime( $action['last_attempt_gmt'] . ' UTC' );
     1137        $now       = time();
     1138
     1139        if ( false === $scheduled ) {
     1140                $scheduled = $now;
     1141        }
     1142
     1143        // Pending actions were created recently. Other actions were created shortly before their schedule.
     1144        $created  = 'pending' === $status ? $now - wp_rand( 60, DAY_IN_SECONDS ) : $scheduled - ( $async ? 0 : wp_rand( 0, HOUR_IN_SECONDS ) );
     1145        $messages = array( array( $created, 'action created' ) );
    11791146
    11801147        if ( 'canceled' === $status ) {
    1181                 $entries[] = array(
    1182                         'ts'      => $last_ts,
    1183                         'message' => 'action canceled',
     1148                $messages[] = array( min( $now, $scheduled + wp_rand( -HOUR_IN_SECONDS, 0 ) ), 'action canceled' );
     1149        } elseif ( false !== $attempt && in_array( $status, array( 'complete', 'failed' ), true ) ) {
     1150                $messages[] = array( $attempt, 'action started via ' . $context );
     1151                if ( 'complete' === $status ) {
     1152                        $messages[] = array( $attempt + wp_rand( 0, 20 ), 'action complete via ' . $context );
     1153                } else {
     1154                        $messages[] = array(
     1155                                $attempt + wp_rand( 0, 60 ),
     1156                                sprintf( 'action failed via %s: Scheduled action for %s will not be executed as no callbacks are registered.', $context, $hook ),
     1157                        );
     1158                }
     1159        }
     1160
     1161        $rows = array();
     1162        foreach ( $messages as $message ) {
     1163                $dates  = wsacsc_populate_mysql_dates( max( 0, (int) $message[0] ) );
     1164                $rows[] = array(
     1165                        'action_id'      => (int) $action['action_id'],
     1166                        'message'        => $message[1],
     1167                        'log_date_gmt'   => $dates['gmt'],
     1168                        'log_date_local' => $dates['local'],
    11841169                );
    1185         } elseif ( 'failed' === $status ) {
    1186                 $entries[] = array(
    1187                         'ts'      => $started_ts,
    1188                         'message' => 'action started',
     1170        }
     1171
     1172        return $rows;
     1173}
     1174
     1175/**
     1176 * Read actions by ID range for log generation.
     1177 *
     1178 * @param int $after_id Read actions with a higher ID.
     1179 * @param int $limit    Max actions.
     1180 * @return array<int, array<string, string>>
     1181 */
     1182function wsacsc_populate_fetch_actions_after( $after_id, $limit ) {
     1183        global $wpdb;
     1184
     1185        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dev utility.
     1186        $rows = $wpdb->get_results(
     1187                $wpdb->prepare(
     1188                        'SELECT action_id, hook, status, scheduled_date_gmt, last_attempt_gmt FROM %i WHERE action_id > %d ORDER BY action_id LIMIT %d',
     1189                        wsacsc_populate_table_name( 'actions' ),
     1190                        (int) $after_id,
     1191                        (int) $limit
     1192                ),
     1193                ARRAY_A
     1194        );
     1195
     1196        return is_array( $rows ) ? $rows : array();
     1197}
     1198
     1199/**
     1200 * Bulk INSERT rows in chunks.
     1201 *
     1202 * @param string                           $table       Full table name.
     1203 * @param array<int, array<string, mixed>> $rows        Rows keyed by column name. All rows have the same keys.
     1204 * @param string[]                         $int_columns Columns using %d placeholders.
     1205 * @return array{inserted: int, first_ids: int[]}|false Rows inserted and the first insert ID of each statement.
     1206 */
     1207function wsacsc_populate_bulk_insert( $table, array $rows, array $int_columns ) {
     1208        global $wpdb;
     1209
     1210        if ( empty( $rows ) ) {
     1211                return array(
     1212                        'inserted'  => 0,
     1213                        'first_ids' => array(),
    11891214                );
    1190                 $entries[] = array(
    1191                         'ts'      => $last_ts,
    1192                         'message' => 'action failed via WP Cron: Simulated timeout in test data',
    1193                 );
    1194         } elseif ( 'pending' === $status ) {
    1195                 return array();
    1196         } else {
    1197                 $entries[] = array(
    1198                         'ts'      => $started_ts,
    1199                         'message' => 'action started',
    1200                 );
    1201                 $entries[] = array(
    1202                         'ts'      => $last_ts,
    1203                         'message' => 'action complete',
    1204                 );
    1205         }
    1206 
    1207         $rows = array();
    1208         foreach ( $entries as $entry ) {
    1209                 $log_gmt = gmdate( 'Y-m-d H:i:s', (int) $entry['ts'] );
    1210                 $rows[]  = array(
    1211                         'action_id'      => (int) $action_id,
    1212                         'message'        => $entry['message'],
    1213                         'log_date_gmt'   => $log_gmt,
    1214                         'log_date_local' => wsacsc_populate_gmt_to_local_mysql( $log_gmt ),
    1215                 );
    1216         }
    1217 
    1218         return $rows;
    1219 }
    1220 
    1221 /**
    1222  * Load action metadata from DB for log population.
    1223  *
    1224  * @param int[] $action_ids Action IDs.
    1225  * @return array<int, array<string, mixed>>
    1226  */
    1227 function wsacsc_populate_fetch_action_meta_for_logs( array $action_ids ) {
    1228         global $wpdb;
    1229 
    1230         $action_ids = array_values( array_filter( array_map( 'intval', $action_ids ) ) );
    1231         if ( empty( $action_ids ) ) {
    1232                 return array();
    1233         }
    1234 
    1235         $actions_table = $wpdb->prefix . 'actionscheduler_actions';
    1236         $ids_sql       = implode( ',', array_map( 'intval', $action_ids ) );
    1237         $sql           = "SELECT action_id, status, last_attempt_gmt, scheduled_date_gmt FROM `{$actions_table}` WHERE action_id IN ({$ids_sql})";
    1238 
    1239         // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
    1240         $results = $wpdb->get_results( $sql, ARRAY_A );
    1241         $map     = array();
    1242 
    1243         if ( is_array( $results ) ) {
    1244                 foreach ( $results as $row ) {
    1245                         $map[ (int) $row['action_id'] ] = array(
    1246                                 'status'             => (string) $row['status'],
    1247                                 'last_attempt_gmt'   => (string) $row['last_attempt_gmt'],
    1248                                 'scheduled_date_gmt' => (string) $row['scheduled_date_gmt'],
    1249                         );
    1250                 }
    1251         }
    1252 
    1253         return $map;
    1254 }
    1255 
    1256 /**
    1257  * Build log rows for a list of action IDs (multiple logs per action when meta known).
    1258  *
    1259  * @param int[]                           $action_ids Action IDs.
    1260  * @param array<int, array<string,mixed>> $meta_by_id Optional action_id => meta.
    1261  * @return array<int, array<string, mixed>>
    1262  */
    1263 function wsacsc_populate_build_log_rows_for_actions( array $action_ids, array $meta_by_id = array() ) {
    1264         if ( empty( $meta_by_id ) ) {
    1265                 $meta_by_id = wsacsc_populate_fetch_action_meta_for_logs( $action_ids );
    1266         }
    1267 
    1268         $rows = array();
    1269         foreach ( $action_ids as $action_id ) {
    1270                 $action_id = (int) $action_id;
    1271                 $meta      = isset( $meta_by_id[ $action_id ] )
    1272                         ? $meta_by_id[ $action_id ]
    1273                         : array(
    1274                                 'status'             => 'complete',
    1275                                 'last_attempt_gmt'   => gmdate( 'Y-m-d H:i:s' ),
    1276                                 'scheduled_date_gmt' => gmdate( 'Y-m-d H:i:s' ),
    1277                         );
    1278                 $rows      = array_merge( $rows, wsacsc_populate_build_log_rows_for_action( $action_id, $meta ) );
    1279         }
    1280 
    1281         return $rows;
    1282 }
    1283 
    1284 /**
    1285  * Strip internal metadata before inserting actions.
    1286  *
    1287  * @param array<int, array<string, mixed>> $rows Action rows.
    1288  * @return array{rows: array<int, array<string, mixed>>, metas: array<int, array<string, mixed>>}
    1289  */
    1290 function wsacsc_populate_prepare_action_rows_for_insert( array $rows ) {
    1291         $clean = array();
    1292         $metas = array();
    1293 
    1294         foreach ( $rows as $row ) {
    1295                 $meta = isset( $row['_populate_meta'] ) && is_array( $row['_populate_meta'] ) ? $row['_populate_meta'] : array();
    1296                 unset( $row['_populate_meta'] );
    1297                 $metas[] = $meta;
    1298                 $clean[] = $row;
    1299         }
    1300 
    1301         return array(
    1302                 'rows'  => $clean,
    1303                 'metas' => $metas,
    1304         );
    1305 }
    1306 
    1307 /**
    1308  * Bulk INSERT rows in chunks.
    1309  *
    1310  * @param string                           $table   Table name.
    1311  * @param string[]                         $columns Column names in order.
    1312  * @param string[]                         $int_columns Columns using %d placeholders.
    1313  * @param array<int, array<string, mixed>> $rows    Rows keyed by column name.
    1314  * @return int|false Total rows inserted or false on failure.
    1315  */
    1316 function wsacsc_populate_bulk_insert( $table, array $columns, array $int_columns, array $rows ) {
    1317         global $wpdb;
    1318 
    1319         if ( empty( $rows ) ) {
    1320                 return 0;
    1321         }
    1322 
    1323         $int_columns = array_flip( $int_columns );
    1324         $inserted    = 0;
    1325         $cols_sql    = '`' . implode( '`,`', $columns ) . '`';
     1215        }
     1216
     1217        $columns   = array_keys( $rows[0] );
     1218        $int_map   = array_flip( $int_columns );
     1219        $inserted  = 0;
     1220        $first_ids = array();
     1221        $cols_sql  = '`' . implode( '`,`', $columns ) . '`';
    13261222
    13271223        foreach ( array_chunk( $rows, wsacsc_populate_bulk_chunk_size() ) as $chunk ) {
    … …  
    13321228                        $tuple = array();
    13331229                        foreach ( $columns as $column ) {
    1334                                 if ( isset( $int_columns[ $column ] ) ) {
     1230                                if ( null === $row[ $column ] ) {
     1231                                        $tuple[] = 'NULL';
     1232                                } elseif ( isset( $int_map[ $column ] ) ) {
    13351233                                        $tuple[]  = '%d';
    13361234                                        $values[] = (int) $row[ $column ];
    13371235                                } else {
    13381236                                        $tuple[]  = '%s';
    1339                                         $values[] = $row[ $column ];
     1237                                        $values[] = (string) $row[ $column ];
    13401238                                }
    13411239                        }
    … …  
    13431241                }
    13441242
    1345                 $sql = "INSERT INTO `{$table}` ({$cols_sql}) VALUES " . implode( ',', $placeholders );
    1346                 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- dev bulk insert.
    1347                 $result = $wpdb->query( $wpdb->prepare( $sql, $values ) );
     1243                // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dev bulk insert. Table and column names come from this file, values are prepared.
     1244                $sql    = "INSERT INTO `{$table}` ({$cols_sql}) VALUES " . implode( ',', $placeholders );
     1245                $result = $wpdb->query( empty( $values ) ? $sql : $wpdb->prepare( $sql, $values ) );
     1246                // phpcs:enable
    13481247
    13491248                if ( false === $result ) {
    … …  
    13511250                }
    13521251
    1353                 $inserted += (int) $result;
    1354         }
    1355 
    1356         return $inserted;
    1357 }
    1358 
    1359 /**
    1360  * Bulk insert actions; returns new action IDs from the last chunk.
    1361  *
    1362  * @param string                           $table Actions table.
    1363  * @param array<int, array<string, mixed>> $rows  Action rows.
    1364  * @return array{inserted: int, ids: int[]}|false
    1365  */
    1366 function wsacsc_populate_bulk_insert_actions( $table, array $rows ) {
     1252                $inserted   += (int) $result;
     1253                $first_ids[] = (int) $wpdb->insert_id;
     1254        }
     1255
     1256        return array(
     1257                'inserted'  => $inserted,
     1258                'first_ids' => $first_ids,
     1259        );
     1260}
     1261
     1262/**
     1263 * Insert one batch of actions and, if enabled, their log entries.
     1264 *
     1265 * The log entries are built from the rows read back from the table, so they always match
     1266 * the stored actions, even when another process inserted actions at the same time.
     1267 *
     1268 * @param array<string, mixed> $job Job (by reference).
     1269 * @return bool False on error.
     1270 */
     1271function wsacsc_populate_insert_action_batch( array &$job ) {
    13671272        global $wpdb;
    13681273
    1369         $columns     = wsacsc_populate_get_action_insert_columns();
    1370         $int_columns = wsacsc_populate_get_action_int_columns();
    1371         $cols_sql    = '`' . implode( '`,`', $columns ) . '`';
    1372         $int_map     = array_flip( $int_columns );
    1373         $inserted    = 0;
    1374         $ids         = array();
    1375 
    1376         foreach ( array_chunk( $rows, wsacsc_populate_bulk_chunk_size() ) as $chunk ) {
    1377                 $placeholders = array();
    1378                 $values       = array();
    1379 
    1380                 foreach ( $chunk as $row ) {
    1381                         foreach ( $columns as $column ) {
    1382                                 if ( ! array_key_exists( $column, $row ) ) {
    1383                                         $row[ $column ] = null;
    1384                                 }
    1385                         }
    1386                         $tuple = array();
    1387                         foreach ( $columns as $column ) {
    1388                                 if ( isset( $int_map[ $column ] ) ) {
    1389                                         $tuple[]  = '%d';
    1390                                         $values[] = (int) $row[ $column ];
    1391                                 } else {
    1392                                         $tuple[]  = '%s';
    1393                                         $values[] = null === $row[ $column ] ? null : (string) $row[ $column ];
    1394                                 }
    1395                         }
    1396                         $placeholders[] = '(' . implode( ',', $tuple ) . ')';
    1397                 }
    1398 
    1399                 $sql = "INSERT INTO `{$table}` ({$cols_sql}) VALUES " . implode( ',', $placeholders );
    1400                 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- dev bulk insert.
    1401                 $result = $wpdb->query( $wpdb->prepare( $sql, $values ) );
    1402 
    1403                 if ( false === $result ) {
     1274        $count = wsacsc_populate_batch_row_count();
     1275        if ( 'rows' === $job['target_mode'] ) {
     1276                $count = min( $count, (int) $job['rows_to_add'] - (int) $job['rows_inserted'] );
     1277        }
     1278
     1279        $result = wsacsc_populate_bulk_insert( wsacsc_populate_table_name( 'actions' ), wsacsc_populate_build_action_rows( $job, $count ), array( 'group_id', 'attempts', 'claim_id', 'priority' ) );
     1280        if ( false === $result ) {
     1281                wsacsc_populate_fail_job( $job, $wpdb->last_error ? $wpdb->last_error : __( 'Failed to insert actions.', 'ws-action-scheduler-cleaner' ) );
     1282                return false;
     1283        }
     1284
     1285        $job['rows_inserted'] = (int) $job['rows_inserted'] + (int) $result['inserted'];
     1286
     1287        if ( ! $job['with_logs'] || empty( $result['first_ids'] ) ) {
     1288                return true;
     1289        }
     1290
     1291        $actions = wsacsc_populate_fetch_actions_after( min( $result['first_ids'] ) - 1, (int) $result['inserted'] );
     1292        $logs    = array();
     1293        foreach ( $actions as $action ) {
     1294                $logs = array_merge( $logs, wsacsc_populate_build_log_rows_for_action( $action ) );
     1295        }
     1296
     1297        $log_result = wsacsc_populate_bulk_insert( wsacsc_populate_table_name( 'logs' ), $logs, array( 'action_id' ) );
     1298        if ( false === $log_result ) {
     1299                wsacsc_populate_fail_job( $job, $wpdb->last_error ? $wpdb->last_error : __( 'Failed to insert logs.', 'ws-action-scheduler-cleaner' ) );
     1300                return false;
     1301        }
     1302
     1303        $job['logs_inserted'] = (int) $job['logs_inserted'] + (int) $log_result['inserted'];
     1304
     1305        return true;
     1306}
     1307
     1308/**
     1309 * Insert one batch of log entries for existing actions, oldest actions first.
     1310 *
     1311 * When the cursor reaches the newest action, it starts again at the oldest action.
     1312 * Further passes add another set of entries per action, as repeated runs of recurring
     1313 * actions would.
     1314 *
     1315 * @param array<string, mixed> $job Job (by reference).
     1316 * @return bool False on error.
     1317 */
     1318function wsacsc_populate_insert_log_batch( array &$job ) {
     1319        global $wpdb;
     1320
     1321        $limit   = max( 1, (int) ceil( wsacsc_populate_batch_row_count() / 2 ) );
     1322        $actions = wsacsc_populate_fetch_actions_after( (int) $job['log_cursor_id'], $limit );
     1323
     1324        if ( empty( $actions ) ) {
     1325                if ( 0 === (int) $job['log_cursor_id'] ) {
     1326                        wsacsc_populate_fail_job( $job, __( 'No actions available to attach logs. Populate actions first.', 'ws-action-scheduler-cleaner' ) );
    14041327                        return false;
    14051328                }
    1406 
    1407                 $chunk_count = (int) $result;
    1408                 $inserted   += $chunk_count;
    1409                 $first_id    = (int) $wpdb->insert_id;
    1410                 if ( $first_id > 0 && $chunk_count > 0 ) {
    1411                         for ( $i = 0; $i < $chunk_count; $i++ ) {
    1412                                 $ids[] = $first_id + $i;
    1413                         }
    1414                 }
    1415         }
    1416 
    1417         return array(
    1418                 'inserted' => $inserted,
    1419                 'ids'      => $ids,
    1420         );
    1421 }
    1422 
    1423 /**
    1424  * Whether the job has reached its target (size or row count).
    1425  *
    1426  * @param array<string, mixed> $job Job.
    1427  * @return bool
    1428  */
    1429 function wsacsc_populate_job_target_met( array $job ) {
     1329                $job['log_cursor_id'] = 0;
     1330                return true;
     1331        }
     1332
     1333        $logs = array();
     1334        foreach ( $actions as $action ) {
     1335                $logs = array_merge( $logs, wsacsc_populate_build_log_rows_for_action( $action ) );
     1336        }
     1337
    14301338        if ( 'rows' === $job['target_mode'] ) {
    1431                 return (int) $job['rows_inserted'] >= (int) $job['rows_to_add'];
    1432         }
    1433 
    1434         return (int) $job['size_bytes'] >= (int) $job['target_bytes'];
    1435 }
    1436 
    1437 /**
    1438  * Update estimated table sizes (information_schema only periodically).
    1439  *
    1440  * @param array<string, mixed> $job  Job (by reference).
    1441  * @param bool                 $force Force schema size query.
    1442  * @return void
    1443  */
    1444 function wsacsc_populate_update_size_estimates( array &$job, $force = false ) {
    1445         global $wpdb;
    1446 
    1447         $db_table = 'actions' === $job['table']
    1448                 ? $wpdb->prefix . 'actionscheduler_actions'
    1449                 : $wpdb->prefix . 'actionscheduler_logs';
    1450 
    1451         $should_measure = $force || 0 === ( (int) $job['batch_count'] % wsacsc_populate_size_check_interval() );
    1452 
    1453         if ( $should_measure ) {
    1454                 $job['size_bytes'] = wsacsc_populate_get_table_size_bytes( $db_table );
    1455 
    1456                 if ( (int) $job['rows_inserted'] > 0 ) {
    1457                         $growth               = max( 0, (int) $job['size_bytes'] - (int) $job['baseline_size_bytes'] );
    1458                         $min_bytes            = 'actions' === $job['table'] ? 200 : 80;
    1459                         $job['est_row_bytes'] = max( $min_bytes, (int) round( $growth / (int) $job['rows_inserted'] ) );
    1460                 }
    1461                 return;
    1462         }
    1463 
    1464         $job['size_bytes'] = (int) $job['baseline_size_bytes'] + ( (int) $job['rows_inserted'] * (int) $job['est_row_bytes'] );
    1465 }
    1466 
    1467 /**
    1468  * Mark job complete when its target is met.
     1339                $logs = array_slice( $logs, 0, max( 0, (int) $job['rows_to_add'] - (int) $job['rows_inserted'] ) );
     1340        }
     1341
     1342        $result = wsacsc_populate_bulk_insert( wsacsc_populate_table_name( 'logs' ), $logs, array( 'action_id' ) );
     1343        if ( false === $result ) {
     1344                wsacsc_populate_fail_job( $job, $wpdb->last_error ? $wpdb->last_error : __( 'Failed to insert logs.', 'ws-action-scheduler-cleaner' ) );
     1345                return false;
     1346        }
     1347
     1348        $last                 = end( $actions );
     1349        $job['log_cursor_id'] = (int) $last['action_id'];
     1350        $job['rows_inserted'] = (int) $job['rows_inserted'] + (int) $result['inserted'];
     1351
     1352        return true;
     1353}
     1354
     1355/**
     1356 * Run batches until the deadline, the target, or an error.
    14691357 *
    14701358 * @param array<string, mixed> $job Job (by reference).
    14711359 * @return void
    14721360 */
    1473 function wsacsc_populate_maybe_finish_job( array &$job ) {
    1474         if ( wsacsc_populate_job_target_met( $job ) ) {
    1475                 $job['status']  = 'complete';
    1476                 $job['message'] = __( 'Population complete.', 'ws-action-scheduler-cleaner' );
    1477         }
    1478 }
    1479 
    1480 /**
    1481  * Normalize job fields (legacy combined jobs are not resumed).
    1482  *
    1483  * @param array<string, mixed> $job Job (by reference).
    1484  * @return void
    1485  */
    1486 function wsacsc_populate_normalize_job( array &$job ) {
    1487         if ( empty( $job['table'] ) && isset( $job['phase'] ) ) {
    1488                 $job['table'] = in_array( $job['phase'], array( 'actions', 'logs' ), true ) ? (string) $job['phase'] : 'actions';
    1489         }
    1490 
    1491         if ( ! isset( $job['target_mode'] ) ) {
    1492                 $job['target_mode'] = ! empty( $job['target_rows'] ) ? 'rows' : 'size';
    1493         }
    1494 
    1495         if ( ! isset( $job['rows_inserted'] ) ) {
    1496                 $job['rows_inserted'] = 0;
    1497                 if ( 'actions' === $job['table'] && isset( $job['actions_inserted'] ) ) {
    1498                         $job['rows_inserted'] = (int) $job['actions_inserted'];
    1499                 } elseif ( 'logs' === $job['table'] && isset( $job['logs_inserted'] ) ) {
    1500                         $job['rows_inserted'] = (int) $job['logs_inserted'];
    1501                 }
    1502         }
    1503 
    1504         if ( ! isset( $job['size_bytes'] ) ) {
    1505                 if ( 'actions' === $job['table'] && isset( $job['actions_size_bytes'] ) ) {
    1506                         $job['size_bytes'] = (int) $job['actions_size_bytes'];
    1507                 } elseif ( 'logs' === $job['table'] && isset( $job['logs_size_bytes'] ) ) {
    1508                         $job['size_bytes'] = (int) $job['logs_size_bytes'];
    1509                 } else {
    1510                         $job['size_bytes'] = 0;
    1511                 }
    1512         }
    1513 
    1514         if ( ! isset( $job['baseline_size_bytes'] ) ) {
    1515                 if ( isset( $job['baseline_actions_bytes'] ) && 'actions' === $job['table'] ) {
    1516                         $job['baseline_size_bytes'] = (int) $job['baseline_actions_bytes'];
    1517                 } elseif ( isset( $job['baseline_logs_bytes'] ) && 'logs' === $job['table'] ) {
    1518                         $job['baseline_size_bytes'] = (int) $job['baseline_logs_bytes'];
    1519                 } else {
    1520                         $job['baseline_size_bytes'] = (int) $job['size_bytes'];
    1521                 }
    1522         }
    1523 
    1524         if ( ! isset( $job['est_row_bytes'] ) ) {
    1525                 if ( isset( $job['est_action_bytes'] ) && 'actions' === $job['table'] ) {
    1526                         $job['est_row_bytes'] = (int) $job['est_action_bytes'];
    1527                 } elseif ( isset( $job['est_log_bytes'] ) && 'logs' === $job['table'] ) {
    1528                         $job['est_row_bytes'] = (int) $job['est_log_bytes'];
    1529                 } else {
    1530                         $job['est_row_bytes'] = 'actions' === $job['table']
    1531                                 ? wsacsc_populate_default_estimated_action_bytes()
    1532                                 : wsacsc_populate_default_estimated_log_bytes();
    1533                 }
    1534         }
    1535 
    1536         if ( ! isset( $job['baseline_rows'] ) ) {
    1537                 $job['baseline_rows'] = 0;
    1538         }
    1539 
    1540         if ( ! isset( $job['rows_to_add'] ) ) {
    1541                 $job['rows_to_add'] = 'rows' === $job['target_mode']
    1542                         ? max( 0, (int) $job['target_rows'] - (int) $job['baseline_rows'] )
    1543                         : 0;
    1544         }
    1545 
    1546         if ( ! isset( $job['include_pending_pct'] ) ) {
    1547                 $job['include_pending_pct'] = 0;
    1548         }
    1549 }
    1550 
    1551 /**
    1552  * Merge new action IDs into the job pool (capped).
    1553  *
    1554  * @param array<string, mixed> $job Job (by reference).
    1555  * @param int[]                $ids New action IDs.
    1556  * @return void
    1557  */
    1558 function wsacsc_populate_merge_action_ids( array &$job, array $ids ) {
    1559         if ( empty( $ids ) ) {
    1560                 return;
    1561         }
    1562 
    1563         $job['last_action_id'] = max( $ids );
    1564         $pool                  = isset( $job['action_id_pool'] ) && is_array( $job['action_id_pool'] ) ? $job['action_id_pool'] : array();
    1565         $pool                  = array_merge( $pool, $ids );
    1566         if ( count( $pool ) > 10000 ) {
    1567                 $pool = array_slice( $pool, -10000 );
    1568         }
    1569         $job['action_id_pool'] = $pool;
    1570 }
    1571 
    1572 /**
    1573  * Pick action IDs for log rows when not inserting actions this cycle.
    1574  *
    1575  * @param array<string, mixed> $job   Job.
    1576  * @param int                  $count How many IDs needed.
    1577  * @return int[]
    1578  */
    1579 function wsacsc_populate_pick_action_ids_for_logs( array $job, $count ) {
    1580         $pool = isset( $job['action_id_pool'] ) && is_array( $job['action_id_pool'] ) ? $job['action_id_pool'] : array();
    1581         if ( empty( $pool ) ) {
    1582                 wsacsc_populate_refresh_action_id_pool( $job );
    1583                 $pool = $job['action_id_pool'];
    1584         }
    1585         if ( empty( $pool ) ) {
    1586                 return array();
    1587         }
    1588 
    1589         $ids = array();
    1590         wsacsc_populate_normalize_job( $job );
    1591         $offset = (int) $job['rows_inserted'] % count( $pool );
    1592         for ( $i = 0; $i < $count; $i++ ) {
    1593                 $ids[] = (int) $pool[ ( $offset + $i ) % count( $pool ) ];
    1594         }
    1595         return $ids;
    1596 }
    1597 
    1598 /**
    1599  * Refresh cached action IDs for log linking.
    1600  *
    1601  * @param array<string, mixed> $job Job (by reference).
    1602  * @return void
    1603  */
    1604 function wsacsc_populate_refresh_action_id_pool( array &$job ) {
    1605         global $wpdb;
    1606 
    1607         $actions_table         = $wpdb->prefix . 'actionscheduler_actions';
    1608         $pool_query            = $wpdb->prepare(
    1609                 'SELECT action_id FROM %i ORDER BY action_id DESC LIMIT 10000',
    1610                 $actions_table
    1611         );
    1612         $ids                   = $wpdb->get_col( $pool_query );
    1613         $job['action_id_pool'] = is_array( $ids ) ? array_map( 'intval', $ids ) : array();
    1614 }
    1615 
    1616 /**
    1617  * Insert rows for one table within a time slice (bulk SQL).
    1618  *
    1619  * @param array<string, mixed> $job Job (by reference).
    1620  * @param int                  $deadline Unix timestamp deadline.
    1621  * @return bool False on error.
    1622  */
    1623 function wsacsc_populate_insert_batch( array &$job, $deadline ) {
    1624         global $wpdb;
    1625 
    1626         wsacsc_populate_normalize_job( $job );
    1627 
    1628         $batch_size  = wsacsc_populate_batch_row_count();
    1629         $log_columns = array( 'action_id', 'message', 'log_date_gmt', 'log_date_local' );
    1630 
    1631         if ( function_exists( 'wp_suspend_cache_addition' ) ) {
    1632                 wp_suspend_cache_addition( true );
    1633         }
    1634 
    1635         while ( time() < $deadline ) {
    1636                 wsacsc_populate_maybe_finish_job( $job );
    1637                 if ( 'complete' === $job['status'] || wsacsc_populate_job_target_met( $job ) ) {
    1638                         wsacsc_populate_maybe_finish_job( $job );
     1361function wsacsc_populate_process_batch( array &$job ) {
     1362        $deadline = time() + wsacsc_populate_max_seconds_per_batch();
     1363
     1364        wp_suspend_cache_addition( true );
     1365
     1366        while ( 'running' === $job['status'] && time() < $deadline ) {
     1367                if ( (int) $job['rows_inserted'] >= wsacsc_populate_max_rows_per_table() ) {
     1368                        wsacsc_populate_fail_job( $job, __( 'Row safety limit reached.', 'ws-action-scheduler-cleaner' ) );
    16391369                        break;
    16401370                }
    16411371
    1642                 if ( (int) $job['rows_inserted'] >= wsacsc_populate_max_rows_per_table() ) {
    1643                         $job['status']  = 'error';
    1644                         $job['error']   = 'actions' === $job['table']
    1645                                 ? __( 'Actions row safety limit reached.', 'ws-action-scheduler-cleaner' )
    1646                                 : __( 'Logs row safety limit reached.', 'ws-action-scheduler-cleaner' );
    1647                         $job['message'] = $job['error'];
    1648                         if ( function_exists( 'wp_suspend_cache_addition' ) ) {
    1649                                 wp_suspend_cache_addition( false );
    1650                         }
    1651                         return false;
    1652                 }
    1653 
    1654                 if ( 'actions' === $job['table'] ) {
    1655                         $actions_table = $wpdb->prefix . 'actionscheduler_actions';
    1656                         $action_rows   = wsacsc_populate_build_action_rows( $batch_size, $job );
    1657                         $prepared      = wsacsc_populate_prepare_action_rows_for_insert( $action_rows );
    1658                         $result        = wsacsc_populate_bulk_insert_actions( $actions_table, $prepared['rows'] );
    1659 
    1660                         if ( false === $result ) {
    1661                                 $job['status']  = 'error';
    1662                                 $job['error']   = $wpdb->last_error ? $wpdb->last_error : __( 'Failed to insert actions.', 'ws-action-scheduler-cleaner' );
    1663                                 $job['message'] = $job['error'];
    1664                                 if ( function_exists( 'wp_suspend_cache_addition' ) ) {
    1665                                         wp_suspend_cache_addition( false );
    1666                                 }
    1667                                 return false;
    1668                         }
    1669 
    1670                         $job['rows_inserted'] = (int) $job['rows_inserted'] + (int) $result['inserted'];
    1671                         wsacsc_populate_merge_action_ids( $job, $result['ids'] );
    1672                 } else {
    1673                         $logs_table     = $wpdb->prefix . 'actionscheduler_logs';
    1674                         $log_action_ids = wsacsc_populate_pick_action_ids_for_logs( $job, $batch_size );
    1675 
    1676                         if ( empty( $log_action_ids ) ) {
    1677                                 $job['status']  = 'error';
    1678                                 $job['error']   = __( 'No actions available to attach logs.', 'ws-action-scheduler-cleaner' );
    1679                                 $job['message'] = $job['error'];
    1680                                 if ( function_exists( 'wp_suspend_cache_addition' ) ) {
    1681                                         wp_suspend_cache_addition( false );
    1682                                 }
    1683                                 return false;
    1684                         }
    1685 
    1686                         $log_rows  = wsacsc_populate_build_log_rows_for_actions( $log_action_ids );
    1687                         $log_count = wsacsc_populate_bulk_insert( $logs_table, $log_columns, array( 'action_id' ), $log_rows );
    1688 
    1689                         if ( false === $log_count ) {
    1690                                 $job['status']  = 'error';
    1691                                 $job['error']   = $wpdb->last_error ? $wpdb->last_error : __( 'Failed to insert logs.', 'ws-action-scheduler-cleaner' );
    1692                                 $job['message'] = $job['error'];
    1693                                 if ( function_exists( 'wp_suspend_cache_addition' ) ) {
    1694                                         wp_suspend_cache_addition( false );
    1695                                 }
    1696                                 return false;
    1697                         }
    1698 
    1699                         $job['rows_inserted'] = (int) $job['rows_inserted'] + (int) $log_count;
     1372                $ok = 'actions' === $job['table'] ? wsacsc_populate_insert_action_batch( $job ) : wsacsc_populate_insert_log_batch( $job );
     1373                if ( ! $ok ) {
     1374                        break;
    17001375                }
    17011376
    … …  
    17031378                wsacsc_populate_update_size_estimates( $job );
    17041379                wsacsc_populate_maybe_finish_job( $job );
    1705 
    1706                 if ( 'complete' === $job['status'] ) {
    1707                         break;
    1708                 }
    1709         }
    1710 
    1711         if ( function_exists( 'wp_suspend_cache_addition' ) ) {
    1712                 wp_suspend_cache_addition( false );
    1713         }
    1714 
    1715         wsacsc_populate_update_size_estimates( $job, true );
    1716         wsacsc_populate_maybe_finish_job( $job );
    1717 
    1718         return true;
    1719 }
    1720 
    1721 /**
    1722  * Run one batch for the current job phase.
    1723  *
    1724  * @param array<string, mixed> $job Job (by reference).
     1380        }
     1381
     1382        wp_suspend_cache_addition( false );
     1383
     1384        if ( 'error' !== $job['status'] ) {
     1385                wsacsc_populate_update_size_estimates( $job, true );
     1386                wsacsc_populate_maybe_finish_job( $job );
     1387        }
     1388
     1389        if ( 'running' === $job['status'] && $job['with_logs'] && 'actions' === $job['table'] ) {
     1390                $job['message'] = sprintf(
     1391                        /* translators: 1: actions inserted, 2: log entries inserted. */
     1392                        __( 'Populating actions… %1$s actions and %2$s log entries added.', 'ws-action-scheduler-cleaner' ),
     1393                        number_format_i18n( (int) $job['rows_inserted'] ),
     1394                        number_format_i18n( (int) $job['logs_inserted'] )
     1395                );
     1396        }
     1397
     1398        wsacsc_populate_save_job( $job );
     1399}
     1400
     1401/*
     1402 * -------------------------------------------------------------------------
     1403 * AJAX and CLI entry points
     1404 * -------------------------------------------------------------------------
     1405 */
     1406
     1407/**
     1408 * Send the job state as JSON.
     1409 *
     1410 * @param array<string, mixed> $job Job.
    17251411 * @return void
    17261412 */
    1727 function wsacsc_populate_process_batch( array &$job ) {
    1728         wsacsc_populate_normalize_job( $job );
    1729 
    1730         $deadline = time() + wsacsc_populate_max_seconds_per_batch();
    1731 
    1732         if ( 'complete' !== $job['status'] ) {
    1733                 $ok = wsacsc_populate_insert_batch( $job, $deadline );
    1734                 if ( false === $ok && 'running' === $job['status'] ) {
    1735                         // Error already set on $job.
    1736                 }
    1737         }
    1738 
    1739         if ( wsacsc_populate_job_target_met( $job ) && 'running' === $job['status'] ) {
    1740                 $job['status']  = 'complete';
    1741                 $job['message'] = __( 'Population complete.', 'ws-action-scheduler-cleaner' );
    1742         }
    1743 
    1744         if ( 'complete' === $job['status'] ) {
    1745                 wp_cache_flush();
    1746         }
    1747 
    1748         wsacsc_populate_save_job( $job );
    1749 }
    1750 
    1751 /**
    1752  * AJAX: start population.
    1753  *
    1754  * @param array<string, mixed> $payload Request payload.
    1755  * @return void
    1756  */
    1757 function wsacsc_populate_ajax_start( array $payload ) {
    1758         if ( ! wsacsc_populate_tables_exist() ) {
    1759                 wsacsc_populate_json_response( false, array( 'message' => __( 'Action Scheduler tables do not exist.', 'ws-action-scheduler-cleaner' ) ) );
    1760         }
    1761 
    1762         $options = wsacsc_populate_parse_start_options( $payload );
    1763         if ( is_wp_error( $options ) ) {
    1764                 wsacsc_populate_json_response( false, array( 'message' => $options->get_error_message() ) );
    1765         }
    1766 
    1767         $job = wsacsc_populate_create_job( $options );
    1768         if ( 'running' === $job['status'] ) {
    1769                 wsacsc_populate_process_batch( $job );
    1770         }
    1771 
     1413function wsacsc_populate_send_job( array $job ) {
    17721414        wsacsc_populate_json_response(
    17731415                true,
    … …  
    17801422
    17811423/**
    1782  * AJAX: run batch.
     1424 * AJAX: start population.
    17831425 *
    17841426 * @param array<string, mixed> $payload Request payload.
    17851427 * @return void
    17861428 */
     1429function wsacsc_populate_ajax_start( array $payload ) {
     1430        if ( ! wsacsc_populate_tables_exist() ) {
     1431                wsacsc_populate_json_response( false, array( 'message' => __( 'Action Scheduler tables do not exist.', 'ws-action-scheduler-cleaner' ) ) );
     1432        }
     1433
     1434        $options = wsacsc_populate_parse_start_options( $payload );
     1435        if ( is_wp_error( $options ) ) {
     1436                wsacsc_populate_json_response( false, array( 'message' => $options->get_error_message() ) );
     1437        }
     1438
     1439        $job = wsacsc_populate_create_job( $options );
     1440        if ( 'running' === $job['status'] ) {
     1441                wsacsc_populate_process_batch( $job );
     1442        }
     1443
     1444        wsacsc_populate_send_job( $job );
     1445}
     1446
     1447/**
     1448 * AJAX: run batch.
     1449 *
     1450 * @param array<string, mixed> $payload Request payload.
     1451 * @return void
     1452 */
    17871453function wsacsc_populate_ajax_batch( array $payload ) {
    1788         $populate_id = isset( $payload['populate_id'] ) ? sanitize_key( (string) $payload['populate_id'] ) : '';
    1789         $job         = wsacsc_populate_get_job( $populate_id );
    1790 
     1454        $job = wsacsc_populate_get_job( isset( $payload['populate_id'] ) ? (string) $payload['populate_id'] : '' );
    17911455        if ( false === $job ) {
    17921456                wsacsc_populate_json_response( false, array( 'message' => __( 'Population job not found or expired.', 'ws-action-scheduler-cleaner' ) ) );
    17931457        }
    17941458
    1795         if ( 'running' !== $job['status'] ) {
    1796                 wsacsc_populate_json_response(
    1797                         true,
    1798                         array(
    1799                                 'message'  => $job['message'],
    1800                                 'progress' => wsacsc_populate_job_progress( $job ),
    1801                         )
    1802                 );
    1803         }
    1804 
    1805         wsacsc_populate_process_batch( $job );
    1806 
    1807         wsacsc_populate_json_response(
    1808                 true,
    1809                 array(
    1810                         'message'  => $job['message'],
    1811                         'progress' => wsacsc_populate_job_progress( $job ),
    1812                 )
    1813         );
     1459        if ( 'running' === $job['status'] ) {
     1460                wsacsc_populate_process_batch( $job );
     1461        }
     1462
     1463        wsacsc_populate_send_job( $job );
    18141464}
    18151465
    … …  
    18211471 */
    18221472function wsacsc_populate_ajax_status( array $payload ) {
    1823         $populate_id = isset( $payload['populate_id'] ) ? sanitize_key( (string) $payload['populate_id'] ) : '';
    1824         $job         = wsacsc_populate_get_job( $populate_id );
    1825 
     1473        $job = wsacsc_populate_get_job( isset( $payload['populate_id'] ) ? (string) $payload['populate_id'] : '' );
    18261474        if ( false === $job ) {
    18271475                wsacsc_populate_json_response( false, array( 'message' => __( 'Population job not found or expired.', 'ws-action-scheduler-cleaner' ) ) );
    18281476        }
    18291477
    1830         wsacsc_populate_normalize_job( $job );
    1831         $light = ! empty( $payload['light'] );
    1832         wsacsc_populate_update_size_estimates( $job, ! $light );
    1833         wsacsc_populate_save_job( $job );
    1834 
    1835         wsacsc_populate_json_response(
    1836                 true,
    1837                 array(
    1838                         'message'  => $job['message'],
    1839                         'progress' => wsacsc_populate_job_progress( $job ),
    1840                 )
    1841         );
     1478        // Read-only: the batch request owns the job state, so a status poll must not save it.
     1479        wsacsc_populate_send_job( $job );
    18421480}
    18431481
    … …  
    18581496
    18591497/**
    1860  * Run population from CLI (wp eval-file … -- --target-mb=100).
    1861  *
     1498 * Run population from WP-CLI.
     1499 *
     1500 * Accepts key=value arguments (for example table=actions target-mb=500) and, for
     1501 * compatibility, --key=value entries in the process arguments.
     1502 *
     1503 * @param string[] $cli_args Positional arguments from wp eval-file.
    18621504 * @return void
    18631505 */
    1864 function wsacsc_populate_run_cli() {
     1506function wsacsc_populate_run_cli( array $cli_args ) {
    18651507        global $argv;
    18661508
    1867         $cli_args = array(
    1868                 'table'       => 'actions',
    1869                 'target_mode' => 'size',
    1870                 'target_mb'   => 100,
     1509        $raw = array();
     1510        foreach ( array_merge( (array) $argv, $cli_args ) as $arg ) {
     1511                if ( is_string( $arg ) && preg_match( '/^(?:--)?([a-z-]+)=(.*)$/', $arg, $matches ) ) {
     1512                        $raw[ $matches[1] ] = $matches[2];
     1513                }
     1514        }
     1515
     1516        $payload = array(
     1517                'table'       => $raw['table'] ?? 'actions',
     1518                'target_mode' => isset( $raw['target-rows'] ) ? 'rows' : 'size',
     1519                'target_mb'   => $raw['target-mb'] ?? 100,
     1520                'target_rows' => $raw['target-rows'] ?? 0,
     1521                'span_days'   => $raw['days'] ?? wsacsc_populate_default_span_days(),
     1522                'pending_pct' => $raw['pending-pct'] ?? ( $raw['include-pending-pct'] ?? 0 ),
     1523                'with_logs'   => $raw['logs'] ?? '1',
    18711524        );
    18721525
    1873         if ( is_array( $argv ) ) {
    1874                 foreach ( $argv as $arg ) {
    1875                         if ( ! is_string( $arg ) ) {
    1876                                 continue;
    1877                         }
    1878                         if ( preg_match( '/^--table=(actions|logs)$/', $arg, $matches ) ) {
    1879                                 $cli_args['table'] = $matches[1];
    1880                         } elseif ( preg_match( '/^--target-mb=(\d+)$/', $arg, $matches ) ) {
    1881                                 $cli_args['target_mode'] = 'size';
    1882                                 $cli_args['target_mb']   = (int) $matches[1];
    1883                         } elseif ( preg_match( '/^--target-rows=(\d+)$/', $arg, $matches ) ) {
    1884                                 $cli_args['target_mode'] = 'rows';
    1885                                 $cli_args['target_rows'] = (int) $matches[1];
    1886                         } elseif ( preg_match( '/^--include-pending-pct=(\d+)$/', $arg, $matches ) ) {
    1887                                 $cli_args['include_pending_pct'] = (int) $matches[1];
    1888                         }
    1889                 }
    1890         }
    1891 
    1892         $options = wsacsc_populate_parse_start_options( $cli_args );
     1526        $options = wsacsc_populate_parse_start_options( $payload );
    18931527        if ( is_wp_error( $options ) ) {
    18941528                WP_CLI::error( $options->get_error_message() );
    … …  
    19001534
    19011535        $job = wsacsc_populate_create_job( $options );
    1902         if ( 'size' === $options['target_mode'] ) {
    1903                 WP_CLI::log(
    1904                         sprintf(
    1905                                 'Starting %s population: %d MB.',
    1906                                 $options['table'],
    1907                                 $options['target_mb']
    1908                         )
    1909                 );
    1910         } else {
    1911                 WP_CLI::log(
    1912                         sprintf(
    1913                                 'Starting %s population: %d rows.',
    1914                                 $options['table'],
    1915                                 $options['target_rows']
    1916                         )
    1917                 );
    1918         }
     1536        WP_CLI::log(
     1537                sprintf(
     1538                        'Starting %s population: %s.',
     1539                        $options['table'],
     1540                        'size' === $options['target_mode'] ? $options['target_mb'] . ' MB' : number_format_i18n( $options['target_rows'] ) . ' rows'
     1541                )
     1542        );
    19191543
    19201544        while ( 'running' === $job['status'] ) {
    … …  
    19231547                WP_CLI::log(
    19241548                        sprintf(
    1925                                 '%s: %s (%d%%) | %s rows inserted',
     1549                                '%s: %s (%d%%) | %s rows inserted%s',
    19261550                                $progress['table'],
    19271551                                $progress['size_label'],
    19281552                                $progress['percent'],
    1929                                 number_format_i18n( $progress['rows_inserted'] )
     1553                                number_format_i18n( $progress['rows_inserted'] ),
     1554                                $progress['logs_inserted'] ? ' | ' . number_format_i18n( $progress['logs_inserted'] ) . ' log entries' : ''
    19301555                        )
    19311556                );
    1932 
    1933                 if ( 'error' === $job['status'] ) {
    1934                         WP_CLI::error( $job['error'] );
    1935                 }
    19361557        }
    19371558
    19381559        wsacsc_populate_delete_job( $job['populate_id'] );
     1560
     1561        if ( 'error' === $job['status'] ) {
     1562                WP_CLI::error( $job['error'] );
     1563        }
     1564
    19391565        WP_CLI::success( 'Population complete.' );
    19401566}
    1941 
    19421567/**
    19431568 * Render populate controls for one table (actions or logs).
    … …  
    19491574 * @param int    $default_mb  Default MB value.
    19501575 * @param int    $default_rows Default row count value.
    1951  * @param bool   $show_pending Whether to show pending-backlog option (actions only).
     1576 * @param bool   $show_pending Whether to show the actions-only options (history span, pending backlog, logs).
    19521577 * @return void
    19531578 */
    … …  
    19821607
    19831608                <?php if ( $show_pending ) : ?>
     1609                <div class="wsacsc-field" id="<?php echo esc_attr( $id ); ?>-field-days">
     1610                        <label for="<?php echo esc_attr( $id ); ?>-span-days"><?php esc_html_e( 'History span (days)', 'ws-action-scheduler-cleaner' ); ?></label>
     1611                        <input type="number" id="<?php echo esc_attr( $id ); ?>-span-days" min="1" max="730" value="<?php echo esc_attr( (string) wsacsc_populate_default_span_days() ); ?>" />
     1612                        <p class="wsacsc-description">
     1613                                <?php esc_html_e( 'New actions are spread over this many days before now, oldest first, so that action IDs follow time as on a real site.', 'ws-action-scheduler-cleaner' ); ?>
     1614                        </p>
     1615                </div>
    19841616                <div class="wsacsc-field" id="<?php echo esc_attr( $id ); ?>-field-pending">
    19851617                        <label for="<?php echo esc_attr( $id ); ?>-pending-pct"><?php esc_html_e( 'Pending backlog (%)', 'ws-action-scheduler-cleaner' ); ?></label>
    19861618                        <input type="number" id="<?php echo esc_attr( $id ); ?>-pending-pct" min="0" max="30" value="0" />
    1987                         <p class="description" style="margin:0.35rem 0 0;font-size:0.85rem;color:#50575e;">
    1988                                 <?php esc_html_e( 'Optional: share of new actions with status “pending” and a future schedule (0 = finished statuses only). Does not affect cleaner retention tests.', 'ws-action-scheduler-cleaner' ); ?>
     1619                        <p class="wsacsc-description">
     1620                                <?php esc_html_e( 'Optional: share of the newest actions with status “pending” and a future schedule (0 = finished statuses only).', 'ws-action-scheduler-cleaner' ); ?>
    19891621                        </p>
    19901622                </div>
     1623                <div class="wsacsc-field" id="<?php echo esc_attr( $id ); ?>-field-logs">
     1624                        <label>
     1625                                <input type="checkbox" id="<?php echo esc_attr( $id ); ?>-with-logs" checked />
     1626                                <?php esc_html_e( 'Also add the log entries of each action', 'ws-action-scheduler-cleaner' ); ?>
     1627                        </label>
     1628                        <p class="wsacsc-description">
     1629                                <?php esc_html_e( 'Action Scheduler writes 2 to 3 log entries per action. Keep this on for realistic clear and retention timings.', 'ws-action-scheduler-cleaner' ); ?>
     1630                        </p>
     1631                </div>
     1632                <?php else : ?>
     1633                <p class="wsacsc-description">
     1634                        <?php esc_html_e( 'Adds the log entries of existing actions, oldest first. When every action has its entries, another pass adds a further set per action.', 'ws-action-scheduler-cleaner' ); ?>
     1635                </p>
    19911636                <?php endif; ?>
    19921637
    … …  
    20251670
    20261671        $nonce         = wp_create_nonce( 'wsacsc_populate' );
    2027         $ajax_url      = esc_url( add_query_arg( array(), wp_unslash( $_SERVER['REQUEST_URI'] ?? '' ) ) );
     1672        $ajax_url      = esc_url_raw( add_query_arg( array(), sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ?? '' ) ) ) );
    20281673        $max_mb        = wsacsc_populate_max_target_mb();
    20291674        $max_rows      = wsacsc_populate_max_rows_per_table();
    … …  
    20391684        if ( $tables_ok ) {
    20401685                $parts = array();
    2041                 if ( $schema['has_completed_date'] ) {
    2042                         $parts[] = 'completed_date_gmt';
    2043                 }
    20441686                if ( $schema['has_priority'] ) {
    20451687                        $parts[] = 'priority';
    … …  
    20481690                        $parts[] = 'extended_args';
    20491691                }
    2050                 if ( wsacsc_populate_can_use_as_classes() ) {
     1692                if ( class_exists( 'ActionScheduler_SimpleSchedule' ) ) {
    20511693                        $parts[] = __( 'serialized AS schedules', 'ws-action-scheduler-cleaner' );
    20521694                }
    … …  
    21961838                        font-size: 1rem;
    21971839                }
     1840                .wsacsc-field label input[type="checkbox"] {
     1841                        margin-right: 0.35rem;
     1842                }
     1843                .wsacsc-description {
     1844                        margin: 0.35rem 0 0;
     1845                        font-size: 0.85rem;
     1846                        color: var(--wsacsc-muted);
     1847                }
    21981848                .wsacsc-field input:focus {
    21991849                        border-color: var(--wsacsc-primary);
    … …  
    23552005                <div class="wsacsc-card" id="wsacsc-card">
    23562006                        <h1><?php esc_html_e( 'Test Data Populator', 'ws-action-scheduler-cleaner' ); ?></h1>
    2357                         <p class="wsacsc-subtitle"><?php esc_html_e( 'Fill Action Scheduler tables with realistic rows for cleanup testing.', 'ws-action-scheduler-cleaner' ); ?></p>
     2007                        <p class="wsacsc-subtitle"><?php esc_html_e( 'Fill Action Scheduler tables with realistic rows for cleanup testing: time-ordered IDs, mostly completed actions, and the log entries of each action.', 'ws-action-scheduler-cleaner' ); ?></p>
    23582008
    23592009                        <div class="wsacsc-notice" role="alert">
    … …  
    24542104                        var inputRows = document.getElementById(prefix + '-target-rows');
    24552105                        var pendingInput = table === 'actions' ? document.getElementById(prefix + '-pending-pct') : null;
     2106                        var daysInput = table === 'actions' ? document.getElementById(prefix + '-span-days') : null;
     2107                        var logsInput = table === 'actions' ? document.getElementById(prefix + '-with-logs') : null;
    24562108                        var statusBar = document.getElementById(prefix + '-status');
    24572109                        var statusText = document.getElementById(prefix + '-status-text');
    … …  
    24732125                                pollBackoff: 1000,
    24742126                                animFrameId: null,
    2475                                 statusPollId: null,
    24762127                                displayPct: 0,
    24772128                                targetPct: 0,
    … …  
    24902141                                inputMb.disabled = rowsMode || state.running;
    24912142                                inputRows.disabled = !rowsMode || state.running;
    2492                                 if (pendingInput) {
    2493                                         pendingInput.disabled = state.running;
    2494                                 }
     2143                                [pendingInput, daysInput, logsInput].forEach(function (input) {
     2144                                        if (input) {
     2145                                                input.disabled = state.running;
     2146                                        }
     2147                                });
    24952148                                modeRadios.forEach(function (radio) {
    24962149                                        radio.disabled = state.running;
    … …  
    25022155                                var inserted = (progress.rows_inserted || 0).toLocaleString();
    25032156                                var sizeLabel = progress.size_label || '';
     2157                                if (progress.logs_inserted) {
     2158                                        sizeLabel += ' — ' + progress.logs_inserted.toLocaleString() + ' log entries added';
     2159                                }
    25042160                                if (progress.target_mode === 'rows') {
    25052161                                        var total = (progress.baseline_rows || 0) + (progress.rows_to_add || 0);
    … …  
    25432199                                if (isRunning) {
    25442200                                        startProgressAnimation();
    2545                                         startStatusPolling();
    25462201                                } else {
    25472202                                        stopProgressAnimation();
    2548                                         stopStatusPolling();
    25492203                                }
    25502204                        }
    … …  
    25932247                                        cancelAnimationFrame(state.animFrameId);
    25942248                                        state.animFrameId = null;
    2595                                 }
    2596                         }
    2597 
    2598                         function startStatusPolling() {
    2599                                 if (state.statusPollId) {
    2600                                         return;
    2601                                 }
    2602                                 state.statusPollId = window.setInterval(function () {
    2603                                         if (!state.running || !state.populateId) {
    2604                                                 return;
    2605                                         }
    2606                                         postJson('status', { populate_id: state.populateId, light: 1 })
    2607                                                 .then(function (data) {
    2608                                                         if (data && data.success && data.progress) {
    2609                                                                 setProgressTargets(data.progress);
    2610                                                         }
    2611                                                 })
    2612                                                 .catch(function () {});
    2613                                 }, 250);
    2614                         }
    2615 
    2616                         function stopStatusPolling() {
    2617                                 if (state.statusPollId) {
    2618                                         clearInterval(state.statusPollId);
    2619                                         state.statusPollId = null;
    26202249                                }
    26212250                        }
    … …  
    26942323                                if (pendingInput) {
    26952324                                        var pct = parseInt(pendingInput.value, 10);
    2696                                         payload.include_pending_pct = isNaN(pct) ? 0 : Math.max(0, Math.min(30, pct));
     2325                                        payload.pending_pct = isNaN(pct) ? 0 : Math.max(0, Math.min(30, pct));
     2326                                }
     2327                                if (daysInput) {
     2328                                        payload.span_days = parseInt(daysInput.value, 10);
     2329                                }
     2330                                if (logsInput) {
     2331                                        payload.with_logs = logsInput.checked ? '1' : '0';
    26972332                                }
    26982333                                return payload;
    … …  
    27072342                                } else if (isNaN(payload.target_rows) || payload.target_rows < 1 || payload.target_rows > config.maxRows) {
    27082343                                        setLog(table + ': enter a row count between 1 and ' + config.maxRows.toLocaleString() + '.', 'error');
     2344                                        return false;
     2345                                }
     2346                                if (typeof payload.span_days !== 'undefined' && (isNaN(payload.span_days) || payload.span_days < 1 || payload.span_days > 730)) {
     2347                                        setLog(table + ': enter a history span between 1 and 730 days.', 'error');
    27092348                                        return false;
    27102349                                }
Note: See TracChangeset for help on using the changeset viewer.