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
← All changes | lib/user.php +2136 -0 22.5.222.7.0 View file →
@@ -1,0 +1,2136 @@
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( 'WpssoUser' ) ) {
24 +
25 + class WpssoUser extends WpssoAbstractWpMeta {
26 +
27 + private static $cache_user_prefs = array(); // Used by get_pref() and save_pref().
28 +
29 + public function __construct( &$plugin ) {
30 +
31 + $this->p =& $plugin;
32 +
33 + if ( $this->p->debug->enabled ) {
34 +
35 + $this->p->debug->mark();
36 + }
37 +
38 + /*
39 + * This hook is fired once WordPress, plugins, and the theme are fully loaded and instantiated.
40 + */
41 + add_action( 'wp_loaded', array( $this, 'add_wp_callbacks' ) );
42 + }
43 +
44 + /*
45 + * Add WordPress action and filter callbacks.
46 + */
47 + public function add_wp_callbacks() {
48 +
49 + if ( $this->p->debug->enabled ) {
50 +
51 + $this->p->debug->mark();
52 + }
53 +
54 + /*
55 + * Since WPSSO Core v17.0.0.
56 + *
57 + * Register our user meta.
58 + */
59 + $this->register_meta( $object_type = 'user', WPSSO_META_NAME );
60 +
61 + $is_admin = is_admin(); // Only check once.
62 +
63 + $cm_fb_name = $this->p->options[ 'plugin_cm_fb_name' ];
64 +
65 + if ( ! SucomUtilWP::role_exists( 'person' ) ) {
66 +
67 + $role_label_transl = _x( 'Person', 'user role', 'wpsso' );
68 +
69 + add_role( 'person', $role_label_transl, array() );
70 + }
71 +
72 + if ( ! empty( $this->p->options[ 'plugin_new_user_is_person' ] ) ) {
73 +
74 + if ( is_multisite() ) {
75 +
76 + add_action( 'wpmu_new_user', array( __CLASS__, 'add_role_by_id' ), 20, 1 );
77 +
78 + } else add_action( 'user_register', array( __CLASS__, 'add_role_by_id' ), 20, 1 );
79 + }
80 +
81 + add_filter( 'user_contactmethods', array( $this, 'add_contact_methods' ), 20, 2 );
82 + add_filter( 'user_' . $cm_fb_name . '_label', array( $this, 'modify_fb_contact_label' ), 20, 1 );
83 +
84 + add_action( 'wpsso_add_person_role', array( $this, 'add_person_role' ), 10, 1 ); // For single scheduled task.
85 + add_action( 'wpsso_remove_person_role', array( $this, 'remove_person_role' ), 10, 1 ); // For single scheduled task.
86 +
87 + /*
88 + * Hook a minimum number of admin actions to maximize performance. The user_id argument is
89 + * always present when we're editing a user, but missing when viewing our own profile page.
90 + */
91 + if ( $is_admin ) {
92 +
93 + if ( ! empty( $_GET ) ) { // Skip some action hooks if no query argument(s).
94 +
95 + /*
96 + * load_meta_page() priorities: 100 post, 200 user, 300 term.
97 + *
98 + * Sets the parent::$head_tags and parent::$head_info class properties.
99 + */
100 + add_action( 'current_screen', array( $this, 'load_meta_page' ), 200, 1 );
101 +
102 + /*
103 + * Fires after the 'About the User' settings table on the 'Edit User' screen.
104 + */
105 + add_action( 'edit_user_profile', array( $this, 'add_meta_boxes' ), 10, 1 );
106 + }
107 +
108 + add_action( 'admin_bar_menu', array( $this, 'add_admin_bar_menu_view_profile' ), WPSSO_TB_VIEW_PROFILE_MENU_ORDER, 1 );
109 +
110 + add_filter( 'views_users', array( $this, 'add_person_view' ) );
111 +
112 + /*
113 + * Add edit table columns.
114 + */
115 + if ( $this->p->debug->enabled ) {
116 +
117 + $this->p->debug->log( 'adding column filters for users' );
118 + }
119 +
120 + add_filter( 'manage_users_columns', array( $this, 'add_user_column_headings' ), WPSSO_ADD_COLUMN_PRIORITY, 1 );
121 + add_filter( 'manage_users_sortable_columns', array( $this, 'add_sortable_columns' ), 10, 1 );
122 + add_filter( 'manage_users_custom_column', array( $this, 'get_column_content' ), 10, 3 );
123 +
124 + /*
125 + * The 'parse_query' action is hooked once in the WpssoPost class to set the column orderby for
126 + * post, term, and user edit tables.
127 + *
128 + * This comment is here as a reminder - do not uncomment the following 'parse_query' action hook.
129 + *
130 + * add_action( 'parse_query', array( $this, 'set_column_orderby' ), 10, 1 );
131 + */
132 +
133 + /*
134 + * Maybe create or update the user column content.
135 + */
136 + add_action( 'get_user_metadata', array( $this, 'check_sortable_meta' ), 1000, 4 );
137 +
138 + /*
139 + * Hooks when editing a user.
140 + */
141 + add_action( 'edit_user_profile', array( $this, 'show_metaboxes' ), 20, 1 );
142 +
143 + add_action( 'edit_user_profile_update', array( $this, 'save_about_section' ), -3000, 1 );
144 + add_action( 'edit_user_profile_update', array( $this, 'sanitize_submit_cm' ), -2000, 1 );
145 + add_action( 'edit_user_profile_update', array( $this, 'save_options' ), WPSSO_META_SAVE_PRIORITY, 1 );
146 + add_action( 'edit_user_profile_update', array( $this, 'clear_cache' ), WPSSO_META_CLEAR_PRIORITY, 1 );
147 + add_action( 'edit_user_profile_update', array( $this, 'refresh_cache' ), WPSSO_META_REFRESH_PRIORITY, 1 );
148 +
149 + /*
150 + * Hooks when editing personal profile.
151 + */
152 + add_action( 'personal_options_update', array( $this, 'save_about_section' ), -3000, 1 );
153 + add_action( 'personal_options_update', array( $this, 'sanitize_submit_cm' ), -2000, 1 );
154 + add_action( 'personal_options_update', array( $this, 'save_options' ), WPSSO_META_SAVE_PRIORITY, 1 );
155 + add_action( 'personal_options_update', array( $this, 'clear_cache' ), WPSSO_META_CLEAR_PRIORITY, 1 );
156 + add_action( 'personal_options_update', array( $this, 'refresh_cache' ), WPSSO_META_REFRESH_PRIORITY, 1 );
157 +
158 + /*
159 + * Use the 'show_password_fields' filter as an action to get more information about the user.
160 + */
161 + add_filter( 'show_password_fields', array( $this, 'pre_password_fields' ), -1000, 2 );
162 + }
163 + }
164 +
165 + /*
166 + * Get the $mod object for a user id.
167 + */
168 + public function get_mod( $user_id ) {
169 +
170 + if ( $this->p->debug->enabled ) {
171 +
172 + $this->p->debug->mark_caller();
173 +
174 + $this->p->debug->log_args( array(
175 + 'user_id' => $user_id,
176 + ) );
177 + }
178 +
179 + static $local_fifo = array();
180 +
181 + /*
182 + * Maybe return the array from the local cache.
183 + */
184 + if ( isset( $local_fifo[ $user_id ] ) ) {
185 +
186 + if ( ! $this->md_cache_disabled ) {
187 +
188 + if ( $this->p->debug->enabled ) {
189 +
190 + $this->p->debug->log( 'exiting early: user id ' . $user_id . ' mod array from local cache' );
191 + }
192 +
193 + return $local_fifo[ $user_id ];
194 +
195 + } else unset( $local_fifo[ $user_id ] );
196 + }
197 +
198 + /*
199 + * Maybe limit the number of array elements.
200 + */
201 + $local_fifo = SucomUtil::array_slice_fifo( $local_fifo, WPSSO_CACHE_ARRAY_FIFO_MAX );
202 +
203 + $mod = self::get_mod_defaults();
204 +
205 + /*
206 + * Common elements.
207 + */
208 + $mod[ 'id' ] = is_numeric( $user_id ) ? (int) $user_id : 0; // Cast as integer.
209 + $mod[ 'name' ] = 'user';
210 + $mod[ 'name_transl' ] = _x( 'user', 'module name', 'wpsso' );
211 + $mod[ 'obj' ] =& $this;
212 +
213 + /*
214 + * WpssoUser elements.
215 + */
216 + $mod[ 'is_user' ] = true;
217 + $mod[ 'is_archive' ] = true; // Required for WpssoUtil->get_url_paged().
218 +
219 + if ( $mod[ 'id' ] ) { // Just in case.
220 +
221 + $mod[ 'wp_obj' ] = SucomUtilWP::get_user_object( $mod[ 'id' ] ); // Optimize and fetch once.
222 +
223 + if ( $mod[ 'wp_obj' ] instanceof WP_User ) { // Just in case.
224 +
225 + $mod[ 'user_name' ] = (string) $mod[ 'wp_obj' ]->display_name;
226 +
227 + } else $mod[ 'wp_obj' ] = false;
228 + }
229 +
230 + /*
231 + * Filter the user mod array.
232 + */
233 + $mod = apply_filters( 'wpsso_get_user_mod', $mod, $user_id );
234 +
235 + if ( $this->p->debug->enabled ) {
236 +
237 + $this->p->debug->log_arr( 'mod', $mod );
238 + }
239 +
240 + /*
241 + * Maybe save the array to the local cache.
242 + */
243 + if ( ! $this->md_cache_disabled ) {
244 +
245 + $local_fifo[ $user_id ] = $mod;
246 +
247 + if ( $this->p->debug->enabled ) {
248 +
249 + $this->p->debug->log_size( 'local_fifo', $local_fifo );
250 + }
251 + }
252 +
253 + return $mod;
254 + }
255 +
256 + public function get_mod_wp_object( array $mod ) {
257 +
258 + if ( $mod[ 'wp_obj' ] instanceof WP_User ) {
259 +
260 + return $mod[ 'wp_obj' ];
261 + }
262 +
263 + return SucomUtilWP::get_user_object( $mod[ 'id' ] );
264 + }
265 +
266 + /*
267 + * Option handling methods:
268 + *
269 + * get_defaults()
270 + * get_options()
271 + * save_options()
272 + * delete_options()
273 + */
274 + public function get_options( $user_id, $md_key = false, $filter_opts = true, $merge_defs = false ) {
275 +
276 + if ( $this->p->debug->enabled ) {
277 +
278 + $this->p->debug->mark_caller();
279 +
280 + $this->p->debug->log_args( array(
281 + 'user_id' => $user_id,
282 + 'md_key' => $md_key,
283 + 'filter_opts' => $filter_opts,
284 + 'merge_defs' => $merge_defs, // Fallback to value in meta defaults.
285 + ) );
286 + }
287 +
288 + $user_id = false === $user_id ? get_current_user_id() : $user_id;
289 +
290 + if ( empty( $user_id ) ) {
291 +
292 + if ( false !== $md_key ) {
293 +
294 + return null;
295 + }
296 +
297 + return array();
298 + }
299 +
300 + static $local_fifo = array();
301 +
302 + /*
303 + * Use $user_id and $filter_opts to create the cache ID string, but do not add $merge_defs.
304 + */
305 + $cache_id = SucomUtil::get_assoc_salt( array( 'id' => $user_id, 'filter' => $filter_opts ) );
306 +
307 + /*
308 + * Maybe initialize a new local cache element. Use isset() instead of empty() to allow for an empty array.
309 + */
310 + if ( ! isset( $local_fifo[ $cache_id ] ) ) {
311 +
312 + /*
313 + * Maybe limit the number of array elements.
314 + */
315 + $local_fifo = SucomUtil::array_slice_fifo( $local_fifo, WPSSO_CACHE_ARRAY_FIFO_MAX );
316 +
317 + $local_fifo[ $cache_id ] = null; // Create an element to reference.
318 + }
319 +
320 + $md_opts =& $local_fifo[ $cache_id ]; // Reference the local cache element.
321 +
322 + if ( null === $md_opts ) { // Maybe read metadata into a new local cache element.
323 +
324 + if ( $this->p->debug->enabled ) {
325 +
326 + $this->p->debug->log( 'getting metadata for user id ' . $user_id );
327 + }
328 +
329 + $user_exists = SucomUtilWP::user_exists( $user_id );
330 +
331 + if ( $user_exists ) {
332 +
333 + $user_exists_id = $user_id;
334 +
335 + $md_opts = self::get_meta( $user_exists_id, WPSSO_META_NAME, $single = true );
336 +
337 + if ( ! is_array( $md_opts ) ) {
338 +
339 + $md_opts = array(); // WPSSO_META_NAME not found.
340 + }
341 +
342 + } else {
343 +
344 + $user_exists_id = 0;
345 +
346 + $md_opts = apply_filters( 'wpsso_get_other_user_meta', array(), $user_id );
347 + }
348 +
349 + unset( $md_opts[ 'opt_filtered' ] ); // Just in case.
350 +
351 + /*
352 + * Check if options need to be upgraded and saved.
353 + */
354 + if ( $this->p->opt->is_upgrade_required( $md_opts ) ) {
355 +
356 + $md_opts = $this->upgrade_options( $md_opts, $user_exists_id );
357 +
358 + if ( $user_exists ) {
359 +
360 + self::update_meta( $user_exists_id, WPSSO_META_NAME, $md_opts );
361 +
362 + } else apply_filters( 'wpsso_update_other_user_meta', $md_opts, $user_id );
363 + }
364 + }
365 +
366 + if ( $filter_opts ) {
367 +
368 + if ( ! empty( $md_opts[ 'opt_filtered' ] ) ) { // Set before calling filters to prevent recursion.
369 +
370 + if ( $this->p->debug->enabled ) {
371 +
372 + $this->p->debug->log( 'skipping filters: options already filtered' );
373 + }
374 +
375 + } else {
376 +
377 + if ( $this->p->debug->enabled ) {
378 +
379 + $this->p->debug->log( 'setting opt_filtered to 1' );
380 + }
381 +
382 + $md_opts[ 'opt_filtered' ] = 1; // Set before calling filters to prevent recursion.
383 +
384 + if ( $this->p->debug->enabled ) {
385 +
386 + $this->p->debug->log( 'required call to WpssoUser->get_mod() for user ID ' . $user_id );
387 + }
388 +
389 + $mod = $this->get_mod( $user_id );
390 +
391 + $filter_name = 'wpsso_get_md_options';
392 +
393 + if ( $this->p->debug->enabled ) {
394 +
395 + $this->p->debug->log( 'applying filters "' . $filter_name . '"' );
396 + }
397 +
398 + $md_opts = apply_filters( $filter_name, $md_opts, $mod );
399 +
400 + $filter_name = 'wpsso_get_' . $mod[ 'name' ] . '_options';
401 +
402 + if ( $this->p->debug->enabled ) {
403 +
404 + $this->p->debug->log( 'applying filters "' . $filter_name . '"' );
405 + }
406 +
407 + $md_opts = apply_filters( $filter_name, $md_opts, $user_id, $mod );
408 +
409 + $filter_name = 'wpsso_sanitize_md_options';
410 +
411 + if ( $this->p->debug->enabled ) {
412 +
413 + $this->p->debug->log( 'applying filters "' . $filter_name . '"' );
414 + }
415 +
416 + $md_opts = apply_filters( $filter_name, $md_opts, $mod );
417 +
418 + /*
419 + * Prevent users from modifying specific options.
420 + */
421 + $disable_keys = array(
422 + 'og_type',
423 + 'schema_type',
424 + 'canonical_url',
425 + 'redirect_url',
426 + );
427 +
428 + $filter_name = 'wpsso_get_user_options_keys_disabled';
429 +
430 + if ( $this->p->debug->enabled ) {
431 +
432 + $this->p->debug->log( 'applying filters "' . $filter_name . '"' );
433 + }
434 +
435 + $disable_keys = apply_filters( $filter_name, $disable_keys, $user_id, $mod );
436 +
437 + if ( ! empty( $disable_keys ) ) {
438 +
439 + foreach ( $disable_keys as $opt_key ) {
440 +
441 + $md_opts[ $opt_key . ':disabled' ] = true;
442 + }
443 + }
444 + }
445 + }
446 +
447 + /*
448 + * Maybe save the array to the local cache.
449 + */
450 + if ( $this->md_cache_disabled ) {
451 +
452 + $deref_md_opts = $local_fifo[ $cache_id ]; // Dereference.
453 +
454 + unset( $local_fifo, $md_opts );
455 +
456 + return $this->return_options( $user_id, $deref_md_opts, $md_key, $merge_defs );
457 + }
458 +
459 + return $this->return_options( $user_id, $md_opts, $md_key, $merge_defs );
460 + }
461 +
462 + /*
463 + * Use $rel = false to extend WpssoAbstractWpMeta->save_options().
464 + */
465 + public function save_options( $user_id, $rel = false ) {
466 +
467 + if ( $this->p->debug->enabled ) {
468 +
469 + $this->p->debug->log_args( array(
470 + 'user_id' => $user_id,
471 + ) );
472 + }
473 +
474 + if ( empty( $user_id ) ) { // Just in case.
475 +
476 + if ( $this->p->debug->enabled ) {
477 +
478 + $this->p->debug->log( 'exiting early: user id is empty' );
479 + }
480 +
481 + return;
482 +
483 + } elseif ( ! $this->verify_submit_nonce() ) {
484 +
485 + if ( $this->p->debug->enabled ) {
486 +
487 + $this->p->debug->log( 'exiting early: verify_submit_nonce failed' );
488 + }
489 +
490 + return;
491 +
492 + /*
493 + * Check user capability for the user id.
494 + */
495 + } elseif ( ! $this->user_can_edit( $user_id ) ) {
496 +
497 + if ( $this->p->debug->enabled ) {
498 +
499 + $user_id = get_current_user_id();
500 +
501 + $this->p->debug->log( 'exiting early: user id ' . $user_id . ' cannot edit use id ' . $user_id );
502 + }
503 +
504 + return;
505 + }
506 +
507 + $this->md_cache_disable(); // Disable the local cache.
508 +
509 + $mod = $this->get_mod( $user_id );
510 +
511 + $md_opts = $this->get_submit_opts( $mod ); // Merge previous + submitted options and then sanitize.
512 +
513 + $this->md_cache_enable(); // Re-enable the local cache.
514 +
515 + if ( false === $md_opts ) {
516 +
517 + if ( $this->p->debug->enabled ) {
518 +
519 + $this->p->debug->log( 'exiting early: returned submit options is false' );
520 + }
521 +
522 + return;
523 + }
524 +
525 + $md_opts = apply_filters( 'wpsso_save_md_options', $md_opts, $mod );
526 +
527 + $md_opts = apply_filters( 'wpsso_save_' . $mod[ 'name' ] . '_options', $md_opts, $user_id, $mod );
528 +
529 + return self::update_meta( $user_id, WPSSO_META_NAME, $md_opts );
530 + }
531 +
532 + /*
533 + * Use $rel = false to extend WpssoAbstractWpMeta->delete_options().
534 + */
535 + public function delete_options( $user_id, $rel = false ) {
536 +
537 + return self::delete_meta( $user_id, WPSSO_META_NAME );
538 + }
539 +
540 + /*
541 + * Get all publicly accessible user ids in the 'creator' array.
542 + */
543 + public static function get_public_ids( array $users_args = array() ) {
544 +
545 + $wpsso =& Wpsso::get_instance();
546 +
547 + $mtime_start = microtime( $get_float = true );
548 +
549 + $role_names = empty( $users_args[ 'role' ] ) ? $wpsso->cf[ 'wp' ][ 'roles' ][ 'creator' ] : array( $users_args[ 'role' ] );
550 +
551 + $users_args = array_merge( $users_args, array( 'fields' => 'ids' ) );
552 +
553 + $public_ids = array();
554 +
555 + foreach ( $role_names as $name ) {
556 +
557 + /*
558 + * See https://developer.wordpress.org/reference/classes/wp_user_query/__construct/.
559 + */
560 + $query_args = array_merge( $users_args, array( 'role' => $name ) );
561 +
562 + $users_ids = get_users( $query_args );
563 +
564 + if ( is_array( $users_ids ) ) {
565 +
566 + foreach ( $users_ids as $user_id ) {
567 +
568 + if ( is_numeric( $user_id ) ) {
569 +
570 + $public_ids[ $user_id ] = $user_id; // Prevents duplicates.
571 + }
572 + }
573 + }
574 + }
575 +
576 + unset( $query_args, $users_ids );
577 +
578 + /*
579 + * Sort public user IDs with the newest user ID first.
580 + *
581 + * Note that rsort() assigns new keys to elements in the array.
582 + *
583 + * See https://www.php.net/manual/en/function.rsort.php.
584 + */
585 + rsort( $public_ids );
586 +
587 + $mtime_total = microtime( $get_float = true ) - $mtime_start;
588 +
589 + if ( $wpsso->debug->enabled ) {
590 +
591 + $wpsso->debug->log( count( $public_ids ) . ' user IDs returned in ' . sprintf( '%0.3f secs', $mtime_total ) );
592 + }
593 +
594 + return apply_filters( 'wpsso_user_public_ids', $public_ids, $users_args );
595 + }
596 +
597 + /*
598 + * Get the posts for a user.
599 + *
600 + * Returns an array of post IDs for a given $mod object.
601 + *
602 + * The 'posts_per_page' value should be set for an archive page before calling this method.
603 + *
604 + * See WpssoAbstractWpMeta->get_posts_mods().
605 + */
606 + public function get_posts_ids( array $mod ) {
607 +
608 + if ( $this->p->debug->enabled ) {
609 +
610 + $this->p->debug->mark();
611 + }
612 +
613 + if ( empty( $mod[ 'is_user' ] ) ) {
614 +
615 + if ( $this->p->debug->enabled ) {
616 +
617 + $this->p->debug->log( 'exiting early: ' . $mod[ 'name' ] . ' ID ' . $mod[ 'id' ] . ' is not a user' );
618 + }
619 +
620 + return array();
621 + }
622 +
623 + $posts_args = array_merge( array(
624 + 'has_password' => false,
625 + 'order' => 'DESC', // Newest first.
626 + 'orderby' => 'date',
627 + 'post_status' => 'publish', // Only 'publish' (not 'auto-draft', 'draft', 'future', 'inherit', 'pending', 'private', or 'trash').
628 + 'post_type' => 'post', // Return only posts authored by the user.
629 + 'author' => $mod[ 'id' ],
630 + ), $mod[ 'posts_args' ], array( 'fields' => 'ids' ) ); // Return an array of post IDs.
631 +
632 + if ( $this->p->debug->enabled ) {
633 +
634 + $this->p->debug->log( 'getting posts for ' . $mod[ 'name' ] . ' ID ' . $mod[ 'id' ] );
635 +
636 + $this->p->debug->log_arr( 'posts_args', $posts_args );
637 + }
638 +
639 + $mtime_start = microtime( $get_float = true );
640 +
641 + $posts_ids = SucomUtilWP::get_posts( $posts_args ); // Alternative to get_posts() that does not exclude sticky posts.
642 +
643 + $mtime_total = microtime( $get_float = true ) - $mtime_start;
644 +
645 + if ( $this->p->debug->enabled ) {
646 +
647 + $this->p->debug->log( count( $posts_ids ) . ' post IDs returned in ' . sprintf( '%0.3f secs', $mtime_total ) );
648 + }
649 +
650 + return $posts_ids;
651 + }
652 +
653 + public function add_user_column_headings( $columns ) {
654 +
655 + if ( $this->p->debug->enabled ) {
656 +
657 + $this->p->debug->mark();
658 + }
659 +
660 + return $this->add_column_headings( $columns, $opt_suffix = 'user_page' );
661 + }
662 +
663 + public function get_update_meta_cache( $user_id ) {
664 +
665 + return SucomUtilWP::get_update_meta_cache( $user_id, $meta_type = 'user' );
666 + }
667 +
668 + /*
669 + * Hooked into the current_screen action.
670 + *
671 + * Sets the parent::$head_tags and parent::$head_info class properties.
672 + */
673 + public function load_meta_page( $screen = false ) {
674 +
675 + if ( $this->p->debug->enabled ) {
676 +
677 + $this->p->debug->mark();
678 + }
679 +
680 + /*
681 + * All meta modules set this property, so use it to optimize code execution.
682 + */
683 + if ( false !== parent::$head_tags || ! isset( $screen->id ) ) {
684 +
685 + return;
686 + }
687 +
688 + if ( $this->p->debug->enabled ) {
689 +
690 + $this->p->debug->log( 'screen id = ' . $screen->id );
691 + }
692 +
693 + switch ( $screen->id ) {
694 +
695 + case ( 0 === strpos( $screen->id, 'users_page_wpsso-add-' ) ? true : false ): // Add user page.
696 +
697 + $user_id = null;
698 +
699 + $mod = $this->get_mod( null );
700 +
701 + break;
702 +
703 + case 'profile': // User profile page.
704 + case 'user-edit': // User editing page.
705 + case ( 0 === strpos( $screen->id, 'profile_page_' ) ? true : false ): // Your profile page.
706 + case ( 0 === strpos( $screen->id, 'users_page_' . $this->p->id ) ? true : false ): // Profile SSO page.
707 +
708 + /*
709 + * Get the user id.
710 + *
711 + * Returns the current user id if the 'user_id' query argument is empty.
712 + */
713 + $user_id = SucomUtilWP::get_user_object( false, 'id' );
714 +
715 + $mod = $this->get_mod( $user_id );
716 +
717 + break;
718 +
719 + default:
720 +
721 + if ( $this->p->debug->enabled ) {
722 +
723 + $this->p->debug->log( 'exiting early: not a recognized user page' );
724 + }
725 +
726 + return;
727 + }
728 +
729 + /*
730 + * Define parent::$head_tags and signal to other 'current_screen' actions that this is a user page.
731 + */
732 + parent::$head_tags = array(); // Used by WpssoAbstractWpMeta->is_meta_page().
733 +
734 + if ( $this->p->debug->enabled ) {
735 +
736 + $this->p->debug->log( 'user id = ' . $user_id );
737 + $this->p->debug->log( 'home url = ' . get_option( 'home' ) );
738 + $this->p->debug->log( 'locale default = ' . SucomUtilWP::get_locale() );
739 + $this->p->debug->log( 'locale current = ' . SucomUtilWP::get_locale( 'current' ) );
740 + $this->p->debug->log( 'locale mod = ' . SucomUtilWP::get_locale( $mod ) );
741 + $this->p->debug->log( SucomUtil::get_array_pretty( $mod ) );
742 + }
743 +
744 + if ( $user_id && ! empty( $this->p->options[ 'plugin_add_to_user_page' ] ) ) {
745 +
746 + do_action( 'wpsso_admin_user_head', $mod, $screen->id );
747 +
748 + list(
749 + parent::$head_tags, // Used by WpssoAbstractWpMeta->is_meta_page().
750 + parent::$head_info // Used by WpssoAbstractWpMeta->check_head_info().
751 + ) = $this->p->util->cache->refresh_mod_head_meta( $mod );
752 +
753 + /*
754 + * Check for missing open graph image and description values.
755 + */
756 + if ( $mod[ 'id' ] && $mod[ 'is_public' ] ) { // Since WPSSO Core v7.0.0.
757 +
758 + $this->check_head_info( $mod );
759 + }
760 + }
761 +
762 + $action_query = 'wpsso-action';
763 +
764 + if ( ! empty( $_GET[ $action_query ] ) ) {
765 +
766 + $action_name = SucomUtil::sanitize_hookname( $_GET[ $action_query ] );
767 +
768 + if ( $this->p->debug->enabled ) {
769 +
770 + $this->p->debug->log( 'found action query: ' . $action_name );
771 +
772 + }
773 +
774 + if ( empty( $_GET[ WPSSO_NONCE_NAME ] ) ) { // WPSSO_NONCE_NAME is an md5() string
775 +
776 + if ( $this->p->debug->enabled ) {
777 +
778 + $this->p->debug->log( 'nonce token query field missing' );
779 + }
780 +
781 + } elseif ( ! wp_verify_nonce( $_GET[ WPSSO_NONCE_NAME ], WpssoAdmin::get_nonce_action() ) ) {
782 +
783 + $this->p->notice->err( sprintf( __( 'Nonce token validation failed for %1$s action "%2$s".', 'wpsso' ), 'user', $action_name ) );
784 +
785 + } else {
786 +
787 + $_SERVER[ 'REQUEST_URI' ] = remove_query_arg( array( $action_query, WPSSO_NONCE_NAME ) );
788 +
789 + switch ( $action_name ) {
790 +
791 + default:
792 +
793 + do_action( 'wpsso_load_meta_page_user_' . $action_name, $user_id, $screen->id );
794 +
795 + break;
796 + }
797 + }
798 + }
799 + }
800 +
801 + /*
802 + * Use $rel = false to extend WpssoAbstractWpMeta->add_meta_boxes().
803 + */
804 + public function add_meta_boxes( $user_obj, $rel = false ) {
805 +
806 + if ( $this->p->debug->enabled ) {
807 +
808 + $this->p->debug->mark();
809 + }
810 +
811 + $user_id = empty( $user_obj->ID ) ? 0 : $user_obj->ID;
812 +
813 + if ( empty( $this->p->options[ 'plugin_add_to_user_page' ] ) ) {
814 +
815 + if ( $this->p->debug->enabled ) {
816 +
817 + $this->p->debug->log( 'exiting early: cannot add metabox to user page' );
818 + }
819 +
820 + return;
821 + }
822 +
823 + $capability = 'edit_user';
824 +
825 + if ( ! current_user_can( $capability, $user_id ) ) {
826 +
827 + if ( $this->p->debug->enabled ) {
828 +
829 + $this->p->debug->log( 'exiting early: cannot ' . $capability . ' for user id ' . $user_id );
830 + }
831 +
832 + return;
833 + }
834 +
835 + $metabox_id = $this->p->cf[ 'meta' ][ 'id' ];
836 + $metabox_title = _x( $this->p->cf[ 'meta' ][ 'title' ], 'metabox title', 'wpsso' );
837 + $metabox_screen = 'wpsso-user';
838 + $metabox_context = 'normal';
839 + $metabox_prio = 'default';
840 + $callback_args = array( // Second argument passed to the callback.
841 + 'metabox_id' => $metabox_id,
842 + 'metabox_title' => $metabox_title,
843 + '__block_editor_compatible_meta_box' => true,
844 + );
845 +
846 + if ( $this->p->debug->enabled ) {
847 +
848 + $this->p->debug->log( 'adding metabox id wpsso_' . $metabox_id . ' for screen ' . $metabox_screen );
849 + }
850 +
851 + add_meta_box( 'wpsso_' . $metabox_id, $metabox_title, array( $this, 'show_metabox_' . $metabox_id ),
852 + $metabox_screen, $metabox_context, $metabox_prio, $callback_args );
853 + }
854 +
855 + /*
856 + * Show additional fields in the user profile About Yourself / About the user sections.
857 + *
858 + * Hooked to the 'show_password_fields' filter (not an action).
859 + */
860 + public function pre_password_fields( $show_password_fields, $user_obj ) {
861 +
862 + if ( ! isset( $user_obj->ID ) ) { // Just in case.
863 +
864 + /*
865 + * This is a filter, so return the filter value unchanged.
866 + */
867 + return $show_password_fields;
868 + }
869 +
870 + if ( ! current_user_can( 'edit_user', $user_obj->ID ) ) { // Just in case.
871 +
872 + /*
873 + * This is a filter, so return the filter value unchanged.
874 + */
875 + return $show_password_fields;
876 + }
877 +
878 + $this->show_about_section( $user_obj->ID ); // Echo the additional input fields.
879 +
880 + /*
881 + * This is a filter, so return the filter value unchanged.
882 + */
883 + return $show_password_fields;
884 + }
885 +
886 + /*
887 + * Called by the WpssoUser->pre_password_fields() and WpssoUsersAddPerson->show_post_body_settings_form() methods.
888 + */
889 + public function show_about_section( $user_id = 0 ) {
890 +
891 + foreach ( $this->p->cf[ 'opt' ][ 'user_about' ] as $about_key => $about_label ) {
892 +
893 + if ( empty( $this->p->options[ 'plugin_user_about_' . $about_key ] ) ) {
894 +
895 + continue;
896 + }
897 +
898 + echo '<tr>';
899 + echo '<th><label for="' . $about_key . '">' . esc_html( _x( $about_label, 'option label', 'wpsso' ) ) . '</label></th><td>';
900 +
901 + foreach ( $this->get_user_about_meta_keys( $about_key ) as $meta_key ) {
902 +
903 + $val = $user_id ? self::get_meta( $user_id, $meta_key, $single = true ) : '';
904 +
905 + echo '<p><input type="text" class="regular-text" name="' . $meta_key . '" id="' . $meta_key . '" value="' . esc_attr( $val ) . '"></p>';
906 + }
907 +
908 + switch ( $about_key ) {
909 +
910 + case 'honorific_prefix':
911 +
912 + echo '<p class="description">' . __( 'Examples: Dr, Mrs, Mr.', 'wpsso' ) . '</p>';
913 +
914 + break;
915 +
916 + case 'honorific_suffix':
917 +
918 + echo '<p class="description">' . __( 'Examples: CPA, Esq., M.D., P.E., PhD., PMP, RN', 'wpsso' ) . '</p>';
919 +
920 + break;
921 + }
922 +
923 + echo '</td></tr>';
924 + }
925 + }
926 +
927 + public function show_metaboxes( $user_obj ) {
928 +
929 + if ( ! isset( $user_obj->ID ) ) { // Just in case.
930 +
931 + return;
932 + }
933 +
934 + if ( empty( $this->p->options[ 'plugin_add_to_user_page' ] ) ) {
935 +
936 + return;
937 + }
938 +
939 + if ( ! current_user_can( 'edit_user', $user_obj->ID ) ) { // Just in case.
940 +
941 + return;
942 + }
943 +
944 + $metabox_screen = 'wpsso-user';
945 + $metabox_context = 'normal';
946 +
947 + echo '<div class="metabox-holder">' . "\n";
948 +
949 + do_meta_boxes( $metabox_screen, $metabox_context, $user_obj );
950 +
951 + echo "\n" . '</div><!-- .metabox-holder -->' . "\n";
952 + }
953 +
954 + public function ajax_get_metabox_sso() {
955 +
956 + die( -1 ); // Nothing to do.
957 + }
958 +
959 + public function get_form_contact_fields( $fields = array() ) {
960 +
961 + return array( 'none' => '[None]' ) + $this->add_contact_methods( array(
962 + 'author' => 'Author Archive',
963 + 'url' => 'WebSite'
964 + ) );
965 + }
966 +
967 + public function add_contact_methods( $fields = array(), $user = null ) {
968 +
969 + /*
970 + * Unset built-in contact fields and/or update their labels.
971 + */
972 + if ( ! empty( $this->p->cf[ 'wp' ][ 'cm_names' ] ) && is_array( $this->p->cf[ 'wp' ][ 'cm_names' ] ) ) {
973 +
974 + foreach ( $this->p->cf[ 'wp' ][ 'cm_names' ] as $id => $desc ) {
975 +
976 + $cm_enabled_key = 'wp_cm_' . $id . '_enabled';
977 + $cm_label_key = 'wp_cm_' . $id . '_label';
978 +
979 + if ( isset( $this->p->options[ $cm_enabled_key ] ) ) {
980 +
981 + if ( ! empty( $this->p->options[ $cm_enabled_key ] ) ) {
982 +
983 + $cm_label_value = SucomUtilOptions::get_key_value( $cm_label_key, $this->p->options );
984 +
985 + if ( ! empty( $cm_label_value ) ) { // Just in case.
986 +
987 + $fields[ $id ] = $cm_label_value;
988 + }
989 +
990 + } else {
991 +
992 + unset( $fields[ $id ] );
993 + }
994 + }
995 + }
996 + }
997 +
998 + /*
999 + * Loop through each social website option prefix.
1000 + */
1001 + foreach ( $this->p->cf[ 'opt' ][ 'cm_prefix' ] as $id => $opt_pre ) {
1002 +
1003 + $cm_enabled_key = 'plugin_cm_' . $opt_pre . '_enabled';
1004 + $cm_name_key = 'plugin_cm_' . $opt_pre . '_name';
1005 + $cm_label_key = 'plugin_cm_' . $opt_pre . '_label';
1006 +
1007 + if ( ! empty( $this->p->options[ $cm_enabled_key ] ) && ! empty( $this->p->options[ $cm_name_key ] ) ) {
1008 +
1009 + $cm_label_value = SucomUtilOptions::get_key_value( $cm_label_key, $this->p->options );
1010 +
1011 + if ( ! empty( $cm_label_value ) ) {
1012 +
1013 + $fields[ $this->p->options[ $cm_name_key ] ] = $cm_label_value;
1014 + }
1015 + }
1016 + }
1017 +
1018 + uasort( $fields, 'strnatcmp' ); // Sort associative array by value.
1019 +
1020 + return $fields;
1021 + }
1022 +
1023 + public function modify_fb_contact_label( $label ) {
1024 +
1025 + return $label . '<br/><span class="description" style="font-weight:normal;">' .
1026 + __( '(not a Facebook Pages URL)', 'wpsso' ) . '</span>';
1027 + }
1028 +
1029 + /*
1030 + * Save the additional fields for the user profile About Yourself / About the user sections.
1031 + *
1032 + * Hooked to the 'edit_user_profile_update' and 'personal_options_update' actions.
1033 + *
1034 + * Also called by the WpssoUsersAddPerson->add_person() method.
1035 + */
1036 + public function save_about_section( $user_id ) {
1037 +
1038 + static $do_once = array(); // Just in case - prevent recursion.
1039 +
1040 + if ( isset( $do_once[ $user_id ] ) ) return; // Stop here.
1041 +
1042 + $do_once[ $user_id ] = true;
1043 +
1044 + if ( ! current_user_can( 'edit_user', $user_id ) ) {
1045 +
1046 + return;
1047 + }
1048 +
1049 + foreach ( $this->p->cf[ 'opt' ][ 'user_about' ] as $about_key => $about_label ) {
1050 +
1051 + if ( empty( $this->p->options[ 'plugin_user_about_' . $about_key ] ) ) {
1052 +
1053 + continue;
1054 + }
1055 +
1056 + foreach ( $this->get_user_about_meta_keys( $about_key ) as $meta_key ) {
1057 +
1058 + /*
1059 + * Regular text input fields.
1060 + *
1061 + * See https://developer.wordpress.org/themes/theme-security/data-sanitization-escaping/.
1062 + */
1063 + if ( isset( $_POST[ $meta_key ] ) ) {
1064 +
1065 + self::update_meta( $user_id, $meta_key, sanitize_text_field( $_POST[ $meta_key ] ) );
1066 + }
1067 + }
1068 + }
1069 + }
1070 +
1071 + public function sanitize_submit_cm( $user_id ) {
1072 +
1073 + static $do_once = array(); // Just in case - prevent recursion.
1074 +
1075 + if ( isset( $do_once[ $user_id ] ) ) return; // Stop here.
1076 +
1077 + $do_once[ $user_id ] = true;
1078 +
1079 + if ( ! current_user_can( 'edit_user', $user_id ) ) {
1080 +
1081 + return;
1082 + }
1083 +
1084 + foreach ( $this->p->cf[ 'opt' ][ 'cm_prefix' ] as $id => $opt_pre ) {
1085 +
1086 + /*
1087 + * Check that the social site has a contact field.
1088 + */
1089 + if ( isset( $this->p->options[ 'plugin_cm_' . $opt_pre . '_name' ] ) ) {
1090 +
1091 + $cm_enabled_value = $this->p->options[ 'plugin_cm_' . $opt_pre . '_enabled' ];
1092 + $cm_name_value = $this->p->options[ 'plugin_cm_' . $opt_pre . '_name' ];
1093 +
1094 + /*
1095 + * Sanitize values only for those enabled contact methods.
1096 + */
1097 + if ( isset( $_POST[ $cm_name_value ] ) && ! empty( $cm_enabled_value ) && ! empty( $cm_name_value ) ) {
1098 +
1099 + $value = wp_filter_nohtml_kses( $_POST[ $cm_name_value ] );
1100 +
1101 + if ( ! empty( $value ) ) {
1102 +
1103 + switch ( $cm_name_value ) {
1104 +
1105 + case $this->p->options[ 'plugin_cm_skype_name' ]:
1106 +
1107 + /*
1108 + * No change.
1109 + */
1110 +
1111 + break;
1112 +
1113 + case $this->p->options[ 'plugin_cm_twitter_name' ]:
1114 +
1115 + $value = SucomUtil::sanitize_twitter_name( $value );
1116 +
1117 + break;
1118 +
1119 + default:
1120 +
1121 + /*
1122 + * All other contact methods are assumed to be URLs.
1123 + */
1124 +
1125 + if ( false === strpos( $value, '://' ) ) {
1126 +
1127 + $value = '';
1128 + }
1129 +
1130 + break;
1131 + }
1132 + }
1133 +
1134 + $_POST[ $cm_name_value ] = $value;
1135 + }
1136 + }
1137 + }
1138 +
1139 + return $user_id;
1140 + }
1141 +
1142 + public function get_user_sameas( $user_id ) {
1143 +
1144 + $user_sameas = array();
1145 +
1146 + $contact_methods = WpssoUser::get_user_id_contact_methods( $user_id );
1147 +
1148 + foreach ( $contact_methods as $cm_id => $cm_label ) {
1149 +
1150 + $url = $this->get_author_meta( $user_id, $cm_id );
1151 +
1152 + if ( empty( $url ) ) {
1153 +
1154 + continue;
1155 +
1156 + } elseif ( $cm_id === $this->p->options[ 'plugin_cm_twitter_name' ] ) { // Convert twitter name to url.
1157 +
1158 + $url = 'https://twitter.com/' . SucomUtil::sanitize_twitter_name( $url, $add_at = false );
1159 + }
1160 +
1161 + if ( false === filter_var( $url, FILTER_VALIDATE_URL ) ) { // Just in case.
1162 +
1163 + if ( $this->p->debug->enabled ) {
1164 +
1165 + $this->p->debug->log( 'skipping ' . $cm_id . ': url "' . $url . '" is invalid' );
1166 + }
1167 +
1168 + } else $user_sameas[] = $url;
1169 + }
1170 +
1171 + return $user_sameas;
1172 + }
1173 +
1174 + /*
1175 + * Convert user ID to user object and call wp_get_user_contact_methods().
1176 + */
1177 + public static function get_user_id_contact_methods( $user_id ) {
1178 +
1179 + $user_obj = get_user_by( 'ID', $user_id );
1180 +
1181 + return wp_get_user_contact_methods( $user_obj );
1182 + }
1183 +
1184 + /*
1185 + * Returns the user id for a comment author, post author, or user module.
1186 + */
1187 + public static function get_author_id( array $mod ) {
1188 +
1189 + $author_id = false;
1190 +
1191 + if ( $mod[ 'is_user' ] ) {
1192 +
1193 + $author_id = $mod[ 'id' ];
1194 +
1195 + } elseif ( $mod[ 'is_comment' ] ) {
1196 +
1197 + if ( $mod[ 'comment_author' ] ) {
1198 +
1199 + $author_id = $mod[ 'comment_author' ];
1200 + }
1201 +
1202 + } elseif ( $mod[ 'is_post' ] ) {
1203 +
1204 + if ( $mod[ 'post_author' ] ) {
1205 +
1206 + $author_id = $mod[ 'post_author' ];
1207 + }
1208 + }
1209 +
1210 + return $author_id;
1211 + }
1212 +
1213 + /*
1214 + * Returns the display name for a user module, comment author, or post author.
1215 + */
1216 + public function get_author_name( array $mod ) {
1217 +
1218 + $author_name = '';
1219 +
1220 + if ( $mod[ 'is_user' ] ) {
1221 +
1222 + $author_name = get_the_author_meta( 'display_name', $mod[ 'id' ] );
1223 +
1224 + } elseif ( $mod[ 'is_comment' ] ) {
1225 +
1226 + if ( $mod[ 'comment_author_name' ] ) {
1227 +
1228 + $author_id = $mod[ 'comment_author_name' ];
1229 + }
1230 +
1231 + } elseif ( $author_id = self::get_author_id( $mod ) ) {
1232 +
1233 + $author_name = get_the_author_meta( 'display_name', $author_id );
1234 + }
1235 +
1236 + return $author_name;
1237 + }
1238 +
1239 + /*
1240 + * Returns the description for a user module or post author.
1241 + */
1242 + public function get_author_description( array $mod ) {
1243 +
1244 + $author_desc = '';
1245 +
1246 + if ( $mod[ 'is_user' ] ) {
1247 +
1248 + $author_desc = get_the_author_meta( 'description', $mod[ 'id' ] );
1249 +
1250 + } elseif ( $author_id = self::get_author_id( $mod ) ) {
1251 +
1252 + $author_desc = get_the_author_meta( 'description', $author_id );
1253 + }
1254 +
1255 + return $author_desc;
1256 + }
1257 +
1258 + public function get_author_meta( $user_id, $meta_key ) {
1259 +
1260 + if ( $this->p->debug->enabled ) {
1261 +
1262 + $this->p->debug->log_args( array(
1263 + 'user_id' => $user_id,
1264 + 'meta_key' => $meta_key,
1265 + ) );
1266 + }
1267 +
1268 + static $local_fifo = array();
1269 +
1270 + if ( isset( $local_fifo[ $user_id ] ) ) {
1271 +
1272 + if ( isset( $local_fifo[ $user_id ][ $meta_key ] ) ) {
1273 +
1274 + return $local_fifo[ $user_id ][ $meta_key ];
1275 + }
1276 +
1277 + } else {
1278 +
1279 + /*
1280 + * Maybe limit the number of array elements.
1281 + */
1282 + $local_fifo = SucomUtil::array_slice_fifo( $local_fifo, WPSSO_CACHE_ARRAY_FIFO_MAX );
1283 +
1284 + $local_fifo[ $user_id ] = array();
1285 + }
1286 +
1287 + $user_exists = SucomUtilWP::user_exists( $user_id );
1288 +
1289 + $author_meta = '';
1290 +
1291 + if ( $user_exists ) {
1292 +
1293 + switch ( $meta_key ) {
1294 +
1295 + case 'none':
1296 +
1297 + break;
1298 +
1299 + case 'fullname':
1300 +
1301 + $author_meta = get_the_author_meta( 'first_name', $user_id ) . ' ' . get_the_author_meta( 'last_name', $user_id );
1302 +
1303 + break;
1304 +
1305 + case 'description':
1306 +
1307 + $author_meta = preg_replace( '/[\s\n\r]+/s', ' ', get_the_author_meta( $meta_key, $user_id ) );
1308 +
1309 + break;
1310 +
1311 + case 'awards':
1312 +
1313 + $author_meta = array();
1314 +
1315 + foreach ( $this->get_user_about_meta_keys( 'award' ) as $meta_key ) {
1316 +
1317 + $val = self::get_meta( $user_id, $meta_key, $single = true );
1318 +
1319 + if ( SucomUtil::is_valid_option_value( $val ) ) {
1320 +
1321 + $author_meta[] = $val;
1322 + }
1323 + }
1324 +
1325 + break;
1326 +
1327 + default:
1328 +
1329 + $author_meta = get_the_author_meta( $meta_key, $user_id );
1330 +
1331 + break;
1332 + }
1333 +
1334 + if ( is_string( $author_meta ) ) {
1335 +
1336 + $author_meta = trim( $author_meta ); // Just in case.
1337 + }
1338 +
1339 + } elseif ( $this->p->debug->enabled ) {
1340 +
1341 + $this->p->debug->log( 'user id ' . $user_id . ' is not a WordPress user' );
1342 + }
1343 +
1344 + $filter_name = 'wpsso_get_author_meta';
1345 +
1346 + if ( $this->p->debug->enabled ) {
1347 +
1348 + $this->p->debug->log( 'applying filters "' . $filter_name . '"' );
1349 + }
1350 +
1351 + $author_meta = apply_filters( $filter_name, $author_meta, $user_id, $meta_key, $user_exists );
1352 +
1353 + return $local_fifo[ $user_id ][ $meta_key ] = $author_meta;
1354 + }
1355 +
1356 + public function get_author_website( $user_id, $meta_key = 'url' ) {
1357 +
1358 + if ( $this->p->debug->enabled ) {
1359 +
1360 + $this->p->debug->log_args( array(
1361 + 'user_id' => $user_id,
1362 + 'meta_key' => $meta_key,
1363 + ) );
1364 + }
1365 +
1366 + static $local_fifo = array();
1367 +
1368 + if ( isset( $local_fifo[ $user_id ] ) ) {
1369 +
1370 + if ( isset( $local_fifo[ $user_id ][ $meta_key ] ) ) {
1371 +
1372 + return $local_fifo[ $user_id ][ $meta_key ];
1373 + }
1374 +
1375 + } else {
1376 +
1377 + /*
1378 + * Maybe limit the number of array elements.
1379 + */
1380 + $local_fifo = SucomUtil::array_slice_fifo( $local_fifo, WPSSO_CACHE_ARRAY_FIFO_MAX );
1381 +
1382 + $local_fifo[ $user_id ] = array();
1383 + }
1384 +
1385 + $user_exists = SucomUtilWP::user_exists( $user_id );
1386 +
1387 + $website_url = '';
1388 +
1389 + if ( $user_exists ) {
1390 +
1391 + switch ( $meta_key ) {
1392 +
1393 + case 'none':
1394 +
1395 + break;
1396 +
1397 + case 'archive':
1398 +
1399 + $website_url = get_author_posts_url( $user_id );
1400 +
1401 + break;
1402 +
1403 + case 'twitter':
1404 +
1405 + $website_url = get_the_author_meta( $meta_key, $user_id );
1406 +
1407 + if ( false === filter_var( $website_url, FILTER_VALIDATE_URL ) ) {
1408 +
1409 + $website_url = 'https://twitter.com/' . preg_replace( '/^@/', '', $website_url );
1410 + }
1411 +
1412 + break;
1413 +
1414 + case 'url':
1415 + case 'website':
1416 +
1417 + $website_url = get_the_author_meta( 'url', $user_id );
1418 +
1419 + break;
1420 +
1421 + default:
1422 +
1423 + $website_url = get_the_author_meta( $meta_key, $user_id );
1424 +
1425 + break;
1426 + }
1427 +
1428 + $website_url = trim( $website_url ); // Just in case.
1429 +
1430 + } elseif ( $this->p->debug->enabled ) {
1431 +
1432 + $this->p->debug->log( 'user id ' . $user_id . ' is not a WordPress user' );
1433 + }
1434 +
1435 + $website_url = apply_filters( 'wpsso_get_author_website', $website_url, $user_id, $meta_key, $user_exists );
1436 +
1437 + return $local_fifo[ $user_id ][ $meta_key ] = (string) $website_url;
1438 + }
1439 +
1440 + /*
1441 + * WpssoUser class specific methods.
1442 + *
1443 + * Called by WpssoOpenGraph->get_array() for a single post author and (possibly) several coauthors.
1444 + */
1445 + public function get_authors_websites( $users_ids, $meta_key = 'url' ) {
1446 +
1447 + $urls = array();
1448 +
1449 + if ( empty( $users_ids ) ) { // Just in case.
1450 +
1451 + return $urls;
1452 + }
1453 +
1454 + if ( ! is_array( $users_ids ) ) {
1455 +
1456 + $users_ids = array( $users_ids );
1457 + }
1458 +
1459 + if ( $meta_key && 'none' !== $meta_key ) { // Just in case.
1460 +
1461 + foreach ( $users_ids as $user_id ) {
1462 +
1463 + if ( empty( $user_id ) ) {
1464 +
1465 + continue;
1466 + }
1467 +
1468 + $value = $this->get_author_website( $user_id, $meta_key ); // Returns a single URL string.
1469 +
1470 + if ( ! empty( $value ) ) { // Make sure we don't add empty values.
1471 +
1472 + $urls[] = $value;
1473 + }
1474 + }
1475 + }
1476 +
1477 + return $urls;
1478 + }
1479 +
1480 + /*
1481 + * Called by the WpssoRegister::uninstall_plugin() method.
1482 + *
1483 + * Do not use Wpsso::get_instance() since the Wpsso class may not exist.
1484 + */
1485 + public static function delete_metabox_prefs( $user_id = false, $slug_prefix = 'wpsso' ) {
1486 +
1487 + $cf = WpssoConfig::get_config();
1488 +
1489 + $user_id = empty( $user_id ) ? get_current_user_id() : $user_id;
1490 +
1491 + $parent_slug = 'options-general.php';
1492 +
1493 + if ( ! empty( $cf[ '*' ][ 'lib' ][ 'settings' ] ) ) {
1494 +
1495 + foreach ( array_keys( $cf[ '*' ][ 'lib' ][ 'settings' ] ) as $lib_id ) {
1496 +
1497 + $menu_slug = $slug_prefix . '-' . $lib_id;
1498 +
1499 + self::delete_metabox_pagehook( $user_id, $menu_slug, $parent_slug );
1500 + }
1501 + }
1502 +
1503 + if ( ! empty( $cf[ '*' ][ 'lib' ][ 'submenu' ] ) ) {
1504 +
1505 + $parent_slug = $slug_prefix . '-' . key( $cf[ '*' ][ 'lib' ][ 'submenu' ] );
1506 +
1507 + foreach ( array_keys( $cf[ '*' ][ 'lib' ][ 'submenu' ] ) as $lib_id ) {
1508 +
1509 + $menu_slug = $slug_prefix . '-' . $lib_id;
1510 +
1511 + self::delete_metabox_pagehook( $user_id, $menu_slug, $parent_slug );
1512 + }
1513 + }
1514 + }
1515 +
1516 + private static function delete_metabox_pagehook( $user_id, $menu_slug, $parent_slug ) {
1517 +
1518 + $pagehook = get_plugin_page_hookname( $menu_slug, $parent_slug);
1519 +
1520 + foreach ( array( 'meta-box-order', 'metaboxhidden', 'closedpostboxes' ) as $mb_state ) {
1521 +
1522 + $meta_key = $mb_state . '_' . $pagehook;
1523 +
1524 + if ( false === $user_id ) {
1525 +
1526 + $users_args = array(
1527 + 'role' => 'contributor', // Contributors can delete_posts, edit_posts, read.
1528 + 'order' => 'DESC', // Newest user first.
1529 + 'orderby' => 'ID',
1530 + 'meta_key' => $meta_key, // The meta_key in the wp_usermeta table.
1531 + 'fields' => array( // Save memory and only return only specific fields.
1532 + 'ID',
1533 + ),
1534 + );
1535 +
1536 + foreach ( get_users( $users_args ) as $user_obj ) {
1537 +
1538 + if ( ! empty( $user_obj->ID ) ) { // Just in case.
1539 +
1540 + /*
1541 + * Deletes user option with global blog capability.
1542 + *
1543 + * User options are just like user metadata except that they have support
1544 + * for global blog options. If the 'is_global' parameter is false, which it
1545 + * is by default, it will prepend the WordPress table prefix to the option
1546 + * name.
1547 + */
1548 + delete_user_option( $user_obj->ID, $meta_key, $global = false );
1549 +
1550 + delete_user_option( $user_obj->ID, $meta_key, $global = true );
1551 + }
1552 + }
1553 +
1554 + } elseif ( is_numeric( $user_id ) ) {
1555 +
1556 + delete_user_option( $user_id, $meta_key, $global = false );
1557 +
1558 + delete_user_option( $user_id, $meta_key, $global = true );
1559 + }
1560 + }
1561 + }
1562 +
1563 + public static function is_metabox_hidden( $metabox_id, $screen_id = '', $user_id = null ) {
1564 +
1565 + $screen_id = empty( $screen_id ) ? SucomUtilWP::get_screen_id() : $screen_id;
1566 + $user_id = empty( $user_id ) ? get_current_user_id() : $user_id;
1567 + $md_key = SucomUtil::sanitize_hookname( 'metaboxhidden_' . $screen_id );
1568 + $md = get_metadata( 'user', $user_id, $md_key, $single = true );
1569 +
1570 + return is_array( $md ) && in_array( $metabox_id, $md ) ? true : false;
1571 + }
1572 +
1573 + public static function is_show_all( $user_id = false ) {
1574 +
1575 + return self::show_opts( 'all', $user_id );
1576 + }
1577 +
1578 + public static function get_show_val( $user_id = false ) {
1579 +
1580 + return self::show_opts( false, $user_id );
1581 + }
1582 +
1583 + /*
1584 + * Returns the value for show_opts, or return true/false if a value to compare is provided.
1585 + */
1586 + public static function show_opts( $compare = false, $user_id = false ) {
1587 +
1588 + $user_id = empty( $user_id ) ? get_current_user_id() : $user_id;
1589 +
1590 + $show_opts = self::get_pref( 'show_opts' );
1591 +
1592 + if ( $compare ) {
1593 +
1594 + return $compare === $show_opts ? true : false;
1595 + }
1596 +
1597 + return $show_opts;
1598 + }
1599 +
1600 + public static function get_pref( $pref_key = false, $user_id = false ) {
1601 +
1602 + $user_id = empty( $user_id ) ? get_current_user_id() : $user_id;
1603 +
1604 + if ( ! isset( self::$cache_user_prefs[ $user_id ][ 'prefs_filtered' ] ) || ! self::$cache_user_prefs[ $user_id ][ 'prefs_filtered' ] ) {
1605 +
1606 + $wpsso =& Wpsso::get_instance();
1607 +
1608 + self::$cache_user_prefs[ $user_id ] = self::get_meta( $user_id, WPSSO_PREF_NAME, $single = true );
1609 +
1610 + if ( ! is_array( self::$cache_user_prefs[ $user_id ] ) ) {
1611 +
1612 + self::$cache_user_prefs[ $user_id ] = array();
1613 + }
1614 +
1615 + self::$cache_user_prefs[ $user_id ][ 'prefs_filtered' ] = true; // Set before calling filter to prevent recursion.
1616 +
1617 + self::$cache_user_prefs[ $user_id ] = apply_filters( 'wpsso_get_user_pref', self::$cache_user_prefs[ $user_id ], $user_id );
1618 +
1619 + if ( ! isset( self::$cache_user_prefs[ $user_id ][ 'show_opts' ] ) ) {
1620 +
1621 + self::$cache_user_prefs[ $user_id ][ 'show_opts' ] = $wpsso->options[ 'plugin_show_opts' ];
1622 + }
1623 +
1624 + if ( $wpsso->debug->enabled ) {
1625 +
1626 + $wpsso->debug->log_arr( 'cache_user_prefs', self::$cache_user_prefs[ $user_id ] );
1627 + }
1628 + }
1629 +
1630 + if ( false !== $pref_key ) {
1631 +
1632 + if ( isset( self::$cache_user_prefs[ $user_id ][ $pref_key ] ) ) {
1633 +
1634 + return self::$cache_user_prefs[ $user_id ][ $pref_key ];
1635 + }
1636 +
1637 + return false;
1638 +
1639 + }
1640 +
1641 + return self::$cache_user_prefs[ $user_id ];
1642 + }
1643 +
1644 + public static function save_pref( $user_prefs, $user_id = false ) {
1645 +
1646 + $user_id = empty( $user_id ) ? get_current_user_id() : $user_id;
1647 +
1648 + if ( ! current_user_can( 'edit_user', $user_id ) ) {
1649 +
1650 + return false;
1651 + }
1652 +
1653 + if ( ! is_array( $user_prefs ) || empty( $user_prefs ) ) {
1654 +
1655 + return false;
1656 + }
1657 +
1658 + $old_prefs = self::get_pref( false, $user_id ); // get all prefs for user
1659 +
1660 + $new_prefs = array_merge( $old_prefs, $user_prefs );
1661 +
1662 + /*
1663 + * Don't bother saving unless we have to.
1664 + */
1665 + if ( $old_prefs !== $new_prefs ) {
1666 +
1667 + self::$cache_user_prefs[ $user_id ] = $new_prefs; // update the pref cache
1668 +
1669 + unset( $new_prefs[ 'prefs_filtered' ] );
1670 +
1671 + self::update_meta( $user_id, WPSSO_PREF_NAME, $new_prefs );
1672 +
1673 + return true;
1674 + }
1675 +
1676 + return false;
1677 + }
1678 +
1679 + /*
1680 + * Use $rel = false to extend WpssoAbstractWpMeta->clear_cache().
1681 + */
1682 + public function clear_cache( $user_id, $rel = false ) {
1683 +
1684 + if ( $this->p->debug->enabled ) {
1685 +
1686 + $this->p->debug->log_args( array(
1687 + 'user_id' => $user_id,
1688 + ) );
1689 + }
1690 +
1691 + static $do_once = array(); // Just in case - prevent recursion.
1692 +
1693 + if ( isset( $do_once[ $user_id ] ) ) return; // Stop here.
1694 +
1695 + $do_once[ $user_id ] = true;
1696 +
1697 + if ( empty( $user_id ) ) return; // Just in case.
1698 +
1699 + $mod = $this->get_mod( $user_id );
1700 +
1701 + $this->clear_mod_cache( $mod );
1702 +
1703 + do_action( 'wpsso_clear_user_cache', $user_id, $mod );
1704 + }
1705 +
1706 + /*
1707 + * Refresh the cache for a single user ID.
1708 + *
1709 + * Use $rel = false to extend WpssoAbstractWpMeta->refresh_cache().
1710 + */
1711 + public function refresh_cache( $user_id, $rel = false ) {
1712 +
1713 + if ( $this->p->debug->enabled ) {
1714 +
1715 + $this->p->debug->log_args( array(
1716 + 'user_id' => $user_id,
1717 + ) );
1718 + }
1719 +
1720 + static $do_once = array(); // Just in case - prevent recursion.
1721 +
1722 + if ( isset( $do_once[ $user_id ] ) ) return; // Stop here.
1723 +
1724 + $do_once[ $user_id ] = true;
1725 +
1726 + if ( empty( $user_id ) ) return; // Just in case.
1727 +
1728 + $mod = $this->get_mod( $user_id );
1729 +
1730 + $this->p->util->cache->refresh_mod_head_meta( $mod );
1731 +
1732 + do_action( 'wpsso_refresh_user_cache', $user_id, $mod );
1733 + }
1734 +
1735 + /*
1736 + * Check user capability for the user id.
1737 + *
1738 + * Use $rel = false to extend WpssoAbstractWpMeta->user_can_edit().
1739 + */
1740 + public function user_can_edit( $user_id, $rel = false ) {
1741 +
1742 + $capability = 'edit_user';
1743 +
1744 + if ( ! current_user_can( $capability, $user_id ) ) {
1745 +
1746 + if ( $this->p->debug->enabled ) {
1747 +
1748 + $this->p->debug->log( 'exiting early: cannot ' . $capability . ' for user id ' . $user_id );
1749 + }
1750 +
1751 + /*
1752 + * Add notice only if the admin notices have not already been shown.
1753 + */
1754 + if ( $this->p->notice->is_admin_pre_notices() ) {
1755 +
1756 + $this->p->notice->err( sprintf( __( 'Insufficient privileges to edit user ID %1$s.', 'wpsso' ), $user_id ) );
1757 + }
1758 +
1759 + return false;
1760 + }
1761 +
1762 + return true;
1763 + }
1764 +
1765 + /*
1766 + * Returns an array of single image associative arrays.
1767 + *
1768 + * $md_pre can be a text string or array of prefixes.
1769 + */
1770 + public function get_og_images( $num, $size_names, $user_id, $md_pre = 'og', $mt_pre = 'og' ) {
1771 +
1772 + if ( $this->p->debug->enabled ) {
1773 +
1774 + $this->p->debug->mark();
1775 + }
1776 +
1777 + $mod = $this->get_mod( $user_id );
1778 + $user_exists = SucomUtilWP::user_exists( $user_id ); // Check if this is a valid WordPress user.
1779 + $filter_name = 'wpsso_get_other_user_images';
1780 +
1781 + if ( $user_exists ) {
1782 +
1783 + if ( $this->p->debug->enabled ) {
1784 +
1785 + $this->p->debug->log( 'skipping filters "' . $filter_name . '" (user exists)' );
1786 + }
1787 +
1788 + return $this->get_md_images( $num, $size_names, $mod, $md_pre, $mt_pre );
1789 + }
1790 +
1791 + if ( $this->p->debug->enabled ) {
1792 +
1793 + $this->p->debug->log( 'applying filters "' . $filter_name . '"' );
1794 + }
1795 +
1796 + return apply_filters( $filter_name, array(), $num, $size_names, $user_id, $md_pre );
1797 + }
1798 +
1799 + /*
1800 + * Schedule the addition of user roles for self::get_public_ids().
1801 + */
1802 + public function schedule_add_person_role( $user_id = null ) {
1803 +
1804 + $user_id = $this->p->util->maybe_change_user_id( $user_id ); // Maybe change textdomain for user id.
1805 + $task_name = 'add the Person role';
1806 + $task_name_transl = _x( 'add the Person role', 'task name', 'wpsso' );
1807 + $event_time = time() + WPSSO_SCHEDULE_SINGLE_EVENT_TIME; // Default event time is now + 10 seconds.
1808 + $human_time = human_time_diff( 0, WPSSO_SCHEDULE_SINGLE_EVENT_TIME );
1809 + $event_hook = 'wpsso_add_person_role';
1810 + $event_args = array( $user_id );
1811 +
1812 + if ( $user_id ) { // Just in case.
1813 +
1814 + $notice_msg = sprintf( __( 'A background task will begin in the next %1$s to %2$s for content creators.', 'wpsso' ),
1815 + $human_time, $task_name_transl );
1816 +
1817 + $notice_key = $task_name . '-scheduled';
1818 +
1819 + $this->p->notice->upd( $notice_msg, $user_id, $notice_key );
1820 + }
1821 +
1822 + wp_schedule_single_event( $event_time, $event_hook, $event_args );
1823 + }
1824 +
1825 + public function add_admin_bar_menu_view_profile( &$wp_admin_bar ) { // Pass by reference OK.
1826 +
1827 + if ( ! is_admin() ) { // Just in case.
1828 +
1829 + return;
1830 + }
1831 +
1832 + $screen_id = SucomUtilWP::get_screen_id();
1833 +
1834 + switch ( $screen_id ) {
1835 +
1836 + case 'profile': // User profile page.
1837 + case ( 0 === strpos( $screen_id, 'profile_page_' ) ? true : false ): // Your profile page.
1838 + case ( 0 === strpos( $screen_id, 'users_page_' . $this->p->id ) ? true : false ): // Profile SSO page.
1839 +
1840 + $user_id = SucomUtilWP::get_user_object( false, 'id' );
1841 +
1842 + $mod = $this->get_mod( $user_id );
1843 +
1844 + break;
1845 +
1846 + default:
1847 +
1848 + return false;
1849 + }
1850 +
1851 + if ( $mod[ 'is_user' ] ) {
1852 +
1853 + $parent_id = 'wpsso-view-profile';
1854 + $menu_title = _x( 'View Profile', 'toolbar menu title', 'wpsso' );
1855 + $canonical_url = $this->p->util->get_canonical_url( $mod );
1856 +
1857 + $wp_admin_bar->add_node( array(
1858 + 'id' => $parent_id,
1859 + 'title' => $menu_title,
1860 + 'parent' => false,
1861 + 'href' => $canonical_url,
1862 + 'group' => false,
1863 + ) );
1864 +
1865 + return $parent_id;
1866 + }
1867 +
1868 + return false;
1869 + }
1870 +
1871 + public function add_person_role( $user_id = null ) {
1872 +
1873 + if ( $this->p->debug->enabled ) {
1874 +
1875 + $this->p->debug->mark();
1876 + }
1877 +
1878 + $user_id = $this->p->util->maybe_change_user_id( $user_id ); // Maybe change textdomain for user id.
1879 + $role_label_transl = _x( 'Person', 'user role', 'wpsso' );
1880 + $task_name = 'add the Person role';
1881 + $task_name_transl = _x( 'add the Person role', 'task name', 'wpsso' );
1882 +
1883 + if ( ! $this->p->util->cache->task_start( $user_id, $task_name, WPSSO_ADD_ROLE_MAX_TIME ) ) {
1884 +
1885 + return; // Stop here - background task already running.
1886 + }
1887 +
1888 + if ( $user_id ) {
1889 +
1890 + $mtime_start = microtime( $get_float = true );
1891 + $time_on_date = SucomUtil::sprintf_date_time( _x( '%2$s on %1$s', 'time on date', 'wpsso' ) );
1892 + $notice_msg = sprintf( __( 'A task to %1$s to content creators was started at %2$s.', 'wpsso' ), $role_label_transl, $time_on_date );
1893 + $notice_key = $task_name . '-task-info';
1894 +
1895 + $this->p->notice->inf( $notice_msg, $user_id, $notice_key );
1896 + }
1897 +
1898 + if ( 0 === get_current_user_id() ) { // User is the scheduler.
1899 +
1900 + $this->p->util->cache->set_task_limit( $user_id, $task_name, WPSSO_ADD_ROLE_MAX_TIME );
1901 + }
1902 +
1903 + if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
1904 +
1905 + /*
1906 + * Register image sizes and include WooCommerce front-end libs.
1907 + */
1908 + do_action( 'wpsso_scheduled_task_started', $user_id );
1909 + }
1910 +
1911 + $count = 0;
1912 +
1913 + $users_ids = self::get_public_ids(); // Aka 'administrator', 'editor', 'author', and 'contributor'.
1914 +
1915 + foreach ( $users_ids as $id ) {
1916 +
1917 + $count += self::add_role_by_id( $id, $role = 'person' );
1918 + }
1919 +
1920 + unset( $users_ids );
1921 +
1922 + if ( $user_id ) {
1923 +
1924 + $mtime_total = microtime( $get_float = true ) - $mtime_start;
1925 + $human_time = human_time_diff( 0, $mtime_total );
1926 + $notice_msg = sprintf( __( 'The %1$s role has been added to %2$d content creators.', 'wpsso' ), $role_label_transl, $count ) . ' ';
1927 + $notice_msg .= sprintf( __( 'The total execution time for this task was %s.', 'wpsso' ), $human_time ) . ' ';
1928 + $notice_key = $task_name . '-task-info';
1929 +
1930 + $this->p->notice->inf( $notice_msg, $user_id, $notice_key );
1931 + }
1932 +
1933 + $this->p->util->cache->task_end( $user_id, $task_name );
1934 + }
1935 +
1936 + /*
1937 + * Schedule the removal of user roles for self::get_public_ids().
1938 + */
1939 + public function schedule_remove_person_role( $user_id = null ) {
1940 +
1941 + $user_id = $this->p->util->maybe_change_user_id( $user_id ); // Maybe change textdomain for user id.
1942 + $task_name = 'remove the Person role';
1943 + $task_name_transl = _x( 'remove the Person role', 'task name', 'wpsso' );
1944 + $event_time = time() + WPSSO_SCHEDULE_SINGLE_EVENT_TIME; // Default event time is now + 10 seconds.
1945 + $human_time = human_time_diff( 0, WPSSO_SCHEDULE_SINGLE_EVENT_TIME );
1946 + $event_hook = 'wpsso_remove_person_role';
1947 + $event_args = array( $user_id );
1948 +
1949 + if ( $user_id ) { // Just in case.
1950 +
1951 + $notice_msg = sprintf( __( 'A background task will begin in the next %1$s to %2$s from all users.', 'wpsso' ),
1952 + $human_time, $task_name_transl );
1953 +
1954 + $notice_key = $task_name . '-scheduled';
1955 +
1956 + $this->p->notice->upd( $notice_msg, $user_id, $notice_key );
1957 + }
1958 +
1959 + wp_schedule_single_event( $event_time, $event_hook, $event_args );
1960 + }
1961 +
1962 + public function remove_person_role( $user_id = null ) {
1963 +
1964 + if ( $this->p->debug->enabled ) {
1965 +
1966 + $this->p->debug->mark();
1967 + }
1968 +
1969 + $user_id = $this->p->util->maybe_change_user_id( $user_id ); // Maybe change textdomain for user id.
1970 + $role_label_transl = _x( 'Person', 'user role', 'wpsso' );
1971 + $task_name = 'remove the Person role';
1972 + $task_name_transl = _x( 'remove the Person role', 'task name', 'wpsso' );
1973 +
1974 + if ( ! $this->p->util->cache->task_start( $user_id, $task_name, WPSSO_REMOVE_ROLE_MAX_TIME ) ) {
1975 +
1976 + return; // Stop here - background task already running.
1977 + }
1978 +
1979 + if ( $user_id ) {
1980 +
1981 + $mtime_start = microtime( $get_float = true );
1982 + $time_on_date = SucomUtil::sprintf_date_time( _x( '%2$s on %1$s', 'time on date', 'wpsso' ) );
1983 + $notice_msg = sprintf( __( 'A task to %1$s from all users was started at %2$s.', 'wpsso' ), $role_label_transl, $time_on_date );
1984 + $notice_key = $task_name . '-task-info';
1985 +
1986 + $this->p->notice->inf( $notice_msg, $user_id, $notice_key );
1987 + }
1988 +
1989 + if ( 0 === get_current_user_id() ) { // User is the scheduler.
1990 +
1991 + $this->p->util->cache->set_task_limit( $user_id, $task_name, WPSSO_REMOVE_ROLE_MAX_TIME );
1992 + }
1993 +
1994 + if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
1995 +
1996 + /*
1997 + * Register image sizes and include WooCommerce front-end libs.
1998 + */
1999 + do_action( 'wpsso_scheduled_task_started', $user_id );
2000 + }
2001 +
2002 + $count = 0;
2003 +
2004 + $blog_id = get_current_blog_id();
2005 +
2006 + while ( $users_ids = SucomUtilWP::get_users_ids( $blog_id, $role = '', $limit = 1000 ) ) { // Get a maximum of 1000 user ids at a time.
2007 +
2008 + foreach ( $users_ids as $id ) {
2009 +
2010 + $count += self::remove_role_by_id( $id, $role = 'person' );
2011 + }
2012 + }
2013 +
2014 + unset( $users_ids );
2015 +
2016 + if ( $user_id ) {
2017 +
2018 + $mtime_total = microtime( $get_float = true ) - $mtime_start;
2019 + $human_time = human_time_diff( 0, $mtime_total );
2020 + $notice_msg = sprintf( __( 'The %1$s role has been removed from %2$d users.', 'wpsso' ), $role_label_transl, $count ) . ' ';
2021 + $notice_msg .= sprintf( __( 'The total execution time for this task was %s.', 'wpsso' ), $human_time );
2022 + $notice_key = $task_name . '-task-info';
2023 +
2024 + $this->p->notice->inf( $notice_msg, $user_id, $notice_key );
2025 + }
2026 +
2027 + $this->p->util->cache->task_end( $user_id, $task_name );
2028 + }
2029 +
2030 + /*
2031 + * Hooked to the 'wpmu_new_user' and 'user_register' actions, which only provides a single argument.
2032 + */
2033 + public static function add_role_by_id( $user_id, $role = 'person' ) {
2034 +
2035 + $user_obj = get_user_by( 'ID', $user_id );
2036 +
2037 + if ( ! in_array( $role, $user_obj->roles ) ) {
2038 +
2039 + $user_obj->add_role( $role ); // Method does not return anything - assume it worked.
2040 +
2041 + return 1;
2042 + }
2043 +
2044 + return 0;
2045 + }
2046 +
2047 + public static function remove_role_by_id( $user_id, $role = 'person' ) {
2048 +
2049 + $user_obj = get_user_by( 'ID', $user_id );
2050 +
2051 + if ( in_array( $role, $user_obj->roles ) ) {
2052 +
2053 + $user_obj->remove_role( $role ); // Method does not return anything - assume it worked.
2054 +
2055 + return 1;
2056 + }
2057 +
2058 + return 0;
2059 + }
2060 +
2061 + public static function get_persons_names( $add_none = true, $roles_id = 'person' ) {
2062 +
2063 + $wpsso =& Wpsso::get_instance();
2064 +
2065 + $users = array();
2066 +
2067 + if ( isset( $wpsso->cf[ 'wp' ][ 'roles' ][ $roles_id ] ) ) { // Just in case.
2068 +
2069 + $roles = $wpsso->cf[ 'wp' ][ 'roles' ][ $roles_id ];
2070 + $users = SucomUtilWP::get_roles_users_select( $roles, $blog_id = null, $add_none );
2071 + $users = array_slice( $users, 0, SucomUtil::get_const( 'WPSSO_SELECT_PERSON_NAMES_MAX', 200 ), $preserve_keys = true );
2072 + }
2073 +
2074 + return $users;
2075 + }
2076 +
2077 + public function add_person_view( $user_views ) {
2078 +
2079 + $user_views = array_reverse( $user_views );
2080 + $all_view_link = $user_views[ 'all' ];
2081 +
2082 + unset( $user_views[ 'all' ], $user_views[ 'person' ] );
2083 +
2084 + $role_label_transl = _x( 'Person', 'user role', 'wpsso' );
2085 + $role_view = add_query_arg( 'role', 'person', admin_url( 'users.php' ) );
2086 + $user_query = new WP_User_Query( array( 'role' => 'person' ) );
2087 + $user_count = $user_query->get_total();
2088 +
2089 + $user_views[ 'person' ] = '<a href="' . $role_view . '">' . $role_label_transl . '</a> (' . $user_count . ')';
2090 + $user_views[ 'all' ] = $all_view_link;
2091 +
2092 + $user_views = array_reverse( $user_views );
2093 +
2094 + return $user_views;
2095 + }
2096 +
2097 + private function get_user_about_meta_keys( $about_key ) {
2098 +
2099 + $meta_keys = array();
2100 +
2101 + if ( 'award' === $about_key ) {
2102 +
2103 + if ( $awards_max = SucomUtil::get_const( 'WPSSO_SCHEMA_AWARDS_MAX' ) ) {
2104 +
2105 + foreach ( range( 0, $awards_max - 1, 1 ) as $key_num ) {
2106 +
2107 + $meta_keys[] = $about_key . '_' . $key_num;
2108 + }
2109 + }
2110 +
2111 + } else $meta_keys[] = $about_key;
2112 +
2113 + return $meta_keys;
2114 + }
2115 +
2116 + /*
2117 + * If $meta_key is en empty string, retrieves all metadata for the specified object ID.
2118 + *
2119 + * See https://developer.wordpress.org/reference/functions/get_metadata/.
2120 + */
2121 + public static function get_meta( $user_id, $meta_key = '', $single = false ) {
2122 +
2123 + return get_metadata( 'user', $user_id, $meta_key, $single );
2124 + }
2125 +
2126 + public static function update_meta( $user_id, $meta_key, $value ) {
2127 +
2128 + return update_metadata( 'user', $user_id, $meta_key, $value );
2129 + }
2130 +
2131 + public static function delete_meta( $user_id, $meta_key ) {
2132 +
2133 + return delete_metadata( 'user', $user_id, $meta_key );
2134 + }
2135 + }
2136 +}