| @@ -55,11 +55,84 @@ | ||
| 55 | 55 | 'item_type' => 'string', |
| 56 | 56 | 'label' => __( 'Auto-Cleanup Types', 'xspeed' ), |
| 57 | 57 | 'description' => __( 'Which cleanup categories run on the schedule above. Leave empty to keep auto-cleanup disabled even if a schedule is set.', 'xspeed' ), |
| 58 | 58 | ), |
| 59 | + 'limit_revisions' => array( | |
| 60 | + 'type' => 'bool', | |
| 61 | + 'default' => false, | |
| 62 | + 'label' => __( 'Limit Post Revisions', 'xspeed' ), | |
| 63 | + 'description' => __( 'Cap how many revisions WordPress keeps for each post. Cleanup removes revisions that already exist; this stops them piling up again.', 'xspeed' ), | |
| 64 | + ), | |
| 65 | + 'revisions_to_keep' => array( | |
| 66 | + 'type' => 'int', | |
| 67 | + 'default' => 5, | |
| 68 | + 'min' => 0, | |
| 69 | + 'max' => 500, | |
| 70 | + 'label' => __( 'Revisions to Keep', 'xspeed' ), | |
| 71 | + 'description' => __( 'Used when Limit Post Revisions is on. 0 turns revisions off completely. Older revisions are trimmed the next time each post is saved; to remove the backlog now, clean Post Revisions above.', 'xspeed' ), | |
| 72 | + ), | |
| 59 | 73 | ); |
| 60 | 74 | } |
| 61 | 75 | |
| 76 | + /** | |
| 77 | + * WP_POST_REVISIONS as wp-config.php (or an earlier plugin) set it, or | |
| 78 | + * null when nobody did. Read in boot(), on plugins_loaded: after that, | |
| 79 | + * core defines it as `true` itself, so defined() stops telling the two | |
| 80 | + * cases apart. | |
| 81 | + * | |
| 82 | + * Not the schema's `constants` pinning (#398): that tests defined() at | |
| 83 | + * request time, when core's own default makes it always true. | |
| 84 | + * | |
| 85 | + * @var bool|int|null | |
| 86 | + */ | |
| 87 | + private static $configured_revisions = null; | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * @param int $num Revisions WordPress would keep; -1 means all. | |
| 91 | + * @param \WP_Post $post | |
| 92 | + * @return int | |
| 93 | + */ | |
| 94 | + public static function filter_revisions_to_keep( $num, $post ) { | |
| 95 | + // A wp-config.php value is the site owner's decision; leave it alone. | |
| 96 | + if ( null !== self::$configured_revisions ) { | |
| 97 | + return $num; | |
| 98 | + } | |
| 99 | + // Core already answered 0 for post types without revision support. | |
| 100 | + if ( ! $post instanceof \WP_Post || ! post_type_supports( $post->post_type, 'revisions' ) ) { | |
| 101 | + return $num; | |
| 102 | + } | |
| 103 | + $opts = Settings_Manager::get( self::SLUG ); | |
| 104 | + if ( empty( $opts['limit_revisions'] ) ) { | |
| 105 | + return $num; | |
| 106 | + } | |
| 107 | + return max( 0, (int) ( $opts['revisions_to_keep'] ?? 5 ) ); | |
| 108 | + } | |
| 109 | + | |
| 110 | + public function ui_notices(): array { | |
| 111 | + if ( null === self::$configured_revisions ) { | |
| 112 | + return array(); | |
| 113 | + } | |
| 114 | + $value = self::$configured_revisions; | |
| 115 | + if ( true === $value ) { | |
| 116 | + $shown = 'true'; | |
| 117 | + } elseif ( false === $value ) { | |
| 118 | + $shown = 'false'; | |
| 119 | + } else { | |
| 120 | + $shown = (string) (int) $value; | |
| 121 | + } | |
| 122 | + return array( | |
| 123 | + array( | |
| 124 | + 'tone' => 'info', | |
| 125 | + 'title' => __( 'The revision limit is set outside xSpeed', 'xspeed' ), | |
| 126 | + 'body' => sprintf( | |
| 127 | + /* translators: %s: value of WP_POST_REVISIONS, e.g. 5 or false. */ | |
| 128 | + __( 'WP_POST_REVISIONS is set to %s, usually in wp-config.php, so Limit Post Revisions below has no effect. Remove that definition to manage the limit here.', 'xspeed' ), | |
| 129 | + $shown | |
| 130 | + ), | |
| 131 | + ), | |
| 132 | + ); | |
| 133 | + } | |
| 134 | + | |
| 62 | 135 | public function rest_routes(): array { |
| 63 | 136 | // Schema POST/GET come from the base; we add three custom routes. |
| 64 | 137 | $default = parent::rest_routes(); |
| 65 | 138 | return array_merge( |
| @@ -108,8 +181,10 @@ | ||
| 108 | 181 | ); |
| 109 | 182 | } |
| 110 | 183 | |
| 111 | 184 | public function boot(): void { |
| 185 | + self::$configured_revisions = defined( 'WP_POST_REVISIONS' ) ? constant( 'WP_POST_REVISIONS' ) : null; | |
| 186 | + add_filter( 'wp_revisions_to_keep', array( __CLASS__, 'filter_revisions_to_keep' ), 10, 2 ); | |
| 112 | 187 | add_action( Database_Cleaner::CRON_HOOK, array( Database_Cleaner::class, 'cron_tick' ) ); |
| 113 | 188 | add_action( 'update_option_xspeed_module_database', array( $this, 'on_settings_change' ), 10, 2 ); |
| 114 | 189 | add_action( 'add_option_xspeed_module_database', array( $this, 'on_settings_added' ), 10, 2 ); |
| 115 | 190 | } |
| @@ -118,8 +193,16 @@ | ||
| 118 | 193 | wp_clear_scheduled_hook( Database_Cleaner::CRON_HOOK ); |
| 119 | 194 | } |
| 120 | 195 | |
| 121 | 196 | public function on_settings_change( $old, $new ): void { |
| 197 | + // A revision-limit save must not reschedule cleanup: apply_schedule() | |
| 198 | + // restarts the timer, which pulled a weekly run forward on every save. | |
| 199 | + $old = is_array( $old ) ? $old : array(); | |
| 200 | + if ( is_array( $new ) | |
| 201 | + && ( $old['schedule'] ?? null ) === ( $new['schedule'] ?? null ) | |
| 202 | + && ( $old['included_types'] ?? null ) === ( $new['included_types'] ?? null ) ) { | |
| 203 | + return; | |
| 204 | + } | |
| 122 | 205 | $schedule = is_array( $new ) ? (string) ( $new['schedule'] ?? 'manual' ) : 'manual'; |
| 123 | 206 | $types = is_array( $new ) && isset( $new['included_types'] ) && is_array( $new['included_types'] ) ? $new['included_types'] : array(); |
| 124 | 207 | Database_Cleaner::apply_schedule( $schedule, $types ); |
| 125 | 208 | } |