PluginProbe
FlyWP Helper – Page Cache, Page Optimization, Emails for FlyWP Server Control Panel / 1.8.0
FlyWP Helper – Page Cache, Page Optimization, Emails for FlyWP Server Control Panel v1.8.0
1.8.0 1.7.1 1.7.0 1.6.0 1.5.2 trunk 0.1 0.2.0 0.2.1 0.3 0.3.1 0.3.2 0.3.3 0.3.4 0.4 0.4.1 0.4.2 0.4.3 1.0 1.1 1.2 1.3.1 1.4.0 1.4.1 1.5.0 All 27 releases
flywp / includes / StaticSite / Engine / Discovery / RedirectSourceUrls.php

RedirectSourceUrls.php in FlyWP Helper – Page Cache, Page Optimization, Emails for FlyWP Server Control Panel 1.8.0, at includes/StaticSite/Engine/Discovery/RedirectSourceUrls.php

285 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FlyWP\StaticSite\Engine\Discovery;
4
5 /**
6 * Source URLs of redirect plugins. The crawler fetches them, the origin answers with a 3xx,
7 * and the engine writes the rule.
8 *
9 * - Plugins: Redirection, Rank Math, Yoast SEO Premium, Safe Redirect Manager and Simple 301 Redirects.
10 * - One class that returns absolute URLs on the origin.
11 * - Absolute sources on a site host (with or without "www.", http or https) move to the origin scheme and host.
12 * - No Rank Math row limit. The _redirects limits apply later.
13 * - Simple 301 wildcard sources become dynamic rules only when its wildcard option is on.
14 * - `wp flywp static site` writes the result to site.json.
15 *
16 * - A plugin is read only when its classes or functions exist (the plugin is active).
17 * - Regex rules and sources with "*" are not crawled.
18 *
19 * @since 1.8.0
20 */
21 class RedirectSourceUrls {
22
23 const RANK_MATH_PAGE_SIZE = 500;
24
25 const CODES = [ 301, 302, 307, 308 ];
26
27 /**
28 * Absolute source URLs on the origin.
29 *
30 * @param string $origin_url Origin URL.
31 * @param string[] $site_urls Other URLs of the site (home URL, site URL).
32 *
33 * @return string[]
34 */
35 public static function all( $origin_url, array $site_urls = [] ) {
36 $sources = array_merge(
37 self::redirection(),
38 self::rank_math(),
39 self::yoast_premium(),
40 self::safe_redirect_manager(),
41 self::simple_301_redirects()
42 );
43
44 $urls = [];
45
46 foreach ( $sources as $source ) {
47 $url = self::to_origin( (string) $source, $origin_url, $site_urls );
48
49 if ( $url !== null && strpos( $url, '*' ) === false ) {
50 $urls[ $url ] = true;
51 }
52 }
53
54 return array_keys( $urls );
55 }
56
57 /**
58 * Simple 301 Redirects wildcard rules, when its wildcard option is on.
59 *
60 * @param string $origin_url Origin URL.
61 * @param string[] $site_urls Other URLs of the site.
62 *
63 * @return array<int, array{from: string, to: string, status: int}>
64 */
65 public static function wildcard_rules( $origin_url, array $site_urls = [] ) {
66 if ( ! class_exists( 'Simple301Redirects' ) || get_option( '301_redirects_wildcard' ) !== 'true' ) {
67 return [];
68 }
69
70 $rules = [];
71
72 foreach ( (array) get_option( '301_redirects' ) as $from => $to ) {
73 $from_url = self::to_origin( (string) $from, $origin_url, $site_urls );
74
75 if ( $from_url === null || strpos( $from_url, '*' ) === false ) {
76 continue;
77 }
78
79 $to_url = self::to_origin( (string) $to, $origin_url, $site_urls );
80 $rules[] = [
81 'from' => $from_url,
82 'to' => $to_url !== null ? $to_url : (string) $to,
83 'status' => 301,
84 ];
85 }
86
87 return $rules;
88 }
89
90 /**
91 * Move a source onto the origin URL.
92 *
93 * @param string $source Relative path or absolute URL.
94 * @param string $origin_url Origin URL.
95 * @param string[] $site_urls Other URLs of the site.
96 *
97 * @return string|null Null for an empty source or a source on another host.
98 */
99 public static function to_origin( $source, $origin_url, array $site_urls ) {
100 $source = trim( $source );
101
102 if ( $source === '' ) {
103 return null;
104 }
105
106 // Plugins store site-root paths ("/blog/old-page" on a site in "/blog"), so resolve them like a browser.
107 if ( ! Url::is_http( $source ) ) {
108 return Url::resolve( rtrim( $origin_url, '/' ) . '/', $source );
109 }
110
111 $hosts = [];
112
113 foreach ( array_merge( [ $origin_url ], $site_urls ) as $url ) {
114 $hosts[ self::bare_host( $url ) ] = true;
115 }
116
117 if ( ! isset( $hosts[ self::bare_host( $source ) ] ) ) {
118 return null;
119 }
120
121 $parts = Url::parts( $source );
122 $origin = Url::parts( $origin_url );
123
124 $parts['scheme'] = $origin['scheme'];
125 $parts['host'] = $origin['host'];
126 $parts['port'] = $origin['port'];
127 $parts['user'] = '';
128 $parts['pass'] = '';
129
130 return Url::build( $parts );
131 }
132
133 /**
134 * Host without "www.".
135 *
136 * @param string $url URL.
137 *
138 * @return string
139 */
140 private static function bare_host( $url ) {
141 return (string) preg_replace( '/^www\./', '', Url::parts( $url )['host'] );
142 }
143
144 /**
145 * Redirection plugin.
146 *
147 * @return string[]
148 */
149 private static function redirection() {
150 if ( ! class_exists( 'Red_Item' ) || ! method_exists( 'Red_Item', 'get_all' ) ) {
151 return [];
152 }
153
154 $urls = [];
155
156 foreach ( \Red_Item::get_all() as $item ) {
157 if ( ! $item->is_enabled() || $item->is_dynamic() || $item->is_regex() ) {
158 continue;
159 }
160
161 if ( $item->get_match_type() !== 'url' || $item->get_action_type() !== 'url' ) {
162 continue;
163 }
164
165 $urls[] = $item->get_url();
166 }
167
168 return $urls;
169 }
170
171 /**
172 * Rank Math, all active rules, page by page.
173 *
174 * @return string[]
175 */
176 private static function rank_math() {
177 if ( ! class_exists( '\RankMath\Redirections\DB' ) ) {
178 return [];
179 }
180
181 $urls = [];
182 $first_id = null;
183
184 for ( $page = 1; ; $page++ ) {
185 $result = \RankMath\Redirections\DB::get_redirections(
186 [
187 'status' => 'active',
188 'limit' => self::RANK_MATH_PAGE_SIZE,
189 'paged' => $page,
190 ]
191 );
192 $redirects = isset( $result['redirections'] ) ? array_values( (array) $result['redirections'] ) : [];
193 $page_id = isset( $redirects[0]['id'] ) ? $redirects[0]['id'] : null;
194
195 // Stop when the plugin ignores "paged" and gives the first page again.
196 if ( ! $redirects || ( $page > 1 && $page_id === $first_id ) ) {
197 break;
198 }
199
200 $first_id = $page === 1 ? $page_id : $first_id;
201
202 foreach ( $redirects as $redirect ) {
203 if ( ! in_array( (int) $redirect['header_code'], self::CODES, true ) ) {
204 continue;
205 }
206
207 foreach ( (array) maybe_unserialize( $redirect['sources'] ) as $source ) {
208 if ( isset( $source['comparison'], $source['pattern'] ) && $source['comparison'] === 'exact' ) {
209 $urls[] = $source['pattern'];
210 }
211 }
212 }
213
214 if ( count( $redirects ) < self::RANK_MATH_PAGE_SIZE ) {
215 break;
216 }
217 }
218
219 return $urls;
220 }
221
222 /**
223 * Yoast SEO Premium.
224 *
225 * @return string[]
226 */
227 private static function yoast_premium() {
228 if ( ! class_exists( 'WPSEO_Redirect_Manager' ) ) {
229 return [];
230 }
231
232 $urls = [];
233
234 foreach ( (array) get_option( 'wpseo-premium-redirects-base' ) as $item ) {
235 if ( is_array( $item ) && isset( $item['format'], $item['type'], $item['origin'] ) && $item['format'] === 'plain' && in_array( (int) $item['type'], self::CODES, true ) ) {
236 $urls[] = $item['origin'];
237 }
238 }
239
240 return $urls;
241 }
242
243 /**
244 * Safe Redirect Manager.
245 *
246 * @return string[]
247 */
248 private static function safe_redirect_manager() {
249 if ( ! class_exists( 'SRM_Redirect' ) || ! function_exists( 'srm_get_redirects' ) || ! function_exists( 'srm_get_max_redirects' ) ) {
250 return [];
251 }
252
253 $redirects = srm_get_redirects(
254 [
255 'posts_per_page' => srm_get_max_redirects(), // phpcs:ignore WordPress.WP.PostsPerPage -- the limit of Safe Redirect Manager itself.
256 'post_status' => 'publish',
257 ]
258 );
259 $urls = [];
260
261 foreach ( (array) $redirects as $item ) {
262 if ( empty( $item['enable_regex'] ) && in_array( (int) $item['status_code'], self::CODES, true ) ) {
263 $urls[] = $item['redirect_from'];
264 }
265 }
266
267 return $urls;
268 }
269
270 /**
271 * Simple 301 Redirects. Sources with "*" are removed in all().
272 *
273 * @return string[]
274 */
275 private static function simple_301_redirects() {
276 if ( ! class_exists( 'Simple301Redirects' ) ) {
277 return [];
278 }
279
280 $redirects = get_option( '301_redirects' );
281
282 return is_array( $redirects ) ? array_map( 'strval', array_keys( $redirects ) ) : [];
283 }
284 }
285