css
22 hours ago
docs
22 hours ago
img
22 hours ago
js
22 hours ago
tabs
22 hours ago
api.php
22 hours ago
cleanup.php
22 hours ago
colors.php
22 hours ago
deprecated.php
22 hours ago
header.php
22 hours ago
helpers.php
22 hours ago
index.php
22 hours ago
menu.php
22 hours ago
plugins-page.php
22 hours ago
post-type-help-doc-imports.php
22 hours ago
post-type-help-docs.php
22 hours ago
shortcodes.php
22 hours ago
taxonomy-folders.php
22 hours ago
shortcodes.php
612 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Shortcodes |
| 4 | */ |
| 5 | |
| 6 | namespace PluginRx\AdminHelpDocs; |
| 7 | |
| 8 | if ( ! defined( 'ABSPATH' ) ) exit; |
| 9 | |
| 10 | class Shortcodes { |
| 11 | |
| 12 | /** |
| 13 | * The single instance of the class |
| 14 | * |
| 15 | * @var self|null |
| 16 | */ |
| 17 | private static ?Shortcodes $instance = null; |
| 18 | |
| 19 | |
| 20 | /** |
| 21 | * Get the singleton instance |
| 22 | * |
| 23 | * @return self |
| 24 | */ |
| 25 | public static function instance() : self { |
| 26 | return self::$instance ??= new self(); |
| 27 | } // End instance() |
| 28 | |
| 29 | |
| 30 | /** |
| 31 | * Constructor |
| 32 | */ |
| 33 | private function __construct() { |
| 34 | |
| 35 | // Display shortcodes without executing them |
| 36 | add_shortcode( 'dont_do_shortcode', [ $this, 'dont_do_shortcode' ] ); |
| 37 | |
| 38 | // Deprecated: Add custom CSS to documents |
| 39 | add_shortcode( 'helpdocs_css', [ $this, 'helpdocs_css' ] ); |
| 40 | |
| 41 | // Stale posts and and pages |
| 42 | add_shortcode( 'helpdocs_stale_content', [ $this, 'stale_content' ] ); |
| 43 | |
| 44 | // Display information about the currently logged-in user |
| 45 | add_shortcode( 'helpdocs_current_user', [ $this, 'current_user' ] ); |
| 46 | |
| 47 | // Display site information like name and URL and other site options |
| 48 | add_shortcode( 'helpdocs_site_info', [ $this, 'site_info' ] ); |
| 49 | |
| 50 | // List all posts with certain criteria |
| 51 | add_shortcode( 'helpdocs_posts', [ $this, 'posts' ] ); |
| 52 | |
| 53 | // List all users with certain criteria |
| 54 | add_shortcode( 'helpdocs_users', [ $this, 'users' ] ); |
| 55 | |
| 56 | } // End __construct() |
| 57 | |
| 58 | |
| 59 | /** |
| 60 | * Display shortcodes without executing them |
| 61 | * USAGE: [dont_do_shortcode click_to_copy="false" code="false"][your_shortcode_here][/dont_do_shortcode] |
| 62 | * |
| 63 | * @param array $atts |
| 64 | * @return string |
| 65 | */ |
| 66 | public function dont_do_shortcode( $atts, $content = null ) : string { |
| 67 | $atts = shortcode_atts( [ |
| 68 | 'content' => '', |
| 69 | 'code' => true, |
| 70 | 'click_to_copy' => true |
| 71 | ], $atts ); |
| 72 | |
| 73 | $wrapper = ( strtolower( sanitize_text_field( $atts[ 'code' ] ) ) == 'false' ) ? 'span' : 'code'; |
| 74 | $click_to_copy = ( strtolower( sanitize_text_field( $atts[ 'click_to_copy' ] ) ) == 'false' ) ? false : true; |
| 75 | |
| 76 | // Support legacy method of passing content as an attribute with curly braces instead of square brackets |
| 77 | if ( empty( $content ) && ! empty( $atts[ 'content' ] ) ) { |
| 78 | $content = $atts[ 'content' ]; |
| 79 | $content = str_replace( '{', '[[', $content ); |
| 80 | $content = str_replace( '}', ']]', $content ); |
| 81 | } |
| 82 | |
| 83 | $click_to_copy_class = $click_to_copy ? ' helpdocs-click-to-copy' : ''; |
| 84 | |
| 85 | return '<' . $wrapper . ' class="helpdocs_dont_do_shortcode' . $click_to_copy_class . '">' . $content . '</' . $wrapper . '>'; |
| 86 | } // End dont_do_shortcode() |
| 87 | |
| 88 | |
| 89 | /** |
| 90 | * Add custom CSS (External or Inline) to the document |
| 91 | * |
| 92 | * @deprecated Add CSS to main docs page from the settings page now. |
| 93 | * @return string |
| 94 | */ |
| 95 | public function helpdocs_css() : string { |
| 96 | _deprecated_function( __FUNCTION__, '2.0', 'Add CSS to main docs page from the settings page now.' ); |
| 97 | return ''; |
| 98 | } // End helpdocs_css() |
| 99 | |
| 100 | |
| 101 | /** |
| 102 | * Shortcode: List stale posts or pages that haven't been updated in over X time. |
| 103 | * |
| 104 | * Usage: |
| 105 | * [helpdocs_stale_content post_types="post, custom_post_type" since="6 months"] |
| 106 | * [helpdocs_stale_content post_types="page" since="1 year"] |
| 107 | * [helpdocs_stale_content since="90 days"] |
| 108 | * [helpdocs_stale_content since="2 weeks" limit="20"] |
| 109 | * |
| 110 | * @param array $atts Shortcode attributes. |
| 111 | * @return string Rendered HTML output. |
| 112 | */ |
| 113 | public function stale_content( $atts ) { |
| 114 | $atts = shortcode_atts( |
| 115 | [ |
| 116 | 'since' => '1 year', // e.g. "6 months", "90 days", "2 weeks", "1 year" |
| 117 | 'limit' => 50, |
| 118 | 'post_types' => 'post, page', |
| 119 | ], |
| 120 | $atts, |
| 121 | ); |
| 122 | |
| 123 | // Build post type array — default to post + page if blank. |
| 124 | if ( ! empty( $atts[ 'post_types' ] ) ) { |
| 125 | $post_types = array_map( 'sanitize_key', array_map( 'trim', explode( ',', $atts[ 'post_types' ] ) ) ); |
| 126 | } else { |
| 127 | $post_types = [ 'post', 'page' ]; |
| 128 | } |
| 129 | |
| 130 | // Parse the "since" value into a cutoff date. |
| 131 | $cutoff = Helpers::parse_since_to_date( $atts[ 'since' ] ); |
| 132 | |
| 133 | if ( ! $cutoff ) { |
| 134 | return '<p class="helpdocs-error">' |
| 135 | . esc_html__( 'Invalid "since" value. Use a format like "6 months", "90 days", "2 weeks", or "1 year".', 'admin-help-docs' ) |
| 136 | . '</p>'; |
| 137 | } |
| 138 | |
| 139 | $query = new \WP_Query( [ |
| 140 | 'post_type' => $post_types, |
| 141 | 'post_status' => 'publish', |
| 142 | 'posts_per_page' => (int) $atts[ 'limit' ], |
| 143 | 'orderby' => 'modified', |
| 144 | 'order' => 'ASC', // Oldest first — most stale at the top. |
| 145 | 'date_query' => [ |
| 146 | [ |
| 147 | 'column' => 'post_modified_gmt', |
| 148 | 'before' => $cutoff, |
| 149 | ], |
| 150 | ], |
| 151 | ] ); |
| 152 | |
| 153 | if ( ! $query->have_posts() ) { |
| 154 | return '<p class="helpdocs-table-none">' |
| 155 | . esc_html__( 'No content due for review was found.', 'admin-help-docs' ) |
| 156 | . '</p>'; |
| 157 | } |
| 158 | |
| 159 | $rows = ''; |
| 160 | while ( $query->have_posts() ) { |
| 161 | $query->the_post(); |
| 162 | |
| 163 | $last_modified = get_the_modified_date( 'Y-m-d' ); |
| 164 | |
| 165 | $rows .= sprintf( |
| 166 | '<tr> |
| 167 | <td class="helpdocs-table-title"><a href="%s">%s</a></td> |
| 168 | <td class="helpdocs-table-type">%s</td> |
| 169 | <td class="helpdocs-table-last-modified">%s</td> |
| 170 | <td class="helpdocs-table-age">%s</td> |
| 171 | </tr>', |
| 172 | esc_url( get_permalink() ), |
| 173 | esc_html( get_the_title() ), |
| 174 | esc_html( get_post_type_object( get_post_type() )->labels->singular_name ), |
| 175 | esc_html( $last_modified ), |
| 176 | esc_html( Helpers::time_elapsed_string( $last_modified ) ) |
| 177 | ); |
| 178 | } |
| 179 | wp_reset_postdata(); |
| 180 | |
| 181 | return sprintf( |
| 182 | '<table class="helpdocs-table"> |
| 183 | <thead> |
| 184 | <tr> |
| 185 | <th class="helpdocs-table-title">%s</th> |
| 186 | <th class="helpdocs-table-type">%s</th> |
| 187 | <th class="helpdocs-table-last-modified">%s</th> |
| 188 | <th class="helpdocs-table-age">%s</th> |
| 189 | </tr> |
| 190 | </thead> |
| 191 | <tbody>%s</tbody> |
| 192 | </table>', |
| 193 | esc_html__( 'Title', 'admin-help-docs' ), |
| 194 | esc_html__( 'Type', 'admin-help-docs' ), |
| 195 | esc_html__( 'Last Modified', 'admin-help-docs' ), |
| 196 | esc_html__( 'Age', 'admin-help-docs' ), |
| 197 | $rows |
| 198 | ); |
| 199 | } // End stale_content() |
| 200 | |
| 201 | |
| 202 | /** |
| 203 | * Shortcode: Display information about the currently logged-in user. |
| 204 | * |
| 205 | * Usage: |
| 206 | * [helpdocs_current_user] — Display name |
| 207 | * [helpdocs_current_user field="first_name"] — First name |
| 208 | * [helpdocs_current_user field="user_email"] — Email address |
| 209 | * [helpdocs_current_user field="my_custom_meta"] — Any custom user meta key |
| 210 | * |
| 211 | * @param array $atts Shortcode attributes. |
| 212 | * @return string The user field value, or empty string if not found. |
| 213 | */ |
| 214 | public function current_user( $atts ) { |
| 215 | $atts = shortcode_atts( [ |
| 216 | 'field' => 'display_name', |
| 217 | 'date_format' => '', |
| 218 | ], $atts ); |
| 219 | |
| 220 | $user = wp_get_current_user(); |
| 221 | if ( ! $user || ! $user->exists() ) { |
| 222 | return ''; |
| 223 | } |
| 224 | |
| 225 | $field = sanitize_key( $atts[ 'field' ] ); |
| 226 | $value = ''; |
| 227 | if ( isset( $user->$field ) ) { |
| 228 | $value = $user->$field; |
| 229 | } else { |
| 230 | $meta = get_user_meta( $user->ID, $field, true ); |
| 231 | if ( $meta ) { |
| 232 | $value = $meta; |
| 233 | } |
| 234 | } |
| 235 | if ( $value === '' ) { |
| 236 | return ''; |
| 237 | } |
| 238 | |
| 239 | if ( ! empty( $atts[ 'date_format' ] ) ) { |
| 240 | $timestamp = is_numeric( $value ) ? (int) $value : strtotime( $value ); |
| 241 | if ( $timestamp ) { |
| 242 | return esc_html( date_i18n( $atts[ 'date_format' ], $timestamp ) ); |
| 243 | } |
| 244 | } |
| 245 | return esc_html( $value ); |
| 246 | } // End current_user() |
| 247 | |
| 248 | |
| 249 | /** |
| 250 | * Shortcode: Display site information like name and URL and other site options. |
| 251 | * |
| 252 | * Usage: |
| 253 | * [helpdocs_site_info field="site_title"] — Site title |
| 254 | * [helpdocs_site_info field="admin_email"] — Admin email |
| 255 | * |
| 256 | * @param array $atts Shortcode attributes. |
| 257 | * @return string The requested site information, or empty string if not found. |
| 258 | */ |
| 259 | public function site_info( $atts ) { |
| 260 | $atts = shortcode_atts( [ |
| 261 | 'field' => 'site_title', |
| 262 | 'date_format' => '', |
| 263 | ], $atts ); |
| 264 | |
| 265 | $map = [ |
| 266 | 'site_title' => 'blogname', |
| 267 | 'tagline' => 'blogdescription', |
| 268 | 'admin_email' => 'admin_email', |
| 269 | 'timezone' => 'timezone_string', |
| 270 | 'permalink_structure' => 'permalink_structure', |
| 271 | 'language' => 'WPLANG', |
| 272 | 'wp_version' => null, |
| 273 | 'front_page' => null, |
| 274 | 'posts_page' => null, |
| 275 | 'date_format' => 'date_format', |
| 276 | 'time_format' => 'time_format', |
| 277 | 'uploads_path' => 'upload_path', |
| 278 | 'site_url' => 'siteurl', |
| 279 | 'home_url' => 'home', |
| 280 | 'charset' => 'blog_charset', |
| 281 | 'posts_per_page' => 'posts_per_page', |
| 282 | 'anyone_can_register' => 'users_can_register', |
| 283 | 'default_role' => 'default_role', |
| 284 | 'comments_open' => 'default_comment_status', |
| 285 | ]; |
| 286 | |
| 287 | $field = sanitize_key( $atts[ 'field' ] ); |
| 288 | $value = ''; |
| 289 | if ( $field === 'wp_version' ) { |
| 290 | global $wp_version; |
| 291 | $value = $wp_version; |
| 292 | } elseif ( $field === 'front_page' ) { |
| 293 | $page_id = get_option( 'page_on_front' ); |
| 294 | $value = $page_id ? get_the_title( $page_id ) : esc_html__( 'Latest Posts', 'admin-help-docs' ); |
| 295 | } elseif ( $field === 'posts_page' ) { |
| 296 | $page_id = get_option( 'page_for_posts' ); |
| 297 | $value = $page_id ? get_the_title( $page_id ) : esc_html__( 'Not set', 'admin-help-docs' ); |
| 298 | } elseif ( isset( $map[ $field ] ) ) { |
| 299 | $value = get_option( $map[ $field ], '' ); |
| 300 | } else { |
| 301 | $value = get_option( $field, '' ); |
| 302 | } |
| 303 | if ( $value === '' ) { |
| 304 | return ''; |
| 305 | } |
| 306 | if ( ! empty( $atts[ 'date_format' ] ) ) { |
| 307 | $timestamp = is_numeric( $value ) ? (int) $value : strtotime( $value ); |
| 308 | if ( $timestamp ) { |
| 309 | return esc_html( date_i18n( $atts[ 'date_format' ], $timestamp ) ); |
| 310 | } |
| 311 | } |
| 312 | return esc_html( $value ); |
| 313 | } // End site_info() |
| 314 | |
| 315 | |
| 316 | /** |
| 317 | * Shortcode: List posts with various criteria. |
| 318 | * |
| 319 | * Usage: |
| 320 | * [helpdocs_posts] — Lists recent posts and pages. |
| 321 | * [helpdocs_posts post_type="post, page" post_status="publish, draft" limit="10" order="ASC" orderby="title" date_format="F j, Y"] |
| 322 | * [helpdocs_posts post_type="custom_post_type" author="admin, editor" category="news, updates" tag="featured"] |
| 323 | * [helpdocs_posts meta_key="my_meta_key" meta_value="my_meta_value"] |
| 324 | * |
| 325 | * @param array $atts Shortcode attributes. |
| 326 | * @return string Rendered HTML output. |
| 327 | */ |
| 328 | public function posts( $atts ) { |
| 329 | $reserved = [ 'post_type', 'post_status', 'limit', 'order', 'orderby', 'date_format', 'author', 'category', 'tag', 'before', 'after', 'post_password__not', 'post_password' ]; |
| 330 | $atts = $atts ? $atts : []; |
| 331 | $split = function( $value ) { |
| 332 | return array_map( 'trim', explode( ',', $value ) ); |
| 333 | }; |
| 334 | $post_types = isset( $atts[ 'post_type' ] ) ? $split( $atts[ 'post_type' ] ) : [ 'post', 'page' ]; |
| 335 | $post_statuses = isset( $atts[ 'post_status' ] ) ? $split( $atts[ 'post_status' ] ) : [ 'publish' ]; |
| 336 | $order = isset( $atts[ 'order' ] ) ? strtoupper( $atts[ 'order' ] ) : 'DESC'; |
| 337 | $orderby = isset( $atts[ 'orderby' ] ) ? $atts[ 'orderby' ] : 'date'; |
| 338 | $limit = isset( $atts[ 'limit' ] ) ? (int) $atts[ 'limit' ] : 50; |
| 339 | $date_format = isset( $atts[ 'date_format' ] ) ? $atts[ 'date_format' ] : 'Y-m-d'; |
| 340 | $show_type = count( $post_types ) > 1; |
| 341 | $show_status = count( $post_statuses ) > 1; |
| 342 | $query_args = [ |
| 343 | 'post_type' => $post_types, |
| 344 | 'post_status' => $post_statuses, |
| 345 | 'posts_per_page' => $limit, |
| 346 | 'order' => in_array( $order, [ 'ASC', 'DESC' ] ) ? $order : 'DESC', |
| 347 | 'orderby' => sanitize_key( $orderby ), |
| 348 | ]; |
| 349 | if ( isset( $atts[ 'author' ] ) ) { |
| 350 | $authors = $split( $atts[ 'author' ] ); |
| 351 | $author_ids = []; |
| 352 | foreach ( $authors as $author ) { |
| 353 | if ( is_numeric( $author ) ) { |
| 354 | $author_ids[] = (int) $author; |
| 355 | } else { |
| 356 | $user = get_user_by( 'login', $author ); |
| 357 | if ( $user ) { |
| 358 | $author_ids[] = $user->ID; |
| 359 | } |
| 360 | } |
| 361 | } |
| 362 | if ( $author_ids ) { |
| 363 | $query_args[ 'author__in' ] = $author_ids; |
| 364 | } |
| 365 | } |
| 366 | if ( isset( $atts[ 'category' ] ) ) { |
| 367 | $cats = $split( $atts[ 'category' ] ); |
| 368 | $cat_ids = []; |
| 369 | foreach ( $cats as $cat ) { |
| 370 | if ( is_numeric( $cat ) ) { |
| 371 | $cat_ids[] = (int) $cat; |
| 372 | } else { |
| 373 | $term = get_term_by( 'slug', $cat, 'category' ); |
| 374 | if ( $term ) { |
| 375 | $cat_ids[] = $term->term_id; |
| 376 | } |
| 377 | } |
| 378 | } |
| 379 | if ( $cat_ids ) { |
| 380 | $query_args[ 'category__in' ] = $cat_ids; |
| 381 | } |
| 382 | } |
| 383 | if ( isset( $atts[ 'tag' ] ) ) { |
| 384 | $tags = $split( $atts[ 'tag' ] ); |
| 385 | $tag_ids = []; |
| 386 | foreach ( $tags as $t ) { |
| 387 | if ( is_numeric( $t ) ) { |
| 388 | $tag_ids[] = (int) $t; |
| 389 | } else { |
| 390 | $term = get_term_by( 'slug', $t, 'post_tag' ); |
| 391 | if ( $term ) { |
| 392 | $tag_ids[] = $term->term_id; |
| 393 | } |
| 394 | } |
| 395 | } |
| 396 | if ( $tag_ids ) { |
| 397 | $query_args[ 'tag__in' ] = $tag_ids; |
| 398 | } |
| 399 | } |
| 400 | if ( isset( $atts[ 'post_password__not' ] ) && $atts[ 'post_password__not' ] === '' ) { |
| 401 | $query_args[ 'has_password' ] = true; |
| 402 | } |
| 403 | if ( isset( $atts[ 'post_password' ] ) && $atts[ 'post_password' ] === '' ) { |
| 404 | $query_args[ 'has_password' ] = false; |
| 405 | } |
| 406 | if ( isset( $atts[ 'before' ] ) || isset( $atts[ 'after' ] ) ) { |
| 407 | $date_query = []; |
| 408 | if ( isset( $atts[ 'after' ] ) ) { |
| 409 | $date_query[ 'after' ] = sanitize_text_field( $atts[ 'after' ] ); |
| 410 | } |
| 411 | if ( isset( $atts[ 'before' ] ) ) { |
| 412 | $date_query[ 'before' ] = sanitize_text_field( $atts[ 'before' ] ); |
| 413 | } |
| 414 | $date_query[ 'inclusive' ] = true; |
| 415 | $query_args[ 'date_query' ] = [ $date_query ]; |
| 416 | } |
| 417 | $meta_query = []; |
| 418 | foreach ( $atts as $key => $value ) { |
| 419 | if ( in_array( $key, $reserved ) ) { |
| 420 | continue; |
| 421 | } |
| 422 | $negated = str_ends_with( $key, '__not' ); |
| 423 | $meta_key = $negated ? substr( $key, 0, -5 ) : $key; |
| 424 | $values = $split( $value ); |
| 425 | $compare = $negated ? 'NOT IN' : 'IN'; |
| 426 | $meta_query[] = [ |
| 427 | 'key' => sanitize_key( $meta_key ), |
| 428 | 'value' => $values, |
| 429 | 'compare' => $compare, |
| 430 | ]; |
| 431 | } |
| 432 | if ( $meta_query ) { |
| 433 | $meta_query[ 'relation' ] = 'AND'; |
| 434 | $query_args[ 'meta_query' ] = $meta_query; |
| 435 | } |
| 436 | $query = new \WP_Query( $query_args ); |
| 437 | if ( ! $query->have_posts() ) { |
| 438 | return '<p class="helpdocs-table-none">' |
| 439 | . esc_html__( 'No posts found.', 'admin-help-docs' ) |
| 440 | . '</p>'; |
| 441 | } |
| 442 | $rows = ''; |
| 443 | while ( $query->have_posts() ) { |
| 444 | $query->the_post(); |
| 445 | $type_cell = $show_type ? '<td class="helpdocs-posts-type">' . esc_html( get_post_type_object( get_post_type() )->labels->singular_name ) . '</td>' : ''; |
| 446 | $status_label = get_post_status_object( get_post_status() ); |
| 447 | $status_cell = $show_status ? '<td class="helpdocs-posts-status">' . esc_html( $status_label ? $status_label->label : get_post_status() ) . '</td>' : ''; |
| 448 | $rows .= sprintf( |
| 449 | '<tr> |
| 450 | <td class="helpdocs-posts-title"><a href="%s">%s</a></td> |
| 451 | %s |
| 452 | %s |
| 453 | <td class="helpdocs-posts-date">%s</td> |
| 454 | </tr>', |
| 455 | esc_url( get_permalink() ), |
| 456 | esc_html( get_the_title() ), |
| 457 | $type_cell, |
| 458 | $status_cell, |
| 459 | esc_html( date_i18n( $date_format, get_the_date( 'U' ) ) ) |
| 460 | ); |
| 461 | } |
| 462 | wp_reset_postdata(); |
| 463 | $type_header = $show_type ? '<th class="helpdocs-posts-type">' . esc_html__( 'Type', 'admin-help-docs' ) . '</th>' : ''; |
| 464 | $status_header = $show_status ? '<th class="helpdocs-posts-status">' . esc_html__( 'Status', 'admin-help-docs' ) . '</th>' : ''; |
| 465 | return sprintf( |
| 466 | '<table class="helpdocs-table"> |
| 467 | <thead> |
| 468 | <tr> |
| 469 | <th class="helpdocs-posts-title">%s</th> |
| 470 | %s |
| 471 | %s |
| 472 | <th class="helpdocs-posts-date">%s</th> |
| 473 | </tr> |
| 474 | </thead> |
| 475 | <tbody>%s</tbody> |
| 476 | </table>', |
| 477 | esc_html__( 'Title', 'admin-help-docs' ), |
| 478 | $type_header, |
| 479 | $status_header, |
| 480 | esc_html__( 'Published', 'admin-help-docs' ), |
| 481 | $rows |
| 482 | ); |
| 483 | } // End posts() |
| 484 | |
| 485 | |
| 486 | /** |
| 487 | * Shortcode: List users with various criteria. |
| 488 | * |
| 489 | * Usage: |
| 490 | * [helpdocs_users] — Lists all users. |
| 491 | * [helpdocs_users role="administrator, editor" role__not="subscriber" limit="20" order="ASC" orderby="display_name" date_format="F j, Y" before="2024-01-01" after="2023-01-01"] |
| 492 | * [helpdocs_users meta_key="my_meta_key" meta_value="my_meta_value" can_view="administrator, editor"] |
| 493 | * |
| 494 | * @param array $atts Shortcode attributes. |
| 495 | * @return string Rendered HTML output. |
| 496 | */ |
| 497 | public function users( $atts ) { |
| 498 | $reserved = [ 'role', 'role__not', 'limit', 'order', 'orderby', 'date_format', 'before', 'after', 'can_view' ]; |
| 499 | $atts = $atts ? $atts : []; |
| 500 | $split = function( $value ) { |
| 501 | return array_map( 'trim', explode( ',', $value ) ); |
| 502 | }; |
| 503 | $can_view = isset( $atts[ 'can_view' ] ) ? $split( $atts[ 'can_view' ] ) : [ 'administrator' ]; |
| 504 | $current_user = wp_get_current_user(); |
| 505 | if ( ! $current_user->exists() ) { |
| 506 | return ''; |
| 507 | } |
| 508 | $user_roles = (array) $current_user->roles; |
| 509 | $has_access = array_intersect( $user_roles, $can_view ); |
| 510 | if ( ! $has_access ) { |
| 511 | return ''; |
| 512 | } |
| 513 | $order = isset( $atts[ 'order' ] ) ? strtoupper( $atts[ 'order' ] ) : 'ASC'; |
| 514 | $orderby = isset( $atts[ 'orderby' ] ) ? $atts[ 'orderby' ] : 'display_name'; |
| 515 | $limit = isset( $atts[ 'limit' ] ) ? (int) $atts[ 'limit' ] : 50; |
| 516 | $date_format = isset( $atts[ 'date_format' ] ) ? $atts[ 'date_format' ] : 'Y-m-d'; |
| 517 | $query_args = [ |
| 518 | 'number' => $limit, |
| 519 | 'order' => in_array( $order, [ 'ASC', 'DESC' ] ) ? $order : 'ASC', |
| 520 | 'orderby' => sanitize_key( $orderby ), |
| 521 | ]; |
| 522 | if ( isset( $atts[ 'role' ] ) ) { |
| 523 | $query_args[ 'role__in' ] = $split( $atts[ 'role' ] ); |
| 524 | } |
| 525 | if ( isset( $atts[ 'role__not' ] ) ) { |
| 526 | $query_args[ 'role__not_in' ] = $split( $atts[ 'role__not' ] ); |
| 527 | } |
| 528 | if ( isset( $atts[ 'before' ] ) || isset( $atts[ 'after' ] ) ) { |
| 529 | $date_query = []; |
| 530 | if ( isset( $atts[ 'after' ] ) ) { |
| 531 | $date_query[ 'after' ] = sanitize_text_field( $atts[ 'after' ] ); |
| 532 | } |
| 533 | if ( isset( $atts[ 'before' ] ) ) { |
| 534 | $date_query[ 'before' ] = sanitize_text_field( $atts[ 'before' ] ); |
| 535 | } |
| 536 | $date_query[ 'inclusive' ] = true; |
| 537 | $query_args[ 'date_query' ] = [ $date_query ]; |
| 538 | } |
| 539 | $meta_query = []; |
| 540 | foreach ( $atts as $key => $value ) { |
| 541 | if ( in_array( $key, $reserved ) ) { |
| 542 | continue; |
| 543 | } |
| 544 | $negated = str_ends_with( $key, '__not' ); |
| 545 | $meta_key = $negated ? substr( $key, 0, -5 ) : $key; |
| 546 | $values = $split( $value ); |
| 547 | $compare = $negated ? 'NOT IN' : 'IN'; |
| 548 | $meta_query[] = [ |
| 549 | 'key' => sanitize_key( $meta_key ), |
| 550 | 'value' => $values, |
| 551 | 'compare' => $compare, |
| 552 | ]; |
| 553 | } |
| 554 | if ( $meta_query ) { |
| 555 | $meta_query[ 'relation' ] = 'AND'; |
| 556 | $query_args[ 'meta_query' ] = $meta_query; |
| 557 | } |
| 558 | $users = get_users( $query_args ); |
| 559 | if ( empty( $users ) ) { |
| 560 | return '<p class="helpdocs-table-none">' |
| 561 | . esc_html__( 'No users found.', 'admin-help-docs' ) |
| 562 | . '</p>'; |
| 563 | } |
| 564 | $rows = ''; |
| 565 | foreach ( $users as $user ) { |
| 566 | $roles = array_map( function( $role ) { |
| 567 | $wp_roles = wp_roles(); |
| 568 | return isset( $wp_roles->roles[ $role ] ) ? $wp_roles->roles[ $role ][ 'name' ] : $role; |
| 569 | }, $user->roles ); |
| 570 | $rows .= sprintf( |
| 571 | '<tr> |
| 572 | <td class="helpdocs-users-name"><a href="%s">%s</a></td> |
| 573 | <td class="helpdocs-users-login">%s</td> |
| 574 | <td class="helpdocs-users-email"><a href="mailto:%s">%s</a></td> |
| 575 | <td class="helpdocs-users-roles">%s</td> |
| 576 | <td class="helpdocs-users-registered">%s</td> |
| 577 | </tr>', |
| 578 | esc_url( get_edit_user_link( $user->ID ) ), |
| 579 | esc_html( $user->display_name ), |
| 580 | esc_html( $user->user_login ), |
| 581 | esc_attr( $user->user_email ), |
| 582 | esc_html( $user->user_email ), |
| 583 | esc_html( implode( ', ', $roles ) ), |
| 584 | esc_html( date_i18n( $date_format, strtotime( $user->user_registered ) ) ) |
| 585 | ); |
| 586 | } |
| 587 | return sprintf( |
| 588 | '<table class="helpdocs-table"> |
| 589 | <thead> |
| 590 | <tr> |
| 591 | <th class="helpdocs-users-name">%s</th> |
| 592 | <th class="helpdocs-users-login">%s</th> |
| 593 | <th class="helpdocs-users-email">%s</th> |
| 594 | <th class="helpdocs-users-roles">%s</th> |
| 595 | <th class="helpdocs-users-registered">%s</th> |
| 596 | </tr> |
| 597 | </thead> |
| 598 | <tbody>%s</tbody> |
| 599 | </table>', |
| 600 | esc_html__( 'Display Name', 'admin-help-docs' ), |
| 601 | esc_html__( 'Username', 'admin-help-docs' ), |
| 602 | esc_html__( 'Email', 'admin-help-docs' ), |
| 603 | esc_html__( 'Role(s)', 'admin-help-docs' ), |
| 604 | esc_html__( 'Registered', 'admin-help-docs' ), |
| 605 | $rows |
| 606 | ); |
| 607 | } // End users() |
| 608 | |
| 609 | } |
| 610 | |
| 611 | |
| 612 | Shortcodes::instance(); |