PluginProbe
Tag Groups is the Advanced Way to Display Your Taxonomy Terms / trunk
Tag Groups is the Advanced Way to Display Your Taxonomy Terms vtrunk
2.2.2 2.2.1 2.2.0 trunk 1.40.0 1.40.2 1.41.0 1.42.1 1.43.0 1.43.1 1.43.10 1.43.10.1 1.43.2 1.43.3 1.43.4 1.43.5 1.43.6 1.43.7 1.43.9 1.44.0 1.44.1 1.44.3 1.44.3.1 2.0.0 2.0.1 All 36 releases
tag-groups / include / admin / class.group_admin.php

class.group_admin.php in Tag Groups is the Advanced Way to Display Your Taxonomy Terms trunk, at include/admin/class.group_admin.php

411 lines 19.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * @package Tag Groups
5 * @author Christoph Amthor
6 * @copyright 2021 Christoph Amthor (@ Chatty Mango, chattymango.com)
7 * @license GPL-3.0+
8 */
9
10 if (!class_exists('TagGroups_Group_Admin')) {
11 // phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace, Squiz.Classes.ValidClassName.NotCamelCaps -- Legacy class structure
12 class TagGroups_Group_Admin
13 {
14 /**
15 * Outputs a table on a submenu page where you can add, delete, change tag groups, their labels and their order.
16 *
17 * @param void
18 * @return void
19 */
20 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps, Squiz.Scope.MethodScope.Missing -- Legacy method naming
21 static function render_group_administration()
22 {
23 global $tag_group_groups ;
24 $tag_group_show_filter_tags = TagGroups_Options::get_option('tag_group_show_filter_tags', 0);
25 //tags
26 $tag_group_show_filter = TagGroups_Options::get_option('tag_group_show_filter', 0);
27 // posts
28 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Read-only admin page display
29 $this_post_type = preg_replace('/tag-groups_(.+)/', '$1', sanitize_title(wp_unslash($_GET['page'])));
30 $post_type_taxonomies = get_object_taxonomies($this_post_type);
31 $first_enabled_taxonomy = '';
32 $taxonomies = TagGroups_Taxonomy::get_enabled_taxonomies($post_type_taxonomies);
33 /**
34 * Check if the tag filter is activated
35 */
36 if ($tag_group_show_filter_tags) {
37 // get first of taxonomies that are associated with that $post_type
38 /**
39 * Show the link to the taxonomy filter only if there is only one taxonomy for this post type (otherwise ambiguous where to link)
40 */
41 if (!empty($taxonomies) && count($taxonomies) == 1) {
42 $first_enabled_taxonomy = TagGroups_Utilities::get_first_element($taxonomies);
43 }
44 }
45 /**
46 * In case we use the WPML plugin: consider the language
47 */
48 $current_language = TagGroups_WPML::get_current_language();
49
50 if ($current_language) {
51 if ('all' == $current_language) {
52 $wpml_piece = '&lang=' . (string) apply_filters('wpml_default_language', null);
53 } else {
54 $wpml_piece = '&lang=' . $current_language;
55 }
56 } else {
57 $wpml_piece = '';
58 }
59
60
61 if ($this_post_type == 'post') {
62 $post_type_piece = '';
63 } else {
64 $post_type_piece = '&post_type=' . $this_post_type;
65 }
66
67 $items_per_page = self::get_items_per_page();
68 $protocol = ( isset($_SERVER['HTTPS']) ? 'https://' : 'http://' );
69 $post_url = ( empty($tag_group_show_filter) ? '' : admin_url('edit.php?post_type=' . $this_post_type . $wpml_piece, $protocol) );
70 $tags_url = ( empty($first_enabled_taxonomy) ? '' : admin_url('edit-tags.php?taxonomy=' . $first_enabled_taxonomy . $wpml_piece . $post_type_piece, $protocol) );
71 $settings_url = admin_url('admin.php?page=tag-groups-settings');
72 $admin_url = admin_url('admin-ajax.php', $protocol);
73 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin page display
74 if (isset($_GET['lang'])) {
75 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin page display
76 $admin_url = add_query_arg('lang', sanitize_key(wp_unslash($_GET['lang'])), $admin_url);
77 }
78
79 if ('all' == $current_language) {
80 $view = new TagGroups_View('partials/language_notice');
81 $view->render();
82 }
83
84 $view = new TagGroups_View('admin/tag_groups_admin');
85 if (TagGroups_Utilities::is_premium_plan() && defined('TAG_GROUPS_PREMIUM_PLUGIN_ABSOLUTE_PATH')) {
86 $premium_view_path = TAG_GROUPS_PREMIUM_PLUGIN_ABSOLUTE_PATH . '/include/helpers/class.premium_view.php';
87 if (!class_exists('TagGroups_Premium_View') && file_exists($premium_view_path)) {
88 require_once $premium_view_path;
89 }
90
91 if (class_exists('TagGroups_Premium_View')) {
92 $view = new TagGroups_Premium_View('admin/tag_groups_admin');
93 }
94 }
95 $view->set(array(
96 'tag_group_show_filter' => $tag_group_show_filter || $tag_group_show_filter_tags,
97 'show_parents' => TagGroups_Utilities::is_premium_plan(),
98 'post_url' => $post_url,
99 'tags_url' => $tags_url,
100 'items_per_page' => $items_per_page,
101 'settings_url' => $settings_url,
102 'admin_url' => $admin_url,
103 'taxonomies' => $taxonomies,
104 ));
105 $view->render();
106 }
107
108 /**
109 * AJAX handler to manage Tag Groups
110 */
111 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps, Squiz.Scope.MethodScope.Missing -- Legacy method naming
112 static function ajax_manage_groups()
113 {
114 global $tag_group_groups ;
115 /**
116 * default: We allow duplicate group names if we have parents
117 */
118 $allow_duplicate_group_name = TagGroups_Utilities::is_premium_plan() && !empty($tag_group_groups->get_parents());
119 /**
120 * Here we can programmatically allow duplicate group names
121 *
122 * @param bool
123 * @return bool
124 */
125 $allow_duplicate_group_names = apply_filters('tag_groups_allow_duplicate_group_names', $allow_duplicate_group_name);
126
127 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verified below
128 if (isset($_REQUEST['tag_groups_task'])) {
129 $task = sanitize_key(wp_unslash($_REQUEST['tag_groups_task']));
130 } else {
131 $task = 'refresh';
132 }
133
134
135 if (isset($_REQUEST['tag_groups_taxonomy'])) {
136 if (is_array($_REQUEST['tag_groups_taxonomy'])) {
137 $taxonomy = array_map('sanitize_title', wp_unslash($_REQUEST['tag_groups_taxonomy']));
138 } else {
139 $taxonomy = sanitize_title(wp_unslash($_REQUEST['tag_groups_taxonomy']));
140 }
141 } else {
142 $taxonomy = array( 'post_tag' );
143 }
144
145 $message = '';
146 $tag_group_role_edit_groups = 'edit_pages';
147
148 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verification
149 if (!(current_user_can($tag_group_role_edit_groups) && wp_verify_nonce(wp_unslash($_REQUEST['nonce'] ?? ''), 'tg_groups_management'))) {
150 self::ajax_send_error('Security check', $task);
151 exit;
152 }
153
154
155 if (isset($_REQUEST['tag_groups_position'])) {
156 $position = (int) $_REQUEST['tag_groups_position'];
157 } else {
158 $position = 0;
159 }
160
161
162 if (isset($_REQUEST['tag_groups_new_position'])) {
163 $new_position = (int) $_REQUEST['tag_groups_new_position'];
164 } else {
165 $new_position = 0;
166 }
167
168
169 if (isset($_REQUEST['tag_groups_filter_label'])) {
170 $tag_groups_filter_label = sanitize_text_field(wp_unslash($_REQUEST['tag_groups_filter_label']));
171 } else {
172 $tag_groups_filter_label = '';
173 }
174
175 if (isset($_REQUEST['tag_groups_start_position'])) {
176 $start_position = (int) $_REQUEST['tag_groups_start_position'];
177 }
178 if (empty($start_position) || $start_position < 1) {
179 $start_position = 1;
180 }
181 $tg_group = new TagGroups_Group();
182 switch ($task) {
183 case "sortup":
184 $tag_group_groups->sort('up')->save();
185 $message = __('The groups have been sorted alphabetically.', 'tag-groups');
186 break;
187 case "sortdown":
188 $tag_group_groups->sort('down')->save();
189 $message = __('The groups have been sorted alphabetically.', 'tag-groups');
190 break;
191 case "new":
192 if (isset($_REQUEST['tag_groups_label'])) {
193 $label = sanitize_text_field(wp_unslash($_REQUEST['tag_groups_label']));
194 }
195
196 if (empty($label)) {
197 $message = __('The label cannot be empty.', 'tag-groups');
198 self::ajax_send_error($message, $task);
199 } elseif (!$allow_duplicate_group_names && $tg_group->find_by_label($label)) {
200 /* translators: %s is the tag group label */
201 $message = sprintf(__('A tag group with the label \'%s\' already exists, or the label has not changed. Please choose another one or go back.', 'tag-groups'), $label);
202 self::ajax_send_error($message, $task);
203 } else {
204 $tg_group->create($label, $position + 1);
205 /* translators: %s is the tag group label */
206 $message = sprintf(__('A new tag group with the label \'%s\' has been created!', 'tag-groups'), $label);
207 }
208
209 break;
210 case "new-parent":
211 if (TagGroups_Utilities::is_premium_plan()) {
212 if (isset($_REQUEST['tag_groups_label'])) {
213 $label = sanitize_text_field(wp_unslash($_REQUEST['tag_groups_label']));
214 }
215
216 if (empty($label)) {
217 $message = __('The label cannot be empty.', 'tag-groups');
218 self::ajax_send_error($message, $task);
219 } elseif ($tg_group->find_by_label($label)) {
220 /* translators: %s is the tag group label */
221 $message = sprintf(__('A tag group with the label \'%s\' already exists, or the label has not changed. Please choose another one or go back.', 'tag-groups'), $label);
222 self::ajax_send_error($message, $task);
223 } else {
224 $tg_group->create($label, $position, true);
225 /* translators: %s is the tag group label */
226 $message = sprintf(__('A new parent group with the label \'%s\' has been created at the bottom of the table!', 'tag-groups'), $label);
227 }
228 }
229
230 break;
231 case "update":
232 if (isset($_REQUEST['tag_groups_label'])) {
233 $label = sanitize_text_field(wp_unslash($_REQUEST['tag_groups_label']));
234 }
235
236 if (empty($label)) {
237 $message = __('The label cannot be empty.', 'tag-groups');
238 self::ajax_send_error($message, $task);
239 } elseif (!$allow_duplicate_group_names && $tg_group->find_by_label($label)) {
240 if (!empty($position) && $position == $tg_group->get_position()) {
241 // Label hast not changed, just ignore
242 } else {
243 /* translators: %s is the tag group label */
244 $message = sprintf(__('A tag group with the label \'%s\' already exists.', 'tag-groups'), $label);
245 self::ajax_send_error($message, $task);
246 }
247 } else {
248 if (!empty($position)) {
249 if ($tg_group->find_by_position($position)) {
250 $tg_group->set_label($label)->save();
251 }
252 } else {
253 self::ajax_send_error('error: invalid position: ' . $position, $task);
254 }
255
256 /* translators: %s is the tag group label */
257 $message = sprintf(__('The tag group with the label \'%s\' has been saved!', 'tag-groups'), $label);
258 }
259
260 break;
261 case "delete":
262 if (!empty($position) && $tg_group->find_by_position($position)) {
263 /* translators: %1$s is the group ID, %2$s is the group label */
264 $message = sprintf(__('A tag group with the id %1$s and the label \'%2$s\' has been deleted.', 'tag-groups'), $tg_group->get_group_id(), $tg_group->get_label());
265 $tg_group->delete();
266 } else {
267 self::ajax_send_error('error: invalid position: ' . $position, $task);
268 }
269
270 break;
271 case "up":
272 if ($position > 1 && $tg_group->find_by_position($position)) {
273 if ($tg_group->move_to_position($position - 1) !== false) {
274 $tg_group->save();
275 }
276 }
277 break;
278 case "down":
279 if ($position < $tag_group_groups->get_max_position() && $tg_group->find_by_position($position)) {
280 if ($tg_group->move_to_position($position + 1) !== false) {
281 $tg_group->save();
282 }
283 }
284 break;
285 case "move":
286 if ($new_position < 1) {
287 $new_position = 1;
288 }
289 if ($new_position > $tag_group_groups->get_max_position()) {
290 $new_position = $tag_group_groups->get_max_position();
291 }
292 if ($position == $new_position) {
293 break;
294 }
295 if ($tg_group->find_by_position($position)) {
296 if ($tg_group->move_to_position($new_position) !== false) {
297 $tg_group->save();
298 }
299 }
300 break;
301 case "refresh":
302 // do nothing here
303 break;
304 case 'test':
305 wp_send_json(array(
306 'data' => 'success',
307 'supplemental' => array(
308 'message' => 'This is the regular Ajax response.',
309 ),
310 ));
311 break;
312 }
313 $tag_group_groups_filtered = clone $tag_group_groups;
314 $number_of_filtered_term_groups = $tag_group_groups_filtered->filter_by_substring($tag_groups_filter_label)->get_number_of_term_groups();
315 if ($start_position > $number_of_filtered_term_groups) {
316 $start_position = $number_of_filtered_term_groups;
317 }
318 $items_per_page = self::get_items_per_page();
319 // calculate start and end positions
320 $start_position = (int) floor(($start_position - 1) / $items_per_page) * $items_per_page + 1;
321
322 if ($start_position + $items_per_page - 1 < $number_of_filtered_term_groups) {
323 $end_position = $start_position + $items_per_page - 1;
324 } else {
325 $end_position = $number_of_filtered_term_groups;
326 }
327
328 wp_send_json(array(
329 'data' => 'success',
330 'supplemental' => array(
331 'task' => $task,
332 'message' => $message,
333 'nonce' => wp_create_nonce('tg_groups_management'),
334 'start_position' => $start_position,
335 'groups' => self::assemble_group_table(
336 $start_position,
337 $end_position,
338 $taxonomy,
339 $tag_group_groups_filtered
340 ),
341 'max_number' => $number_of_filtered_term_groups,
342 'parents_available' => TagGroups_Utilities::is_premium_plan() && !empty($tag_group_groups->get_parents()),
343 'only_parents' => TagGroups_Utilities::is_premium_plan() && $tag_group_groups->is_only_parents(),
344 'is_filtered' => !empty($tag_groups_filter_label),
345 ),
346 ));
347 }
348
349 /**
350 * Rerturns an error message to AJAX
351 */
352 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps, Squiz.Scope.MethodScope.Missing -- Legacy method naming
353 static function ajax_send_error($message = 'error', $task = 'unknown')
354 {
355 wp_send_json(array(
356 'data' => 'error',
357 'supplemental' => array(
358 'message' => $message,
359 'nonce' => wp_create_nonce('tg_groups_management'),
360 'task' => sanitize_key($task),
361 ),
362 ));
363 }
364
365 /**
366 * Assemble the content of the table of tag groups for AJAX
367 */
368 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps, Squiz.Scope.MethodScope.Missing -- Legacy method naming
369 static function assemble_group_table(
370 $start_position,
371 $end_position,
372 $taxonomy,
373 $tag_group_groups_filtered
374 ) {
375 $term_groups = array_values($tag_group_groups_filtered->get_all_with_position_as_key(true));
376 $output = array();
377 if (count($term_groups) <= 1) {
378 return $output;
379 }
380 for ($i = $start_position; $i <= $end_position; $i++) {
381 if (empty($term_groups[$i])) {
382 continue;
383 }
384 $tg_group = new TagGroups_Group($term_groups[$i]['term_group']);
385 array_push($output, array(
386 'id' => $term_groups[$i]['term_group'],
387 'label' => $term_groups[$i]['label'],
388 'position' => $term_groups[$i]['position'],
389 'amount' => $tg_group->get_number_of_terms($taxonomy),
390 'is_parent' => $tg_group->is_parent,
391 'parent_label' => $tg_group->get_parent_label(),
392 ));
393 }
394 return $output;
395 }
396
397 /**
398 * Returns the items per page on the tag groups screen
399 *
400 * @param void
401 * @return int
402 */
403 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- Legacy method naming
404 public static function get_items_per_page()
405 {
406 $items_per_page = TAG_GROUPS_ITEMS_PER_PAGE;
407 return $items_per_page;
408 }
409 }
410 }
411