PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.0.7
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.0.7
1.3.2 1.3.1 1.3.0 1.2.4 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.2.0 All 28 releases
xspeed / includes / class-cache-meta-box.php

class-cache-meta-box.php in xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN 1.0.7, at includes/class-cache-meta-box.php

139 lines 4.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Per-post cache rules meta box (Phase 3.4).
4 *
5 * Renders in the classic editor sidebar and (with WP 5.0+'s legacy
6 * meta-box compatibility) in the block editor's bottom panel. The
7 * Gutenberg-native sidebar UI is a separate enhancement; this file
8 * ships the read/write surface so power users get the feature today
9 * regardless of editor choice.
10 *
11 * The postmetas themselves are registered (with show_in_rest) by
12 * Cache_Rules::register_post_meta — letting any REST consumer
13 * (Gutenberg, automation, an external CMS) read + write the rules
14 * without going through this meta box.
15 *
16 * @package XSpeed
17 */
18
19 declare(strict_types=1);
20
21 namespace XSpeed;
22
23 defined( 'ABSPATH' ) || exit;
24
25 final class Cache_Meta_Box {
26
27 public const NONCE_ACTION = 'xspeed_per_post_rules';
28 public const NONCE_FIELD = 'xspeed_per_post_rules_nonce';
29
30 public static function boot(): void {
31 add_action( 'init', array( Cache_Rules::class, 'register_post_meta' ) );
32 add_action( 'add_meta_boxes', array( __CLASS__, 'register_meta_box' ) );
33 add_action( 'save_post', array( __CLASS__, 'handle_save' ), 10, 2 );
34 }
35
36 public static function register_meta_box(): void {
37 foreach ( Cache_Rules::supported_post_types() as $type ) {
38 add_meta_box(
39 'xspeed-cache-rules',
40 __( 'xSpeed · Cache Rules', 'xspeed' ),
41 array( __CLASS__, 'render' ),
42 $type,
43 'side',
44 'default'
45 );
46 }
47 }
48
49 public static function render( \WP_Post $post ): void {
50 wp_nonce_field( self::NONCE_ACTION, self::NONCE_FIELD );
51
52 $no_cache = (bool) get_post_meta( $post->ID, Cache_Rules::META_NO_CACHE, true );
53 $expiry = (int) get_post_meta( $post->ID, Cache_Rules::META_EXPIRY_HOURS, true );
54 ?>
55 <p>
56 <label>
57 <input
58 type="checkbox"
59 name="xspeed_no_cache"
60 value="1"
61 <?php checked( $no_cache ); ?>
62 />
63 <?php esc_html_e( 'Never cache this page', 'xspeed' ); ?>
64 </label>
65 </p>
66 <p style="font-size:12px;color:#666;margin:-8px 0 12px;">
67 <?php esc_html_e( 'Skip the page cache entirely for this post. Useful for highly dynamic pages.', 'xspeed' ); ?>
68 </p>
69
70 <p>
71 <label for="xspeed_expiry_hours">
72 <?php esc_html_e( 'Custom cache lifetime', 'xspeed' ); ?>
73 </label>
74 <br />
75 <input
76 type="number"
77 id="xspeed_expiry_hours"
78 name="xspeed_expiry_hours"
79 min="0"
80 max="720"
81 value="<?php echo esc_attr( (string) max( 0, $expiry ) ); ?>"
82 style="width:80px;"
83 />
84 <span style="font-size:12px;color:#666;">
85 <?php esc_html_e( 'hours · 0 = use global', 'xspeed' ); ?>
86 </span>
87 </p>
88 <p style="font-size:12px;color:#666;margin:-4px 0 0;">
89 <?php esc_html_e( 'Override the global cache expiry for this post (1–720 hours). Leave at 0 to inherit the site default.', 'xspeed' ); ?>
90 </p>
91 <?php
92 }
93
94 /**
95 * @param int $post_id
96 * @param \WP_Post $post
97 */
98 public static function handle_save( $post_id, $post ): void {
99 // Skip the noise paths first — autosaves, revisions, ajax,
100 // REST writes (REST has its own auth via register_post_meta).
101 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
102 return;
103 }
104 if ( wp_is_post_revision( $post_id ) ) {
105 return;
106 }
107 if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
108 return; // block editor goes through register_post_meta + the REST auth_callback.
109 }
110 if ( ! isset( $_POST[ self::NONCE_FIELD ] ) ) {
111 return; // meta box wasn't rendered on this save (quick edit, bulk edit, etc.).
112 }
113 if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ self::NONCE_FIELD ] ) ), self::NONCE_ACTION ) ) {
114 return;
115 }
116 if ( ! current_user_can( 'edit_post', $post_id ) ) {
117 return;
118 }
119 if ( ! in_array( $post->post_type, Cache_Rules::supported_post_types(), true ) ) {
120 return;
121 }
122
123 $no_cache = ! empty( $_POST['xspeed_no_cache'] );
124 if ( $no_cache ) {
125 update_post_meta( $post_id, Cache_Rules::META_NO_CACHE, true );
126 } else {
127 delete_post_meta( $post_id, Cache_Rules::META_NO_CACHE );
128 }
129
130 $expiry = isset( $_POST['xspeed_expiry_hours'] ) ? (int) $_POST['xspeed_expiry_hours'] : 0;
131 $expiry = max( 0, min( 720, $expiry ) );
132 if ( $expiry > 0 ) {
133 update_post_meta( $post_id, Cache_Rules::META_EXPIRY_HOURS, $expiry );
134 } else {
135 delete_post_meta( $post_id, Cache_Rules::META_EXPIRY_HOURS );
136 }
137 }
138 }
139