| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * List Table API: WP_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 installed themes in a list table. 12 * 13 * @since 3.1.0 14 * 15 * @see WP_List_Table 16 */ 17 class WP_Themes_List_Table extends WP_List_Table { 18 19 protected $search_terms = array(); 20 public $features = array(); 21 22 /** 23 * Constructor. 24 * 25 * @since 3.1.0 26 * 27 * @see WP_List_Table::__construct() for more information on default arguments. 28 * 29 * @param array $args An associative array of arguments. 30 */ 31 public function __construct( $args = array() ) { 32 parent::__construct( 33 array( 34 'ajax' => true, 35 'screen' => $args['screen'] ?? null, 36 ) 37 ); 38 } 39 40 /** 41 * @return bool 42 */ 43 public function ajax_user_can() { 44 // Do not check edit_theme_options here. Ajax calls for available themes require switch_themes. 45 return current_user_can( 'switch_themes' ); 46 } 47 48 /** 49 */ 50 public function prepare_items() { 51 $themes = wp_get_themes( array( 'allowed' => true ) ); 52 53 if ( ! empty( $_REQUEST['s'] ) ) { 54 $this->search_terms = array_unique( array_filter( array_map( 'trim', explode( ',', strtolower( wp_unslash( $_REQUEST['s'] ) ) ) ) ) ); 55 } 56 57 if ( ! empty( $_REQUEST['features'] ) ) { 58 $this->features = $_REQUEST['features']; 59 } 60 61 if ( $this->search_terms || $this->features ) { 62 foreach ( $themes as $key => $theme ) { 63 if ( ! $this->search_theme( $theme ) ) { 64 unset( $themes[ $key ] ); 65 } 66 } 67 } 68 69 unset( $themes[ get_option( 'stylesheet' ) ] ); 70 WP_Theme::sort_by_name( $themes ); 71 72 $per_page = 36; 73 $page = $this->get_pagenum(); 74 75 $start = ( $page - 1 ) * $per_page; 76 77 $this->items = array_slice( $themes, $start, $per_page, true ); 78 79 $this->set_pagination_args( 80 array( 81 'total_items' => count( $themes ), 82 'per_page' => $per_page, 83 'infinite_scroll' => true, 84 ) 85 ); 86 } 87 88 /** 89 */ 90 public function no_items() { 91 if ( $this->search_terms || $this->features ) { 92 _e( 'No items found.' ); 93 return; 94 } 95 96 $blog_id = get_current_blog_id(); 97 if ( is_multisite() ) { 98 if ( current_user_can( 'install_themes' ) && current_user_can( 'manage_network_themes' ) ) { 99 printf( 100 /* translators: 1: URL to Themes tab on Edit Site screen, 2: URL to Add Themes screen. */ 101 __( 'You only have one theme enabled for this site right now. Visit the Network Admin to <a href="%1$s">enable</a> or <a href="%2$s">install</a> more themes.' ), 102 network_admin_url( 'site-themes.php?id=' . $blog_id ), 103 network_admin_url( 'theme-install.php' ) 104 ); 105 106 return; 107 } elseif ( current_user_can( 'manage_network_themes' ) ) { 108 printf( 109 /* translators: %s: URL to Themes tab on Edit Site screen. */ 110 __( 'You only have one theme enabled for this site right now. Visit the Network Admin to <a href="%s">enable</a> more themes.' ), 111 network_admin_url( 'site-themes.php?id=' . $blog_id ) 112 ); 113 114 return; 115 } 116 // Else, fallthrough. install_themes doesn't help if you can't enable it. 117 } else { 118 if ( current_user_can( 'install_themes' ) ) { 119 printf( 120 /* translators: %s: URL to Add Themes screen. */ 121 __( 'You only have one theme installed right now. Live a little! You can choose from over 1,000 free themes in the WordPress Theme Directory at any time: just click on the <a href="%s">Install Themes</a> tab above.' ), 122 admin_url( 'theme-install.php' ) 123 ); 124 125 return; 126 } 127 } 128 // Fallthrough. 129 printf( 130 /* translators: %s: Network title. */ 131 __( 'Only the active theme is available to you. Contact the %s administrator for information about accessing additional themes.' ), 132 get_site_option( 'site_name' ) 133 ); 134 } 135 136 /** 137 * Displays the table navigation, including the pagination. 138 * 139 * @since 3.1.0 140 * 141 * @param string $which Optional. The location of the navigation: Either 'top' or 'bottom'. 142 * Default 'top'. 143 * 144 * @phpstan-param 'top'|'bottom' $which 145 */ 146 public function tablenav( $which = 'top' ) { 147 if ( $this->get_pagination_arg( 'total_pages' ) <= 1 ) { 148 return; 149 } 150 ?> 151 <div class="tablenav themes <?php echo $which; ?>"> 152 <?php $this->pagination( $which ); ?> 153 <span class="spinner"></span> 154 <br class="clear" /> 155 </div> 156 <?php 157 } 158 159 /** 160 * Displays the themes table. 161 * 162 * Overrides the parent display() method to provide a different container. 163 * 164 * @since 3.1.0 165 */ 166 public function display() { 167 wp_nonce_field( 'fetch-list-' . get_class( $this ), '_ajax_fetch_list_nonce' ); 168 ?> 169 <?php $this->tablenav( 'top' ); ?> 170 171 <div id="availablethemes"> 172 <?php $this->display_rows_or_placeholder(); ?> 173 </div> 174 175 <?php $this->tablenav( 'bottom' ); ?> 176 <?php 177 } 178 179 /** 180 * @return string[] Array of column titles keyed by their column name. 181 */ 182 public function get_columns() { 183 return array(); 184 } 185 186 /** 187 */ 188 public function display_rows_or_placeholder() { 189 if ( $this->has_items() ) { 190 $this->display_rows(); 191 } else { 192 echo '<div class="no-items">'; 193 $this->no_items(); 194 echo '</div>'; 195 } 196 } 197 198 /** 199 * Generates the list table rows. 200 * 201 * @since 3.1.0 202 */ 203 public function display_rows() { 204 $themes = $this->items; 205 206 foreach ( $themes as $theme ) : 207 ?> 208 <div class="available-theme"> 209 <?php 210 211 $template = $theme->get_template(); 212 $stylesheet = $theme->get_stylesheet(); 213 $title = $theme->display( 'Name' ); 214 $version = $theme->display( 'Version' ); 215 $author = $theme->display( 'Author' ); 216 217 $activate_link = wp_nonce_url( 'themes.php?action=activate&template=' . urlencode( $template ) . '&stylesheet=' . urlencode( $stylesheet ), 'switch-theme_' . $stylesheet ); 218 219 $actions = array(); 220 $actions['activate'] = sprintf( 221 '<a href="%s" class="activatelink" aria-label="%s">%s</a>', 222 $activate_link, 223 /* translators: %s: Theme name. */ 224 esc_attr( sprintf( _x( 'Activate “%s”', 'theme' ), $title ) ), 225 _x( 'Activate', 'theme' ) 226 ); 227 228 if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { 229 $actions['preview'] .= sprintf( 230 '<a href="%s" class="load-customize hide-if-no-customize">%s</a>', 231 wp_customize_url( $stylesheet ), 232 __( 'Live Preview' ) 233 ); 234 } 235 236 if ( ! is_multisite() && current_user_can( 'delete_themes' ) ) { 237 $actions['delete'] = sprintf( 238 '<a class="submitdelete deletion" href="%s" onclick="return confirm( \'%s\' );">%s</a>', 239 wp_nonce_url( 'themes.php?action=delete&stylesheet=' . urlencode( $stylesheet ), 'delete-theme_' . $stylesheet ), 240 /* translators: %s: Theme name. */ 241 esc_js( sprintf( __( "You are about to delete this theme '%s'\n 'Cancel' to stop, 'OK' to delete." ), $title ) ), 242 __( 'Delete' ) 243 ); 244 } 245 246 /** This filter is documented in wp-admin/includes/class-wp-ms-themes-list-table.php */ 247 $actions = apply_filters( 'theme_action_links', $actions, $theme, 'all' ); 248 249 /** This filter is documented in wp-admin/includes/class-wp-ms-themes-list-table.php */ 250 $actions = apply_filters( "theme_action_links_{$stylesheet}", $actions, $theme, 'all' ); 251 $delete_action = isset( $actions['delete'] ) ? '<div class="delete-theme">' . $actions['delete'] . '</div>' : ''; 252 unset( $actions['delete'] ); 253 254 $screenshot = $theme->get_screenshot(); 255 ?> 256 257 <span class="screenshot hide-if-customize"> 258 <?php if ( $screenshot ) : ?> 259 <img src="<?php echo esc_url( $screenshot . '?ver=' . $theme->version ); ?>" alt="" /> 260 <?php endif; ?> 261 </span> 262 <a href="<?php echo wp_customize_url( $stylesheet ); ?>" class="screenshot load-customize hide-if-no-customize"> 263 <?php if ( $screenshot ) : ?> 264 <img src="<?php echo esc_url( $screenshot . '?ver=' . $theme->version ); ?>" alt="" /> 265 <?php endif; ?> 266 </a> 267 268 <h3><?php echo $title; ?></h3> 269 <div class="theme-author"> 270 <?php 271 /* translators: %s: Theme author. */ 272 printf( __( 'By %s' ), $author ); 273 ?> 274 </div> 275 <div class="action-links"> 276 <ul> 277 <?php foreach ( $actions as $action ) : ?> 278 <li><?php echo $action; ?></li> 279 <?php endforeach; ?> 280 <li class="hide-if-no-js"><a href="#" class="theme-detail"><?php _e( 'Details' ); ?></a></li> 281 </ul> 282 <?php echo $delete_action; ?> 283 284 <?php theme_update_available( $theme ); ?> 285 </div> 286 287 <div class="themedetaildiv hide-if-js"> 288 <p><strong><?php _e( 'Version:' ); ?></strong> <?php echo $version; ?></p> 289 <p><?php echo $theme->display( 'Description' ); ?></p> 290 <?php 291 if ( $theme->parent() ) { 292 printf( 293 /* translators: 1: Link to documentation on child themes, 2: Name of parent theme. */ 294 ' <p class="howto">' . __( 'This <a href="%1$s">child theme</a> requires its parent theme, %2$s.' ) . '</p>', 295 __( 'https://developer.wordpress.org/themes/advanced-topics/child-themes/' ), 296 $theme->parent()->display( 'Name' ) 297 ); 298 } 299 ?> 300 </div> 301 302 </div> 303 <?php 304 endforeach; 305 } 306 307 /** 308 * @param WP_Theme $theme 309 * @return bool 310 */ 311 public function search_theme( $theme ) { 312 // Search the features. 313 foreach ( $this->features as $word ) { 314 if ( ! in_array( $word, $theme->get( 'Tags' ), true ) ) { 315 return false; 316 } 317 } 318 319 // Match all phrases. 320 foreach ( $this->search_terms as $word ) { 321 if ( in_array( $word, $theme->get( 'Tags' ), true ) ) { 322 continue; 323 } 324 325 foreach ( array( 'Name', 'Description', 'Author', 'AuthorURI' ) as $header ) { 326 // Don't mark up; Do translate. 327 if ( false !== stripos( strip_tags( $theme->display( $header, false, true ) ), $word ) ) { 328 continue 2; 329 } 330 } 331 332 if ( false !== stripos( $theme->get_stylesheet(), $word ) ) { 333 continue; 334 } 335 336 if ( false !== stripos( $theme->get_template(), $word ) ) { 337 continue; 338 } 339 340 return false; 341 } 342 343 return true; 344 } 345 346 /** 347 * Send required variables to JavaScript land 348 * 349 * @since 3.4.0 350 * @since 7.2.0 Prints the script through wp_print_inline_script_tag() so it can carry 351 * attributes, such as a per-request nonce, added via wp_inline_script_attributes. 352 * 353 * @param array $extra_args 354 */ 355 public function _js_vars( $extra_args = array() ) { 356 $search_string = isset( $_REQUEST['s'] ) ? esc_attr( wp_unslash( $_REQUEST['s'] ) ) : ''; 357 358 $args = array( 359 'search' => $search_string, 360 'features' => $this->features, 361 'paged' => $this->get_pagenum(), 362 'total_pages' => ! empty( $this->_pagination_args['total_pages'] ) ? $this->_pagination_args['total_pages'] : 1, 363 ); 364 365 if ( is_array( $extra_args ) ) { 366 $args = array_merge( $args, $extra_args ); 367 } 368 369 wp_print_inline_script_tag( 370 sprintf( 'var theme_list_args = %s;', wp_json_encode( $args, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ) 371 ); 372 parent::_js_vars(); 373 } 374 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Fri Oct 16 08:20:34 2026 | Cross-referenced by PHPXref |