PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.2
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.2
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / inc / class-yoast-dynamic-rewrites.php

class-yoast-dynamic-rewrites.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.2, at inc/class-yoast-dynamic-rewrites.php

179 lines 5.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WPSEO plugin file.
4 *
5 * @package WPSEO\Internals
6 */
7
8 /**
9 * Class containing an alternative rewrite rules API for handling them dynamically without requiring flushing rules.
10 */
11 class Yoast_Dynamic_Rewrites implements WPSEO_WordPress_Integration {
12
13 /**
14 * Additional rewrite rules with high priority.
15 *
16 * @var array
17 */
18 protected $extra_rules_top = [];
19
20 /**
21 * Additional rewrite rules with low priority.
22 *
23 * @var array
24 */
25 protected $extra_rules_bottom = [];
26
27 /**
28 * Main instance holder.
29 *
30 * @var self|null
31 */
32 protected static $instance = null;
33
34 /**
35 * WP_Rewrite instance to use.
36 *
37 * @var WP_Rewrite
38 */
39 public $wp_rewrite;
40
41 /**
42 * Gets the main instance of the class.
43 *
44 * @return self Dynamic rewrites main instance.
45 */
46 public static function instance() {
47 if ( self::$instance === null ) {
48 self::$instance = new self();
49 self::$instance->register_hooks();
50 }
51
52 return self::$instance;
53 }
54
55 /**
56 * Constructor.
57 *
58 * Sets the WP_Rewrite instance to use.
59 *
60 * @param WP_Rewrite|null $rewrite Optional. WP_Rewrite instance to use. Default is the $wp_rewrite global.
61 * @throws RuntimeException Throws an exception if the $wp_rewrite global is not set.
62 */
63 public function __construct( $rewrite = null ) {
64 if ( ! $rewrite ) {
65 if ( empty( $GLOBALS['wp_rewrite'] ) ) {
66 /* translators: 1: PHP class name, 2: PHP variable name */
67 throw new RuntimeException( sprintf( __( 'The %1$s class must not be instantiated before the %2$s global is set.', 'wordpress-seo' ), self::class, '$wp_rewrite' ) );
68 }
69
70 $rewrite = $GLOBALS['wp_rewrite'];
71 }
72
73 $this->wp_rewrite = $rewrite;
74 }
75
76 /**
77 * Registers all necessary hooks with WordPress.
78 *
79 * @return void
80 */
81 public function register_hooks() {
82 add_action( 'init', [ $this, 'trigger_dynamic_rewrite_rules_hook' ], 1 );
83 add_filter( 'option_rewrite_rules', [ $this, 'filter_rewrite_rules_option' ] );
84 add_filter( 'sanitize_option_rewrite_rules', [ $this, 'sanitize_rewrite_rules_option' ] );
85 }
86
87 /**
88 * Adds a dynamic rewrite rule that transforms a URL structure to a set of query vars.
89 *
90 * Rules registered with this method are applied dynamically and do not require the rewrite rules
91 * to be flushed in order to become active, which is a benefit over the regular WordPress core API.
92 * Note however that the dynamic application only works for rules that correspond to index.php.
93 * Non-WordPress rewrite rules still require flushing.
94 *
95 * Any value in the $after parameter that isn't 'bottom' will result in the rule
96 * being placed at the top of the rewrite rules.
97 *
98 * @param string $regex Regular expression to match request against.
99 * @param string|array $query The corresponding query vars for this rewrite rule.
100 * @param string $priority Optional. Priority of the new rule. Accepts 'top'
101 * or 'bottom'. Default 'bottom'.
102 *
103 * @return void
104 */
105 public function add_rule( $regex, $query, $priority = 'bottom' ) {
106 if ( is_array( $query ) ) {
107 $query = add_query_arg( $query, 'index.php' );
108 }
109
110 $this->wp_rewrite->add_rule( $regex, $query, $priority );
111
112 // Do not further handle external rules.
113 if ( substr( $query, 0, strlen( $this->wp_rewrite->index . '?' ) ) !== $this->wp_rewrite->index . '?' ) {
114 return;
115 }
116
117 if ( $priority === 'bottom' ) {
118 $this->extra_rules_bottom[ $regex ] = $query;
119 return;
120 }
121
122 $this->extra_rules_top[ $regex ] = $query;
123 }
124
125 /**
126 * Triggers the hook on which rewrite rules should be added.
127 *
128 * This allows for a more specific point in time from the generic `init` hook where this is
129 * otherwise handled.
130 *
131 * @return void
132 */
133 public function trigger_dynamic_rewrite_rules_hook() {
134
135 /**
136 * Fires when the plugin's dynamic rewrite rules should be added.
137 *
138 * @param self $dynamic_rewrites Dynamic rewrites handler instance. Use its `add_rule()` method
139 * to add dynamic rewrite rules.
140 */
141 do_action( 'yoast_add_dynamic_rewrite_rules', $this );
142 }
143
144 /**
145 * Filters the rewrite rules option to dynamically add additional rewrite rules.
146 *
147 * @param array|string $rewrite_rules Array of rewrite rule $regex => $query pairs, or empty string
148 * if currently not set.
149 *
150 * @return array|string Filtered value of $rewrite_rules.
151 */
152 public function filter_rewrite_rules_option( $rewrite_rules ) {
153 // Do not add extra rewrite rules if the rules need to be flushed.
154 if ( empty( $rewrite_rules ) ) {
155 return $rewrite_rules;
156 }
157
158 return array_merge( $this->extra_rules_top, $rewrite_rules, $this->extra_rules_bottom );
159 }
160
161 /**
162 * Sanitizes the rewrite rules option prior to writing it to the database.
163 *
164 * This method ensures that the dynamic rewrite rules do not become part of the actual option.
165 *
166 * @param array|string $rewrite_rules Array pf rewrite rule $regex => $query pairs, or empty string
167 * in order to unset.
168 *
169 * @return array|string Filtered value of $rewrite_rules before writing the option.
170 */
171 public function sanitize_rewrite_rules_option( $rewrite_rules ) {
172 if ( empty( $rewrite_rules ) ) {
173 return $rewrite_rules;
174 }
175
176 return array_diff_key( $rewrite_rules, $this->extra_rules_top, $this->extra_rules_bottom );
177 }
178 }
179