PluginProbe
WPSSO Core – Complete Schema Markup and Meta Tags / 22.7.0
WPSSO Core – Complete Schema Markup and Meta Tags v22.7.0
22.7.0 22.6.1 22.6.0 22.5.3 22.5.2 22.5.1 22.4.0 22.3.0 22.2.1 22.2.0 22.1.3 22.1.2 22.1.1 22.1.0 22.0.0 21.13.3 21.13.2 trunk 21.13.1
wpsso / lib / term.php

term.php in WPSSO Core – Complete Schema Markup and Meta Tags 22.7.0, at lib/term.php

997 lines 27.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * License: GPLv3
4 * License URI: https://www.gnu.org/licenses/gpl.txt
5 * Copyright 2012-2026 Jean-Sebastien Morisset (https://wpsso.com/)
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9
10 die( 'These aren\'t the droids you\'re looking for.' );
11 }
12
13 if ( ! defined( 'WPSSO_PLUGINDIR' ) ) {
14
15 die( 'Do. Or do not. There is no try.' );
16 }
17
18 if ( ! class_exists( 'WpssoAbstractWpMeta' ) ) {
19
20 require_once WPSSO_PLUGINDIR . 'lib/abstract/wp-meta.php';
21 }
22
23 if ( ! class_exists( 'WpssoTerm' ) ) {
24
25 class WpssoTerm extends WpssoAbstractWpMeta {
26
27 private $query_term_id = 0;
28 private $query_tax_slug = '';
29
30 public function __construct( &$plugin ) {
31
32 $this->p =& $plugin;
33
34 if ( $this->p->debug->enabled ) {
35
36 $this->p->debug->mark();
37 }
38
39 /*
40 * This hook is fired once WordPress, plugins, and the theme are fully loaded and instantiated.
41 */
42 add_action( 'wp_loaded', array( $this, 'add_wp_callbacks' ) );
43 }
44
45 /*
46 * Add WordPress action and filter callbacks.
47 */
48 public function add_wp_callbacks() {
49
50 if ( $this->p->debug->enabled ) {
51
52 $this->p->debug->mark();
53 }
54
55 /*
56 * Since WPSSO Core v17.0.0.
57 *
58 * Register our term meta.
59 */
60 $this->register_meta( $object_type = 'term', WPSSO_META_NAME );
61
62 $is_admin = is_admin(); // Only check once.
63
64 if ( $is_admin ) {
65
66 /*
67 * Hook a minimum number of admin actions to maximize performance. The taxonomy and tag_ID
68 * arguments are always present when we're editing a category and/or tag page, so return
69 * immediately if they're not present.
70 */
71 if ( ( $this->query_tax_slug = SucomUtil::get_request_value( 'taxonomy' ) ) === '' ) { // Uses sanitize_text_field.
72
73 if ( $this->p->debug->enabled ) {
74
75 $this->p->debug->log( 'exiting early: no taxonomy query argument' );
76 }
77
78 return;
79 }
80
81 if ( $this->p->debug->enabled ) {
82
83 $this->p->debug->log( 'query tax slug = ' . $this->query_tax_slug );
84 }
85
86 /*
87 * Add edit table columns.
88 */
89 if ( $this->p->debug->enabled ) {
90
91 $this->p->debug->log( 'adding column filters for taxonomy ' . $this->query_tax_slug );
92 }
93
94 add_filter( 'manage_edit-' . $this->query_tax_slug . '_columns', array( $this, 'add_term_column_headings' ), WPSSO_ADD_COLUMN_PRIORITY, 1 );
95 add_filter( 'manage_edit-' . $this->query_tax_slug . '_sortable_columns', array( $this, 'add_sortable_columns' ), 10, 1 );
96 add_filter( 'manage_' . $this->query_tax_slug . '_custom_column', array( $this, 'get_column_content' ), 10, 3 );
97
98 /*
99 * The 'parse_query' action is hooked once in the WpssoPost class to set the column orderby for
100 * post, term, and user edit tables.
101 *
102 * This comment is here as a reminder - do not uncomment the following 'parse_query' action hook.
103 *
104 * add_action( 'parse_query', array( $this, 'set_column_orderby' ), 10, 1 );
105 */
106
107 /*
108 * Maybe create or update the term column content.
109 */
110 add_filter( 'get_term_metadata', array( $this, 'check_sortable_meta' ), 1000, 4 );
111
112 if ( ( $this->query_term_id = SucomUtil::get_request_value( 'tag_ID' ) ) === '' ) { // Uses sanitize_text_field.
113
114 return;
115 }
116
117 if ( $this->p->debug->enabled ) {
118
119 $this->p->debug->log( 'query term_id = ' . $this->query_term_id );
120 }
121
122 /*
123 * Available taxonomy and term actions:
124 *
125 * do_action( "create_$taxonomy", $term_id, $tt_id );
126 * do_action( "created_$taxonomy", $term_id, $tt_id );
127 * do_action( "edited_$taxonomy", $term_id, $tt_id );
128 * do_action( "delete_$taxonomy", $term_id, $tt_id, $deleted_term );
129 *
130 * do_action( "create_term", $term_id, $tt_id, $taxonomy );
131 * do_action( "created_term", $term_id, $tt_id, $taxonomy );
132 * do_action( "edited_term", $term_id, $tt_id, $taxonomy );
133 * do_action( 'delete_term', $term_id, $tt_id, $taxonomy, $deleted_term );
134 */
135 if ( ! empty( $_GET ) ) { // Skip some action hooks if no query argument(s).
136
137 /*
138 * load_meta_page() priorities: 100 post, 200 user, 300 term
139 *
140 * Sets the parent::$head_tags and parent::$head_info class properties.
141 */
142 add_action( 'current_screen', array( $this, 'load_meta_page' ), 300, 1 );
143
144 add_action( $this->query_tax_slug . '_pre_edit_form', array( $this, 'add_meta_boxes' ), 10, 2 );
145 add_action( $this->query_tax_slug . '_edit_form', array( $this, 'show_metaboxes' ), -100, 2 );
146 }
147
148 add_action( 'created_' . $this->query_tax_slug, array( $this, 'save_options' ), WPSSO_META_SAVE_PRIORITY, 2 );
149 add_action( 'created_' . $this->query_tax_slug, array( $this, 'clear_cache' ), WPSSO_META_CLEAR_PRIORITY, 2 );
150 add_action( 'created_' . $this->query_tax_slug, array( $this, 'refresh_cache' ), WPSSO_META_REFRESH_PRIORITY, 2 );
151
152 add_action( 'edited_' . $this->query_tax_slug, array( $this, 'save_options' ), WPSSO_META_SAVE_PRIORITY, 2 );
153 add_action( 'edited_' . $this->query_tax_slug, array( $this, 'clear_cache' ), WPSSO_META_CLEAR_PRIORITY, 2 );
154 add_action( 'edited_' . $this->query_tax_slug, array( $this, 'refresh_cache' ), WPSSO_META_REFRESH_PRIORITY, 2 );
155
156 add_action( 'delete_' . $this->query_tax_slug, array( $this, 'delete_options' ), WPSSO_META_SAVE_PRIORITY, 2 );
157 add_action( 'delete_' . $this->query_tax_slug, array( $this, 'clear_cache' ), WPSSO_META_CLEAR_PRIORITY, 2 );
158 }
159 }
160
161 /*
162 * Get the $mod object for a term id.
163 */
164 public function get_mod( $term_id, $tax_slug = '' ) {
165
166 if ( $this->p->debug->enabled ) {
167
168 $this->p->debug->mark_caller();
169
170 $this->p->debug->log_args( array(
171 'term_id' => $term_id,
172 'tax_slug' => $tax_slug,
173 ) );
174 }
175
176 static $local_fifo = array();
177
178 /*
179 * Maybe return the array from the local cache.
180 *
181 * Term IDs in older WordPress versions are not unique, so use the term ID and the taxonomy slug as a cache index.
182 */
183 if ( isset( $local_fifo[ $term_id ][ $tax_slug ] ) ) {
184
185 if ( ! $this->md_cache_disabled ) {
186
187 if ( $this->p->debug->enabled ) {
188
189 $this->p->debug->log( 'exiting early: term id ' . $term_id . ' mod array from local cache' );
190 }
191
192 return $local_fifo[ $term_id ][ $tax_slug ];
193
194 } else unset( $local_fifo[ $term_id ][ $tax_slug ] );
195 }
196
197 /*
198 * Maybe limit the number of array elements.
199 */
200 $local_fifo = SucomUtil::array_slice_fifo( $local_fifo, WPSSO_CACHE_ARRAY_FIFO_MAX );
201
202 $mod = self::get_mod_defaults();
203
204 /*
205 * Common elements.
206 */
207 $mod[ 'id' ] = is_numeric( $term_id ) ? (int) $term_id : 0; // Cast as integer.
208 $mod[ 'name' ] = 'term';
209 $mod[ 'name_transl' ] = _x( 'term', 'module name', 'wpsso' );
210 $mod[ 'obj' ] =& $this;
211
212 /*
213 * WpssoTerm elements.
214 */
215 $mod[ 'is_term' ] = true;
216 $mod[ 'is_archive' ] = true; // Required for WpssoUtil->get_url_paged().
217
218 if ( $mod[ 'id' ] ) { // Just in case.
219
220 $mod[ 'wp_obj' ] = SucomUtilWP::get_term_object( $mod[ 'id' ], (string) $tax_slug );
221
222 if ( $mod[ 'wp_obj' ] instanceof WP_Term ) { // Just in case.
223
224 $mod[ 'term_tax_id' ] = (int) $mod[ 'wp_obj' ]->term_taxonomy_id;
225 $mod[ 'tax_slug' ] = (string) $mod[ 'wp_obj' ]->taxonomy;
226
227 if ( $mod[ 'tax_slug' ] ) { // Just in case.
228
229 $tax_obj = get_taxonomy( $mod[ 'tax_slug' ] );
230
231 if ( $tax_obj instanceof WP_Taxonomy ) { // Just in case.
232
233 if ( isset( $tax_obj->labels->name ) ) {
234
235 $mod[ 'tax_label_plural' ] = $tax_obj->labels->name;
236 }
237
238 if ( isset( $tax_obj->labels->singular_name ) ) {
239
240 $mod[ 'tax_label_single' ] = $tax_obj->labels->singular_name;
241 }
242
243 if ( isset( $tax_obj->public ) ) {
244
245 $mod[ 'is_public' ] = $tax_obj->public ? true : false;
246 }
247 }
248 }
249
250 } else $mod[ 'wp_obj' ] = false;
251 }
252
253 /*
254 * Filter the term mod array.
255 */
256 $mod = apply_filters( 'wpsso_get_term_mod', $mod, $term_id, $tax_slug );
257
258 if ( $this->p->debug->enabled ) {
259
260 $this->p->debug->log_arr( 'mod', $mod );
261 }
262
263 /*
264 * Maybe save the array to the local cache.
265 */
266 if ( ! $this->md_cache_disabled ) {
267
268 if ( ! isset( $local_fifo[ $term_id ] ) ) {
269
270 $local_fifo[ $term_id ] = array();
271 }
272
273 $local_fifo[ $term_id ][ $tax_slug ] = $mod;
274
275 if ( $this->p->debug->enabled ) {
276
277 $this->p->debug->log_size( 'local_fifo', $local_fifo );
278 }
279 }
280
281 return $mod;
282 }
283
284 public function get_mod_wp_object( array $mod ) {
285
286 if ( $mod[ 'wp_obj' ] instanceof WP_Term ) {
287
288 return $mod[ 'wp_obj' ];
289 }
290
291 return SucomUtilWP::get_term_object( $mod[ 'id' ], $mod[ 'tax_slug' ] );
292 }
293
294 /*
295 * Option handling methods:
296 *
297 * get_defaults()
298 * get_options()
299 * save_options()
300 * delete_options()
301 */
302 public function get_options( $term_id, $md_key = false, $filter_opts = true, $merge_defs = false ) {
303
304 if ( $this->p->debug->enabled ) {
305
306 $this->p->debug->mark_caller();
307
308 $this->p->debug->log_args( array(
309 'term_id' => $term_id,
310 'md_key' => $md_key,
311 'filter_opts' => $filter_opts,
312 'merge_defs' => $merge_defs, // Fallback to value in meta defaults.
313 ) );
314 }
315
316 static $local_fifo = array();
317
318 /*
319 * Use $term_id and $filter_opts to create the cache ID string, but do not add $merge_defs.
320 */
321 $cache_id = SucomUtil::get_assoc_salt( array( 'id' => $term_id, 'filter' => $filter_opts ) );
322
323 /*
324 * Maybe initialize a new local cache element. Use isset() instead of empty() to allow for an empty array.
325 */
326 if ( ! isset( $local_fifo[ $cache_id ] ) ) {
327
328 /*
329 * Maybe limit the number of array elements.
330 */
331 $local_fifo = SucomUtil::array_slice_fifo( $local_fifo, WPSSO_CACHE_ARRAY_FIFO_MAX );
332
333 $local_fifo[ $cache_id ] = null; // Create an element to reference.
334 }
335
336 $md_opts =& $local_fifo[ $cache_id ]; // Reference the local cache element.
337
338 if ( null === $md_opts ) { // Maybe read metadata into a new local cache element.
339
340 if ( $this->p->debug->enabled ) {
341
342 $this->p->debug->log( 'getting metadata for term id ' . $term_id );
343 }
344
345 $md_opts = self::get_meta( $term_id, WPSSO_META_NAME, true );
346
347 if ( ! is_array( $md_opts ) ) {
348
349 $md_opts = array(); // WPSSO_META_NAME not found.
350 }
351
352 unset( $md_opts[ 'opt_filtered' ] ); // Just in case.
353
354 /*
355 * Check if options need to be upgraded and saved.
356 */
357 if ( $this->p->opt->is_upgrade_required( $md_opts ) ) {
358
359 $md_opts = $this->upgrade_options( $md_opts, $term_id );
360
361 self::update_meta( $term_id, WPSSO_META_NAME, $md_opts );
362 }
363 }
364
365 if ( $filter_opts ) {
366
367 if ( ! empty( $md_opts[ 'opt_filtered' ] ) ) { // Set before calling filters to prevent recursion.
368
369 if ( $this->p->debug->enabled ) {
370
371 $this->p->debug->log( 'skipping filters: options already filtered' );
372 }
373
374 } else {
375
376 if ( $this->p->debug->enabled ) {
377
378 $this->p->debug->log( 'setting opt_filtered to 1' );
379 }
380
381 $md_opts[ 'opt_filtered' ] = 1; // Set before calling filters to prevent recursion.
382
383 if ( $this->p->debug->enabled ) {
384
385 $this->p->debug->log( 'required call to WpssoTerm->get_mod() for term ID ' . $term_id );
386 }
387
388 $mod = $this->get_mod( $term_id );
389
390 /*
391 * Overwrite parent options with those of the child, allowing only undefined child options
392 * to be inherited from the parent.
393 */
394 if ( $this->p->debug->enabled ) {
395
396 $this->p->debug->log( 'inheriting parent metadata options for term id ' . $term_id );
397 }
398
399 $parent_opts = $this->get_inherited_md_opts( $mod );
400
401 if ( ! empty( $parent_opts ) ) {
402
403 $md_opts = array_merge( $parent_opts, $md_opts );
404 }
405
406 $filter_name = 'wpsso_get_md_options';
407
408 if ( $this->p->debug->enabled ) {
409
410 $this->p->debug->log( 'applying filters "' . $filter_name . '"' );
411 }
412
413 $md_opts = apply_filters( 'wpsso_get_md_options', $md_opts, $mod );
414
415 $filter_name = 'wpsso_get_' . $mod[ 'name' ] . '_options';
416
417 if ( $this->p->debug->enabled ) {
418
419 $this->p->debug->log( 'applying filters "' . $filter_name . '"' );
420 }
421
422 $md_opts = apply_filters( $filter_name, $md_opts, $term_id, $mod );
423
424 $filter_name = 'wpsso_sanitize_md_options';
425
426 if ( $this->p->debug->enabled ) {
427
428 $this->p->debug->log( 'applying filters "' . $filter_name . '"' );
429 }
430
431 $md_opts = apply_filters( $filter_name, $md_opts, $mod );
432 }
433 }
434
435 /*
436 * Maybe save the array to the local cache.
437 */
438 if ( $this->md_cache_disabled ) {
439
440 $deref_md_opts = $local_fifo[ $cache_id ]; // Dereference.
441
442 unset( $local_fifo, $md_opts );
443
444 return $this->return_options( $term_id, $deref_md_opts, $md_key, $merge_defs );
445 }
446
447 return $this->return_options( $term_id, $md_opts, $md_key, $merge_defs );
448 }
449
450 /*
451 * Use $term_tax_id = false to extend WpssoAbstractWpMeta->save_options().
452 */
453 public function save_options( $term_id, $term_tax_id = false ) {
454
455 if ( $this->p->debug->enabled ) {
456
457 $this->p->debug->log_args( array(
458 'term_id' => $term_id,
459 'term_tax_id' => $term_tax_id,
460 ) );
461 }
462
463 if ( empty( $term_id ) ) { // Just in case.
464
465 if ( $this->p->debug->enabled ) {
466
467 $this->p->debug->log( 'exiting early: term id is empty' );
468 }
469
470 return;
471
472 } elseif ( ! $this->verify_submit_nonce() ) {
473
474 if ( $this->p->debug->enabled ) {
475
476 $this->p->debug->log( 'exiting early: verify_submit_nonce failed' );
477 }
478
479 return;
480
481 /*
482 * Check user capability for the term id.
483 */
484 } elseif ( ! $this->user_can_edit( $term_id, $term_tax_id ) ) {
485
486 if ( $this->p->debug->enabled ) {
487
488 $user_id = get_current_user_id();
489
490 $this->p->debug->log( 'exiting early: user id ' . $user_id . ' cannot edit term id ' . $term_id );
491 }
492
493 return;
494 }
495
496 $this->md_cache_disable(); // Disable the local cache.
497
498 $term_obj = get_term_by( 'term_taxonomy_id', $term_tax_id, $tax_slug = '' );
499
500 $mod = isset( $term_obj->taxonomy ) ? $this->get_mod( $term_id, $term_obj->taxonomy ) : $mod = $this->get_mod( $term_id );
501
502 $md_opts = $this->get_submit_opts( $mod ); // Merge previous + submitted options and then sanitize.
503
504 $this->md_cache_enable(); // Re-enable the local cache.
505
506 if ( false === $md_opts ) {
507
508 if ( $this->p->debug->enabled ) {
509
510 $this->p->debug->log( 'exiting early: returned submit options is false' );
511 }
512
513 return;
514 }
515
516 $md_opts = apply_filters( 'wpsso_save_md_options', $md_opts, $mod );
517
518 $md_opts = apply_filters( 'wpsso_save_' . $mod[ 'name' ] . '_options', $md_opts, $term_id, $mod );
519
520 return self::update_meta( $term_id, WPSSO_META_NAME, $md_opts );
521 }
522
523 /*
524 * Use $term_tax_id = false to extend WpssoAbstractWpMeta->delete_options().
525 */
526 public function delete_options( $term_id, $term_tax_id = false ) {
527
528 return self::delete_meta( $term_id, WPSSO_META_NAME );
529 }
530
531 /*
532 * Get all publicly accessible term ids.
533 */
534 public static function get_public_ids( array $terms_args = array() ) {
535
536 $wpsso =& Wpsso::get_instance();
537
538 if ( $wpsso->debug->enabled ) {
539
540 $wpsso->debug->mark();
541 }
542
543 $mtime_start = microtime( $get_float = true );
544
545 $tax_names = empty( $terms_args[ 'taxonomy' ] ) ? SucomUtilWP::get_taxonomies( $output = 'names' ) : array( $terms_args[ 'taxonomy' ] );
546
547 $terms_args = array_merge( $terms_args, array( 'fields' => 'ids' ) );
548
549 $public_ids = array();
550
551 foreach ( $tax_names as $name ) {
552
553 /*
554 * See https://developer.wordpress.org/reference/classes/wp_term_query/__construct/.
555 */
556 $query_args = array_merge( $terms_args, array( 'taxonomy' => $name ) );
557
558 $terms_ids = get_terms( $query_args );
559
560 if ( is_array( $terms_ids ) ) {
561
562 foreach ( $terms_ids as $term_id ) {
563
564 if ( is_numeric( $term_id ) ) {
565
566 $public_ids[ $term_id ] = $term_id; // Prevents duplicates.
567 }
568 }
569 }
570 }
571
572 unset( $query_args, $terms_ids );
573
574 /*
575 * Sort public term IDs with the newest term ID first.
576 *
577 * Note that rsort() assigns new keys to elements in the array.
578 *
579 * See https://www.php.net/manual/en/function.rsort.php.
580 */
581 rsort( $public_ids );
582
583 $mtime_total = microtime( $get_float = true ) - $mtime_start;
584
585 if ( $wpsso->debug->enabled ) {
586
587 $wpsso->debug->log( count( $public_ids ) . ' term IDs returned in ' . sprintf( '%0.3f secs', $mtime_total ) );
588 }
589
590 return apply_filters( 'wpsso_term_public_ids', $public_ids, $terms_args );
591 }
592
593 /*
594 * Get the posts for a term.
595 *
596 * Returns an array of post ids for a given $mod object, including posts in child terms as well.
597 *
598 * The 'posts_per_page' value should be set for an archive page before calling this method.
599 *
600 * See WpssoAbstractWpMeta->get_posts_mods().
601 */
602 public function get_posts_ids( array $mod ) {
603
604 if ( $this->p->debug->enabled ) {
605
606 $this->p->debug->mark();
607 }
608
609 if ( empty( $mod[ 'is_term' ] ) ) {
610
611 if ( $this->p->debug->enabled ) {
612
613 $this->p->debug->log( 'exiting early: ' . $mod[ 'name' ] . ' ID ' . $mod[ 'id' ] . ' is not a term' );
614 }
615
616 return array();
617 }
618
619 $posts_args = array_merge( array(
620 'has_password' => false,
621 'order' => 'DESC', // Newest first.
622 'orderby' => 'date',
623 'post_status' => 'publish', // Only 'publish' (not 'auto-draft', 'draft', 'future', 'inherit', 'pending', 'private', or 'trash').
624 'post_type' => 'any', // Return posts, pages, or any custom post type.
625 'tax_query' => array(
626 array(
627 'taxonomy' => $mod[ 'tax_slug' ],
628 'field' => 'term_id',
629 'terms' => $mod[ 'id' ],
630 'include_children' => true
631 )
632 ),
633 ), $mod[ 'posts_args' ], array( 'fields' => 'ids' ) ); // Return an array of post ids.
634
635 if ( $this->p->debug->enabled ) {
636
637 $this->p->debug->log( 'getting posts for ' . $mod[ 'name' ] . ' ID ' . $mod[ 'id' ] . ' in taxonomy ' . $mod[ 'tax_slug' ] );
638
639 $this->p->debug->log_arr( 'posts_args', $posts_args );
640 }
641
642 $mtime_start = microtime( $get_float = true );
643
644 $posts_ids = SucomUtilWP::get_posts( $posts_args ); // Alternative to get_posts() that does not exclude sticky posts.
645
646 $mtime_total = microtime( $get_float = true ) - $mtime_start;
647
648 if ( $this->p->debug->enabled ) {
649
650 $this->p->debug->log( count( $posts_ids ) . ' post IDs returned in ' . sprintf( '%0.3f secs', $mtime_total ) );
651 }
652
653 return $posts_ids;
654 }
655
656 public function add_term_column_headings( $columns ) {
657
658 if ( $this->p->debug->enabled ) {
659
660 $this->p->debug->mark();
661 }
662
663 return $this->add_column_headings( $columns, $opt_suffix = 'tax_' . $this->query_tax_slug );
664 }
665
666 public function get_update_meta_cache( $term_id ) {
667
668 return SucomUtilWP::get_update_meta_cache( $term_id, $meta_type = 'term' );
669 }
670
671 /*
672 * Hooked into the current_screen action.
673 *
674 * Sets the parent::$head_tags and parent::$head_info class properties.
675 */
676 public function load_meta_page( $screen = false ) {
677
678 if ( $this->p->debug->enabled ) {
679
680 $this->p->debug->mark();
681 }
682
683 /*
684 * All meta modules set this property, so use it to optimize code execution.
685 */
686 if ( false !== parent::$head_tags || ! isset( $screen->id ) ) {
687
688 return;
689 }
690
691 if ( $this->p->debug->enabled ) {
692
693 $this->p->debug->log( 'screen id = ' . $screen->id );
694 $this->p->debug->log( 'query tax slug = ' . $this->query_tax_slug );
695 }
696
697 switch ( $screen->id ) {
698
699 case 'edit-' . $this->query_tax_slug:
700
701 $mod = $this->get_mod( $this->query_term_id, $this->query_tax_slug );
702
703 break;
704
705 default:
706
707 if ( $this->p->debug->enabled ) {
708
709 $this->p->debug->log( 'exiting early: not a recognized term page' );
710 }
711
712 return;
713 }
714
715 /*
716 * Define parent::$head_tags and signal to other 'current_screen' actions that this is a term page.
717 */
718 parent::$head_tags = array(); // Used by WpssoAbstractWpMeta->is_meta_page().
719
720 if ( $this->p->debug->enabled ) {
721
722 $this->p->debug->log( 'term id = ' . $this->query_term_id );
723 $this->p->debug->log( 'home url = ' . get_option( 'home' ) );
724 $this->p->debug->log( 'locale current = ' . SucomUtilWP::get_locale() );
725 $this->p->debug->log( 'locale default = ' . SucomUtilWP::get_locale( 'default' ) );
726 $this->p->debug->log( 'locale mod = ' . SucomUtilWP::get_locale( $mod ) );
727 $this->p->debug->log( SucomUtil::get_array_pretty( $mod ) );
728 }
729
730 if ( $this->query_term_id && ! empty( $this->p->options[ 'plugin_add_to_tax_' . $this->query_tax_slug ] ) ) {
731
732 do_action( 'wpsso_admin_term_head', $mod, $screen->id );
733
734 list(
735 parent::$head_tags, // Used by WpssoAbstractWpMeta->is_meta_page().
736 parent::$head_info // Used by WpssoAbstractWpMeta->check_head_info().
737 ) = $this->p->util->cache->refresh_mod_head_meta( $mod );
738
739 /*
740 * Check for missing open graph image and description values.
741 */
742 if ( $mod[ 'id' ] && $mod[ 'is_public' ] ) { // Since WPSSO Core v7.0.0.
743
744 $this->check_head_info( $mod );
745 }
746 }
747
748 $action_query = 'wpsso-action';
749
750 if ( ! empty( $_GET[ $action_query ] ) ) {
751
752 $action_name = SucomUtil::sanitize_hookname( $_GET[ $action_query ] );
753
754 if ( $this->p->debug->enabled ) {
755
756 $this->p->debug->log( 'found action query: ' . $action_name );
757 }
758
759 if ( empty( $_GET[ WPSSO_NONCE_NAME ] ) ) { // WPSSO_NONCE_NAME is an md5() string
760
761 if ( $this->p->debug->enabled ) {
762
763 $this->p->debug->log( 'nonce token query field missing' );
764 }
765
766 } elseif ( ! wp_verify_nonce( $_GET[ WPSSO_NONCE_NAME ], WpssoAdmin::get_nonce_action() ) ) {
767
768 $this->p->notice->err( sprintf( __( 'Nonce token validation failed for %1$s action "%2$s".', 'wpsso' ), 'term', $action_name ) );
769
770 } else {
771
772 $_SERVER[ 'REQUEST_URI' ] = remove_query_arg( array( $action_query, WPSSO_NONCE_NAME ) );
773
774 switch ( $action_name ) {
775
776 default:
777
778 do_action( 'wpsso_load_meta_page_term_' . $action_name, $this->query_term_id );
779
780 break;
781 }
782 }
783 }
784 }
785
786 /*
787 * Use $tax_slug = false to extend WpssoAbstractWpMeta->add_meta_boxes().
788 */
789 public function add_meta_boxes( $term_obj, $tax_slug = false ) {
790
791 if ( $this->p->debug->enabled ) {
792
793 $this->p->debug->mark();
794 }
795
796 $term_id = empty( $term_obj->term_id ) ? 0 : $term_obj->term_id;
797 $tax_obj = get_taxonomy( $tax_slug );
798
799 if ( empty( $this->p->options[ 'plugin_add_to_tax_' . $tax_slug ] ) ) {
800
801 if ( $this->p->debug->enabled ) {
802
803 $this->p->debug->log( 'exiting early: cannot add metabox to taxonomy "' . $tax_slug . '"' );
804 }
805
806 return;
807 }
808
809 $capability = $tax_obj->cap->edit_terms;
810
811 if ( ! current_user_can( $capability, $term_id ) ) {
812
813 if ( $this->p->debug->enabled ) {
814
815 $this->p->debug->log( 'exiting early: cannot ' . $capability . ' for term id ' . $term_id );
816 }
817
818 return;
819 }
820
821 $metabox_id = $this->p->cf[ 'meta' ][ 'id' ];
822 $metabox_title = _x( $this->p->cf[ 'meta' ][ 'title' ], 'metabox title', 'wpsso' );
823 $metabox_screen = 'wpsso-term';
824 $metabox_context = 'normal';
825 $metabox_prio = 'default';
826 $callback_args = array( // Second argument passed to the callback.
827 'metabox_id' => $metabox_id,
828 'metabox_title' => $metabox_title,
829 '__block_editor_compatible_meta_box' => true,
830 );
831
832 if ( $this->p->debug->enabled ) {
833
834 $this->p->debug->log( 'adding metabox id wpsso_' . $metabox_id . ' for screen ' . $metabox_screen );
835 }
836
837 add_meta_box( 'wpsso_' . $metabox_id, $metabox_title, array( $this, 'show_metabox_' . $metabox_id ),
838 $metabox_screen, $metabox_context, $metabox_prio, $callback_args );
839 }
840
841 public function show_metaboxes( $term_obj, $tax_slug ) {
842
843 $term_id = empty( $term_obj->term_id ) ? 0 : $term_obj->term_id;
844 $tax_obj = get_taxonomy( $tax_slug );
845 $capability = $tax_obj->cap->edit_terms;
846
847 if ( empty( $this->p->options[ 'plugin_add_to_tax_' . $tax_slug ] ) ) {
848
849 return;
850
851 } elseif ( ! current_user_can( $capability, $term_id ) ) {
852
853 return;
854 }
855
856 $metabox_screen = 'wpsso-term';
857 $metabox_context = 'normal';
858
859 /*
860 * Keep the original 800px width for the form table and allow metaboxes to take the screen width.
861 */
862 echo '<style type="text/css">';
863 echo 'div.wrap form#edittag { max-width:none; }';
864 echo 'div.wrap form#edittag table.form-table { max-width:800px; }';
865 echo '</style>' . "\n";
866 echo '<div class="metabox-holder">' . "\n";
867
868 do_meta_boxes( $metabox_screen, $metabox_context, $term_obj );
869
870 echo "\n" . '</div><!-- .metabox-holder -->' . "\n";
871 }
872
873 public function ajax_get_metabox_sso() {
874
875 die( -1 ); // Nothing to do.
876 }
877
878 /*
879 * Hooked to these actions:
880 *
881 * do_action( "created_$taxonomy", $term_id, $tt_id );
882 * do_action( "edited_$taxonomy", $term_id, $tt_id );
883 * do_action( "delete_$taxonomy", $term_id, $tt_id, $deleted_term );
884 *
885 * Also called by WpssoPost::clear_cache() to clear the post term cache.
886 *
887 * Use $term_tax_id = false to extend WpssoAbstractWpMeta->clear_cache().
888 */
889 public function clear_cache( $term_id, $term_tax_id = false ) {
890
891 if ( $this->p->debug->enabled ) {
892
893 $this->p->debug->log_args( array(
894 'term_id' => $term_id,
895 'term_tax_id' => $term_tax_id,
896 ) );
897 }
898
899 static $do_once = array(); // Just in case - prevent recursion.
900
901 if ( isset( $do_once[ $term_id ][ $term_tax_id ] ) ) return; // Stop here.
902
903 $do_once[ $term_id ][ $term_tax_id ] = true;
904
905 if ( empty( $term_id ) ) return; // Just in case.
906
907 $term_obj = get_term_by( 'term_taxonomy_id', $term_tax_id, $tax_slug = '' );
908
909 $mod = isset( $term_obj->taxonomy ) ? $this->get_mod( $term_id, $term_obj->taxonomy ) : $this->get_mod( $term_id );
910
911 unset( $term_obj );
912
913 $this->clear_mod_cache( $mod );
914
915 do_action( 'wpsso_clear_term_cache', $term_id, $mod );
916 }
917
918 /*
919 * Refresh the cache for a single term ID.
920 *
921 * Use $term_tax_id = false to extend WpssoAbstractWpMeta->refresh_cache().
922 */
923 public function refresh_cache( $term_id, $term_tax_id = false ) {
924
925 static $do_once = array(); // Just in case - prevent recursion.
926
927 if ( isset( $do_once[ $term_id ][ $term_tax_id ] ) ) return; // Stop here.
928
929 $do_once[ $term_id ][ $term_tax_id ] = true;
930
931 if ( empty( $term_id ) ) return; // Just in case.
932
933 $term_obj = get_term_by( 'term_taxonomy_id', $term_tax_id, $tax_slug = '' );
934
935 $mod = isset( $term_obj->taxonomy ) ? $this->get_mod( $term_id, $term_obj->taxonomy ) : $this->get_mod( $term_id );
936
937 unset( $term_obj );
938
939 $this->p->util->cache->refresh_mod_head_meta( $mod );
940
941 do_action( 'wpsso_refresh_term_cache', $term_id, $mod );
942 }
943
944 /*
945 * Check user capability for the term id.
946 *
947 * Use $term_tax_id = false to extend WpssoAbstractWpMeta->user_can_edit().
948 */
949 public function user_can_edit( $term_id, $term_tax_id = false ) {
950
951 $term_obj = get_term_by( 'term_taxonomy_id', $term_tax_id, $tax_slug = '' );
952 $tax_obj = get_taxonomy( $term_obj->taxonomy );
953 $capability = $tax_obj->cap->edit_terms;
954
955 if ( ! current_user_can( $capability, $term_id ) ) {
956
957 if ( $this->p->debug->enabled ) {
958
959 $this->p->debug->log( 'exiting early: cannot ' . $capability . ' for term id ' . $term_id );
960 }
961
962 /*
963 * Add notice only if the admin notices have not already been shown.
964 */
965 if ( $this->p->notice->is_admin_pre_notices() ) {
966
967 $this->p->notice->err( sprintf( __( 'Insufficient privileges to edit term ID %1$s.', 'wpsso' ), $term_id ) );
968 }
969
970 return false;
971 }
972
973 return true;
974 }
975
976 /*
977 * If $meta_key is en empty string, retrieves all metadata for the specified object ID.
978 *
979 * See https://developer.wordpress.org/reference/functions/get_metadata/.
980 */
981 public static function get_meta( $term_id, $meta_key = '', $single = false ) {
982
983 return get_metadata( 'term', $term_id, $meta_key, $single );
984 }
985
986 public static function update_meta( $term_id, $meta_key, $value ) {
987
988 return update_metadata( 'term', $term_id, $meta_key, $value );
989 }
990
991 public static function delete_meta( $term_id, $meta_key ) {
992
993 return delete_metadata( 'term', $term_id, $meta_key );
994 }
995 }
996 }
997