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 / view / View_ListTableChrome.php

View_ListTableChrome.php in 404 Solution trunk, at includes/view/View_ListTableChrome.php

187 lines 8.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 * Admin list-table chrome shared by the Page Redirects and Captured 404 URLs
9 * admin tables. Owns the widgets that surround the data rows: subsubsub filter
10 * row, per-page selector, score-range filter, bulk-action form URL/options,
11 * empty-trash form, and the i18n strings for the pagination auto-refresh
12 * indicator. Pagination itself is rendered by ABJ_404_Solution_AdminPaginationLinks
13 * (single source of truth) and reaches the page over the same AJAX warmup channel.
14 */
15 class ABJ_404_Solution_View_ListTableChrome extends ABJ_404_Solution_ViewComponent {
16
17 /** Load a template file from includes/html/ and trim its trailing newline. */
18 private function tpl(string $name): string {
19 $raw = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . '/html/' . $name, false);
20 return rtrim((string)$raw, "\n");
21 }
22
23 /**
24 * Load a template and substitute an associative array of placeholders.
25 * @param array<string,string> $vars
26 */
27 private function fillTpl(string $name, array $vars): string {
28 return (string)$this->f->str_replace(array_keys($vars), array_values($vars), $this->tpl($name));
29 }
30
31 /**
32 * Build the rows-per-page <option> list HTML.
33 *
34 * @param int|string $currentPerPage
35 */
36 public function buildPerpageOptions($currentPerPage): string {
37 $optionTpl = $this->tpl('viewRedirectsTablePerpageOption.html');
38 $html = '';
39 foreach (array(10, 25, 50, 100, 200) as $opt) {
40 $selected = ($currentPerPage == $opt) ? ' selected' : '';
41 $html .= $this->f->str_replace(
42 array('{value}', '{selected_attr}'),
43 array((string)$opt, $selected),
44 $optionTpl
45 ) . "\n";
46 }
47 return $html;
48 }
49
50 /** Build a bulk-action button (the type that posts to the bulk form). */
51 public function buildBulkButton(string $value, string $label): string {
52 return $this->f->str_replace(
53 array('{value}', '{label}'),
54 array(esc_attr($value), $label),
55 $this->tpl('viewRedirectsTableBulkButton.html')
56 ) . "\n";
57 }
58
59 /**
60 * Build the i18n string for the pagination "Refresh available" pill
61 * data-* attr. The pill is the only background-refresh surface: the table
62 * always renders live from the denorm read, so there is no "refreshing /
63 * data refreshed" progress toast (and no started/finished strings).
64 *
65 * @return array{available:string}
66 */
67 public function paginationRefreshStrings(): array {
68 $available = __('Refresh available', '404-solution');
69 return array('available' => $available);
70 }
71
72 /** Build the Confidence-filter <option> list for the Redirects table. */
73 public function buildScoreRangeOptions(string $currentScoreRange): string {
74 $opts = array(
75 'all' => __('All', '404-solution'),
76 // allow-em-dash: pre-existing translation string with U+2265 in published .po files
77 'high' => __('High (≥80%)', '404-solution'),
78 // allow-em-dash: pre-existing translation string with U+2013 in published .po files
79 'medium' => __('Medium (50–79%)', '404-solution'),
80 'low' => __('Low (<50%)', '404-solution'),
81 // Value stays 'manual' (it is in bookmarked URLs); the LABEL says
82 // what the option actually selects. A row without a score is not
83 // necessarily manual: a captured 404 that no engine scored has none
84 // either. See RedirectRowPresenter::noScoreTitle().
85 'manual' => __('No score', '404-solution'),
86 );
87 $tpl = $this->tpl('viewRedirectsTableScoreRangeOption.html');
88 $html = '';
89 foreach ($opts as $val => $label) {
90 $html .= $this->f->str_replace(
91 array('{value}', '{selected_attr}', '{label}'),
92 array(esc_attr($val), ($currentScoreRange === $val) ? ' selected' : '', esc_html($label)),
93 $tpl
94 ) . "\n";
95 }
96 return $html;
97 }
98
99 /**
100 * Build the bulk-action <option> list for the Redirects table.
101 * @param mixed $currentFilter
102 */
103 public function buildRedirectsBulkActionOptions($currentFilter): string {
104 $tpl = $this->tpl('viewRedirectsTableBulkActionOption.html');
105 $opts = array();
106 if ($currentFilter != ABJ404_STATUS_AUTO) { $opts[] = array('editRedirect', esc_html__('Edit Redirects', '404-solution')); }
107 if ($currentFilter != ABJ404_TRASH_FILTER) { $opts[] = array('bulktrash', esc_html__('Move to Trash', '404-solution')); }
108 if ($currentFilter == ABJ404_TRASH_FILTER) {
109 $opts[] = array('bulk_trash_restore', esc_html__('Restore Redirects', '404-solution'));
110 $opts[] = array('bulk_trash_delete_permanently', esc_html__('Delete Permanently', '404-solution'));
111 }
112 $html = '';
113 foreach ($opts as $o) {
114 $html .= $this->f->str_replace(array('{value}', '{label}'), $o, $tpl) . "\n";
115 }
116 return $html;
117 }
118
119 /** Build the standalone Empty-Trash form shown below the redirects table when viewing the Trash filter. */
120 public function buildEmptyTrashForm(string $sub): string {
121 $eturl = wp_nonce_url("?page=" . ABJ404_PP . "&filter=" . ABJ404_TRASH_FILTER . "&subpage=" . $sub, "abj404_bulkProcess");
122 return $this->fillTpl('viewRedirectsTableEmptyTrashForm.html', array(
123 '{action_url}' => esc_url($eturl),
124 '{confirm_js}' => esc_js(__('Are you sure you want to permanently delete all items in the trash?', '404-solution')),
125 '{label}' => esc_html__('Empty Trash', '404-solution'),
126 ));
127 }
128
129 /**
130 * Build the native-WordPress subsubsub filter row for a list-table page.
131 *
132 * Counts are emitted as a placeholder character; the real numbers are
133 * populated by the pagination AJAX response (see view_updater_pagination.js).
134 *
135 * @param string $sub Subpage key (abj404_redirects, abj404_captured).
136 * @param array<int, array{0:int|string, 1:string}> $items One [filterValue, label] pair per link.
137 * @param array<string, mixed> $tableOptions Current table options (for active-link detection).
138 */
139 public function buildSubsubsubFilters(string $sub, array $items, array $tableOptions): string {
140 $currentFilter = isset($tableOptions['filter']) ? $tableOptions['filter'] : 0;
141 $itemTpl = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/listTableSubsubsubItem.html");
142 $itemsHtml = '';
143 $lastIndex = count($items) - 1;
144 foreach ($items as $i => $pair) {
145 list($filter, $label) = $pair;
146 $url = "?page=" . ABJ404_PP . "&subpage=" . $sub;
147 if ($filter != 0) {
148 $url .= "&filter=" . $filter;
149 }
150 $isCurrent = ($currentFilter == $filter);
151 $classAttr = $isCurrent ? ' class="current"' : '';
152 $separator = ($i < $lastIndex) ? ' |' : '';
153
154 $row = $itemTpl;
155 $row = str_replace('{url}', esc_url($url), $row);
156 $row = str_replace('{classAttr}', $classAttr, $row);
157 $row = str_replace('{filter}', esc_attr((string)$filter), $row);
158 $row = str_replace('{label}', esc_html($label), $row);
159 $row = str_replace('{count}', '&hellip;', $row);
160 $row = str_replace('{separator}', $separator, $row);
161 $itemsHtml .= $row;
162 }
163
164 $outer = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/listTableSubsubsub.html");
165 return str_replace('{items}', $itemsHtml, $outer);
166 }
167
168 /**
169 * @param array<string, mixed> $tableOptions
170 */
171 public function getBulkOperationsFormURL(string $sub, array $tableOptions): string {
172 $url = "?page=" . ABJ404_PP . "&subpage=" . $sub;
173 $filter = array_key_exists('filter', $tableOptions) && is_scalar($tableOptions['filter']) ? $tableOptions['filter'] : 0;
174 if ($filter != 0) {
175 $url .= "&filter=" . $filter;
176 }
177 $orderby = array_key_exists('orderby', $tableOptions) && is_string($tableOptions['orderby']) ? $tableOptions['orderby'] : 'url';
178 $order = array_key_exists('order', $tableOptions) && is_string($tableOptions['order']) ? $tableOptions['order'] : 'ASC';
179 if (!($orderby == "url" && $order == "ASC")) {
180 $url .= "&orderby=" . sanitize_text_field($orderby) . "&order=" . sanitize_text_field($order);
181 }
182 $url = wp_nonce_url($url, 'abj404_bulkProcess');
183 return $url;
184 }
185
186 }
187