PluginProbe
404 Solution / trunk
404 Solution vtrunk
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / matching / OldPermalinkStructureResolver.php

OldPermalinkStructureResolver.php in 404 Solution trunk, at includes/matching/OldPermalinkStructureResolver.php

116 lines 3.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) {
4 exit;
5 }
6
7 /**
8 * Resolves a 404 request against previously used WordPress permalink
9 * structures without building a full old-URL map.
10 *
11 * Orchestrates three collaborators: ABJ_404_Solution_OldPermalinkCandidateStructureProvider
12 * (which structures to try), ABJ_404_Solution_PermalinkStructureCompiler
13 * (structure -> regex), and ABJ_404_Solution_OldPermalinkPostResolver (regex
14 * match -> validated post).
15 */
16 class ABJ_404_Solution_OldPermalinkStructureResolver {
17
18 /** @var ABJ_404_Solution_PermalinkStructureCompiler */
19 private $compiler;
20
21 /** @var ABJ_404_Solution_OldPermalinkCandidateStructureProvider */
22 private $candidateProvider;
23
24 /** @var ABJ_404_Solution_OldPermalinkPostResolver */
25 private $postResolver;
26
27 /** @var ABJ_404_Solution_Logging */
28 private $logger;
29
30 /**
31 * @param ABJ_404_Solution_OldPermalinkStructureStore $structureStore
32 * @param ABJ_404_Solution_ContentRepositoryInterface $contentRepository
33 * @param ABJ_404_Solution_Logging $logger
34 */
35 public function __construct(
36 ABJ_404_Solution_OldPermalinkStructureStore $structureStore,
37 ABJ_404_Solution_ContentRepositoryInterface $contentRepository,
38 ABJ_404_Solution_Logging $logger
39 ) {
40 $this->compiler = new ABJ_404_Solution_PermalinkStructureCompiler();
41 $this->candidateProvider = new ABJ_404_Solution_OldPermalinkCandidateStructureProvider($structureStore, $this->compiler);
42 $this->postResolver = new ABJ_404_Solution_OldPermalinkPostResolver($contentRepository, $logger);
43 $this->logger = $logger;
44 }
45
46 /**
47 * @param ABJ_404_Solution_MatchRequest $request
48 * @return array{id: string, type: string, link: string, title: string, score: float}|null
49 */
50 public function resolve(ABJ_404_Solution_MatchRequest $request): ?array {
51 $path = $this->normalizeRequestPath($request->getRequestedURL());
52 if ($path === '') {
53 return null;
54 }
55
56 foreach ($this->candidateProvider->candidatesFor($path) as $candidate) {
57 $compiled = $this->compiler->compile($candidate['structure']);
58 if ($compiled === null) {
59 $this->logger->debugMessage('Old permalink structure skipped: ' . $candidate['structure']);
60 continue;
61 }
62
63 $matches = array();
64 $matched = @preg_match($compiled['regex'], $path, $matches);
65 if ($matched !== 1) {
66 continue;
67 }
68
69 $postId = $this->postResolver->resolve($matches, $candidate, $request->getOptions());
70 if ($postId === null) {
71 continue;
72 }
73
74 $link = function_exists('get_permalink') ? get_permalink($postId) : '';
75 if (!is_string($link) || $link === '') {
76 return null;
77 }
78
79 if ($this->normalizeRequestPath($link) === $path) {
80 $this->logger->debugMessage('Old permalink structure matched canonical URL; skipping self redirect.');
81 return null;
82 }
83
84 return array(
85 'id' => (string)$postId,
86 'type' => (string)ABJ404_TYPE_POST,
87 'link' => $link,
88 'title' => function_exists('get_the_title') ? (string)get_the_title($postId) : '',
89 'score' => 100.0,
90 );
91 }
92
93 return null;
94 }
95
96 /**
97 * @param string $requestedURL
98 * @return string
99 */
100 private function normalizeRequestPath(string $requestedURL): string {
101 $path = parse_url($requestedURL, PHP_URL_PATH);
102 if (!is_string($path)) {
103 $path = $requestedURL;
104 }
105 $path = trim($path);
106 if ($path === '') {
107 return '';
108 }
109 if ($path[0] !== '/') {
110 $path = '/' . $path;
111 }
112 $path = '/' . trim($path, '/');
113 return $path === '/' ? '/' : $path . '/';
114 }
115 }
116