[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * List Table API: WP_MS_Themes_List_Table class 4 * 5 * @package WordPress 6 * @subpackage Administration 7 * @since 3.1.0 8 */ 9 10 /** 11 * Core class used to implement displaying themes in a list table for the network admin. 12 * 13 * @since 3.1.0 14 * 15 * @see WP_List_Table 16 */ 17 class WP_MS_Themes_List_Table extends WP_List_Table { 18 19 public $site_id; 20 public $is_site_themes; 21 22 private $has_items; 23 24 /** 25 * Whether to show the auto-updates UI. 26 * 27 * @since 5.5.0 28 * 29 * @var bool True if auto-updates UI is to be shown, false otherwise. 30 */ 31 protected $show_autoupdates = true; 32 33 /** 34 * Constructor. 35 * 36 * @since 3.1.0 37 * 38 * @see WP_List_Table::__construct() for more information on default arguments. 39 * 40 * @global string $status 41 * @global int $page 42 * 43 * @param array $args An associative array of arguments. 44 */ 45 public function __construct( $args = array() ) { 46 global $status, $page; 47 48 parent::__construct( 49 array( 50 'plural' => 'themes', 51 'screen' => isset( $args['screen'] ) ? $args['screen'] : null, 52 ) 53 ); 54 55 $status = isset( $_REQUEST['theme_status'] ) ? $_REQUEST['theme_status'] : 'all'; 56 if ( ! in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken', 'auto-update-enabled', 'auto-update-disabled' ), true ) ) { 57 $status = 'all'; 58 } 59 60 $page = $this->get_pagenum(); 61 62 $this->is_site_themes = ( 'site-themes-network' === $this->screen->id ) ? true : false; 63 64 if ( $this->is_site_themes ) { 65 $this->site_id = isset( $_REQUEST['id'] ) ? (int) $_REQUEST['id'] : 0; 66 } 67 68 $this->show_autoupdates = wp_is_auto_update_enabled_for_type( 'theme' ) && 69 ! $this->is_site_themes && current_user_can( 'update_themes' ); 70 } 71 72 /** 73 * @return array 74 */ 75 protected function get_table_classes() { 76 // @todo Remove and add CSS for .themes. 77 return array( 'widefat', 'plugins' ); 78 } 79 80 /** 81 * @return bool 82 */ 83 public function ajax_user_can() { 84 if ( $this->is_site_themes ) { 85 return current_user_can( 'manage_sites' ); 86 } else { 87 return current_user_can( 'manage_network_themes' ); 88 } 89 } 90 91 /** 92 * @global string $status 93 * @global array $totals 94 * @global int $page 95 * @global string $orderby 96 * @global string $order 97 * @global string $s 98 */ 99 public function prepare_items() { 100 global $status, $totals, $page, $orderby, $order, $s; 101 102 wp_reset_vars( array( 'orderby', 'order', 's' ) ); 103 104 $themes = array( 105 /** 106 * Filters the full array of WP_Theme objects to list in the Multisite 107 * themes list table. 108 * 109 * @since 3.1.0 110 * 111 * @param WP_Theme[] $all Array of WP_Theme objects to display in the list table. 112 */ 113 'all' => apply_filters( 'all_themes', wp_get_themes() ), 114 'search' => array(), 115 'enabled' => array(), 116 'disabled' => array(), 117 'upgrade' => array(), 118 'broken' => $this->is_site_themes ? array() : wp_get_themes( array( 'errors' => true ) ), 119 ); 120 121 if ( $this->show_autoupdates ) { 122 $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); 123 124 $themes['auto-update-enabled'] = array(); 125 $themes['auto-update-disabled'] = array(); 126 } 127 128 if ( $this->is_site_themes ) { 129 $themes_per_page = $this->get_items_per_page( 'site_themes_network_per_page' ); 130 $allowed_where = 'site'; 131 } else { 132 $themes_per_page = $this->get_items_per_page( 'themes_network_per_page' ); 133 $allowed_where = 'network'; 134 } 135 136 $current = get_site_transient( 'update_themes' ); 137 $maybe_update = current_user_can( 'update_themes' ) && ! $this->is_site_themes && $current; 138 139 foreach ( (array) $themes['all'] as $key => $theme ) { 140 if ( $this->is_site_themes && $theme->is_allowed( 'network' ) ) { 141 unset( $themes['all'][ $key ] ); 142 continue; 143 } 144 145 if ( $maybe_update && isset( $current->response[ $key ] ) ) { 146 $themes['all'][ $key ]->update = true; 147 $themes['upgrade'][ $key ] = $themes['all'][ $key ]; 148 } 149 150 $filter = $theme->is_allowed( $allowed_where, $this->site_id ) ? 'enabled' : 'disabled'; 151 $themes[ $filter ][ $key ] = $themes['all'][ $key ]; 152 153 $theme_data = array( 154 'update_supported' => isset( $theme->update_supported ) ? $theme->update_supported : true, 155 ); 156 157 // Extra info if known. array_merge() ensures $theme_data has precedence if keys collide. 158 if ( isset( $current->response[ $key ] ) ) { 159 $theme_data = array_merge( (array) $current->response[ $key ], $theme_data ); 160 } elseif ( isset( $current->no_update[ $key ] ) ) { 161 $theme_data = array_merge( (array) $current->no_update[ $key ], $theme_data ); 162 } else { 163 $theme_data['update_supported'] = false; 164 } 165 166 $theme->update_supported = $theme_data['update_supported']; 167 168 /* 169 * Create the expected payload for the auto_update_theme filter, this is the same data 170 * as contained within $updates or $no_updates but used when the Theme is not known. 171 */ 172 $filter_payload = array( 173 'theme' => $key, 174 'new_version' => '', 175 'url' => '', 176 'package' => '', 177 'requires' => '', 178 'requires_php' => '', 179 ); 180 181 $filter_payload = (object) array_merge( $filter_payload, array_intersect_key( $theme_data, $filter_payload ) ); 182 183 $auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, $filter_payload ); 184 185 if ( ! is_null( $auto_update_forced ) ) { 186 $theme->auto_update_forced = $auto_update_forced; 187 } 188 189 if ( $this->show_autoupdates ) { 190 $enabled = in_array( $key, $auto_updates, true ) && $theme->update_supported; 191 if ( isset( $theme->auto_update_forced ) ) { 192 $enabled = (bool) $theme->auto_update_forced; 193 } 194 195 if ( $enabled ) { 196 $themes['auto-update-enabled'][ $key ] = $theme; 197 } else { 198 $themes['auto-update-disabled'][ $key ] = $theme; 199 } 200 } 201 } 202 203 if ( $s ) { 204 $status = 'search'; 205 $themes['search'] = array_filter( array_merge( $themes['all'], $themes['broken'] ), array( $this, '_search_callback' ) ); 206 } 207 208 $totals = array(); 209 $js_themes = array(); 210 foreach ( $themes as $type => $list ) { 211 $totals[ $type ] = count( $list ); 212 $js_themes[ $type ] = array_keys( $list ); 213 } 214 215 if ( empty( $themes[ $status ] ) && ! in_array( $status, array( 'all', 'search' ), true ) ) { 216 $status = 'all'; 217 } 218 219 $this->items = $themes[ $status ]; 220 WP_Theme::sort_by_name( $this->items ); 221 222 $this->has_items = ! empty( $themes['all'] ); 223 $total_this_page = $totals[ $status ]; 224 225 wp_localize_script( 226 'updates', 227 '_wpUpdatesItemCounts', 228 array( 229 'themes' => $js_themes, 230 'totals' => wp_get_update_data(), 231 ) 232 ); 233 234 if ( $orderby ) { 235 $orderby = ucfirst( $orderby ); 236 $order = strtoupper( $order ); 237 238 if ( 'Name' === $orderby ) { 239 if ( 'ASC' === $order ) { 240 $this->items = array_reverse( $this->items ); 241 } 242 } else { 243 uasort( $this->items, array( $this, '_order_callback' ) ); 244 } 245 } 246 247 $start = ( $page - 1 ) * $themes_per_page; 248 249 if ( $total_this_page > $themes_per_page ) { 250 $this->items = array_slice( $this->items, $start, $themes_per_page, true ); 251 } 252 253 $this->set_pagination_args( 254 array( 255 'total_items' => $total_this_page, 256 'per_page' => $themes_per_page, 257 ) 258 ); 259 } 260 261 /** 262 * @param WP_Theme $theme 263 * @return bool 264 */ 265 public function _search_callback( $theme ) { 266 static $term = null; 267 if ( is_null( $term ) ) { 268 $term = wp_unslash( $_REQUEST['s'] ); 269 } 270 271 foreach ( array( 'Name', 'Description', 'Author', 'Author', 'AuthorURI' ) as $field ) { 272 // Don't mark up; Do translate. 273 if ( false !== stripos( $theme->display( $field, false, true ), $term ) ) { 274 return true; 275 } 276 } 277 278 if ( false !== stripos( $theme->get_stylesheet(), $term ) ) { 279 return true; 280 } 281 282 if ( false !== stripos( $theme->get_template(), $term ) ) { 283 return true; 284 } 285 286 return false; 287 } 288 289 // Not used by any core columns. 290 /** 291 * @global string $orderby 292 * @global string $order 293 * @param array $theme_a 294 * @param array $theme_b 295 * @return int 296 */ 297 public function _order_callback( $theme_a, $theme_b ) { 298 global $orderby, $order; 299 300 $a = $theme_a[ $orderby ]; 301 $b = $theme_b[ $orderby ]; 302 303 if ( $a === $b ) { 304 return 0; 305 } 306 307 if ( 'DESC' === $order ) { 308 return ( $a < $b ) ? 1 : -1; 309 } else { 310 return ( $a < $b ) ? -1 : 1; 311 } 312 } 313 314 /** 315 */ 316 public function no_items() { 317 if ( $this->has_items ) { 318 _e( 'No themes found.' ); 319 } else { 320 _e( 'No themes are currently available.' ); 321 } 322 } 323 324 /** 325 * @return string[] Array of column titles keyed by their column name. 326 */ 327 public function get_columns() { 328 $columns = array( 329 'cb' => '<input type="checkbox" />', 330 'name' => __( 'Theme' ), 331 'description' => __( 'Description' ), 332 ); 333 334 if ( $this->show_autoupdates ) { 335 $columns['auto-updates'] = __( 'Automatic Updates' ); 336 } 337 338 return $columns; 339 } 340 341 /** 342 * @return array 343 */ 344 protected function get_sortable_columns() { 345 return array( 346 'name' => array( 'name', false, __( 'Theme' ), __( 'Table ordered by Theme Name.' ), 'asc' ), 347 ); 348 } 349 350 /** 351 * Gets the name of the primary column. 352 * 353 * @since 4.3.0 354 * 355 * @return string Unalterable name of the primary column name, in this case, 'name'. 356 */ 357 protected function get_primary_column_name() { 358 return 'name'; 359 } 360 361 /** 362 * @global array $totals 363 * @global string $status 364 * @return array 365 */ 366 protected function get_views() { 367 global $totals, $status; 368 369 $status_links = array(); 370 foreach ( $totals as $type => $count ) { 371 if ( ! $count ) { 372 continue; 373 } 374 375 switch ( $type ) { 376 case 'all': 377 /* translators: %s: Number of themes. */ 378 $text = _nx( 379 'All <span class="count">(%s)</span>', 380 'All <span class="count">(%s)</span>', 381 $count, 382 'themes' 383 ); 384 break; 385 case 'enabled': 386 /* translators: %s: Number of themes. */ 387 $text = _nx( 388 'Enabled <span class="count">(%s)</span>', 389 'Enabled <span class="count">(%s)</span>', 390 $count, 391 'themes' 392 ); 393 break; 394 case 'disabled': 395 /* translators: %s: Number of themes. */ 396 $text = _nx( 397 'Disabled <span class="count">(%s)</span>', 398 'Disabled <span class="count">(%s)</span>', 399 $count, 400 'themes' 401 ); 402 break; 403 case 'upgrade': 404 /* translators: %s: Number of themes. */ 405 $text = _nx( 406 'Update Available <span class="count">(%s)</span>', 407 'Update Available <span class="count">(%s)</span>', 408 $count, 409 'themes' 410 ); 411 break; 412 case 'broken': 413 /* translators: %s: Number of themes. */ 414 $text = _nx( 415 'Broken <span class="count">(%s)</span>', 416 'Broken <span class="count">(%s)</span>', 417 $count, 418 'themes' 419 ); 420 break; 421 case 'auto-update-enabled': 422 /* translators: %s: Number of themes. */ 423 $text = _n( 424 'Auto-updates Enabled <span class="count">(%s)</span>', 425 'Auto-updates Enabled <span class="count">(%s)</span>', 426 $count 427 ); 428 break; 429 case 'auto-update-disabled': 430 /* translators: %s: Number of themes. */ 431 $text = _n( 432 'Auto-updates Disabled <span class="count">(%s)</span>', 433 'Auto-updates Disabled <span class="count">(%s)</span>', 434 $count 435 ); 436 break; 437 } 438 439 if ( $this->is_site_themes ) { 440 $url = 'site-themes.php?id=' . $this->site_id; 441 } else { 442 $url = 'themes.php'; 443 } 444 445 if ( 'search' !== $type ) { 446 $status_links[ $type ] = array( 447 'url' => esc_url( add_query_arg( 'theme_status', $type, $url ) ), 448 'label' => sprintf( $text, number_format_i18n( $count ) ), 449 'current' => $type === $status, 450 ); 451 } 452 } 453 454 return $this->get_views_links( $status_links ); 455 } 456 457 /** 458 * @global string $status 459 * 460 * @return array 461 */ 462 protected function get_bulk_actions() { 463 global $status; 464 465 $actions = array(); 466 if ( 'enabled' !== $status ) { 467 $actions['enable-selected'] = $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' ); 468 } 469 if ( 'disabled' !== $status ) { 470 $actions['disable-selected'] = $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ); 471 } 472 if ( ! $this->is_site_themes ) { 473 if ( current_user_can( 'update_themes' ) ) { 474 $actions['update-selected'] = __( 'Update' ); 475 } 476 if ( current_user_can( 'delete_themes' ) ) { 477 $actions['delete-selected'] = __( 'Delete' ); 478 } 479 } 480 481 if ( $this->show_autoupdates ) { 482 if ( 'auto-update-enabled' !== $status ) { 483 $actions['enable-auto-update-selected'] = __( 'Enable Auto-updates' ); 484 } 485 486 if ( 'auto-update-disabled' !== $status ) { 487 $actions['disable-auto-update-selected'] = __( 'Disable Auto-updates' ); 488 } 489 } 490 491 return $actions; 492 } 493 494 /** 495 */ 496 public function display_rows() { 497 foreach ( $this->items as $theme ) { 498 $this->single_row( $theme ); 499 } 500 } 501 502 /** 503 * Handles the checkbox column output. 504 * 505 * @since 4.3.0 506 * @since 5.9.0 Renamed `$theme` to `$item` to match parent class for PHP 8 named parameter support. 507 * 508 * @param WP_Theme $item The current WP_Theme object. 509 */ 510 public function column_cb( $item ) { 511 // Restores the more descriptive, specific name for use within this method. 512 $theme = $item; 513 514 $checkbox_id = 'checkbox_' . md5( $theme->get( 'Name' ) ); 515 ?> 516 <input type="checkbox" name="checked[]" value="<?php echo esc_attr( $theme->get_stylesheet() ); ?>" id="<?php echo $checkbox_id; ?>" /> 517 <label for="<?php echo $checkbox_id; ?>" > 518 <span class="screen-reader-text"> 519 <?php 520 printf( 521 /* translators: Hidden accessibility text. %s: Theme name */ 522 __( 'Select %s' ), 523 $theme->display( 'Name' ) 524 ); 525 ?> 526 </span> 527 </label> 528 <?php 529 } 530 531 /** 532 * Handles the name column output. 533 * 534 * @since 4.3.0 535 * 536 * @global string $status 537 * @global int $page 538 * @global string $s 539 * 540 * @param WP_Theme $theme The current WP_Theme object. 541 */ 542 public function column_name( $theme ) { 543 global $status, $page, $s; 544 545 $context = $status; 546 547 if ( $this->is_site_themes ) { 548 $url = "site-themes.php?id={$this->site_id}&"; 549 $allowed = $theme->is_allowed( 'site', $this->site_id ); 550 } else { 551 $url = 'themes.php?'; 552 $allowed = $theme->is_allowed( 'network' ); 553 } 554 555 // Pre-order. 556 $actions = array( 557 'enable' => '', 558 'disable' => '', 559 'delete' => '', 560 ); 561 562 $stylesheet = $theme->get_stylesheet(); 563 $theme_key = urlencode( $stylesheet ); 564 565 if ( ! $allowed ) { 566 if ( ! $theme->errors() ) { 567 $url = add_query_arg( 568 array( 569 'action' => 'enable', 570 'theme' => $theme_key, 571 'paged' => $page, 572 's' => $s, 573 ), 574 $url 575 ); 576 577 if ( $this->is_site_themes ) { 578 /* translators: %s: Theme name. */ 579 $aria_label = sprintf( __( 'Enable %s' ), $theme->display( 'Name' ) ); 580 } else { 581 /* translators: %s: Theme name. */ 582 $aria_label = sprintf( __( 'Network Enable %s' ), $theme->display( 'Name' ) ); 583 } 584 585 $actions['enable'] = sprintf( 586 '<a href="%s" class="edit" aria-label="%s">%s</a>', 587 esc_url( wp_nonce_url( $url, 'enable-theme_' . $stylesheet ) ), 588 esc_attr( $aria_label ), 589 ( $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' ) ) 590 ); 591 } 592 } else { 593 $url = add_query_arg( 594 array( 595 'action' => 'disable', 596 'theme' => $theme_key, 597 'paged' => $page, 598 's' => $s, 599 ), 600 $url 601 ); 602 603 if ( $this->is_site_themes ) { 604 /* translators: %s: Theme name. */ 605 $aria_label = sprintf( __( 'Disable %s' ), $theme->display( 'Name' ) ); 606 } else { 607 /* translators: %s: Theme name. */ 608 $aria_label = sprintf( __( 'Network Disable %s' ), $theme->display( 'Name' ) ); 609 } 610 611 $actions['disable'] = sprintf( 612 '<a href="%s" aria-label="%s">%s</a>', 613 esc_url( wp_nonce_url( $url, 'disable-theme_' . $stylesheet ) ), 614 esc_attr( $aria_label ), 615 ( $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ) ) 616 ); 617 } 618 619 if ( ! $allowed && ! $this->is_site_themes 620 && current_user_can( 'delete_themes' ) 621 && get_option( 'stylesheet' ) !== $stylesheet 622 && get_option( 'template' ) !== $stylesheet 623 ) { 624 $url = add_query_arg( 625 array( 626 'action' => 'delete-selected', 627 'checked[]' => $theme_key, 628 'theme_status' => $context, 629 'paged' => $page, 630 's' => $s, 631 ), 632 'themes.php' 633 ); 634 635 /* translators: %s: Theme name. */ 636 $aria_label = sprintf( _x( 'Delete %s', 'theme' ), $theme->display( 'Name' ) ); 637 638 $actions['delete'] = sprintf( 639 '<a href="%s" class="delete" aria-label="%s">%s</a>', 640 esc_url( wp_nonce_url( $url, 'bulk-themes' ) ), 641 esc_attr( $aria_label ), 642 __( 'Delete' ) 643 ); 644 } 645 /** 646 * Filters the action links displayed for each theme in the Multisite 647 * themes list table. 648 * 649 * The action links displayed are determined by the theme's status, and 650 * which Multisite themes list table is being displayed - the Network 651 * themes list table (themes.php), which displays all installed themes, 652 * or the Site themes list table (site-themes.php), which displays the 653 * non-network enabled themes when editing a site in the Network admin. 654 * 655 * The default action links for the Network themes list table include 656 * 'Network Enable', 'Network Disable', and 'Delete'. 657 * 658 * The default action links for the Site themes list table include 659 * 'Enable', and 'Disable'. 660 * 661 * @since 2.8.0 662 * 663 * @param string[] $actions An array of action links. 664 * @param WP_Theme $theme The current WP_Theme object. 665 * @param string $context Status of the theme, one of 'all', 'enabled', or 'disabled'. 666 */ 667 $actions = apply_filters( 'theme_action_links', array_filter( $actions ), $theme, $context ); 668 669 /** 670 * Filters the action links of a specific theme in the Multisite themes 671 * list table. 672 * 673 * The dynamic portion of the hook name, `$stylesheet`, refers to the 674 * directory name of the theme, which in most cases is synonymous 675 * with the template name. 676 * 677 * @since 3.1.0 678 * 679 * @param string[] $actions An array of action links. 680 * @param WP_Theme $theme The current WP_Theme object. 681 * @param string $context Status of the theme, one of 'all', 'enabled', or 'disabled'. 682 */ 683 $actions = apply_filters( "theme_action_links_{$stylesheet}", $actions, $theme, $context ); 684 685 echo $this->row_actions( $actions, true ); 686 } 687 688 /** 689 * Handles the description column output. 690 * 691 * @since 4.3.0 692 * 693 * @global string $status 694 * @global array $totals 695 * 696 * @param WP_Theme $theme The current WP_Theme object. 697 */ 698 public function column_description( $theme ) { 699 global $status, $totals; 700 701 if ( $theme->errors() ) { 702 $pre = 'broken' === $status ? __( 'Broken Theme:' ) . ' ' : ''; 703 echo '<p><strong class="error-message">' . $pre . $theme->errors()->get_error_message() . '</strong></p>'; 704 } 705 706 if ( $this->is_site_themes ) { 707 $allowed = $theme->is_allowed( 'site', $this->site_id ); 708 } else { 709 $allowed = $theme->is_allowed( 'network' ); 710 } 711 712 $class = ! $allowed ? 'inactive' : 'active'; 713 if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) ) { 714 $class .= ' update'; 715 } 716 717 echo "<div class='theme-description'><p>" . $theme->display( 'Description' ) . "</p></div> 718 <div class='$class second theme-version-author-uri'>"; 719 720 $stylesheet = $theme->get_stylesheet(); 721 $theme_meta = array(); 722 723 if ( $theme->get( 'Version' ) ) { 724 /* translators: %s: Theme version. */ 725 $theme_meta[] = sprintf( __( 'Version %s' ), $theme->display( 'Version' ) ); 726 } 727 728 /* translators: %s: Theme author. */ 729 $theme_meta[] = sprintf( __( 'By %s' ), $theme->display( 'Author' ) ); 730 731 if ( $theme->get( 'ThemeURI' ) ) { 732 /* translators: %s: Theme name. */ 733 $aria_label = sprintf( __( 'Visit theme site for %s' ), $theme->display( 'Name' ) ); 734 735 $theme_meta[] = sprintf( 736 '<a href="%s" aria-label="%s">%s</a>', 737 $theme->display( 'ThemeURI' ), 738 esc_attr( $aria_label ), 739 __( 'Visit Theme Site' ) 740 ); 741 } 742 743 if ( $theme->parent() ) { 744 $theme_meta[] = sprintf( 745 /* translators: %s: Theme name. */ 746 __( 'Child theme of %s' ), 747 '<strong>' . $theme->parent()->display( 'Name' ) . '</strong>' 748 ); 749 } 750 751 /** 752 * Filters the array of row meta for each theme in the Multisite themes 753 * list table. 754 * 755 * @since 3.1.0 756 * 757 * @param string[] $theme_meta An array of the theme's metadata, including 758 * the version, author, and theme URI. 759 * @param string $stylesheet Directory name of the theme. 760 * @param WP_Theme $theme WP_Theme object. 761 * @param string $status Status of the theme. 762 */ 763 $theme_meta = apply_filters( 'theme_row_meta', $theme_meta, $stylesheet, $theme, $status ); 764 765 echo implode( ' | ', $theme_meta ); 766 767 echo '</div>'; 768 } 769 770 /** 771 * Handles the auto-updates column output. 772 * 773 * @since 5.5.0 774 * 775 * @global string $status 776 * @global int $page 777 * 778 * @param WP_Theme $theme The current WP_Theme object. 779 */ 780 public function column_autoupdates( $theme ) { 781 global $status, $page; 782 783 static $auto_updates, $available_updates; 784 785 if ( ! $auto_updates ) { 786 $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); 787 } 788 if ( ! $available_updates ) { 789 $available_updates = get_site_transient( 'update_themes' ); 790 } 791 792 $stylesheet = $theme->get_stylesheet(); 793 794 if ( isset( $theme->auto_update_forced ) ) { 795 if ( $theme->auto_update_forced ) { 796 // Forced on. 797 $text = __( 'Auto-updates enabled' ); 798 } else { 799 $text = __( 'Auto-updates disabled' ); 800 } 801 $action = 'unavailable'; 802 $time_class = ' hidden'; 803 } elseif ( empty( $theme->update_supported ) ) { 804 $text = ''; 805 $action = 'unavailable'; 806 $time_class = ' hidden'; 807 } elseif ( in_array( $stylesheet, $auto_updates, true ) ) { 808 $text = __( 'Disable auto-updates' ); 809 $action = 'disable'; 810 $time_class = ''; 811 } else { 812 $text = __( 'Enable auto-updates' ); 813 $action = 'enable'; 814 $time_class = ' hidden'; 815 } 816 817 $query_args = array( 818 'action' => "{$action}-auto-update", 819 'theme' => $stylesheet, 820 'paged' => $page, 821 'theme_status' => $status, 822 ); 823 824 $url = add_query_arg( $query_args, 'themes.php' ); 825 826 if ( 'unavailable' === $action ) { 827 $html[] = '<span class="label">' . $text . '</span>'; 828 } else { 829 $html[] = sprintf( 830 '<a href="%s" class="toggle-auto-update aria-button-if-js" data-wp-action="%s">', 831 wp_nonce_url( $url, 'updates' ), 832 $action 833 ); 834 835 $html[] = '<span class="dashicons dashicons-update spin hidden" aria-hidden="true"></span>'; 836 $html[] = '<span class="label">' . $text . '</span>'; 837 $html[] = '</a>'; 838 839 } 840 841 if ( isset( $available_updates->response[ $stylesheet ] ) ) { 842 $html[] = sprintf( 843 '<div class="auto-update-time%s">%s</div>', 844 $time_class, 845 wp_get_auto_update_message() 846 ); 847 } 848 849 $html = implode( '', $html ); 850 851 /** 852 * Filters the HTML of the auto-updates setting for each theme in the Themes list table. 853 * 854 * @since 5.5.0 855 * 856 * @param string $html The HTML for theme's auto-update setting, including 857 * toggle auto-update action link and time to next update. 858 * @param string $stylesheet Directory name of the theme. 859 * @param WP_Theme $theme WP_Theme object. 860 */ 861 echo apply_filters( 'theme_auto_update_setting_html', $html, $stylesheet, $theme ); 862 863 wp_admin_notice( 864 '', 865 array( 866 'type' => 'error', 867 'additional_classes' => array( 'notice-alt', 'inline', 'hidden' ), 868 ) 869 ); 870 } 871 872 /** 873 * Handles default column output. 874 * 875 * @since 4.3.0 876 * @since 5.9.0 Renamed `$theme` to `$item` to match parent class for PHP 8 named parameter support. 877 * 878 * @param WP_Theme $item The current WP_Theme object. 879 * @param string $column_name The current column name. 880 */ 881 public function column_default( $item, $column_name ) { 882 // Restores the more descriptive, specific name for use within this method. 883 $theme = $item; 884 885 $stylesheet = $theme->get_stylesheet(); 886 887 /** 888 * Fires inside each custom column of the Multisite themes list table. 889 * 890 * @since 3.1.0 891 * 892 * @param string $column_name Name of the column. 893 * @param string $stylesheet Directory name of the theme. 894 * @param WP_Theme $theme Current WP_Theme object. 895 */ 896 do_action( 'manage_themes_custom_column', $column_name, $stylesheet, $theme ); 897 } 898 899 /** 900 * Handles the output for a single table row. 901 * 902 * @since 4.3.0 903 * 904 * @param WP_Theme $item The current WP_Theme object. 905 */ 906 public function single_row_columns( $item ) { 907 list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info(); 908 909 foreach ( $columns as $column_name => $column_display_name ) { 910 $extra_classes = ''; 911 if ( in_array( $column_name, $hidden, true ) ) { 912 $extra_classes .= ' hidden'; 913 } 914 915 switch ( $column_name ) { 916 case 'cb': 917 echo '<th scope="row" class="check-column">'; 918 919 $this->column_cb( $item ); 920 921 echo '</th>'; 922 break; 923 924 case 'name': 925 $active_theme_label = ''; 926 927 /* The presence of the site_id property means that this is a subsite view and a label for the active theme needs to be added */ 928 if ( ! empty( $this->site_id ) ) { 929 $stylesheet = get_blog_option( $this->site_id, 'stylesheet' ); 930 $template = get_blog_option( $this->site_id, 'template' ); 931 932 /* Add a label for the active template */ 933 if ( $item->get_template() === $template ) { 934 $active_theme_label = ' — ' . __( 'Active Theme' ); 935 } 936 937 /* In case this is a child theme, label it properly */ 938 if ( $stylesheet !== $template && $item->get_stylesheet() === $stylesheet ) { 939 $active_theme_label = ' — ' . __( 'Active Child Theme' ); 940 } 941 } 942 943 echo "<td class='theme-title column-primary{$extra_classes}'><strong>" . $item->display( 'Name' ) . $active_theme_label . '</strong>'; 944 945 $this->column_name( $item ); 946 947 echo '</td>'; 948 break; 949 950 case 'description': 951 echo "<td class='column-description desc{$extra_classes}'>"; 952 953 $this->column_description( $item ); 954 955 echo '</td>'; 956 break; 957 958 case 'auto-updates': 959 echo "<td class='column-auto-updates{$extra_classes}'>"; 960 961 $this->column_autoupdates( $item ); 962 963 echo '</td>'; 964 break; 965 default: 966 echo "<td class='$column_name column-$column_name{$extra_classes}'>"; 967 968 $this->column_default( $item, $column_name ); 969 970 echo '</td>'; 971 break; 972 } 973 } 974 } 975 976 /** 977 * @global string $status 978 * @global array $totals 979 * 980 * @param WP_Theme $theme 981 */ 982 public function single_row( $theme ) { 983 global $status, $totals; 984 985 if ( $this->is_site_themes ) { 986 $allowed = $theme->is_allowed( 'site', $this->site_id ); 987 } else { 988 $allowed = $theme->is_allowed( 'network' ); 989 } 990 991 $stylesheet = $theme->get_stylesheet(); 992 993 $class = ! $allowed ? 'inactive' : 'active'; 994 if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) ) { 995 $class .= ' update'; 996 } 997 998 printf( 999 '<tr class="%s" data-slug="%s">', 1000 esc_attr( $class ), 1001 esc_attr( $stylesheet ) 1002 ); 1003 1004 $this->single_row_columns( $theme ); 1005 1006 echo '</tr>'; 1007 1008 if ( $this->is_site_themes ) { 1009 remove_action( "after_theme_row_$stylesheet", 'wp_theme_update_row' ); 1010 } 1011 1012 /** 1013 * Fires after each row in the Multisite themes list table. 1014 * 1015 * @since 3.1.0 1016 * 1017 * @param string $stylesheet Directory name of the theme. 1018 * @param WP_Theme $theme Current WP_Theme object. 1019 * @param string $status Status of the theme. 1020 */ 1021 do_action( 'after_theme_row', $stylesheet, $theme, $status ); 1022 1023 /** 1024 * Fires after each specific row in the Multisite themes list table. 1025 * 1026 * The dynamic portion of the hook name, `$stylesheet`, refers to the 1027 * directory name of the theme, most often synonymous with the template 1028 * name of the theme. 1029 * 1030 * @since 3.5.0 1031 * 1032 * @param string $stylesheet Directory name of the theme. 1033 * @param WP_Theme $theme Current WP_Theme object. 1034 * @param string $status Status of the theme. 1035 */ 1036 do_action( "after_theme_row_{$stylesheet}", $stylesheet, $theme, $status ); 1037 } 1038 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Sat Dec 2 08:20:01 2023 | Cross-referenced by PHPXref |