PluginProbe
404 Solution / 4.3.3
404 Solution v4.3.3
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 / view / RedirectEditFormPresenter.php

RedirectEditFormPresenter.php in 404 Solution 4.3.3, at includes/view/RedirectEditFormPresenter.php

275 lines 13.7 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 * Renders edit-redirect form templates and form-table rows.
9 */
10 class ABJ_404_Solution_RedirectEditFormPresenter {
11
12 /** @var ABJ_404_Solution_Functions */
13 private $functions;
14
15 /** @var ABJ_404_Solution_RedirectEngineLabeler */
16 private $engineLabeler;
17
18 /**
19 * @param ABJ_404_Solution_Functions $functions
20 * @param ABJ_404_Solution_RedirectEngineLabeler $engineLabeler
21 */
22 public function __construct($functions, ABJ_404_Solution_RedirectEngineLabeler $engineLabeler) {
23 $this->functions = $functions;
24 $this->engineLabeler = $engineLabeler;
25 }
26
27 /**
28 * Build the redirect-to autocomplete dropdown HTML from the template.
29 *
30 * @param string $pageTitle
31 * @param string $pageIDAndType
32 * @return string
33 */
34 public function buildRedirectToDropdownHtml(string $pageTitle, string $pageIDAndType): string {
35 $html = $this->readTemplate('addManualRedirectPageSearchDropdown.html');
36 $html = $this->functions->str_replace('{redirect_to_label}', __('Redirect to', '404-solution'), $html);
37 $html = $this->functions->str_replace('{TOOLTIP_POPUP_EXPLANATION_EMPTY}',
38 __('(Type a page name or an external URL)', '404-solution'), $html);
39 $html = $this->functions->str_replace('{TOOLTIP_POPUP_EXPLANATION_PAGE}',
40 __('(A page has been selected.)', '404-solution'), $html);
41 $html = $this->functions->str_replace('{TOOLTIP_POPUP_EXPLANATION_CUSTOM_STRING}',
42 __('(A custom string has been entered.)', '404-solution'), $html);
43 $html = $this->functions->str_replace('{TOOLTIP_POPUP_EXPLANATION_URL}',
44 __('(An external URL will be used.)', '404-solution'), $html);
45 $html = $this->functions->str_replace('{REDIRECT_TO_USER_FIELD_WARNING}', '', $html);
46 $html = $this->functions->str_replace('{redirectPageTitle}', esc_attr($pageTitle), $html);
47 $html = $this->functions->str_replace('{pageIDAndType}', esc_attr($pageIDAndType), $html);
48 $html = $this->functions->str_replace('{data-url}',
49 "admin-ajax.php?action=echoRedirectToPages&includeDefault404Page=true&includeSpecial=true&nonce=" . wp_create_nonce('abj404_ajax'), $html);
50 return $this->functions->doNormalReplacements($html);
51 }
52
53 /**
54 * @param array<int, array<string, mixed>> $redirects
55 * @return string
56 */
57 public function buildBulkUrlsRowHtml(array $redirects): string {
58 $items = '';
59 $itemTemplate = $this->readTemplate('redirectEditBulkUrlItem.html');
60 foreach ($redirects as $bulkRedirect) {
61 $bulkUrl = is_string($bulkRedirect['url'] ?? '') ? (string)($bulkRedirect['url'] ?? '') : '';
62 $items .= $this->functions->str_replace('{url}', esc_html($bulkUrl), $itemTemplate);
63 }
64
65 $rowHtml = $this->readTemplate('editRedirectBulkUrls.html');
66 $rowHtml = $this->functions->str_replace('{bulk_urls_label}', esc_html__('URLs to redirect', '404-solution'), $rowHtml);
67 $rowHtml = $this->functions->str_replace('{bulk_count}', (string)count($redirects), $rowHtml);
68 return $this->functions->str_replace('{bulk_url_items}', $items, $rowHtml);
69 }
70
71 /**
72 * @param array<int, int> $ids
73 * @return string
74 */
75 public function buildIdsMultipleHiddenInput(array $ids): string {
76 $hiddenInput = $this->readTemplate('editRedirectIdsMultipleHiddenInput.html');
77 return $this->functions->str_replace('{ids_multiple}', esc_attr(implode(',', $ids)), $hiddenInput);
78 }
79
80 /**
81 * Build the suggestion block HTML for a captured URL's best match.
82 *
83 * @param array{title: string, score: int, id_and_type: string, type_label: string} $suggestion
84 * @return string
85 */
86 public function buildSuggestionBlockHtml(array $suggestion): string {
87 $bucket = $suggestion['score'] >= 75 ? 'high' : ($suggestion['score'] >= 50 ? 'medium' : 'low');
88 $typeLabel = '';
89 if (!empty($suggestion['type_label'])) {
90 $typeLabel = $this->readTemplate('editRedirectSuggestionTypeLabel.html');
91 $typeLabel = $this->functions->str_replace('{type_label}', esc_html($suggestion['type_label']), $typeLabel);
92 }
93
94 $html = $this->readTemplate('editRedirectSuggestionBlock.html');
95 $html = $this->functions->str_replace('{suggestion_label}', esc_html__('Suggested destination', '404-solution'), $html);
96 $html = $this->functions->str_replace('{suggestion_title}', esc_html($suggestion['title']), $html);
97 $html = $this->functions->str_replace('{suggestion_title_attr}', esc_attr($suggestion['title']), $html);
98 $html = $this->functions->str_replace('{suggestion_type_label}', $typeLabel, $html);
99 $html = $this->functions->str_replace('{suggestion_score_bucket}', $bucket, $html);
100 $html = $this->functions->str_replace('{suggestion_score}', esc_html((string)$suggestion['score']), $html);
101 $html = $this->functions->str_replace('{suggestion_id_and_type}', esc_attr($suggestion['id_and_type']), $html);
102 $html = $this->functions->str_replace('{match_text}', esc_html__('match', '404-solution'), $html);
103 $html = $this->functions->str_replace('{accept_label}', esc_html__('Accept Suggestion', '404-solution'), $html);
104 return $this->functions->str_replace('{pick_different_label}', esc_html__('Pick a Different Page', '404-solution'), $html);
105 }
106
107 /**
108 * @param string $redirectId
109 * @return string
110 */
111 public function buildRedirectIdHiddenInput(string $redirectId): string {
112 $hiddenInputs = $this->readTemplate('editRedirectIdHiddenInput.html');
113 return $this->functions->str_replace('{redirect_id}', esc_attr($redirectId), $hiddenInputs);
114 }
115
116 /**
117 * Build the URL form-table row with an optional "Auto-matched by" note.
118 *
119 * @return string
120 */
121 public function buildUrlRowHtml(string $redirectUrl, string $redirectEngine): string {
122 $matchedByNote = '';
123 if ($redirectEngine !== '') {
124 $matchedByNote = $this->readTemplate('editRedirectMatchedByNote.html');
125 $matchedByNote = $this->functions->str_replace('{matched_by_label}', esc_html__('Auto-matched by:', '404-solution'), $matchedByNote);
126 $matchedByNote = $this->functions->str_replace('{engine_name}', esc_html($this->engineLabeler->humanize($redirectEngine)), $matchedByNote);
127 }
128 $urlBody = $this->readTemplate('editRedirectUrlRowBody.html');
129 $urlBody = $this->functions->str_replace('{url_value}', esc_attr($redirectUrl), $urlBody);
130 $urlBody = $this->functions->str_replace('{matched_by_note}', $matchedByNote, $urlBody);
131 return $this->buildFieldRowHtml('url', $this->buildRequiredLabel(__('URL', '404-solution')), $urlBody);
132 }
133
134 /**
135 * Build the "regular expression" form-table row.
136 *
137 * @param string $isRegexChecked ' checked' or ''
138 * @return string
139 */
140 public function buildRegexRowHtml(string $isRegexChecked): string {
141 $regexLabel = __('Treat this URL as a regular expression', '404-solution');
142 $body = $this->readTemplate('editRedirectRegexBody.html');
143 $body = $this->functions->str_replace('{regex_label}', esc_html($regexLabel), $body);
144 $body = $this->functions->str_replace('{is_regex_checked}', $isRegexChecked, $body);
145 $body = $this->functions->str_replace('{regex_explain_link}', esc_html__('(Explain)', '404-solution'), $body);
146 $body = $this->functions->str_replace('{regex_explain_text}', esc_html__('When checked, the text is treated as a regular expression. Note that including a bad regular expression or one that takes too long will break your website. So please use caution and test them elsewhere before trying them here. If you don\'t know what you\'re doing please don\'t use this option (as it\'s not necessary for the functioning of the plugin).', '404-solution'), $body);
147 $body = $this->functions->str_replace('{regex_example_label}', esc_html__('Example:', '404-solution'), $body);
148 $body = $this->functions->str_replace('{regex_example_text}', esc_html__('/events/(.+) will match any URL that begins with /events/. Use $1 in the destination to insert the captured text. Site-relative paths such as /archive/$1 and full HTTP(S) URLs are supported.', '404-solution'), $body);
149 return $this->buildFieldRowHtml('is_regex_url', '&nbsp;', $body);
150 }
151
152 /**
153 * Build hidden `source_*` inputs that preserve the originating list-table view.
154 *
155 * @return string
156 */
157 public function buildSourceHiddenInputs(string $sourcePage, string $filter, string $orderby, string $order, string $paged): string {
158 $pairs = array(
159 'source_page' => $sourcePage,
160 'source_filter' => $filter,
161 'source_orderby' => $orderby,
162 'source_order' => $order,
163 'source_paged' => $paged,
164 );
165 $template = $this->readTemplate('editRedirectSourceHiddenInput.html');
166 $html = '';
167 foreach ($pairs as $name => $value) {
168 if ($value === '') {
169 continue;
170 }
171 $line = $this->functions->str_replace('{name}', esc_attr($name), $template);
172 $line = $this->functions->str_replace('{value}', esc_attr($value), $line);
173 $html .= $line;
174 }
175 return $html;
176 }
177
178 /**
179 * Build the back-to-list cancel URL with preserved filter/orderby/order params.
180 *
181 * @return string
182 */
183 public function buildCancelUrl(string $sourcePage, string $filter, string $orderby, string $order): string {
184 $url = '?page=' . ABJ404_PP;
185 $pairs = array(
186 'subpage' => $sourcePage,
187 'filter' => $filter,
188 'orderby' => $orderby,
189 'order' => $order,
190 );
191 foreach ($pairs as $name => $value) {
192 if ($value === '') {
193 continue;
194 }
195 $url .= '&' . $name . '=' . $value;
196 }
197 return $url;
198 }
199
200 /**
201 * Build the Advanced Options section HTML using the template.
202 *
203 * @param string $startDate ISO date for "Active From", or empty.
204 * @param string $endDate ISO date for "Active Until", or empty.
205 * @param string $conditionsHtml Already-rendered conditions section.
206 * @param bool $isOpen Whether the details element starts open.
207 * @return string
208 */
209 public function buildAdvancedOptionsHtml(string $startDate, string $endDate, string $conditionsHtml, bool $isOpen): string {
210 $html = $this->readTemplate('editRedirectAdvancedOptions.html');
211 $html = $this->functions->str_replace('{advanced_options_label}', esc_html__('Advanced Options', '404-solution'), $html);
212 $html = $this->functions->str_replace('{open_attr}', $isOpen ? ' open' : '', $html);
213 $html = $this->functions->str_replace('{start_date_label}', esc_html__('Active From (optional)', '404-solution'), $html);
214 $html = $this->functions->str_replace('{start_date_value}', esc_attr($startDate), $html);
215 $html = $this->functions->str_replace('{start_date_help}', esc_html__('Leave blank to activate immediately', '404-solution'), $html);
216 $html = $this->functions->str_replace('{end_date_label}', esc_html__('Active Until (optional)', '404-solution'), $html);
217 $html = $this->functions->str_replace('{end_date_value}', esc_attr($endDate), $html);
218 $html = $this->functions->str_replace('{end_date_help}', esc_html__('Leave blank to never expire', '404-solution'), $html);
219 return $this->functions->str_replace('{conditions_section}', $conditionsHtml, $html);
220 }
221
222 /**
223 * @return string
224 */
225 public function buildRequiredLabel(string $baseLabel): string {
226 $html = $this->readTemplate('editRedirectRequiredLabelSuffix.html');
227 $html = $this->functions->str_replace('{base_label}', esc_html($baseLabel), $html);
228 return $this->functions->str_replace('{required_label}', esc_html__('(Required)', '404-solution'), $html);
229 }
230
231 /**
232 * Build a single form-table row using the field-row template.
233 *
234 * @param string $fieldId Form-control id used in the label's `for` attribute.
235 * @param string $labelHtml Already-escaped label HTML.
236 * @param string $bodyHtml Already-built input/markup for the td cell.
237 * @return string
238 */
239 public function buildFieldRowHtml(string $fieldId, string $labelHtml, string $bodyHtml): string {
240 $row = $this->readTemplate('editRedirectFieldRow.html');
241 $row = $this->functions->str_replace('{field_id}', esc_attr($fieldId), $row);
242 $row = $this->functions->str_replace('{field_label}', $labelHtml, $row);
243 return $this->functions->str_replace('{field_body}', $bodyHtml, $row);
244 }
245
246 /**
247 * @return string
248 */
249 public function buildManualPickerWrapperHtml(string $hiddenClass, string $innerHtml): string {
250 $redirectToBody = $this->readTemplate('editRedirectManualPickerWrapper.html');
251 $redirectToBody = $this->functions->str_replace('{hidden_class}', $hiddenClass, $redirectToBody);
252 return $this->functions->str_replace('{inner_html}', $innerHtml, $redirectToBody);
253 }
254
255 /**
256 * @param array<string, string> $parts
257 * @return string
258 */
259 public function buildShellHtml(array $parts): string {
260 $shell = $this->readTemplate('editRedirectFormShell.html');
261 foreach ($parts as $placeholder => $value) {
262 $shell = $this->functions->str_replace($placeholder, $value, $shell);
263 }
264 return $shell;
265 }
266
267 /**
268 * @param string $name
269 * @return string
270 */
271 private function readTemplate(string $name): string {
272 return ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . '/html/' . $name);
273 }
274 }
275