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 / OldPermalinkCandidateStructureProvider.php

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

124 lines 4.1 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 * Gathers the old-permalink-structure candidates to evaluate for a request:
9 * previously observed structures from the structure store, a small built-in
10 * well-known-structure list, and whatever the abj404_old_permalink_candidate_structures
11 * filter adds or replaces them with. Normalizes, deduplicates, and caps the
12 * result so a single request never evaluates an unbounded candidate list.
13 *
14 * Extracted from ABJ_404_Solution_OldPermalinkStructureResolver because
15 * assembling the candidate list is a distinct concern from compiling a
16 * structure into a regex or resolving a match to a post.
17 */
18 class ABJ_404_Solution_OldPermalinkCandidateStructureProvider {
19
20 private const MAX_EVALUATED_STRUCTURES = 10;
21
22 /** @var ABJ_404_Solution_OldPermalinkStructureStore */
23 private $structureStore;
24
25 /** @var ABJ_404_Solution_PermalinkStructureCompiler */
26 private $compiler;
27
28 /**
29 * @param ABJ_404_Solution_OldPermalinkStructureStore $structureStore
30 * @param ABJ_404_Solution_PermalinkStructureCompiler $compiler
31 */
32 public function __construct(
33 ABJ_404_Solution_OldPermalinkStructureStore $structureStore,
34 ABJ_404_Solution_PermalinkStructureCompiler $compiler
35 ) {
36 $this->structureStore = $structureStore;
37 $this->compiler = $compiler;
38 }
39
40 /**
41 * @param string $path
42 * @return array<int, array{structure: string, post_types: array<int, string>}>
43 */
44 public function candidatesFor(string $path): array {
45 $raw = array();
46 foreach ($this->structureStore->getObservedStructures() as $item) {
47 $raw[] = array('structure' => $item['structure'], 'post_types' => array());
48 }
49 foreach ($this->defaultWellKnownStructures() as $structure) {
50 $raw[] = array('structure' => $structure, 'post_types' => array());
51 }
52
53 if (function_exists('apply_filters')) {
54 $filtered = apply_filters('abj404_old_permalink_candidate_structures', $raw, $path);
55 if (is_array($filtered)) {
56 $raw = $filtered;
57 }
58 }
59
60 $out = array();
61 $seen = array();
62 foreach ($raw as $entry) {
63 $candidate = $this->normalizeCandidateEntry($entry);
64 if ($candidate === null) {
65 continue;
66 }
67 $key = $candidate['structure'] . '|' . implode(',', $candidate['post_types']);
68 if (isset($seen[$key])) {
69 continue;
70 }
71 $seen[$key] = true;
72 $out[] = $candidate;
73 if (count($out) >= self::MAX_EVALUATED_STRUCTURES) {
74 break;
75 }
76 }
77
78 return $out;
79 }
80
81 /**
82 * @return array<int, string>
83 */
84 private function defaultWellKnownStructures(): array {
85 return array(
86 '/%year%/%monthnum%/%day%/%postname%/',
87 '/%year%/%monthnum%/%postname%/',
88 '/%postname%/%year%/',
89 '/%postname%/%year%/%monthnum%/',
90 '/archives/%post_id%/',
91 );
92 }
93
94 /**
95 * @param mixed $entry
96 * @return array{structure: string, post_types: array<int, string>}|null
97 */
98 private function normalizeCandidateEntry($entry): ?array {
99 if (is_string($entry)) {
100 return array('structure' => $this->compiler->normalizeStructure($entry), 'post_types' => array());
101 }
102 if (!is_array($entry) || !isset($entry['structure']) || !is_scalar($entry['structure'])) {
103 return null;
104 }
105
106 $postTypes = array();
107 if (isset($entry['post_types']) && is_array($entry['post_types'])) {
108 foreach ($entry['post_types'] as $postType) {
109 if (is_scalar($postType)) {
110 $postType = sanitize_key((string)$postType);
111 if ($postType !== '') {
112 $postTypes[] = $postType;
113 }
114 }
115 }
116 }
117
118 return array(
119 'structure' => $this->compiler->normalizeStructure((string)$entry['structure']),
120 'post_types' => array_values(array_unique($postTypes)),
121 );
122 }
123 }
124