File manager - Edit - /home/easyfsul/theinsightreports.com/fda1d3/includes.zip
Back
PK U�g\@fN�o o ! class-wp-ms-themes-list-table.phpnu �[��� <?php /** * List Table API: WP_MS_Themes_List_Table class * * @package WordPress * @subpackage Administration * @since 3.1.0 */ /** * Core class used to implement displaying themes in a list table for the network admin. * * @since 3.1.0 * * @see WP_List_Table */ class WP_MS_Themes_List_Table extends WP_List_Table { public $site_id; public $is_site_themes; private $has_items; /** * Whether to show the auto-updates UI. * * @since 5.5.0 * * @var bool True if auto-updates UI is to be shown, false otherwise. */ protected $show_autoupdates = true; /** * Constructor. * * @since 3.1.0 * * @see WP_List_Table::__construct() for more information on default arguments. * * @global string $status * @global int $page * * @param array $args An associative array of arguments. */ public function __construct( $args = array() ) { global $status, $page; parent::__construct( array( 'plural' => 'themes', 'screen' => isset( $args['screen'] ) ? $args['screen'] : null, ) ); $status = isset( $_REQUEST['theme_status'] ) ? $_REQUEST['theme_status'] : 'all'; if ( ! in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken', 'auto-update-enabled', 'auto-update-disabled' ), true ) ) { $status = 'all'; } $page = $this->get_pagenum(); $this->is_site_themes = ( 'site-themes-network' === $this->screen->id ) ? true : false; if ( $this->is_site_themes ) { $this->site_id = isset( $_REQUEST['id'] ) ? (int) $_REQUEST['id'] : 0; } $this->show_autoupdates = wp_is_auto_update_enabled_for_type( 'theme' ) && ! $this->is_site_themes && current_user_can( 'update_themes' ); } /** * @return array */ protected function get_table_classes() { // @todo Remove and add CSS for .themes. return array( 'widefat', 'plugins' ); } /** * @return bool */ public function ajax_user_can() { if ( $this->is_site_themes ) { return current_user_can( 'manage_sites' ); } else { return current_user_can( 'manage_network_themes' ); } } /** * @global string $status * @global array $totals * @global int $page * @global string $orderby * @global string $order * @global string $s */ public function prepare_items() { global $status, $totals, $page, $orderby, $order, $s; $orderby = ! empty( $_REQUEST['orderby'] ) ? sanitize_text_field( $_REQUEST['orderby'] ) : ''; $order = ! empty( $_REQUEST['order'] ) ? sanitize_text_field( $_REQUEST['order'] ) : ''; $s = ! empty( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : ''; $themes = array( /** * Filters the full array of WP_Theme objects to list in the Multisite * themes list table. * * @since 3.1.0 * * @param WP_Theme[] $all Array of WP_Theme objects to display in the list table. */ 'all' => apply_filters( 'all_themes', wp_get_themes() ), 'search' => array(), 'enabled' => array(), 'disabled' => array(), 'upgrade' => array(), 'broken' => $this->is_site_themes ? array() : wp_get_themes( array( 'errors' => true ) ), ); if ( $this->show_autoupdates ) { $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); $themes['auto-update-enabled'] = array(); $themes['auto-update-disabled'] = array(); } if ( $this->is_site_themes ) { $themes_per_page = $this->get_items_per_page( 'site_themes_network_per_page' ); $allowed_where = 'site'; } else { $themes_per_page = $this->get_items_per_page( 'themes_network_per_page' ); $allowed_where = 'network'; } $current = get_site_transient( 'update_themes' ); $maybe_update = current_user_can( 'update_themes' ) && ! $this->is_site_themes && $current; foreach ( (array) $themes['all'] as $key => $theme ) { if ( $this->is_site_themes && $theme->is_allowed( 'network' ) ) { unset( $themes['all'][ $key ] ); continue; } if ( $maybe_update && isset( $current->response[ $key ] ) ) { $themes['all'][ $key ]->update = true; $themes['upgrade'][ $key ] = $themes['all'][ $key ]; } $filter = $theme->is_allowed( $allowed_where, $this->site_id ) ? 'enabled' : 'disabled'; $themes[ $filter ][ $key ] = $themes['all'][ $key ]; $theme_data = array( 'update_supported' => isset( $theme->update_supported ) ? $theme->update_supported : true, ); // Extra info if known. array_merge() ensures $theme_data has precedence if keys collide. if ( isset( $current->response[ $key ] ) ) { $theme_data = array_merge( (array) $current->response[ $key ], $theme_data ); } elseif ( isset( $current->no_update[ $key ] ) ) { $theme_data = array_merge( (array) $current->no_update[ $key ], $theme_data ); } else { $theme_data['update_supported'] = false; } $theme->update_supported = $theme_data['update_supported']; /* * Create the expected payload for the auto_update_theme filter, this is the same data * as contained within $updates or $no_updates but used when the Theme is not known. */ $filter_payload = array( 'theme' => $key, 'new_version' => '', 'url' => '', 'package' => '', 'requires' => '', 'requires_php' => '', ); $filter_payload = (object) array_merge( $filter_payload, array_intersect_key( $theme_data, $filter_payload ) ); $auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, $filter_payload ); if ( ! is_null( $auto_update_forced ) ) { $theme->auto_update_forced = $auto_update_forced; } if ( $this->show_autoupdates ) { $enabled = in_array( $key, $auto_updates, true ) && $theme->update_supported; if ( isset( $theme->auto_update_forced ) ) { $enabled = (bool) $theme->auto_update_forced; } if ( $enabled ) { $themes['auto-update-enabled'][ $key ] = $theme; } else { $themes['auto-update-disabled'][ $key ] = $theme; } } } if ( $s ) { $status = 'search'; $themes['search'] = array_filter( array_merge( $themes['all'], $themes['broken'] ), array( $this, '_search_callback' ) ); } $totals = array(); $js_themes = array(); foreach ( $themes as $type => $list ) { $totals[ $type ] = count( $list ); $js_themes[ $type ] = array_keys( $list ); } if ( empty( $themes[ $status ] ) && ! in_array( $status, array( 'all', 'search' ), true ) ) { $status = 'all'; } $this->items = $themes[ $status ]; WP_Theme::sort_by_name( $this->items ); $this->has_items = ! empty( $themes['all'] ); $total_this_page = $totals[ $status ]; wp_localize_script( 'updates', '_wpUpdatesItemCounts', array( 'themes' => $js_themes, 'totals' => wp_get_update_data(), ) ); if ( $orderby ) { $orderby = ucfirst( $orderby ); $order = strtoupper( $order ); if ( 'Name' === $orderby ) { if ( 'ASC' === $order ) { $this->items = array_reverse( $this->items ); } } else { uasort( $this->items, array( $this, '_order_callback' ) ); } } $start = ( $page - 1 ) * $themes_per_page; if ( $total_this_page > $themes_per_page ) { $this->items = array_slice( $this->items, $start, $themes_per_page, true ); } $this->set_pagination_args( array( 'total_items' => $total_this_page, 'per_page' => $themes_per_page, ) ); } /** * @param WP_Theme $theme * @return bool */ public function _search_callback( $theme ) { static $term = null; if ( is_null( $term ) ) { $term = wp_unslash( $_REQUEST['s'] ); } foreach ( array( 'Name', 'Description', 'Author', 'Author', 'AuthorURI' ) as $field ) { // Don't mark up; Do translate. if ( false !== stripos( $theme->display( $field, false, true ), $term ) ) { return true; } } if ( false !== stripos( $theme->get_stylesheet(), $term ) ) { return true; } if ( false !== stripos( $theme->get_template(), $term ) ) { return true; } return false; } // Not used by any core columns. /** * @global string $orderby * @global string $order * @param array $theme_a * @param array $theme_b * @return int */ public function _order_callback( $theme_a, $theme_b ) { global $orderby, $order; $a = $theme_a[ $orderby ]; $b = $theme_b[ $orderby ]; if ( $a === $b ) { return 0; } if ( 'DESC' === $order ) { return ( $a < $b ) ? 1 : -1; } else { return ( $a < $b ) ? -1 : 1; } } /** */ public function no_items() { if ( $this->has_items ) { _e( 'No themes found.' ); } else { _e( 'No themes are currently available.' ); } } /** * @return string[] Array of column titles keyed by their column name. */ public function get_columns() { $columns = array( 'cb' => '<input type="checkbox" />', 'name' => __( 'Theme' ), 'description' => __( 'Description' ), ); if ( $this->show_autoupdates ) { $columns['auto-updates'] = __( 'Automatic Updates' ); } return $columns; } /** * @return array */ protected function get_sortable_columns() { return array( 'name' => array( 'name', false, __( 'Theme' ), __( 'Table ordered by Theme Name.' ), 'asc' ), ); } /** * Gets the name of the primary column. * * @since 4.3.0 * * @return string Unalterable name of the primary column name, in this case, 'name'. */ protected function get_primary_column_name() { return 'name'; } /** * @global array $totals * @global string $status * @return array */ protected function get_views() { global $totals, $status; $status_links = array(); foreach ( $totals as $type => $count ) { if ( ! $count ) { continue; } switch ( $type ) { case 'all': /* translators: %s: Number of themes. */ $text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'themes' ); break; case 'enabled': /* translators: %s: Number of themes. */ $text = _nx( 'Enabled <span class="count">(%s)</span>', 'Enabled <span class="count">(%s)</span>', $count, 'themes' ); break; case 'disabled': /* translators: %s: Number of themes. */ $text = _nx( 'Disabled <span class="count">(%s)</span>', 'Disabled <span class="count">(%s)</span>', $count, 'themes' ); break; case 'upgrade': /* translators: %s: Number of themes. */ $text = _nx( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count, 'themes' ); break; case 'broken': /* translators: %s: Number of themes. */ $text = _nx( 'Broken <span class="count">(%s)</span>', 'Broken <span class="count">(%s)</span>', $count, 'themes' ); break; case 'auto-update-enabled': /* translators: %s: Number of themes. */ $text = _n( 'Auto-updates Enabled <span class="count">(%s)</span>', 'Auto-updates Enabled <span class="count">(%s)</span>', $count ); break; case 'auto-update-disabled': /* translators: %s: Number of themes. */ $text = _n( 'Auto-updates Disabled <span class="count">(%s)</span>', 'Auto-updates Disabled <span class="count">(%s)</span>', $count ); break; } if ( $this->is_site_themes ) { $url = 'site-themes.php?id=' . $this->site_id; } else { $url = 'themes.php'; } if ( 'search' !== $type ) { $status_links[ $type ] = array( 'url' => esc_url( add_query_arg( 'theme_status', $type, $url ) ), 'label' => sprintf( $text, number_format_i18n( $count ) ), 'current' => $type === $status, ); } } return $this->get_views_links( $status_links ); } /** * @global string $status * * @return array */ protected function get_bulk_actions() { global $status; $actions = array(); if ( 'enabled' !== $status ) { $actions['enable-selected'] = $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' ); } if ( 'disabled' !== $status ) { $actions['disable-selected'] = $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ); } if ( ! $this->is_site_themes ) { if ( current_user_can( 'update_themes' ) ) { $actions['update-selected'] = __( 'Update' ); } if ( current_user_can( 'delete_themes' ) ) { $actions['delete-selected'] = __( 'Delete' ); } } if ( $this->show_autoupdates ) { if ( 'auto-update-enabled' !== $status ) { $actions['enable-auto-update-selected'] = __( 'Enable Auto-updates' ); } if ( 'auto-update-disabled' !== $status ) { $actions['disable-auto-update-selected'] = __( 'Disable Auto-updates' ); } } return $actions; } /** * Generates the list table rows. * * @since 3.1.0 */ public function display_rows() { foreach ( $this->items as $theme ) { $this->single_row( $theme ); } } /** * Handles the checkbox column output. * * @since 4.3.0 * @since 5.9.0 Renamed `$theme` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Theme $item The current WP_Theme object. */ public function column_cb( $item ) { // Restores the more descriptive, specific name for use within this method. $theme = $item; $checkbox_id = 'checkbox_' . md5( $theme->get( 'Name' ) ); ?> <input type="checkbox" name="checked[]" value="<?php echo esc_attr( $theme->get_stylesheet() ); ?>" id="<?php echo $checkbox_id; ?>" /> <label for="<?php echo $checkbox_id; ?>" > <span class="screen-reader-text"> <?php printf( /* translators: Hidden accessibility text. %s: Theme name */ __( 'Select %s' ), $theme->display( 'Name' ) ); ?> </span> </label> <?php } /** * Handles the name column output. * * @since 4.3.0 * * @global string $status * @global int $page * @global string $s * * @param WP_Theme $theme The current WP_Theme object. */ public function column_name( $theme ) { global $status, $page, $s; $context = $status; if ( $this->is_site_themes ) { $url = "site-themes.php?id={$this->site_id}&"; $allowed = $theme->is_allowed( 'site', $this->site_id ); } else { $url = 'themes.php?'; $allowed = $theme->is_allowed( 'network' ); } // Pre-order. $actions = array( 'enable' => '', 'disable' => '', 'delete' => '', ); $stylesheet = $theme->get_stylesheet(); $theme_key = urlencode( $stylesheet ); if ( ! $allowed ) { if ( ! $theme->errors() ) { $url = add_query_arg( array( 'action' => 'enable', 'theme' => $theme_key, 'paged' => $page, 's' => $s, ), $url ); if ( $this->is_site_themes ) { /* translators: %s: Theme name. */ $aria_label = sprintf( __( 'Enable %s' ), $theme->display( 'Name' ) ); } else { /* translators: %s: Theme name. */ $aria_label = sprintf( __( 'Network Enable %s' ), $theme->display( 'Name' ) ); } $actions['enable'] = sprintf( '<a href="%s" class="edit" aria-label="%s">%s</a>', esc_url( wp_nonce_url( $url, 'enable-theme_' . $stylesheet ) ), esc_attr( $aria_label ), ( $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' ) ) ); } } else { $url = add_query_arg( array( 'action' => 'disable', 'theme' => $theme_key, 'paged' => $page, 's' => $s, ), $url ); if ( $this->is_site_themes ) { /* translators: %s: Theme name. */ $aria_label = sprintf( __( 'Disable %s' ), $theme->display( 'Name' ) ); } else { /* translators: %s: Theme name. */ $aria_label = sprintf( __( 'Network Disable %s' ), $theme->display( 'Name' ) ); } $actions['disable'] = sprintf( '<a href="%s" aria-label="%s">%s</a>', esc_url( wp_nonce_url( $url, 'disable-theme_' . $stylesheet ) ), esc_attr( $aria_label ), ( $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ) ) ); } if ( ! $allowed && ! $this->is_site_themes && current_user_can( 'delete_themes' ) && get_option( 'stylesheet' ) !== $stylesheet && get_option( 'template' ) !== $stylesheet ) { $url = add_query_arg( array( 'action' => 'delete-selected', 'checked[]' => $theme_key, 'theme_status' => $context, 'paged' => $page, 's' => $s, ), 'themes.php' ); /* translators: %s: Theme name. */ $aria_label = sprintf( _x( 'Delete %s', 'theme' ), $theme->display( 'Name' ) ); $actions['delete'] = sprintf( '<a href="%s" class="delete" aria-label="%s">%s</a>', esc_url( wp_nonce_url( $url, 'bulk-themes' ) ), esc_attr( $aria_label ), __( 'Delete' ) ); } /** * Filters the action links displayed for each theme in the Multisite * themes list table. * * The action links displayed are determined by the theme's status, and * which Multisite themes list table is being displayed - the Network * themes list table (themes.php), which displays all installed themes, * or the Site themes list table (site-themes.php), which displays the * non-network enabled themes when editing a site in the Network admin. * * The default action links for the Network themes list table include * 'Network Enable', 'Network Disable', and 'Delete'. * * The default action links for the Site themes list table include * 'Enable', and 'Disable'. * * @since 2.8.0 * * @param string[] $actions An array of action links. * @param WP_Theme $theme The current WP_Theme object. * @param string $context Status of the theme, one of 'all', 'enabled', or 'disabled'. */ $actions = apply_filters( 'theme_action_links', array_filter( $actions ), $theme, $context ); /** * Filters the action links of a specific theme in the Multisite themes * list table. * * The dynamic portion of the hook name, `$stylesheet`, refers to the * directory name of the theme, which in most cases is synonymous * with the template name. * * @since 3.1.0 * * @param string[] $actions An array of action links. * @param WP_Theme $theme The current WP_Theme object. * @param string $context Status of the theme, one of 'all', 'enabled', or 'disabled'. */ $actions = apply_filters( "theme_action_links_{$stylesheet}", $actions, $theme, $context ); echo $this->row_actions( $actions, true ); } /** * Handles the description column output. * * @since 4.3.0 * * @global string $status * @global array $totals * * @param WP_Theme $theme The current WP_Theme object. */ public function column_description( $theme ) { global $status, $totals; if ( $theme->errors() ) { $pre = 'broken' === $status ? '<strong class="error-message">' . __( 'Broken Theme:' ) . '</strong> ' : ''; wp_admin_notice( $pre . $theme->errors()->get_error_message(), array( 'type' => 'error', 'additional_classes' => 'inline', ) ); } if ( $this->is_site_themes ) { $allowed = $theme->is_allowed( 'site', $this->site_id ); } else { $allowed = $theme->is_allowed( 'network' ); } $class = ! $allowed ? 'inactive' : 'active'; if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) ) { $class .= ' update'; } echo "<div class='theme-description'><p>" . $theme->display( 'Description' ) . "</p></div> <div class='$class second theme-version-author-uri'>"; $stylesheet = $theme->get_stylesheet(); $theme_meta = array(); if ( $theme->get( 'Version' ) ) { /* translators: %s: Theme version. */ $theme_meta[] = sprintf( __( 'Version %s' ), $theme->display( 'Version' ) ); } /* translators: %s: Theme author. */ $theme_meta[] = sprintf( __( 'By %s' ), $theme->display( 'Author' ) ); if ( $theme->get( 'ThemeURI' ) ) { /* translators: %s: Theme name. */ $aria_label = sprintf( __( 'Visit theme site for %s' ), $theme->display( 'Name' ) ); $theme_meta[] = sprintf( '<a href="%s" aria-label="%s">%s</a>', $theme->display( 'ThemeURI' ), esc_attr( $aria_label ), __( 'Visit Theme Site' ) ); } if ( $theme->parent() ) { $theme_meta[] = sprintf( /* translators: %s: Theme name. */ __( 'Child theme of %s' ), '<strong>' . $theme->parent()->display( 'Name' ) . '</strong>' ); } /** * Filters the array of row meta for each theme in the Multisite themes * list table. * * @since 3.1.0 * * @param string[] $theme_meta An array of the theme's metadata, including * the version, author, and theme URI. * @param string $stylesheet Directory name of the theme. * @param WP_Theme $theme WP_Theme object. * @param string $status Status of the theme. */ $theme_meta = apply_filters( 'theme_row_meta', $theme_meta, $stylesheet, $theme, $status ); echo implode( ' | ', $theme_meta ); echo '</div>'; } /** * Handles the auto-updates column output. * * @since 5.5.0 * * @global string $status * @global int $page * * @param WP_Theme $theme The current WP_Theme object. */ public function column_autoupdates( $theme ) { global $status, $page; static $auto_updates, $available_updates; if ( ! $auto_updates ) { $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); } if ( ! $available_updates ) { $available_updates = get_site_transient( 'update_themes' ); } $stylesheet = $theme->get_stylesheet(); if ( isset( $theme->auto_update_forced ) ) { if ( $theme->auto_update_forced ) { // Forced on. $text = __( 'Auto-updates enabled' ); } else { $text = __( 'Auto-updates disabled' ); } $action = 'unavailable'; $time_class = ' hidden'; } elseif ( empty( $theme->update_supported ) ) { $text = ''; $action = 'unavailable'; $time_class = ' hidden'; } elseif ( in_array( $stylesheet, $auto_updates, true ) ) { $text = __( 'Disable auto-updates' ); $action = 'disable'; $time_class = ''; } else { $text = __( 'Enable auto-updates' ); $action = 'enable'; $time_class = ' hidden'; } $query_args = array( 'action' => "{$action}-auto-update", 'theme' => $stylesheet, 'paged' => $page, 'theme_status' => $status, ); $url = add_query_arg( $query_args, 'themes.php' ); if ( 'unavailable' === $action ) { $html[] = '<span class="label">' . $text . '</span>'; } else { $html[] = sprintf( '<a href="%s" class="toggle-auto-update aria-button-if-js" data-wp-action="%s">', wp_nonce_url( $url, 'updates' ), $action ); $html[] = '<span class="dashicons dashicons-update spin hidden" aria-hidden="true"></span>'; $html[] = '<span class="label">' . $text . '</span>'; $html[] = '</a>'; } if ( isset( $available_updates->response[ $stylesheet ] ) ) { $html[] = sprintf( '<div class="auto-update-time%s">%s</div>', $time_class, wp_get_auto_update_message() ); } $html = implode( '', $html ); /** * Filters the HTML of the auto-updates setting for each theme in the Themes list table. * * @since 5.5.0 * * @param string $html The HTML for theme's auto-update setting, including * toggle auto-update action link and time to next update. * @param string $stylesheet Directory name of the theme. * @param WP_Theme $theme WP_Theme object. */ echo apply_filters( 'theme_auto_update_setting_html', $html, $stylesheet, $theme ); wp_admin_notice( '', array( 'type' => 'error', 'additional_classes' => array( 'notice-alt', 'inline', 'hidden' ), ) ); } /** * Handles default column output. * * @since 4.3.0 * @since 5.9.0 Renamed `$theme` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Theme $item The current WP_Theme object. * @param string $column_name The current column name. */ public function column_default( $item, $column_name ) { // Restores the more descriptive, specific name for use within this method. $theme = $item; $stylesheet = $theme->get_stylesheet(); /** * Fires inside each custom column of the Multisite themes list table. * * @since 3.1.0 * * @param string $column_name Name of the column. * @param string $stylesheet Directory name of the theme. * @param WP_Theme $theme Current WP_Theme object. */ do_action( 'manage_themes_custom_column', $column_name, $stylesheet, $theme ); } /** * Handles the output for a single table row. * * @since 4.3.0 * * @param WP_Theme $item The current WP_Theme object. */ public function single_row_columns( $item ) { list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info(); foreach ( $columns as $column_name => $column_display_name ) { $extra_classes = ''; if ( in_array( $column_name, $hidden, true ) ) { $extra_classes .= ' hidden'; } switch ( $column_name ) { case 'cb': echo '<th scope="row" class="check-column">'; $this->column_cb( $item ); echo '</th>'; break; case 'name': $active_theme_label = ''; /* 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 */ if ( ! empty( $this->site_id ) ) { $stylesheet = get_blog_option( $this->site_id, 'stylesheet' ); $template = get_blog_option( $this->site_id, 'template' ); /* Add a label for the active template */ if ( $item->get_template() === $template ) { $active_theme_label = ' — ' . __( 'Active Theme' ); } /* In case this is a child theme, label it properly */ if ( $stylesheet !== $template && $item->get_stylesheet() === $stylesheet ) { $active_theme_label = ' — ' . __( 'Active Child Theme' ); } } echo "<td class='theme-title column-primary{$extra_classes}'><strong>" . $item->display( 'Name' ) . $active_theme_label . '</strong>'; $this->column_name( $item ); echo '</td>'; break; case 'description': echo "<td class='column-description desc{$extra_classes}'>"; $this->column_description( $item ); echo '</td>'; break; case 'auto-updates': echo "<td class='column-auto-updates{$extra_classes}'>"; $this->column_autoupdates( $item ); echo '</td>'; break; default: echo "<td class='$column_name column-$column_name{$extra_classes}'>"; $this->column_default( $item, $column_name ); echo '</td>'; break; } } } /** * @global string $status * @global array $totals * * @param WP_Theme $theme */ public function single_row( $theme ) { global $status, $totals; if ( $this->is_site_themes ) { $allowed = $theme->is_allowed( 'site', $this->site_id ); } else { $allowed = $theme->is_allowed( 'network' ); } $stylesheet = $theme->get_stylesheet(); $class = ! $allowed ? 'inactive' : 'active'; if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) ) { $class .= ' update'; } printf( '<tr class="%s" data-slug="%s">', esc_attr( $class ), esc_attr( $stylesheet ) ); $this->single_row_columns( $theme ); echo '</tr>'; if ( $this->is_site_themes ) { remove_action( "after_theme_row_$stylesheet", 'wp_theme_update_row' ); } /** * Fires after each row in the Multisite themes list table. * * @since 3.1.0 * * @param string $stylesheet Directory name of the theme. * @param WP_Theme $theme Current WP_Theme object. * @param string $status Status of the theme. */ do_action( 'after_theme_row', $stylesheet, $theme, $status ); /** * Fires after each specific row in the Multisite themes list table. * * The dynamic portion of the hook name, `$stylesheet`, refers to the * directory name of the theme, most often synonymous with the template * name of the theme. * * @since 3.5.0 * * @param string $stylesheet Directory name of the theme. * @param WP_Theme $theme Current WP_Theme object. * @param string $status Status of the theme. */ do_action( "after_theme_row_{$stylesheet}", $stylesheet, $theme, $status ); } } PK U�g\�l�6 6 % class-language-pack-upgrader-skin.phpnu �[��� <?php /** * Upgrader API: Language_Pack_Upgrader_Skin class * * @package WordPress * @subpackage Upgrader * @since 4.6.0 */ /** * Translation Upgrader Skin for WordPress Translation Upgrades. * * @since 3.7.0 * @since 4.6.0 Moved to its own file from wp-admin/includes/class-wp-upgrader-skins.php. * * @see WP_Upgrader_Skin */ class Language_Pack_Upgrader_Skin extends WP_Upgrader_Skin { public $language_update = null; public $done_header = false; public $done_footer = false; public $display_footer_actions = true; /** * Constructor. * * Sets up the language pack upgrader skin. * * @since 3.7.0 * * @param array $args */ public function __construct( $args = array() ) { $defaults = array( 'url' => '', 'nonce' => '', 'title' => __( 'Update Translations' ), 'skip_header_footer' => false, ); $args = wp_parse_args( $args, $defaults ); if ( $args['skip_header_footer'] ) { $this->done_header = true; $this->done_footer = true; $this->display_footer_actions = false; } parent::__construct( $args ); } /** * Performs an action before a language pack update. * * @since 3.7.0 */ public function before() { $name = $this->upgrader->get_name_for_update( $this->language_update ); echo '<div class="update-messages lp-show-latest">'; /* translators: 1: Project name (plugin, theme, or WordPress), 2: Language. */ printf( '<h2>' . __( 'Updating translations for %1$s (%2$s)…' ) . '</h2>', $name, $this->language_update->language ); } /** * Displays an error message about the update. * * @since 3.7.0 * @since 5.9.0 Renamed `$error` to `$errors` for PHP 8 named parameter support. * * @param string|WP_Error $errors Errors. */ public function error( $errors ) { echo '<div class="lp-error">'; parent::error( $errors ); echo '</div>'; } /** * Performs an action following a language pack update. * * @since 3.7.0 */ public function after() { echo '</div>'; } /** * Displays the footer following the bulk update process. * * @since 3.7.0 */ public function bulk_footer() { $this->decrement_update_count( 'translation' ); $update_actions = array( 'updates_page' => sprintf( '<a href="%s" target="_parent">%s</a>', self_admin_url( 'update-core.php' ), __( 'Go to WordPress Updates page' ) ), ); /** * Filters the list of action links available following a translations update. * * @since 3.7.0 * * @param string[] $update_actions Array of translations update links. */ $update_actions = apply_filters( 'update_translations_complete_actions', $update_actions ); if ( $update_actions && $this->display_footer_actions ) { $this->feedback( implode( ' | ', $update_actions ) ); } } } PK U�g\qH��� � class-wp-screen.phpnu �[��� <?php /** * Screen API: WP_Screen class * * @package WordPress * @subpackage Administration * @since 4.4.0 */ /** * Core class used to implement an admin screen API. * * @since 3.3.0 */ #[AllowDynamicProperties] final class WP_Screen { /** * Any action associated with the screen. * * 'add' for *-add.php and *-new.php screens. Empty otherwise. * * @since 3.3.0 * @var string */ public $action; /** * The base type of the screen. * * This is typically the same as `$id` but with any post types and taxonomies stripped. * For example, for an `$id` of 'edit-post' the base is 'edit'. * * @since 3.3.0 * @var string */ public $base; /** * The number of columns to display. Access with get_columns(). * * @since 3.4.0 * @var int */ private $columns = 0; /** * The unique ID of the screen. * * @since 3.3.0 * @var string */ public $id; /** * Which admin the screen is in. network | user | site | false * * @since 3.5.0 * @var string */ protected $in_admin; /** * Whether the screen is in the network admin. * * Deprecated. Use in_admin() instead. * * @since 3.3.0 * @deprecated 3.5.0 * @var bool */ public $is_network; /** * Whether the screen is in the user admin. * * Deprecated. Use in_admin() instead. * * @since 3.3.0 * @deprecated 3.5.0 * @var bool */ public $is_user; /** * The base menu parent. * * This is derived from `$parent_file` by removing the query string and any .php extension. * `$parent_file` values of 'edit.php?post_type=page' and 'edit.php?post_type=post' * have a `$parent_base` of 'edit'. * * @since 3.3.0 * @var string|null */ public $parent_base; /** * The parent_file for the screen per the admin menu system. * * Some `$parent_file` values are 'edit.php?post_type=page', 'edit.php', and 'options-general.php'. * * @since 3.3.0 * @var string|null */ public $parent_file; /** * The post type associated with the screen, if any. * * The 'edit.php?post_type=page' screen has a post type of 'page'. * The 'edit-tags.php?taxonomy=$taxonomy&post_type=page' screen has a post type of 'page'. * * @since 3.3.0 * @var string */ public $post_type; /** * The taxonomy associated with the screen, if any. * * The 'edit-tags.php?taxonomy=category' screen has a taxonomy of 'category'. * * @since 3.3.0 * @var string */ public $taxonomy; /** * The help tab data associated with the screen, if any. * * @since 3.3.0 * @var array */ private $_help_tabs = array(); /** * The help sidebar data associated with screen, if any. * * @since 3.3.0 * @var string */ private $_help_sidebar = ''; /** * The accessible hidden headings and text associated with the screen, if any. * * @since 4.4.0 * @var string[] */ private $_screen_reader_content = array(); /** * Stores old string-based help. * * @var array */ private static $_old_compat_help = array(); /** * The screen options associated with screen, if any. * * @since 3.3.0 * @var array */ private $_options = array(); /** * The screen object registry. * * @since 3.3.0 * * @var array */ private static $_registry = array(); /** * Stores the result of the public show_screen_options function. * * @since 3.3.0 * @var bool */ private $_show_screen_options; /** * Stores the 'screen_settings' section of screen options. * * @since 3.3.0 * @var string */ private $_screen_settings; /** * Whether the screen is using the block editor. * * @since 5.0.0 * @var bool */ public $is_block_editor = false; /** * Fetches a screen object. * * @since 3.3.0 * * @global string $hook_suffix * * @param string|WP_Screen $hook_name Optional. The hook name (also known as the hook suffix) used to determine the screen. * Defaults to the current $hook_suffix global. * @return WP_Screen Screen object. */ public static function get( $hook_name = '' ) { if ( $hook_name instanceof WP_Screen ) { return $hook_name; } $id = ''; $post_type = null; $taxonomy = null; $in_admin = false; $action = ''; $is_block_editor = false; if ( $hook_name ) { $id = $hook_name; } elseif ( ! empty( $GLOBALS['hook_suffix'] ) ) { $id = $GLOBALS['hook_suffix']; } // For those pesky meta boxes. if ( $hook_name && post_type_exists( $hook_name ) ) { $post_type = $id; $id = 'post'; // Changes later. Ends up being $base. } else { if ( str_ends_with( $id, '.php' ) ) { $id = substr( $id, 0, -4 ); } if ( in_array( $id, array( 'post-new', 'link-add', 'media-new', 'user-new' ), true ) ) { $id = substr( $id, 0, -4 ); $action = 'add'; } } if ( ! $post_type && $hook_name ) { if ( str_ends_with( $id, '-network' ) ) { $id = substr( $id, 0, -8 ); $in_admin = 'network'; } elseif ( str_ends_with( $id, '-user' ) ) { $id = substr( $id, 0, -5 ); $in_admin = 'user'; } $id = sanitize_key( $id ); if ( 'edit-comments' !== $id && 'edit-tags' !== $id && str_starts_with( $id, 'edit-' ) ) { $maybe = substr( $id, 5 ); if ( taxonomy_exists( $maybe ) ) { $id = 'edit-tags'; $taxonomy = $maybe; } elseif ( post_type_exists( $maybe ) ) { $id = 'edit'; $post_type = $maybe; } } if ( ! $in_admin ) { $in_admin = 'site'; } } else { if ( defined( 'WP_NETWORK_ADMIN' ) && WP_NETWORK_ADMIN ) { $in_admin = 'network'; } elseif ( defined( 'WP_USER_ADMIN' ) && WP_USER_ADMIN ) { $in_admin = 'user'; } else { $in_admin = 'site'; } } if ( 'index' === $id ) { $id = 'dashboard'; } elseif ( 'front' === $id ) { $in_admin = false; } $base = $id; // If this is the current screen, see if we can be more accurate for post types and taxonomies. if ( ! $hook_name ) { if ( isset( $_REQUEST['post_type'] ) ) { $post_type = post_type_exists( $_REQUEST['post_type'] ) ? $_REQUEST['post_type'] : false; } if ( isset( $_REQUEST['taxonomy'] ) ) { $taxonomy = taxonomy_exists( $_REQUEST['taxonomy'] ) ? $_REQUEST['taxonomy'] : false; } switch ( $base ) { case 'post': if ( isset( $_GET['post'] ) && isset( $_POST['post_ID'] ) && (int) $_GET['post'] !== (int) $_POST['post_ID'] ) { wp_die( __( 'A post ID mismatch has been detected.' ), __( 'Sorry, you are not allowed to edit this item.' ), 400 ); } elseif ( isset( $_GET['post'] ) ) { $post_id = (int) $_GET['post']; } elseif ( isset( $_POST['post_ID'] ) ) { $post_id = (int) $_POST['post_ID']; } else { $post_id = 0; } if ( $post_id ) { $post = get_post( $post_id ); if ( $post ) { $post_type = $post->post_type; /** This filter is documented in wp-admin/post.php */ $replace_editor = apply_filters( 'replace_editor', false, $post ); if ( ! $replace_editor ) { $is_block_editor = use_block_editor_for_post( $post ); } } } break; case 'edit-tags': case 'term': if ( null === $post_type && is_object_in_taxonomy( 'post', $taxonomy ? $taxonomy : 'post_tag' ) ) { $post_type = 'post'; } break; case 'upload': $post_type = 'attachment'; break; } } switch ( $base ) { case 'post': if ( null === $post_type ) { $post_type = 'post'; } // When creating a new post, use the default block editor support value for the post type. if ( empty( $post_id ) ) { $is_block_editor = use_block_editor_for_post_type( $post_type ); } $id = $post_type; break; case 'edit': if ( null === $post_type ) { $post_type = 'post'; } $id .= '-' . $post_type; break; case 'edit-tags': case 'term': if ( null === $taxonomy ) { $taxonomy = 'post_tag'; } // The edit-tags ID does not contain the post type. Look for it in the request. if ( null === $post_type ) { $post_type = 'post'; if ( isset( $_REQUEST['post_type'] ) && post_type_exists( $_REQUEST['post_type'] ) ) { $post_type = $_REQUEST['post_type']; } } $id = 'edit-' . $taxonomy; break; } if ( 'network' === $in_admin ) { $id .= '-network'; $base .= '-network'; } elseif ( 'user' === $in_admin ) { $id .= '-user'; $base .= '-user'; } if ( isset( self::$_registry[ $id ] ) ) { $screen = self::$_registry[ $id ]; if ( get_current_screen() === $screen ) { return $screen; } } else { $screen = new self(); $screen->id = $id; } $screen->base = $base; $screen->action = $action; $screen->post_type = (string) $post_type; $screen->taxonomy = (string) $taxonomy; $screen->is_user = ( 'user' === $in_admin ); $screen->is_network = ( 'network' === $in_admin ); $screen->in_admin = $in_admin; $screen->is_block_editor = $is_block_editor; self::$_registry[ $id ] = $screen; return $screen; } /** * Makes the screen object the current screen. * * @see set_current_screen() * @since 3.3.0 * * @global WP_Screen $current_screen WordPress current screen object. * @global string $typenow The post type of the current screen. * @global string $taxnow The taxonomy of the current screen. */ public function set_current_screen() { global $current_screen, $taxnow, $typenow; $current_screen = $this; $typenow = $this->post_type; $taxnow = $this->taxonomy; /** * Fires after the current screen has been set. * * @since 3.0.0 * * @param WP_Screen $current_screen Current WP_Screen object. */ do_action( 'current_screen', $current_screen ); } /** * Constructor * * @since 3.3.0 */ private function __construct() {} /** * Indicates whether the screen is in a particular admin. * * @since 3.5.0 * * @param string $admin The admin to check against (network | user | site). * If empty any of the three admins will result in true. * @return bool True if the screen is in the indicated admin, false otherwise. */ public function in_admin( $admin = null ) { if ( empty( $admin ) ) { return (bool) $this->in_admin; } return ( $admin === $this->in_admin ); } /** * Sets or returns whether the block editor is loading on the current screen. * * @since 5.0.0 * * @param bool $set Optional. Sets whether the block editor is loading on the current screen or not. * @return bool True if the block editor is being loaded, false otherwise. */ public function is_block_editor( $set = null ) { if ( null !== $set ) { $this->is_block_editor = (bool) $set; } return $this->is_block_editor; } /** * Sets the old string-based contextual help for the screen for backward compatibility. * * @since 3.3.0 * * @param WP_Screen $screen A screen object. * @param string $help Help text. */ public static function add_old_compat_help( $screen, $help ) { self::$_old_compat_help[ $screen->id ] = $help; } /** * Sets the parent information for the screen. * * This is called in admin-header.php after the menu parent for the screen has been determined. * * @since 3.3.0 * * @param string $parent_file The parent file of the screen. Typically the $parent_file global. */ public function set_parentage( $parent_file ) { $this->parent_file = $parent_file; list( $this->parent_base ) = explode( '?', $parent_file ); $this->parent_base = str_replace( '.php', '', $this->parent_base ); } /** * Adds an option for the screen. * * Call this in template files after admin.php is loaded and before admin-header.php is loaded * to add screen options. * * @since 3.3.0 * * @param string $option Option ID. * @param mixed $args Option-dependent arguments. */ public function add_option( $option, $args = array() ) { $this->_options[ $option ] = $args; } /** * Removes an option from the screen. * * @since 3.8.0 * * @param string $option Option ID. */ public function remove_option( $option ) { unset( $this->_options[ $option ] ); } /** * Removes all options from the screen. * * @since 3.8.0 */ public function remove_options() { $this->_options = array(); } /** * Gets the options registered for the screen. * * @since 3.8.0 * * @return array Options with arguments. */ public function get_options() { return $this->_options; } /** * Gets the arguments for an option for the screen. * * @since 3.3.0 * * @param string $option Option name. * @param string|false $key Optional. Specific array key for when the option is an array. * Default false. * @return string The option value if set, null otherwise. */ public function get_option( $option, $key = false ) { if ( ! isset( $this->_options[ $option ] ) ) { return null; } if ( $key ) { if ( isset( $this->_options[ $option ][ $key ] ) ) { return $this->_options[ $option ][ $key ]; } return null; } return $this->_options[ $option ]; } /** * Gets the help tabs registered for the screen. * * @since 3.4.0 * @since 4.4.0 Help tabs are ordered by their priority. * * @return array Help tabs with arguments. */ public function get_help_tabs() { $help_tabs = $this->_help_tabs; $priorities = array(); foreach ( $help_tabs as $help_tab ) { if ( isset( $priorities[ $help_tab['priority'] ] ) ) { $priorities[ $help_tab['priority'] ][] = $help_tab; } else { $priorities[ $help_tab['priority'] ] = array( $help_tab ); } } ksort( $priorities ); $sorted = array(); foreach ( $priorities as $list ) { foreach ( $list as $tab ) { $sorted[ $tab['id'] ] = $tab; } } return $sorted; } /** * Gets the arguments for a help tab. * * @since 3.4.0 * * @param string $id Help Tab ID. * @return array Help tab arguments. */ public function get_help_tab( $id ) { if ( ! isset( $this->_help_tabs[ $id ] ) ) { return null; } return $this->_help_tabs[ $id ]; } /** * Adds a help tab to the contextual help for the screen. * * Call this on the `load-$pagenow` hook for the relevant screen, * or fetch the `$current_screen` object, or use get_current_screen() * and then call the method from the object. * * You may need to filter `$current_screen` using an if or switch statement * to prevent new help tabs from being added to ALL admin screens. * * @since 3.3.0 * @since 4.4.0 The `$priority` argument was added. * * @param array $args { * Array of arguments used to display the help tab. * * @type string $title Title for the tab. Default false. * @type string $id Tab ID. Must be HTML-safe and should be unique for this menu. * It is NOT allowed to contain any empty spaces. Default false. * @type string $content Optional. Help tab content in plain text or HTML. Default empty string. * @type callable $callback Optional. A callback to generate the tab content. Default false. * @type int $priority Optional. The priority of the tab, used for ordering. Default 10. * } */ public function add_help_tab( $args ) { $defaults = array( 'title' => false, 'id' => false, 'content' => '', 'callback' => false, 'priority' => 10, ); $args = wp_parse_args( $args, $defaults ); $args['id'] = sanitize_html_class( $args['id'] ); // Ensure we have an ID and title. if ( ! $args['id'] || ! $args['title'] ) { return; } // Allows for overriding an existing tab with that ID. $this->_help_tabs[ $args['id'] ] = $args; } /** * Removes a help tab from the contextual help for the screen. * * @since 3.3.0 * * @param string $id The help tab ID. */ public function remove_help_tab( $id ) { unset( $this->_help_tabs[ $id ] ); } /** * Removes all help tabs from the contextual help for the screen. * * @since 3.3.0 */ public function remove_help_tabs() { $this->_help_tabs = array(); } /** * Gets the content from a contextual help sidebar. * * @since 3.4.0 * * @return string Contents of the help sidebar. */ public function get_help_sidebar() { return $this->_help_sidebar; } /** * Adds a sidebar to the contextual help for the screen. * * Call this in template files after admin.php is loaded and before admin-header.php is loaded * to add a sidebar to the contextual help. * * @since 3.3.0 * * @param string $content Sidebar content in plain text or HTML. */ public function set_help_sidebar( $content ) { $this->_help_sidebar = $content; } /** * Gets the number of layout columns the user has selected. * * The layout_columns option controls the max number and default number of * columns. This method returns the number of columns within that range selected * by the user via Screen Options. If no selection has been made, the default * provisioned in layout_columns is returned. If the screen does not support * selecting the number of layout columns, 0 is returned. * * @since 3.4.0 * * @return int Number of columns to display. */ public function get_columns() { return $this->columns; } /** * Gets the accessible hidden headings and text used in the screen. * * @since 4.4.0 * * @see set_screen_reader_content() For more information on the array format. * * @return string[] An associative array of screen reader text strings. */ public function get_screen_reader_content() { return $this->_screen_reader_content; } /** * Gets a screen reader text string. * * @since 4.4.0 * * @param string $key Screen reader text array named key. * @return string Screen reader text string. */ public function get_screen_reader_text( $key ) { if ( ! isset( $this->_screen_reader_content[ $key ] ) ) { return null; } return $this->_screen_reader_content[ $key ]; } /** * Adds accessible hidden headings and text for the screen. * * @since 4.4.0 * * @param array $content { * An associative array of screen reader text strings. * * @type string $heading_views Screen reader text for the filter links heading. * Default 'Filter items list'. * @type string $heading_pagination Screen reader text for the pagination heading. * Default 'Items list navigation'. * @type string $heading_list Screen reader text for the items list heading. * Default 'Items list'. * } */ public function set_screen_reader_content( $content = array() ) { $defaults = array( 'heading_views' => __( 'Filter items list' ), 'heading_pagination' => __( 'Items list navigation' ), 'heading_list' => __( 'Items list' ), ); $content = wp_parse_args( $content, $defaults ); $this->_screen_reader_content = $content; } /** * Removes all the accessible hidden headings and text for the screen. * * @since 4.4.0 */ public function remove_screen_reader_content() { $this->_screen_reader_content = array(); } /** * Renders the screen's help section. * * This will trigger the deprecated filters for backward compatibility. * * @since 3.3.0 * * @global string $screen_layout_columns */ public function render_screen_meta() { /** * Filters the legacy contextual help list. * * @since 2.7.0 * @deprecated 3.3.0 Use {@see get_current_screen()->add_help_tab()} or * {@see get_current_screen()->remove_help_tab()} instead. * * @param array $old_compat_help Old contextual help. * @param WP_Screen $screen Current WP_Screen instance. */ self::$_old_compat_help = apply_filters_deprecated( 'contextual_help_list', array( self::$_old_compat_help, $this ), '3.3.0', 'get_current_screen()->add_help_tab(), get_current_screen()->remove_help_tab()' ); $old_help = isset( self::$_old_compat_help[ $this->id ] ) ? self::$_old_compat_help[ $this->id ] : ''; /** * Filters the legacy contextual help text. * * @since 2.7.0 * @deprecated 3.3.0 Use {@see get_current_screen()->add_help_tab()} or * {@see get_current_screen()->remove_help_tab()} instead. * * @param string $old_help Help text that appears on the screen. * @param string $screen_id Screen ID. * @param WP_Screen $screen Current WP_Screen instance. */ $old_help = apply_filters_deprecated( 'contextual_help', array( $old_help, $this->id, $this ), '3.3.0', 'get_current_screen()->add_help_tab(), get_current_screen()->remove_help_tab()' ); // Default help only if there is no old-style block of text and no new-style help tabs. if ( empty( $old_help ) && ! $this->get_help_tabs() ) { /** * Filters the default legacy contextual help text. * * @since 2.8.0 * @deprecated 3.3.0 Use {@see get_current_screen()->add_help_tab()} or * {@see get_current_screen()->remove_help_tab()} instead. * * @param string $old_help_default Default contextual help text. */ $default_help = apply_filters_deprecated( 'default_contextual_help', array( '' ), '3.3.0', 'get_current_screen()->add_help_tab(), get_current_screen()->remove_help_tab()' ); if ( $default_help ) { $old_help = '<p>' . $default_help . '</p>'; } } if ( $old_help ) { $this->add_help_tab( array( 'id' => 'old-contextual-help', 'title' => __( 'Overview' ), 'content' => $old_help, ) ); } $help_sidebar = $this->get_help_sidebar(); $help_class = 'hidden'; if ( ! $help_sidebar ) { $help_class .= ' no-sidebar'; } // Time to render! ?> <div id="screen-meta" class="metabox-prefs"> <div id="contextual-help-wrap" class="<?php echo esc_attr( $help_class ); ?>" tabindex="-1" aria-label="<?php esc_attr_e( 'Contextual Help Tab' ); ?>"> <div id="contextual-help-back"></div> <div id="contextual-help-columns"> <div class="contextual-help-tabs"> <ul> <?php $class = ' class="active"'; foreach ( $this->get_help_tabs() as $tab ) : $link_id = "tab-link-{$tab['id']}"; $panel_id = "tab-panel-{$tab['id']}"; ?> <li id="<?php echo esc_attr( $link_id ); ?>"<?php echo $class; ?>> <a href="<?php echo esc_url( "#$panel_id" ); ?>" aria-controls="<?php echo esc_attr( $panel_id ); ?>"> <?php echo esc_html( $tab['title'] ); ?> </a> </li> <?php $class = ''; endforeach; ?> </ul> </div> <?php if ( $help_sidebar ) : ?> <div class="contextual-help-sidebar"> <?php echo $help_sidebar; ?> </div> <?php endif; ?> <div class="contextual-help-tabs-wrap"> <?php $classes = 'help-tab-content active'; foreach ( $this->get_help_tabs() as $tab ) : $panel_id = "tab-panel-{$tab['id']}"; ?> <div id="<?php echo esc_attr( $panel_id ); ?>" class="<?php echo $classes; ?>"> <?php // Print tab content. echo $tab['content']; // If it exists, fire tab callback. if ( ! empty( $tab['callback'] ) ) { call_user_func_array( $tab['callback'], array( $this, $tab ) ); } ?> </div> <?php $classes = 'help-tab-content'; endforeach; ?> </div> </div> </div> <?php // Setup layout columns. /** * Filters the array of screen layout columns. * * This hook provides back-compat for plugins using the back-compat * Filters instead of add_screen_option(). * * @since 2.8.0 * * @param array $empty_columns Empty array. * @param string $screen_id Screen ID. * @param WP_Screen $screen Current WP_Screen instance. */ $columns = apply_filters( 'screen_layout_columns', array(), $this->id, $this ); if ( ! empty( $columns ) && isset( $columns[ $this->id ] ) ) { $this->add_option( 'layout_columns', array( 'max' => $columns[ $this->id ] ) ); } if ( $this->get_option( 'layout_columns' ) ) { $this->columns = (int) get_user_option( "screen_layout_$this->id" ); if ( ! $this->columns && $this->get_option( 'layout_columns', 'default' ) ) { $this->columns = $this->get_option( 'layout_columns', 'default' ); } } $GLOBALS['screen_layout_columns'] = $this->columns; // Set the global for back-compat. // Add screen options. if ( $this->show_screen_options() ) { $this->render_screen_options(); } ?> </div> <?php if ( ! $this->get_help_tabs() && ! $this->show_screen_options() ) { return; } ?> <div id="screen-meta-links"> <?php if ( $this->show_screen_options() ) : ?> <div id="screen-options-link-wrap" class="hide-if-no-js screen-meta-toggle"> <button type="button" id="show-settings-link" class="button show-settings" aria-controls="screen-options-wrap" aria-expanded="false"><?php _e( 'Screen Options' ); ?></button> </div> <?php endif; if ( $this->get_help_tabs() ) : ?> <div id="contextual-help-link-wrap" class="hide-if-no-js screen-meta-toggle"> <button type="button" id="contextual-help-link" class="button show-settings" aria-controls="contextual-help-wrap" aria-expanded="false"><?php _e( 'Help' ); ?></button> </div> <?php endif; ?> </div> <?php } /** * @since 3.3.0 * * @global array $wp_meta_boxes Global meta box state. * * @return bool */ public function show_screen_options() { global $wp_meta_boxes; if ( is_bool( $this->_show_screen_options ) ) { return $this->_show_screen_options; } $columns = get_column_headers( $this ); $show_screen = ! empty( $wp_meta_boxes[ $this->id ] ) || $columns || $this->get_option( 'per_page' ); $this->_screen_settings = ''; if ( 'post' === $this->base ) { $expand = '<fieldset class="editor-expand hidden"><legend>' . __( 'Additional settings' ) . '</legend><label for="editor-expand-toggle">'; $expand .= '<input type="checkbox" id="editor-expand-toggle"' . checked( get_user_setting( 'editor_expand', 'on' ), 'on', false ) . ' />'; $expand .= __( 'Enable full-height editor and distraction-free functionality.' ) . '</label></fieldset>'; $this->_screen_settings = $expand; } /** * Filters the screen settings text displayed in the Screen Options tab. * * @since 3.0.0 * * @param string $screen_settings Screen settings. * @param WP_Screen $screen WP_Screen object. */ $this->_screen_settings = apply_filters( 'screen_settings', $this->_screen_settings, $this ); if ( $this->_screen_settings || $this->_options ) { $show_screen = true; } /** * Filters whether to show the Screen Options tab. * * @since 3.2.0 * * @param bool $show_screen Whether to show Screen Options tab. * Default true. * @param WP_Screen $screen Current WP_Screen instance. */ $this->_show_screen_options = apply_filters( 'screen_options_show_screen', $show_screen, $this ); return $this->_show_screen_options; } /** * Renders the screen options tab. * * @since 3.3.0 * * @param array $options { * Options for the tab. * * @type bool $wrap Whether the screen-options-wrap div will be included. Defaults to true. * } */ public function render_screen_options( $options = array() ) { $options = wp_parse_args( $options, array( 'wrap' => true, ) ); $wrapper_start = ''; $wrapper_end = ''; $form_start = ''; $form_end = ''; // Output optional wrapper. if ( $options['wrap'] ) { $wrapper_start = '<div id="screen-options-wrap" class="hidden" tabindex="-1" aria-label="' . esc_attr__( 'Screen Options Tab' ) . '">'; $wrapper_end = '</div>'; } // Don't output the form and nonce for the widgets accessibility mode links. if ( 'widgets' !== $this->base ) { $form_start = "\n<form id='adv-settings' method='post'>\n"; $form_end = "\n" . wp_nonce_field( 'screen-options-nonce', 'screenoptionnonce', false, false ) . "\n</form>\n"; } echo $wrapper_start . $form_start; $this->render_meta_boxes_preferences(); $this->render_list_table_columns_preferences(); $this->render_screen_layout(); $this->render_per_page_options(); $this->render_view_mode(); echo $this->_screen_settings; /** * Filters whether to show the Screen Options submit button. * * @since 4.4.0 * * @param bool $show_button Whether to show Screen Options submit button. * Default false. * @param WP_Screen $screen Current WP_Screen instance. */ $show_button = apply_filters( 'screen_options_show_submit', false, $this ); if ( $show_button ) { submit_button( __( 'Apply' ), 'primary', 'screen-options-apply', true ); } echo $form_end . $wrapper_end; } /** * Renders the meta boxes preferences. * * @since 4.4.0 * * @global array $wp_meta_boxes Global meta box state. */ public function render_meta_boxes_preferences() { global $wp_meta_boxes; if ( ! isset( $wp_meta_boxes[ $this->id ] ) ) { return; } ?> <fieldset class="metabox-prefs"> <legend><?php _e( 'Screen elements' ); ?></legend> <p> <?php _e( 'Some screen elements can be shown or hidden by using the checkboxes.' ); ?> <?php _e( 'Expand or collapse the elements by clicking on their headings, and arrange them by dragging their headings or by clicking on the up and down arrows.' ); ?> </p> <div class="metabox-prefs-container"> <?php meta_box_prefs( $this ); if ( 'dashboard' === $this->id && has_action( 'welcome_panel' ) && current_user_can( 'edit_theme_options' ) ) { if ( isset( $_GET['welcome'] ) ) { $welcome_checked = empty( $_GET['welcome'] ) ? 0 : 1; update_user_meta( get_current_user_id(), 'show_welcome_panel', $welcome_checked ); } else { $welcome_checked = (int) get_user_meta( get_current_user_id(), 'show_welcome_panel', true ); if ( 2 === $welcome_checked && wp_get_current_user()->user_email !== get_option( 'admin_email' ) ) { $welcome_checked = false; } } echo '<label for="wp_welcome_panel-hide">'; echo '<input type="checkbox" id="wp_welcome_panel-hide"' . checked( (bool) $welcome_checked, true, false ) . ' />'; echo _x( 'Welcome', 'Welcome panel' ) . "</label>\n"; } ?> </div> </fieldset> <?php } /** * Renders the list table columns preferences. * * @since 4.4.0 */ public function render_list_table_columns_preferences() { $columns = get_column_headers( $this ); $hidden = get_hidden_columns( $this ); if ( ! $columns ) { return; } $legend = ! empty( $columns['_title'] ) ? $columns['_title'] : __( 'Columns' ); ?> <fieldset class="metabox-prefs"> <legend><?php echo $legend; ?></legend> <?php $special = array( '_title', 'cb', 'comment', 'media', 'name', 'title', 'username', 'blogname' ); foreach ( $columns as $column => $title ) { // Can't hide these for they are special. if ( in_array( $column, $special, true ) ) { continue; } if ( empty( $title ) ) { continue; } /* * The Comments column uses HTML in the display name with some screen * reader text. Make sure to strip tags from the Comments column * title and any other custom column title plugins might add. */ $title = wp_strip_all_tags( $title ); $id = "$column-hide"; echo '<label>'; echo '<input class="hide-column-tog" name="' . $id . '" type="checkbox" id="' . $id . '" value="' . $column . '"' . checked( ! in_array( $column, $hidden, true ), true, false ) . ' />'; echo "$title</label>\n"; } ?> </fieldset> <?php } /** * Renders the option for number of columns on the page. * * @since 3.3.0 */ public function render_screen_layout() { if ( ! $this->get_option( 'layout_columns' ) ) { return; } $screen_layout_columns = $this->get_columns(); $num = $this->get_option( 'layout_columns', 'max' ); ?> <fieldset class='columns-prefs'> <legend class="screen-layout"><?php _e( 'Layout' ); ?></legend> <?php for ( $i = 1; $i <= $num; ++$i ) : ?> <label class="columns-prefs-<?php echo $i; ?>"> <input type='radio' name='screen_columns' value='<?php echo esc_attr( $i ); ?>' <?php checked( $screen_layout_columns, $i ); ?> /> <?php printf( /* translators: %s: Number of columns on the page. */ _n( '%s column', '%s columns', $i ), number_format_i18n( $i ) ); ?> </label> <?php endfor; ?> </fieldset> <?php } /** * Renders the items per page option. * * @since 3.3.0 */ public function render_per_page_options() { if ( null === $this->get_option( 'per_page' ) ) { return; } $per_page_label = $this->get_option( 'per_page', 'label' ); if ( null === $per_page_label ) { $per_page_label = __( 'Number of items per page:' ); } $option = $this->get_option( 'per_page', 'option' ); if ( ! $option ) { $option = str_replace( '-', '_', "{$this->id}_per_page" ); } $per_page = (int) get_user_option( $option ); if ( empty( $per_page ) || $per_page < 1 ) { $per_page = $this->get_option( 'per_page', 'default' ); if ( ! $per_page ) { $per_page = 20; } } if ( 'edit_comments_per_page' === $option ) { $comment_status = isset( $_REQUEST['comment_status'] ) ? $_REQUEST['comment_status'] : 'all'; /** This filter is documented in wp-admin/includes/class-wp-comments-list-table.php */ $per_page = apply_filters( 'comments_per_page', $per_page, $comment_status ); } elseif ( 'categories_per_page' === $option ) { /** This filter is documented in wp-admin/includes/class-wp-terms-list-table.php */ $per_page = apply_filters( 'edit_categories_per_page', $per_page ); } else { /** This filter is documented in wp-admin/includes/class-wp-list-table.php */ $per_page = apply_filters( "{$option}", $per_page ); } // Back compat. if ( isset( $this->post_type ) ) { /** This filter is documented in wp-admin/includes/post.php */ $per_page = apply_filters( 'edit_posts_per_page', $per_page, $this->post_type ); } // This needs a submit button. add_filter( 'screen_options_show_submit', '__return_true' ); ?> <fieldset class="screen-options"> <legend><?php _e( 'Pagination' ); ?></legend> <?php if ( $per_page_label ) : ?> <label for="<?php echo esc_attr( $option ); ?>"><?php echo $per_page_label; ?></label> <input type="number" step="1" min="1" max="999" class="screen-per-page" name="wp_screen_options[value]" id="<?php echo esc_attr( $option ); ?>" value="<?php echo esc_attr( $per_page ); ?>" /> <?php endif; ?> <input type="hidden" name="wp_screen_options[option]" value="<?php echo esc_attr( $option ); ?>" /> </fieldset> <?php } /** * Renders the list table view mode preferences. * * @since 4.4.0 * * @global string $mode List table view mode. */ public function render_view_mode() { global $mode; $screen = get_current_screen(); // Currently only enabled for posts and comments lists. if ( 'edit' !== $screen->base && 'edit-comments' !== $screen->base ) { return; } $view_mode_post_types = get_post_types( array( 'show_ui' => true ) ); /** * Filters the post types that have different view mode options. * * @since 4.4.0 * * @param string[] $view_mode_post_types Array of post types that can change view modes. * Default post types with show_ui on. */ $view_mode_post_types = apply_filters( 'view_mode_post_types', $view_mode_post_types ); if ( 'edit' === $screen->base && ! in_array( $this->post_type, $view_mode_post_types, true ) ) { return; } if ( ! isset( $mode ) ) { $mode = get_user_setting( 'posts_list_mode', 'list' ); } // This needs a submit button. add_filter( 'screen_options_show_submit', '__return_true' ); ?> <fieldset class="metabox-prefs view-mode"> <legend><?php _e( 'View mode' ); ?></legend> <label for="list-view-mode"> <input id="list-view-mode" type="radio" name="mode" value="list" <?php checked( 'list', $mode ); ?> /> <?php _e( 'Compact view' ); ?> </label> <label for="excerpt-view-mode"> <input id="excerpt-view-mode" type="radio" name="mode" value="excerpt" <?php checked( 'excerpt', $mode ); ?> /> <?php _e( 'Extended view' ); ?> </label> </fieldset> <?php } /** * Renders screen reader text. * * @since 4.4.0 * * @param string $key The screen reader text array named key. * @param string $tag Optional. The HTML tag to wrap the screen reader text. Default h2. */ public function render_screen_reader_content( $key = '', $tag = 'h2' ) { if ( ! isset( $this->_screen_reader_content[ $key ] ) ) { return; } echo "<$tag class='screen-reader-text'>" . $this->_screen_reader_content[ $key ] . "</$tag>"; } } PK U�g\�^�Ƙ Ƙ plugin-install.phpnu �[��� <?php /** * WordPress Plugin Install Administration API * * @package WordPress * @subpackage Administration */ /** * Retrieves plugin installer pages from the WordPress.org Plugins API. * * It is possible for a plugin to override the Plugin API result with three * filters. Assume this is for plugins, which can extend on the Plugin Info to * offer more choices. This is very powerful and must be used with care when * overriding the filters. * * The first filter, {@see 'plugins_api_args'}, is for the args and gives the action * as the second parameter. The hook for {@see 'plugins_api_args'} must ensure that * an object is returned. * * The second filter, {@see 'plugins_api'}, allows a plugin to override the WordPress.org * Plugin Installation API entirely. If `$action` is 'query_plugins' or 'plugin_information', * an object MUST be passed. If `$action` is 'hot_tags', an array MUST be passed. * * Finally, the third filter, {@see 'plugins_api_result'}, makes it possible to filter the * response object or array, depending on the `$action` type. * * Supported arguments per action: * * | Argument Name | query_plugins | plugin_information | hot_tags | * | -------------------- | :-----------: | :----------------: | :------: | * | `$slug` | No | Yes | No | * | `$per_page` | Yes | No | No | * | `$page` | Yes | No | No | * | `$number` | No | No | Yes | * | `$search` | Yes | No | No | * | `$tag` | Yes | No | No | * | `$author` | Yes | No | No | * | `$user` | Yes | No | No | * | `$browse` | Yes | No | No | * | `$locale` | Yes | Yes | No | * | `$installed_plugins` | Yes | No | No | * | `$is_ssl` | Yes | Yes | No | * | `$fields` | Yes | Yes | No | * * @since 2.7.0 * * @param string $action API action to perform: 'query_plugins', 'plugin_information', * or 'hot_tags'. * @param array|object $args { * Optional. Array or object of arguments to serialize for the Plugin Info API. * * @type string $slug The plugin slug. Default empty. * @type int $per_page Number of plugins per page. Default 24. * @type int $page Number of current page. Default 1. * @type int $number Number of tags or categories to be queried. * @type string $search A search term. Default empty. * @type string $tag Tag to filter plugins. Default empty. * @type string $author Username of an plugin author to filter plugins. Default empty. * @type string $user Username to query for their favorites. Default empty. * @type string $browse Browse view: 'popular', 'new', 'beta', 'recommended'. * @type string $locale Locale to provide context-sensitive results. Default is the value * of get_locale(). * @type string $installed_plugins Installed plugins to provide context-sensitive results. * @type bool $is_ssl Whether links should be returned with https or not. Default false. * @type array $fields { * Array of fields which should or should not be returned. * * @type bool $short_description Whether to return the plugin short description. Default true. * @type bool $description Whether to return the plugin full description. Default false. * @type bool $sections Whether to return the plugin readme sections: description, installation, * FAQ, screenshots, other notes, and changelog. Default false. * @type bool $tested Whether to return the 'Compatible up to' value. Default true. * @type bool $requires Whether to return the required WordPress version. Default true. * @type bool $requires_php Whether to return the required PHP version. Default true. * @type bool $rating Whether to return the rating in percent and total number of ratings. * Default true. * @type bool $ratings Whether to return the number of rating for each star (1-5). Default true. * @type bool $downloaded Whether to return the download count. Default true. * @type bool $downloadlink Whether to return the download link for the package. Default true. * @type bool $last_updated Whether to return the date of the last update. Default true. * @type bool $added Whether to return the date when the plugin was added to the wordpress.org * repository. Default true. * @type bool $tags Whether to return the assigned tags. Default true. * @type bool $compatibility Whether to return the WordPress compatibility list. Default true. * @type bool $homepage Whether to return the plugin homepage link. Default true. * @type bool $versions Whether to return the list of all available versions. Default false. * @type bool $donate_link Whether to return the donation link. Default true. * @type bool $reviews Whether to return the plugin reviews. Default false. * @type bool $banners Whether to return the banner images links. Default false. * @type bool $icons Whether to return the icon links. Default false. * @type bool $active_installs Whether to return the number of active installations. Default false. * @type bool $contributors Whether to return the list of contributors. Default false. * } * } * @return object|array|WP_Error Response object or array on success, WP_Error on failure. See the * {@link https://developer.wordpress.org/reference/functions/plugins_api/ function reference article} * for more information on the make-up of possible return values depending on the value of `$action`. */ function plugins_api( $action, $args = array() ) { if ( is_array( $args ) ) { $args = (object) $args; } if ( 'query_plugins' === $action ) { if ( ! isset( $args->per_page ) ) { $args->per_page = 24; } } if ( ! isset( $args->locale ) ) { $args->locale = get_user_locale(); } if ( ! isset( $args->wp_version ) ) { $args->wp_version = substr( wp_get_wp_version(), 0, 3 ); // x.y } /** * Filters the WordPress.org Plugin Installation API arguments. * * Important: An object MUST be returned to this filter. * * @since 2.7.0 * * @param object $args Plugin API arguments. * @param string $action The type of information being requested from the Plugin Installation API. */ $args = apply_filters( 'plugins_api_args', $args, $action ); /** * Filters the response for the current WordPress.org Plugin Installation API request. * * Returning a non-false value will effectively short-circuit the WordPress.org API request. * * If `$action` is 'query_plugins' or 'plugin_information', an object MUST be passed. * If `$action` is 'hot_tags', an array should be passed. * * @since 2.7.0 * * @param false|object|array $result The result object or array. Default false. * @param string $action The type of information being requested from the Plugin Installation API. * @param object $args Plugin API arguments. */ $res = apply_filters( 'plugins_api', false, $action, $args ); if ( false === $res ) { $url = 'http://api.wordpress.org/plugins/info/1.2/'; $url = add_query_arg( array( 'action' => $action, 'request' => $args, ), $url ); $http_url = $url; $ssl = wp_http_supports( array( 'ssl' ) ); if ( $ssl ) { $url = set_url_scheme( $url, 'https' ); } $http_args = array( 'timeout' => 15, 'user-agent' => 'WordPress/' . wp_get_wp_version() . '; ' . home_url( '/' ), ); $request = wp_remote_get( $url, $http_args ); if ( $ssl && is_wp_error( $request ) ) { if ( ! wp_is_json_request() ) { wp_trigger_error( __FUNCTION__, sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), __( 'https://wordpress.org/support/forums/' ) ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE ); } $request = wp_remote_get( $http_url, $http_args ); } if ( is_wp_error( $request ) ) { $res = new WP_Error( 'plugins_api_failed', sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), __( 'https://wordpress.org/support/forums/' ) ), $request->get_error_message() ); } else { $res = json_decode( wp_remote_retrieve_body( $request ), true ); if ( is_array( $res ) ) { // Object casting is required in order to match the info/1.0 format. $res = (object) $res; } elseif ( null === $res ) { $res = new WP_Error( 'plugins_api_failed', sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), __( 'https://wordpress.org/support/forums/' ) ), wp_remote_retrieve_body( $request ) ); } if ( isset( $res->error ) ) { $res = new WP_Error( 'plugins_api_failed', $res->error ); } } } elseif ( ! is_wp_error( $res ) ) { $res->external = true; } /** * Filters the Plugin Installation API response results. * * @since 2.7.0 * * @param object|WP_Error $res Response object or WP_Error. * @param string $action The type of information being requested from the Plugin Installation API. * @param object $args Plugin API arguments. */ return apply_filters( 'plugins_api_result', $res, $action, $args ); } /** * Retrieves popular WordPress plugin tags. * * @since 2.7.0 * * @param array $args * @return array|WP_Error */ function install_popular_tags( $args = array() ) { $key = md5( serialize( $args ) ); $tags = get_site_transient( 'poptags_' . $key ); if ( false !== $tags ) { return $tags; } $tags = plugins_api( 'hot_tags', $args ); if ( is_wp_error( $tags ) ) { return $tags; } set_site_transient( 'poptags_' . $key, $tags, 3 * HOUR_IN_SECONDS ); return $tags; } /** * Displays the Featured tab of Add Plugins screen. * * @since 2.7.0 */ function install_dashboard() { display_plugins_table(); ?> <div class="plugins-popular-tags-wrapper"> <h2><?php _e( 'Popular tags' ); ?></h2> <p><?php _e( 'You may also browse based on the most popular tags in the Plugin Directory:' ); ?></p> <?php $api_tags = install_popular_tags(); echo '<p class="popular-tags">'; if ( is_wp_error( $api_tags ) ) { echo $api_tags->get_error_message(); } else { // Set up the tags in a way which can be interpreted by wp_generate_tag_cloud(). $tags = array(); foreach ( (array) $api_tags as $tag ) { $url = self_admin_url( 'plugin-install.php?tab=search&type=tag&s=' . urlencode( $tag['name'] ) ); $data = array( 'link' => esc_url( $url ), 'name' => $tag['name'], 'slug' => $tag['slug'], 'id' => sanitize_title_with_dashes( $tag['name'] ), 'count' => $tag['count'], ); $tags[ $tag['name'] ] = (object) $data; } echo wp_generate_tag_cloud( $tags, array( /* translators: %s: Number of plugins. */ 'single_text' => __( '%s plugin' ), /* translators: %s: Number of plugins. */ 'multiple_text' => __( '%s plugins' ), ) ); } echo '</p><br class="clear" /></div>'; } /** * Displays a search form for searching plugins. * * @since 2.7.0 * @since 4.6.0 The `$type_selector` parameter was deprecated. * * @param bool $deprecated Not used. */ function install_search_form( $deprecated = true ) { $type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term'; $term = isset( $_REQUEST['s'] ) ? urldecode( wp_unslash( $_REQUEST['s'] ) ) : ''; ?> <form class="search-form search-plugins" method="get"> <input type="hidden" name="tab" value="search" /> <label for="search-plugins"><?php _e( 'Search Plugins' ); ?></label> <input type="search" name="s" id="search-plugins" value="<?php echo esc_attr( $term ); ?>" class="wp-filter-search" /> <label class="screen-reader-text" for="typeselector"> <?php /* translators: Hidden accessibility text. */ _e( 'Search plugins by:' ); ?> </label> <select name="type" id="typeselector"> <option value="term"<?php selected( 'term', $type ); ?>><?php _e( 'Keyword' ); ?></option> <option value="author"<?php selected( 'author', $type ); ?>><?php _e( 'Author' ); ?></option> <option value="tag"<?php selected( 'tag', $type ); ?>><?php _ex( 'Tag', 'Plugin Installer' ); ?></option> </select> <?php submit_button( __( 'Search Plugins' ), 'hide-if-js', false, false, array( 'id' => 'search-submit' ) ); ?> </form> <?php } /** * Displays a form to upload plugins from zip files. * * @since 2.8.0 */ function install_plugins_upload() { ?> <div class="upload-plugin"> <p class="install-help"><?php _e( 'If you have a plugin in a .zip format, you may install or update it by uploading it here.' ); ?></p> <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo esc_url( self_admin_url( 'update.php?action=upload-plugin' ) ); ?>"> <?php wp_nonce_field( 'plugin-upload' ); ?> <label class="screen-reader-text" for="pluginzip"> <?php /* translators: Hidden accessibility text. */ _e( 'Plugin zip file' ); ?> </label> <input type="file" id="pluginzip" name="pluginzip" accept=".zip" /> <?php submit_button( _x( 'Install Now', 'plugin' ), '', 'install-plugin-submit', false ); ?> </form> </div> <?php } /** * Shows a username form for the favorites page. * * @since 3.5.0 */ function install_plugins_favorites_form() { $user = get_user_option( 'wporg_favorites' ); $action = 'save_wporg_username_' . get_current_user_id(); ?> <p><?php _e( 'If you have marked plugins as favorites on WordPress.org, you can browse them here.' ); ?></p> <form method="get"> <input type="hidden" name="tab" value="favorites" /> <p> <label for="user"><?php _e( 'Your WordPress.org username:' ); ?></label> <input type="search" id="user" name="user" value="<?php echo esc_attr( $user ); ?>" /> <input type="submit" class="button" value="<?php esc_attr_e( 'Get Favorites' ); ?>" /> <input type="hidden" id="wporg-username-nonce" name="_wpnonce" value="<?php echo esc_attr( wp_create_nonce( $action ) ); ?>" /> </p> </form> <?php } /** * Displays plugin content based on plugin list. * * @since 2.7.0 * * @global WP_List_Table $wp_list_table */ function display_plugins_table() { global $wp_list_table; switch ( current_filter() ) { case 'install_plugins_beta': printf( /* translators: %s: URL to "Features as Plugins" page. */ '<p>' . __( 'You are using a development version of WordPress. These feature plugins are also under development. <a href="%s">Learn more</a>.' ) . '</p>', 'https://make.wordpress.org/core/handbook/about/release-cycle/features-as-plugins/' ); break; case 'install_plugins_featured': echo '<br>'; break; case 'install_plugins_recommended': echo '<p>' . __( 'These suggestions are based on the plugins you and other users have installed.' ) . '</p>'; break; case 'install_plugins_favorites': if ( empty( $_GET['user'] ) && ! get_user_option( 'wporg_favorites' ) ) { return; } break; } ?> <form id="plugin-filter" method="post"> <?php $wp_list_table->display(); ?> </form> <?php } /** * Determines the status we can perform on a plugin. * * @since 3.0.0 * * @param array|object $api Data about the plugin retrieved from the API. * @param bool $loop Optional. Disable further loops. Default false. * @return array { * Plugin installation status data. * * @type string $status Status of a plugin. Could be one of 'install', 'update_available', 'latest_installed' or 'newer_installed'. * @type string $url Plugin installation URL. * @type string $version The most recent version of the plugin. * @type string $file Plugin filename relative to the plugins directory. * } */ function install_plugin_install_status( $api, $loop = false ) { // This function is called recursively, $loop prevents further loops. if ( is_array( $api ) ) { $api = (object) $api; } // Default to a "new" plugin. $status = 'install'; $url = false; $update_file = false; $version = ''; /* * Check to see if this plugin is known to be installed, * and has an update awaiting it. */ $update_plugins = get_site_transient( 'update_plugins' ); if ( isset( $update_plugins->response ) ) { foreach ( (array) $update_plugins->response as $file => $plugin ) { if ( $plugin->slug === $api->slug ) { $status = 'update_available'; $update_file = $file; $version = $plugin->new_version; if ( current_user_can( 'update_plugins' ) ) { $url = wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' . $update_file ), 'upgrade-plugin_' . $update_file ); } break; } } } if ( 'install' === $status ) { if ( is_dir( WP_PLUGIN_DIR . '/' . $api->slug ) ) { $installed_plugin = get_plugins( '/' . $api->slug ); if ( empty( $installed_plugin ) ) { if ( current_user_can( 'install_plugins' ) ) { $url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $api->slug ), 'install-plugin_' . $api->slug ); } } else { $key = array_keys( $installed_plugin ); /* * Use the first plugin regardless of the name. * Could have issues for multiple plugins in one directory if they share different version numbers. */ $key = reset( $key ); $update_file = $api->slug . '/' . $key; if ( version_compare( $api->version, $installed_plugin[ $key ]['Version'], '=' ) ) { $status = 'latest_installed'; } elseif ( version_compare( $api->version, $installed_plugin[ $key ]['Version'], '<' ) ) { $status = 'newer_installed'; $version = $installed_plugin[ $key ]['Version']; } else { // If the above update check failed, then that probably means that the update checker has out-of-date information, force a refresh. if ( ! $loop ) { delete_site_transient( 'update_plugins' ); wp_update_plugins(); return install_plugin_install_status( $api, true ); } } } } else { // "install" & no directory with that slug. if ( current_user_can( 'install_plugins' ) ) { $url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $api->slug ), 'install-plugin_' . $api->slug ); } } } if ( isset( $_GET['from'] ) ) { $url .= '&from=' . urlencode( wp_unslash( $_GET['from'] ) ); } $file = $update_file; return compact( 'status', 'url', 'version', 'file' ); } /** * Displays plugin information in dialog box form. * * @since 2.7.0 * * @global string $tab */ function install_plugin_information() { global $tab; if ( empty( $_REQUEST['plugin'] ) ) { return; } $api = plugins_api( 'plugin_information', array( 'slug' => wp_unslash( $_REQUEST['plugin'] ), ) ); if ( is_wp_error( $api ) ) { wp_die( $api ); } $plugins_allowedtags = array( 'a' => array( 'href' => array(), 'title' => array(), 'target' => array(), ), 'abbr' => array( 'title' => array() ), 'acronym' => array( 'title' => array() ), 'code' => array(), 'pre' => array(), 'em' => array(), 'strong' => array(), 'div' => array( 'class' => array() ), 'span' => array( 'class' => array() ), 'p' => array(), 'br' => array(), 'ul' => array(), 'ol' => array(), 'li' => array(), 'h1' => array(), 'h2' => array(), 'h3' => array(), 'h4' => array(), 'h5' => array(), 'h6' => array(), 'img' => array( 'src' => array(), 'class' => array(), 'alt' => array(), ), 'blockquote' => array( 'cite' => true ), ); $plugins_section_titles = array( 'description' => _x( 'Description', 'Plugin installer section title' ), 'installation' => _x( 'Installation', 'Plugin installer section title' ), 'faq' => _x( 'FAQ', 'Plugin installer section title' ), 'screenshots' => _x( 'Screenshots', 'Plugin installer section title' ), 'changelog' => _x( 'Changelog', 'Plugin installer section title' ), 'reviews' => _x( 'Reviews', 'Plugin installer section title' ), 'other_notes' => _x( 'Other Notes', 'Plugin installer section title' ), ); // Sanitize HTML. foreach ( (array) $api->sections as $section_name => $content ) { $api->sections[ $section_name ] = wp_kses( $content, $plugins_allowedtags ); } foreach ( array( 'version', 'author', 'requires', 'tested', 'homepage', 'downloaded', 'slug' ) as $key ) { if ( isset( $api->$key ) ) { $api->$key = wp_kses( $api->$key, $plugins_allowedtags ); } } $_tab = esc_attr( $tab ); // Default to the Description tab, Do not translate, API returns English. $section = isset( $_REQUEST['section'] ) ? wp_unslash( $_REQUEST['section'] ) : 'description'; if ( empty( $section ) || ! isset( $api->sections[ $section ] ) ) { $section_titles = array_keys( (array) $api->sections ); $section = reset( $section_titles ); } iframe_header( __( 'Plugin Installation' ) ); $_with_banner = ''; if ( ! empty( $api->banners ) && ( ! empty( $api->banners['low'] ) || ! empty( $api->banners['high'] ) ) ) { $_with_banner = 'with-banner'; $low = empty( $api->banners['low'] ) ? $api->banners['high'] : $api->banners['low']; $high = empty( $api->banners['high'] ) ? $api->banners['low'] : $api->banners['high']; ?> <style type="text/css"> #plugin-information-title.with-banner { background-image: url( <?php echo esc_url( $low ); ?> ); } @media only screen and ( -webkit-min-device-pixel-ratio: 1.5 ) { #plugin-information-title.with-banner { background-image: url( <?php echo esc_url( $high ); ?> ); } } </style> <?php } echo '<div id="plugin-information-scrollable">'; echo "<div id='{$_tab}-title' class='{$_with_banner}'><div class='vignette'></div><h2>{$api->name}</h2></div>"; echo "<div id='{$_tab}-tabs' class='{$_with_banner}'>\n"; foreach ( (array) $api->sections as $section_name => $content ) { if ( 'reviews' === $section_name && ( empty( $api->ratings ) || 0 === array_sum( (array) $api->ratings ) ) ) { continue; } if ( isset( $plugins_section_titles[ $section_name ] ) ) { $title = $plugins_section_titles[ $section_name ]; } else { $title = ucwords( str_replace( '_', ' ', $section_name ) ); } $class = ( $section_name === $section ) ? ' class="current"' : ''; $href = add_query_arg( array( 'tab' => $tab, 'section' => $section_name, ) ); $href = esc_url( $href ); $san_section = esc_attr( $section_name ); echo "\t<a name='$san_section' href='$href' $class>$title</a>\n"; } echo "</div>\n"; ?> <div id="<?php echo $_tab; ?>-content" class='<?php echo $_with_banner; ?>'> <div class="fyi"> <ul> <?php if ( ! empty( $api->version ) ) { ?> <li><strong><?php _e( 'Version:' ); ?></strong> <?php echo $api->version; ?></li> <?php } if ( ! empty( $api->author ) ) { ?> <li><strong><?php _e( 'Author:' ); ?></strong> <?php echo links_add_target( $api->author, '_blank' ); ?></li> <?php } if ( ! empty( $api->last_updated ) ) { ?> <li><strong><?php _e( 'Last Updated:' ); ?></strong> <?php /* translators: %s: Human-readable time difference. */ printf( __( '%s ago' ), human_time_diff( strtotime( $api->last_updated ) ) ); ?> </li> <?php } if ( ! empty( $api->requires ) ) { ?> <li> <strong><?php _e( 'Requires WordPress Version:' ); ?></strong> <?php /* translators: %s: Version number. */ printf( __( '%s or higher' ), $api->requires ); ?> </li> <?php } if ( ! empty( $api->tested ) ) { ?> <li><strong><?php _e( 'Compatible up to:' ); ?></strong> <?php echo $api->tested; ?></li> <?php } if ( ! empty( $api->requires_php ) ) { ?> <li> <strong><?php _e( 'Requires PHP Version:' ); ?></strong> <?php /* translators: %s: Version number. */ printf( __( '%s or higher' ), $api->requires_php ); ?> </li> <?php } if ( isset( $api->active_installs ) ) { ?> <li><strong><?php _e( 'Active Installations:' ); ?></strong> <?php if ( $api->active_installs >= 1000000 ) { $active_installs_millions = floor( $api->active_installs / 1000000 ); printf( /* translators: %s: Number of millions. */ _nx( '%s+ Million', '%s+ Million', $active_installs_millions, 'Active plugin installations' ), number_format_i18n( $active_installs_millions ) ); } elseif ( $api->active_installs < 10 ) { _ex( 'Less Than 10', 'Active plugin installations' ); } else { echo number_format_i18n( $api->active_installs ) . '+'; } ?> </li> <?php } if ( ! empty( $api->slug ) && empty( $api->external ) ) { ?> <li><a target="_blank" href="<?php echo esc_url( __( 'https://wordpress.org/plugins/' ) . $api->slug ); ?>/"><?php _e( 'WordPress.org Plugin Page »' ); ?></a></li> <?php } if ( ! empty( $api->homepage ) ) { ?> <li><a target="_blank" href="<?php echo esc_url( $api->homepage ); ?>"><?php _e( 'Plugin Homepage »' ); ?></a></li> <?php } if ( ! empty( $api->donate_link ) && empty( $api->contributors ) ) { ?> <li><a target="_blank" href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin »' ); ?></a></li> <?php } ?> </ul> <?php if ( ! empty( $api->rating ) ) { ?> <h3><?php _e( 'Average Rating' ); ?></h3> <?php wp_star_rating( array( 'rating' => $api->rating, 'type' => 'percent', 'number' => $api->num_ratings, ) ); ?> <p aria-hidden="true" class="fyi-description"> <?php printf( /* translators: %s: Number of ratings. */ _n( '(based on %s rating)', '(based on %s ratings)', $api->num_ratings ), number_format_i18n( $api->num_ratings ) ); ?> </p> <?php } if ( ! empty( $api->ratings ) && array_sum( (array) $api->ratings ) > 0 ) { ?> <h3><?php _e( 'Reviews' ); ?></h3> <p class="fyi-description"><?php _e( 'Read all reviews on WordPress.org or write your own!' ); ?></p> <?php foreach ( $api->ratings as $key => $ratecount ) { // Avoid div-by-zero. $_rating = $api->num_ratings ? ( $ratecount / $api->num_ratings ) : 0; $aria_label = esc_attr( sprintf( /* translators: 1: Number of stars (used to determine singular/plural), 2: Number of reviews. */ _n( 'Reviews with %1$d star: %2$s. Opens in a new tab.', 'Reviews with %1$d stars: %2$s. Opens in a new tab.', $key ), $key, number_format_i18n( $ratecount ) ) ); ?> <div class="counter-container"> <span class="counter-label"> <?php printf( '<a href="%s" target="_blank" aria-label="%s">%s</a>', "https://wordpress.org/support/plugin/{$api->slug}/reviews/?filter={$key}", $aria_label, /* translators: %s: Number of stars. */ sprintf( _n( '%d star', '%d stars', $key ), $key ) ); ?> </span> <span class="counter-back"> <span class="counter-bar" style="width: <?php echo 92 * $_rating; ?>px;"></span> </span> <span class="counter-count" aria-hidden="true"><?php echo number_format_i18n( $ratecount ); ?></span> </div> <?php } } if ( ! empty( $api->contributors ) ) { ?> <h3><?php _e( 'Contributors' ); ?></h3> <ul class="contributors"> <?php foreach ( (array) $api->contributors as $contrib_username => $contrib_details ) { $contrib_name = $contrib_details['display_name']; if ( ! $contrib_name ) { $contrib_name = $contrib_username; } $contrib_name = esc_html( $contrib_name ); $contrib_profile = esc_url( $contrib_details['profile'] ); $contrib_avatar = esc_url( add_query_arg( 's', '36', $contrib_details['avatar'] ) ); echo "<li><a href='{$contrib_profile}' target='_blank'><img src='{$contrib_avatar}' width='18' height='18' alt='' />{$contrib_name}</a></li>"; } ?> </ul> <?php if ( ! empty( $api->donate_link ) ) { ?> <a target="_blank" href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin »' ); ?></a> <?php } ?> <?php } ?> </div> <div id="section-holder"> <?php $requires_php = isset( $api->requires_php ) ? $api->requires_php : null; $requires_wp = isset( $api->requires ) ? $api->requires : null; $compatible_php = is_php_version_compatible( $requires_php ); $compatible_wp = is_wp_version_compatible( $requires_wp ); $tested_wp = ( empty( $api->tested ) || version_compare( get_bloginfo( 'version' ), $api->tested, '<=' ) ); if ( ! $compatible_php ) { $compatible_php_notice_message = '<p>'; $compatible_php_notice_message .= __( '<strong>Error:</strong> This plugin <strong>requires a newer version of PHP</strong>.' ); if ( current_user_can( 'update_php' ) ) { $compatible_php_notice_message .= sprintf( /* translators: %s: URL to Update PHP page. */ ' ' . __( '<a href="%s" target="_blank">Click here to learn more about updating PHP</a>.' ), esc_url( wp_get_update_php_url() ) ) . wp_update_php_annotation( '</p><p><em>', '</em>', false ); } else { $compatible_php_notice_message .= '</p>'; } wp_admin_notice( $compatible_php_notice_message, array( 'type' => 'error', 'additional_classes' => array( 'notice-alt' ), 'paragraph_wrap' => false, ) ); } if ( ! $tested_wp ) { wp_admin_notice( __( '<strong>Warning:</strong> This plugin <strong>has not been tested</strong> with your current version of WordPress.' ), array( 'type' => 'warning', 'additional_classes' => array( 'notice-alt' ), ) ); } elseif ( ! $compatible_wp ) { $compatible_wp_notice_message = __( '<strong>Error:</strong> This plugin <strong>requires a newer version of WordPress</strong>.' ); if ( current_user_can( 'update_core' ) ) { $compatible_wp_notice_message .= sprintf( /* translators: %s: URL to WordPress Updates screen. */ ' ' . __( '<a href="%s" target="_parent">Click here to update WordPress</a>.' ), esc_url( self_admin_url( 'update-core.php' ) ) ); } wp_admin_notice( $compatible_wp_notice_message, array( 'type' => 'error', 'additional_classes' => array( 'notice-alt' ), ) ); } foreach ( (array) $api->sections as $section_name => $content ) { $content = links_add_base_url( $content, 'https://wordpress.org/plugins/' . $api->slug . '/' ); $content = links_add_target( $content, '_blank' ); $san_section = esc_attr( $section_name ); $display = ( $section_name === $section ) ? 'block' : 'none'; echo "\t<div id='section-{$san_section}' class='section' style='display: {$display};'>\n"; echo $content; echo "\t</div>\n"; } echo "</div>\n"; echo "</div>\n"; echo "</div>\n"; // #plugin-information-scrollable echo "<div id='$tab-footer'>\n"; if ( ! empty( $api->download_link ) && ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) ) { $button = wp_get_plugin_action_button( $api->name, $api, $compatible_php, $compatible_wp ); $button = str_replace( 'class="', 'class="right ', $button ); if ( ! str_contains( $button, _x( 'Activate', 'plugin' ) ) ) { $button = str_replace( 'class="', 'id="plugin_install_from_iframe" class="', $button ); } echo wp_kses_post( $button ); } echo "</div>\n"; wp_print_request_filesystem_credentials_modal(); wp_print_admin_notice_templates(); iframe_footer(); exit; } /** * Gets the markup for the plugin install action button. * * @since 6.5.0 * * @param string $name Plugin name. * @param array|object $data { * An array or object of plugin data. Can be retrieved from the API. * * @type string $slug The plugin slug. * @type string[] $requires_plugins An array of plugin dependency slugs. * @type string $version The plugin's version string. Used when getting the install status. * } * @param bool $compatible_php The result of a PHP compatibility check. * @param bool $compatible_wp The result of a WP compatibility check. * @return string The markup for the dependency row button. An empty string if the user does not have capabilities. */ function wp_get_plugin_action_button( $name, $data, $compatible_php, $compatible_wp ) { $button = ''; $data = (object) $data; $status = install_plugin_install_status( $data ); $requires_plugins = $data->requires_plugins ?? array(); // Determine the status of plugin dependencies. $installed_plugins = get_plugins(); $active_plugins = get_option( 'active_plugins', array() ); $plugin_dependencies_count = count( $requires_plugins ); $installed_plugin_dependencies_count = 0; $active_plugin_dependencies_count = 0; foreach ( $requires_plugins as $dependency ) { foreach ( array_keys( $installed_plugins ) as $installed_plugin_file ) { if ( str_contains( $installed_plugin_file, '/' ) && explode( '/', $installed_plugin_file )[0] === $dependency ) { ++$installed_plugin_dependencies_count; } } foreach ( $active_plugins as $active_plugin_file ) { if ( str_contains( $active_plugin_file, '/' ) && explode( '/', $active_plugin_file )[0] === $dependency ) { ++$active_plugin_dependencies_count; } } } $all_plugin_dependencies_installed = $installed_plugin_dependencies_count === $plugin_dependencies_count; $all_plugin_dependencies_active = $active_plugin_dependencies_count === $plugin_dependencies_count; if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) { switch ( $status['status'] ) { case 'install': if ( $status['url'] ) { if ( $compatible_php && $compatible_wp && $all_plugin_dependencies_installed && ! empty( $data->download_link ) ) { $button = sprintf( '<a class="install-now button" data-slug="%s" href="%s" aria-label="%s" data-name="%s" role="button">%s</a>', esc_attr( $data->slug ), esc_url( $status['url'] ), /* translators: %s: Plugin name and version. */ esc_attr( sprintf( _x( 'Install %s now', 'plugin' ), $name ) ), esc_attr( $name ), _x( 'Install Now', 'plugin' ) ); } else { $button = sprintf( '<button type="button" class="install-now button button-disabled" disabled="disabled">%s</button>', _x( 'Install Now', 'plugin' ) ); } } break; case 'update_available': if ( $status['url'] ) { if ( $compatible_php && $compatible_wp ) { $button = sprintf( '<a class="update-now button aria-button-if-js" data-plugin="%s" data-slug="%s" href="%s" aria-label="%s" data-name="%s" role="button">%s</a>', esc_attr( $status['file'] ), esc_attr( $data->slug ), esc_url( $status['url'] ), /* translators: %s: Plugin name and version. */ esc_attr( sprintf( _x( 'Update %s now', 'plugin' ), $name ) ), esc_attr( $name ), _x( 'Update Now', 'plugin' ) ); } else { $button = sprintf( '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', _x( 'Update Now', 'plugin' ) ); } } break; case 'latest_installed': case 'newer_installed': if ( is_plugin_active( $status['file'] ) ) { $button = sprintf( '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', _x( 'Active', 'plugin' ) ); } elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) { if ( $compatible_php && $compatible_wp && $all_plugin_dependencies_active ) { $button_text = _x( 'Activate', 'plugin' ); /* translators: %s: Plugin name. */ $button_label = _x( 'Activate %s', 'plugin' ); $activate_url = add_query_arg( array( '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ), 'action' => 'activate', 'plugin' => $status['file'], ), network_admin_url( 'plugins.php' ) ); if ( is_network_admin() ) { $button_text = _x( 'Network Activate', 'plugin' ); /* translators: %s: Plugin name. */ $button_label = _x( 'Network Activate %s', 'plugin' ); $activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url ); } $button = sprintf( '<a href="%1$s" data-name="%2$s" data-slug="%3$s" data-plugin="%4$s" class="button button-primary activate-now" aria-label="%5$s" role="button">%6$s</a>', esc_url( $activate_url ), esc_attr( $name ), esc_attr( $data->slug ), esc_attr( $status['file'] ), esc_attr( sprintf( $button_label, $name ) ), $button_text ); } else { $button = sprintf( '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', is_network_admin() ? _x( 'Network Activate', 'plugin' ) : _x( 'Activate', 'plugin' ) ); } } else { $button = sprintf( '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', _x( 'Installed', 'plugin' ) ); } break; } } return $button; } PK U�g\O�_�N N theme-install.phpnu �[��� <?php /** * WordPress Theme Installation Administration API * * @package WordPress * @subpackage Administration */ $themes_allowedtags = array( 'a' => array( 'href' => array(), 'title' => array(), 'target' => array(), ), 'abbr' => array( 'title' => array() ), 'acronym' => array( 'title' => array() ), 'code' => array(), 'pre' => array(), 'em' => array(), 'strong' => array(), 'div' => array(), 'p' => array(), 'ul' => array(), 'ol' => array(), 'li' => array(), 'h1' => array(), 'h2' => array(), 'h3' => array(), 'h4' => array(), 'h5' => array(), 'h6' => array(), 'img' => array( 'src' => array(), 'class' => array(), 'alt' => array(), ), ); $theme_field_defaults = array( 'description' => true, 'sections' => false, 'tested' => true, 'requires' => true, 'rating' => true, 'downloaded' => true, 'downloadlink' => true, 'last_updated' => true, 'homepage' => true, 'tags' => true, 'num_ratings' => true, ); /** * Retrieves the list of WordPress theme features (aka theme tags). * * @since 2.8.0 * * @deprecated 3.1.0 Use get_theme_feature_list() instead. * * @return array */ function install_themes_feature_list() { _deprecated_function( __FUNCTION__, '3.1.0', 'get_theme_feature_list()' ); $cache = get_transient( 'wporg_theme_feature_list' ); if ( ! $cache ) { set_transient( 'wporg_theme_feature_list', array(), 3 * HOUR_IN_SECONDS ); } if ( $cache ) { return $cache; } $feature_list = themes_api( 'feature_list', array() ); if ( is_wp_error( $feature_list ) ) { return array(); } set_transient( 'wporg_theme_feature_list', $feature_list, 3 * HOUR_IN_SECONDS ); return $feature_list; } /** * Displays search form for searching themes. * * @since 2.8.0 * * @param bool $type_selector */ function install_theme_search_form( $type_selector = true ) { $type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term'; $term = isset( $_REQUEST['s'] ) ? wp_unslash( $_REQUEST['s'] ) : ''; if ( ! $type_selector ) { echo '<p class="install-help">' . __( 'Search for themes by keyword.' ) . '</p>'; } ?> <form id="search-themes" method="get"> <input type="hidden" name="tab" value="search" /> <?php if ( $type_selector ) : ?> <label class="screen-reader-text" for="typeselector"> <?php /* translators: Hidden accessibility text. */ _e( 'Type of search' ); ?> </label> <select name="type" id="typeselector"> <option value="term" <?php selected( 'term', $type ); ?>><?php _e( 'Keyword' ); ?></option> <option value="author" <?php selected( 'author', $type ); ?>><?php _e( 'Author' ); ?></option> <option value="tag" <?php selected( 'tag', $type ); ?>><?php _ex( 'Tag', 'Theme Installer' ); ?></option> </select> <label class="screen-reader-text" for="s"> <?php switch ( $type ) { case 'term': /* translators: Hidden accessibility text. */ _e( 'Search by keyword' ); break; case 'author': /* translators: Hidden accessibility text. */ _e( 'Search by author' ); break; case 'tag': /* translators: Hidden accessibility text. */ _e( 'Search by tag' ); break; } ?> </label> <?php else : ?> <label class="screen-reader-text" for="s"> <?php /* translators: Hidden accessibility text. */ _e( 'Search by keyword' ); ?> </label> <?php endif; ?> <input type="search" name="s" id="s" size="30" value="<?php echo esc_attr( $term ); ?>" autofocus="autofocus" /> <?php submit_button( __( 'Search' ), '', 'search', false ); ?> </form> <?php } /** * Displays tags filter for themes. * * @since 2.8.0 */ function install_themes_dashboard() { install_theme_search_form( false ); ?> <h4><?php _e( 'Feature Filter' ); ?></h4> <p class="install-help"><?php _e( 'Find a theme based on specific features.' ); ?></p> <form method="get"> <input type="hidden" name="tab" value="search" /> <?php $feature_list = get_theme_feature_list(); echo '<div class="feature-filter">'; foreach ( (array) $feature_list as $feature_name => $features ) { $feature_name = esc_html( $feature_name ); echo '<div class="feature-name">' . $feature_name . '</div>'; echo '<ol class="feature-group">'; foreach ( $features as $feature => $feature_name ) { $feature_name = esc_html( $feature_name ); $feature = esc_attr( $feature ); ?> <li> <input type="checkbox" name="features[]" id="feature-id-<?php echo $feature; ?>" value="<?php echo $feature; ?>" /> <label for="feature-id-<?php echo $feature; ?>"><?php echo $feature_name; ?></label> </li> <?php } ?> </ol> <br class="clear" /> <?php } ?> </div> <br class="clear" /> <?php submit_button( __( 'Find Themes' ), '', 'search' ); ?> </form> <?php } /** * Displays a form to upload themes from zip files. * * @since 2.8.0 */ function install_themes_upload() { ?> <p class="install-help"><?php _e( 'If you have a theme in a .zip format, you may install or update it by uploading it here.' ); ?></p> <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo esc_url( self_admin_url( 'update.php?action=upload-theme' ) ); ?>"> <?php wp_nonce_field( 'theme-upload' ); ?> <label class="screen-reader-text" for="themezip"> <?php /* translators: Hidden accessibility text. */ _e( 'Theme zip file' ); ?> </label> <input type="file" id="themezip" name="themezip" accept=".zip" /> <?php submit_button( _x( 'Install Now', 'theme' ), '', 'install-theme-submit', false ); ?> </form> <?php } /** * Prints a theme on the Install Themes pages. * * @deprecated 3.4.0 * * @global WP_Theme_Install_List_Table $wp_list_table * * @param object $theme */ function display_theme( $theme ) { _deprecated_function( __FUNCTION__, '3.4.0' ); global $wp_list_table; if ( ! isset( $wp_list_table ) ) { $wp_list_table = _get_list_table( 'WP_Theme_Install_List_Table' ); } $wp_list_table->prepare_items(); $wp_list_table->single_row( $theme ); } /** * Displays theme content based on theme list. * * @since 2.8.0 * * @global WP_Theme_Install_List_Table $wp_list_table */ function display_themes() { global $wp_list_table; if ( ! isset( $wp_list_table ) ) { $wp_list_table = _get_list_table( 'WP_Theme_Install_List_Table' ); } $wp_list_table->prepare_items(); $wp_list_table->display(); } /** * Displays theme information in dialog box form. * * @since 2.8.0 * * @global WP_Theme_Install_List_Table $wp_list_table */ function install_theme_information() { global $wp_list_table; $theme = themes_api( 'theme_information', array( 'slug' => wp_unslash( $_REQUEST['theme'] ) ) ); if ( is_wp_error( $theme ) ) { wp_die( $theme ); } iframe_header( __( 'Theme Installation' ) ); if ( ! isset( $wp_list_table ) ) { $wp_list_table = _get_list_table( 'WP_Theme_Install_List_Table' ); } $wp_list_table->theme_installer_single( $theme ); iframe_footer(); exit; } PK U�g\L�v'a� a� nav-menu.phpnu �[��� <?php /** * Core Navigation Menu API * * @package WordPress * @subpackage Nav_Menus * @since 3.0.0 */ /** Walker_Nav_Menu_Edit class */ require_once ABSPATH . 'wp-admin/includes/class-walker-nav-menu-edit.php'; /** Walker_Nav_Menu_Checklist class */ require_once ABSPATH . 'wp-admin/includes/class-walker-nav-menu-checklist.php'; /** * Prints the appropriate response to a menu quick search. * * @since 3.0.0 * * @param array $request The unsanitized request values. */ function _wp_ajax_menu_quick_search( $request = array() ) { $args = array(); $type = isset( $request['type'] ) ? $request['type'] : ''; $object_type = isset( $request['object_type'] ) ? $request['object_type'] : ''; $query = isset( $request['q'] ) ? $request['q'] : ''; $response_format = isset( $request['response-format'] ) ? $request['response-format'] : ''; if ( ! $response_format || ! in_array( $response_format, array( 'json', 'markup' ), true ) ) { $response_format = 'json'; } if ( 'markup' === $response_format ) { $args['walker'] = new Walker_Nav_Menu_Checklist(); } if ( 'get-post-item' === $type ) { if ( post_type_exists( $object_type ) ) { if ( isset( $request['ID'] ) ) { $object_id = (int) $request['ID']; if ( 'markup' === $response_format ) { echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', array( get_post( $object_id ) ) ), 0, (object) $args ); } elseif ( 'json' === $response_format ) { echo wp_json_encode( array( 'ID' => $object_id, 'post_title' => get_the_title( $object_id ), 'post_type' => get_post_type( $object_id ), ) ); echo "\n"; } } } elseif ( taxonomy_exists( $object_type ) ) { if ( isset( $request['ID'] ) ) { $object_id = (int) $request['ID']; if ( 'markup' === $response_format ) { echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', array( get_term( $object_id, $object_type ) ) ), 0, (object) $args ); } elseif ( 'json' === $response_format ) { $post_obj = get_term( $object_id, $object_type ); echo wp_json_encode( array( 'ID' => $object_id, 'post_title' => $post_obj->name, 'post_type' => $object_type, ) ); echo "\n"; } } } } elseif ( preg_match( '/quick-search-(posttype|taxonomy)-([a-zA-Z0-9_-]*\b)/', $type, $matches ) ) { if ( 'posttype' === $matches[1] && get_post_type_object( $matches[2] ) ) { $post_type_obj = _wp_nav_menu_meta_box_object( get_post_type_object( $matches[2] ) ); $query_args = array( 'no_found_rows' => true, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, 'posts_per_page' => 10, 'post_type' => $matches[2], 's' => $query, 'search_columns' => array( 'post_title' ), ); /** * Filter the menu quick search arguments. * * @since 6.9.0 * * @param array $args { * Menu quick search arguments. * * @type boolean $no_found_rows Whether to return found rows data. Default true. * @type boolean $update_post_meta_cache Whether to update post meta cache. Default false. * @type boolean $update_post_term_cache Whether to update post term cache. Default false. * @type int $posts_per_page Number of posts to return. Default 10. * @type string $post_type Type of post to return. * @type string $s Search query. * @type array $search_columns Which post table columns to query. * } */ $query_args = apply_filters( 'wp_ajax_menu_quick_search_args', $query_args ); $args = array_merge( $args, $query_args ); if ( isset( $post_type_obj->_default_query ) ) { $args = array_merge( $args, (array) $post_type_obj->_default_query ); } $search_results_query = new WP_Query( $args ); if ( ! $search_results_query->have_posts() ) { return; } while ( $search_results_query->have_posts() ) { $post = $search_results_query->next_post(); if ( 'markup' === $response_format ) { $var_by_ref = $post->ID; echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', array( get_post( $var_by_ref ) ) ), 0, (object) $args ); } elseif ( 'json' === $response_format ) { echo wp_json_encode( array( 'ID' => $post->ID, 'post_title' => get_the_title( $post->ID ), 'post_type' => $matches[2], ) ); echo "\n"; } } } elseif ( 'taxonomy' === $matches[1] ) { $terms = get_terms( array( 'taxonomy' => $matches[2], 'name__like' => $query, 'number' => 10, 'hide_empty' => false, ) ); if ( empty( $terms ) || is_wp_error( $terms ) ) { return; } foreach ( (array) $terms as $term ) { if ( 'markup' === $response_format ) { echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', array( $term ) ), 0, (object) $args ); } elseif ( 'json' === $response_format ) { echo wp_json_encode( array( 'ID' => $term->term_id, 'post_title' => $term->name, 'post_type' => $matches[2], ) ); echo "\n"; } } } } } /** * Register nav menu meta boxes and advanced menu items. * * @since 3.0.0 */ function wp_nav_menu_setup() { // Register meta boxes. wp_nav_menu_post_type_meta_boxes(); add_meta_box( 'add-custom-links', __( 'Custom Links' ), 'wp_nav_menu_item_link_meta_box', 'nav-menus', 'side', 'default' ); wp_nav_menu_taxonomy_meta_boxes(); // Register advanced menu items (columns). add_filter( 'manage_nav-menus_columns', 'wp_nav_menu_manage_columns' ); // If first time editing, disable advanced items by default. if ( false === get_user_option( 'managenav-menuscolumnshidden' ) ) { $user = wp_get_current_user(); update_user_meta( $user->ID, 'managenav-menuscolumnshidden', array( 0 => 'link-target', 1 => 'css-classes', 2 => 'xfn', 3 => 'description', 4 => 'title-attribute', ) ); } } /** * Limit the amount of meta boxes to pages, posts, links, and categories for first time users. * * @since 3.0.0 * * @global array $wp_meta_boxes Global meta box state. */ function wp_initial_nav_menu_meta_boxes() { global $wp_meta_boxes; if ( get_user_option( 'metaboxhidden_nav-menus' ) !== false || ! is_array( $wp_meta_boxes ) ) { return; } $initial_meta_boxes = array( 'add-post-type-page', 'add-post-type-post', 'add-custom-links', 'add-category' ); $hidden_meta_boxes = array(); foreach ( array_keys( $wp_meta_boxes['nav-menus'] ) as $context ) { foreach ( array_keys( $wp_meta_boxes['nav-menus'][ $context ] ) as $priority ) { foreach ( $wp_meta_boxes['nav-menus'][ $context ][ $priority ] as $box ) { if ( in_array( $box['id'], $initial_meta_boxes, true ) ) { unset( $box['id'] ); } else { $hidden_meta_boxes[] = $box['id']; } } } } $user = wp_get_current_user(); update_user_meta( $user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes ); } /** * Creates meta boxes for any post type menu item.. * * @since 3.0.0 */ function wp_nav_menu_post_type_meta_boxes() { $post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'object' ); if ( ! $post_types ) { return; } foreach ( $post_types as $post_type ) { /** * Filters whether a menu items meta box will be added for the current * object type. * * If a falsey value is returned instead of an object, the menu items * meta box for the current meta box object will not be added. * * @since 3.0.0 * * @param WP_Post_Type|false $post_type The current object to add a menu items * meta box for. */ $post_type = apply_filters( 'nav_menu_meta_box_object', $post_type ); if ( $post_type ) { $id = $post_type->name; // Give pages a higher priority. $priority = ( 'page' === $post_type->name ? 'core' : 'default' ); add_meta_box( "add-post-type-{$id}", $post_type->labels->name, 'wp_nav_menu_item_post_type_meta_box', 'nav-menus', 'side', $priority, $post_type ); } } } /** * Creates meta boxes for any taxonomy menu item. * * @since 3.0.0 */ function wp_nav_menu_taxonomy_meta_boxes() { $taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'object' ); if ( ! $taxonomies ) { return; } foreach ( $taxonomies as $tax ) { /** This filter is documented in wp-admin/includes/nav-menu.php */ $tax = apply_filters( 'nav_menu_meta_box_object', $tax ); if ( $tax ) { $id = $tax->name; add_meta_box( "add-{$id}", $tax->labels->name, 'wp_nav_menu_item_taxonomy_meta_box', 'nav-menus', 'side', 'default', $tax ); } } } /** * Check whether to disable the Menu Locations meta box submit button and inputs. * * @since 3.6.0 * @since 5.3.1 The `$display` parameter was added. * * @global bool $one_theme_location_no_menus to determine if no menus exist * * @param int|string $nav_menu_selected_id ID, name, or slug of the currently selected menu. * @param bool $display Whether to display or just return the string. * @return string|false Disabled attribute if at least one menu exists, false if not. */ function wp_nav_menu_disabled_check( $nav_menu_selected_id, $display = true ) { global $one_theme_location_no_menus; if ( $one_theme_location_no_menus ) { return false; } return disabled( $nav_menu_selected_id, 0, $display ); } /** * Displays a meta box for the custom links menu item. * * @since 3.0.0 * * @global int $_nav_menu_placeholder * @global int|string $nav_menu_selected_id */ function wp_nav_menu_item_link_meta_box() { global $_nav_menu_placeholder, $nav_menu_selected_id; $_nav_menu_placeholder = 0 > $_nav_menu_placeholder ? $_nav_menu_placeholder - 1 : -1; ?> <div class="customlinkdiv" id="customlinkdiv"> <input type="hidden" value="custom" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-type]" /> <p id="menu-item-url-wrap" class="wp-clearfix"> <label class="howto" for="custom-menu-item-url"><?php _e( 'URL' ); ?></label> <input id="custom-menu-item-url" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-url]" type="text"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="code menu-item-textbox form-required" placeholder="https://" /> <span id="custom-url-error" class="error-message" style="display: none;"><?php _e( 'Please provide a valid link.' ); ?></span> </p> <p id="menu-item-name-wrap" class="wp-clearfix"> <label class="howto" for="custom-menu-item-name"><?php _e( 'Link Text' ); ?></label> <input id="custom-menu-item-name" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-title]" type="text"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="regular-text menu-item-textbox" /> </p> <p class="button-controls wp-clearfix"> <span class="add-to-menu"> <input id="submit-customlinkdiv" name="add-custom-menu-item" type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" /> <span class="spinner"></span> </span> </p> </div><!-- /.customlinkdiv --> <?php } /** * Displays a meta box for a post type menu item. * * @since 3.0.0 * * @global int $_nav_menu_placeholder * @global int|string $nav_menu_selected_id * * @param string $data_object Not used. * @param array $box { * Post type menu item meta box arguments. * * @type string $id Meta box 'id' attribute. * @type string $title Meta box title. * @type callable $callback Meta box display callback. * @type WP_Post_Type $args Extra meta box arguments (the post type object for this meta box). * } */ function wp_nav_menu_item_post_type_meta_box( $data_object, $box ) { global $_nav_menu_placeholder, $nav_menu_selected_id; $post_type_name = $box['args']->name; $post_type = get_post_type_object( $post_type_name ); $tab_name = $post_type_name . '-tab'; // Paginate browsing for large numbers of post objects. $per_page = 50; $pagenum = isset( $_REQUEST[ $tab_name ] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1; $offset = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0; $args = array( 'offset' => $offset, 'order' => 'ASC', 'orderby' => 'title', 'posts_per_page' => $per_page, 'post_type' => $post_type_name, 'suppress_filters' => true, 'update_post_term_cache' => false, 'update_post_meta_cache' => false, ); if ( isset( $box['args']->_default_query ) ) { $args = array_merge( $args, (array) $box['args']->_default_query ); } /* * If we're dealing with pages, let's prioritize the Front Page, * Posts Page and Privacy Policy Page at the top of the list. */ $important_pages = array(); if ( 'page' === $post_type_name ) { $suppress_page_ids = array(); // Insert Front Page or custom Home link. $front_page = 'page' === get_option( 'show_on_front' ) ? (int) get_option( 'page_on_front' ) : 0; $front_page_obj = null; if ( ! empty( $front_page ) ) { $front_page_obj = get_post( $front_page ); } if ( $front_page_obj ) { $front_page_obj->front_or_home = true; $important_pages[] = $front_page_obj; $suppress_page_ids[] = $front_page_obj->ID; } else { $_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? (int) $_nav_menu_placeholder - 1 : -1; $front_page_obj = (object) array( 'front_or_home' => true, 'ID' => 0, 'object_id' => $_nav_menu_placeholder, 'post_content' => '', 'post_excerpt' => '', 'post_parent' => '', 'post_title' => _x( 'Home', 'nav menu home label' ), 'post_type' => 'nav_menu_item', 'type' => 'custom', 'url' => home_url( '/' ), ); $important_pages[] = $front_page_obj; } // Insert Posts Page. $posts_page = 'page' === get_option( 'show_on_front' ) ? (int) get_option( 'page_for_posts' ) : 0; if ( ! empty( $posts_page ) ) { $posts_page_obj = get_post( $posts_page ); if ( $posts_page_obj ) { $front_page_obj->posts_page = true; $important_pages[] = $posts_page_obj; $suppress_page_ids[] = $posts_page_obj->ID; } } // Insert Privacy Policy Page. $privacy_policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' ); if ( ! empty( $privacy_policy_page_id ) ) { $privacy_policy_page = get_post( $privacy_policy_page_id ); if ( $privacy_policy_page instanceof WP_Post && 'publish' === $privacy_policy_page->post_status ) { $privacy_policy_page->privacy_policy_page = true; $important_pages[] = $privacy_policy_page; $suppress_page_ids[] = $privacy_policy_page->ID; } } // Add suppression array to arguments for WP_Query. if ( ! empty( $suppress_page_ids ) ) { $args['post__not_in'] = $suppress_page_ids; } } $get_posts = new WP_Query(); $posts = $get_posts->query( $args ); // Only suppress and insert when more than just suppression pages available. if ( ! $get_posts->post_count ) { if ( ! empty( $suppress_page_ids ) ) { unset( $args['post__not_in'] ); $get_posts = new WP_Query(); $posts = $get_posts->query( $args ); } else { echo '<p>' . __( 'No items.' ) . '</p>'; return; } } elseif ( ! empty( $important_pages ) ) { $posts = array_merge( $important_pages, $posts ); } $num_pages = $get_posts->max_num_pages; $page_links = paginate_links( array( 'base' => add_query_arg( array( $tab_name => 'all', 'paged' => '%#%', 'item-type' => 'post_type', 'item-object' => $post_type_name, ) ), 'format' => '', 'prev_text' => '<span aria-label="' . esc_attr__( 'Previous page' ) . '">' . __( '«' ) . '</span>', 'next_text' => '<span aria-label="' . esc_attr__( 'Next page' ) . '">' . __( '»' ) . '</span>', /* translators: Hidden accessibility text. */ 'before_page_number' => '<span class="screen-reader-text">' . __( 'Page' ) . '</span> ', 'total' => $num_pages, 'current' => $pagenum, ) ); $db_fields = false; if ( is_post_type_hierarchical( $post_type_name ) ) { $db_fields = array( 'parent' => 'post_parent', 'id' => 'ID', ); } $walker = new Walker_Nav_Menu_Checklist( $db_fields ); $current_tab = 'most-recent'; if ( isset( $_REQUEST[ $tab_name ] ) && in_array( $_REQUEST[ $tab_name ], array( 'all', 'search' ), true ) ) { $current_tab = $_REQUEST[ $tab_name ]; } if ( ! empty( $_REQUEST[ "quick-search-posttype-{$post_type_name}" ] ) ) { $current_tab = 'search'; } $removed_args = array( 'action', 'customlink-tab', 'edit-menu-item', 'menu-item', 'page-tab', '_wpnonce', ); $most_recent_url = ''; $view_all_url = ''; $search_url = ''; if ( $nav_menu_selected_id ) { $most_recent_url = add_query_arg( $tab_name, 'most-recent', remove_query_arg( $removed_args ) ); $view_all_url = add_query_arg( $tab_name, 'all', remove_query_arg( $removed_args ) ); $search_url = add_query_arg( $tab_name, 'search', remove_query_arg( $removed_args ) ); } ?> <div id="<?php echo esc_attr( "posttype-{$post_type_name}" ); ?>" class="posttypediv"> <ul id="<?php echo esc_attr( "posttype-{$post_type_name}-tabs" ); ?>" class="posttype-tabs add-menu-item-tabs"> <li <?php echo ( 'most-recent' === $current_tab ? ' class="tabs"' : '' ); ?>> <a class="nav-tab-link" data-type="<?php echo esc_attr( "tabs-panel-posttype-{$post_type_name}-most-recent" ); ?>" href="<?php echo esc_url( $most_recent_url . "#tabs-panel-posttype-{$post_type_name}-most-recent" ); ?>" > <?php _e( 'Most Recent' ); ?> </a> </li> <li <?php echo ( 'all' === $current_tab ? ' class="tabs"' : '' ); ?>> <a class="nav-tab-link" data-type="<?php echo esc_attr( "{$post_type_name}-all" ); ?>" href="<?php echo esc_url( $view_all_url . "#{$post_type_name}-all" ); ?>" > <?php _e( 'View All' ); ?> </a> </li> <li <?php echo ( 'search' === $current_tab ? ' class="tabs"' : '' ); ?>> <a class="nav-tab-link" data-type="<?php echo esc_attr( "tabs-panel-posttype-{$post_type_name}-search" ); ?>" href="<?php echo esc_url( $search_url . "#tabs-panel-posttype-{$post_type_name}-search" ); ?>" > <?php _e( 'Search' ); ?> </a> </li> </ul><!-- .posttype-tabs --> <div id="<?php echo esc_attr( "tabs-panel-posttype-{$post_type_name}-most-recent" ); ?>" class="tabs-panel <?php echo ( 'most-recent' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" role="region" aria-label="<?php esc_attr_e( 'Most Recent' ); ?>" tabindex="0" > <ul id="<?php echo esc_attr( "{$post_type_name}checklist-most-recent" ); ?>" class="categorychecklist form-no-clear" > <?php $recent_args = array_merge( $args, array( 'orderby' => 'post_date', 'order' => 'DESC', 'posts_per_page' => 15, ) ); $most_recent = $get_posts->query( $recent_args ); $args['walker'] = $walker; /** * Filters the posts displayed in the 'Most Recent' tab of the current * post type's menu items meta box. * * The dynamic portion of the hook name, `$post_type_name`, refers to the post type name. * * Possible hook names include: * * - `nav_menu_items_post_recent` * - `nav_menu_items_page_recent` * * @since 4.3.0 * @since 4.9.0 Added the `$recent_args` parameter. * * @param WP_Post[] $most_recent An array of post objects being listed. * @param array $args An array of `WP_Query` arguments for the meta box. * @param array $box Arguments passed to `wp_nav_menu_item_post_type_meta_box()`. * @param array $recent_args An array of `WP_Query` arguments for 'Most Recent' tab. */ $most_recent = apply_filters( "nav_menu_items_{$post_type_name}_recent", $most_recent, $args, $box, $recent_args ); echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $most_recent ), 0, (object) $args ); ?> </ul> </div><!-- /.tabs-panel --> <div id="<?php echo esc_attr( "tabs-panel-posttype-{$post_type_name}-search" ); ?>" class="tabs-panel <?php echo ( 'search' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" role="region" aria-label="<?php echo esc_attr( $post_type->labels->search_items ); ?>" tabindex="0" > <?php if ( isset( $_REQUEST[ "quick-search-posttype-{$post_type_name}" ] ) ) { $searched = esc_attr( $_REQUEST[ "quick-search-posttype-{$post_type_name}" ] ); $search_results = get_posts( array( 's' => $searched, 'post_type' => $post_type_name, 'fields' => 'all', 'order' => 'DESC', ) ); } else { $searched = ''; $search_results = array(); } ?> <p class="quick-search-wrap"> <label for="<?php echo esc_attr( "quick-search-posttype-{$post_type_name}" ); ?>" class="screen-reader-text"> <?php /* translators: Hidden accessibility text. */ _e( 'Search' ); ?> </label> <input type="search"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="quick-search" value="<?php echo $searched; ?>" name="<?php echo esc_attr( "quick-search-posttype-{$post_type_name}" ); ?>" id="<?php echo esc_attr( "quick-search-posttype-{$post_type_name}" ); ?>" /> <span class="spinner"></span> <?php submit_button( __( 'Search' ), 'small quick-search-submit hide-if-js', 'submit', false, array( 'id' => "submit-quick-search-posttype-{$post_type_name}" ) ); ?> </p> <ul id="<?php echo esc_attr( "{$post_type_name}-search-checklist" ); ?>" data-wp-lists="<?php echo esc_attr( "list:{$post_type_name}" ); ?>" class="categorychecklist form-no-clear" > <?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?> <?php $args['walker'] = $walker; echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $search_results ), 0, (object) $args ); ?> <?php elseif ( is_wp_error( $search_results ) ) : ?> <li><?php echo $search_results->get_error_message(); ?></li> <?php elseif ( ! empty( $searched ) ) : ?> <li><?php _e( 'No results found.' ); ?></li> <?php endif; ?> </ul> </div><!-- /.tabs-panel --> <div id="<?php echo esc_attr( "{$post_type_name}-all" ); ?>" class="tabs-panel tabs-panel-view-all <?php echo ( 'all' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" role="region" aria-label="<?php echo esc_attr( $post_type->labels->all_items ); ?>" tabindex="0" > <?php if ( ! empty( $page_links ) ) : ?> <div class="add-menu-item-pagelinks"> <?php echo $page_links; ?> </div> <?php endif; ?> <ul id="<?php echo esc_attr( "{$post_type_name}checklist" ); ?>" data-wp-lists="<?php echo esc_attr( "list:{$post_type_name}" ); ?>" class="categorychecklist form-no-clear" > <?php $args['walker'] = $walker; if ( $post_type->has_archive ) { $_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? (int) $_nav_menu_placeholder - 1 : -1; array_unshift( $posts, (object) array( 'ID' => 0, 'object_id' => $_nav_menu_placeholder, 'object' => $post_type_name, 'post_content' => '', 'post_excerpt' => '', 'post_title' => $post_type->labels->archives, 'post_type' => 'nav_menu_item', 'type' => 'post_type_archive', 'url' => get_post_type_archive_link( $post_type_name ), ) ); } /** * Filters the posts displayed in the 'View All' tab of the current * post type's menu items meta box. * * The dynamic portion of the hook name, `$post_type_name`, refers * to the slug of the current post type. * * Possible hook names include: * * - `nav_menu_items_post` * - `nav_menu_items_page` * * @since 3.2.0 * @since 4.6.0 Converted the `$post_type` parameter to accept a WP_Post_Type object. * * @see WP_Query::query() * * @param object[] $posts The posts for the current post type. Mostly `WP_Post` objects, but * can also contain "fake" post objects to represent other menu items. * @param array $args An array of `WP_Query` arguments. * @param WP_Post_Type $post_type The current post type object for this menu item meta box. */ $posts = apply_filters( "nav_menu_items_{$post_type_name}", $posts, $args, $post_type ); $checkbox_items = walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $posts ), 0, (object) $args ); echo $checkbox_items; ?> </ul> <?php if ( ! empty( $page_links ) ) : ?> <div class="add-menu-item-pagelinks"> <?php echo $page_links; ?> </div> <?php endif; ?> </div><!-- /.tabs-panel --> <p class="button-controls wp-clearfix" data-items-type="<?php echo esc_attr( "posttype-{$post_type_name}" ); ?>"> <span class="list-controls hide-if-no-js"> <input type="checkbox"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> id="<?php echo esc_attr( $tab_name ); ?>" class="select-all" /> <label for="<?php echo esc_attr( $tab_name ); ?>"><?php _e( 'Select All' ); ?></label> </span> <span class="add-to-menu"> <input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-post-type-menu-item" id="<?php echo esc_attr( "submit-posttype-{$post_type_name}" ); ?>" /> <span class="spinner"></span> </span> </p> </div><!-- /.posttypediv --> <?php } /** * Displays a meta box for a taxonomy menu item. * * @since 3.0.0 * * @global int|string $nav_menu_selected_id * * @param string $data_object Not used. * @param array $box { * Taxonomy menu item meta box arguments. * * @type string $id Meta box 'id' attribute. * @type string $title Meta box title. * @type callable $callback Meta box display callback. * @type object $args Extra meta box arguments (the taxonomy object for this meta box). * } */ function wp_nav_menu_item_taxonomy_meta_box( $data_object, $box ) { global $nav_menu_selected_id; $taxonomy_name = $box['args']->name; $taxonomy = get_taxonomy( $taxonomy_name ); $tab_name = $taxonomy_name . '-tab'; // Paginate browsing for large numbers of objects. $per_page = 50; $pagenum = isset( $_REQUEST[ $tab_name ] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1; $offset = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0; $args = array( 'taxonomy' => $taxonomy_name, 'child_of' => 0, 'exclude' => '', 'hide_empty' => false, 'hierarchical' => 1, 'include' => '', 'number' => $per_page, 'offset' => $offset, 'order' => 'ASC', 'orderby' => 'name', 'pad_counts' => false, ); $terms = get_terms( $args ); if ( ! $terms || is_wp_error( $terms ) ) { echo '<p>' . __( 'No items.' ) . '</p>'; return; } $num_pages = (int) ceil( (int) wp_count_terms( array_merge( $args, array( 'number' => '', 'offset' => '', ) ) ) / $per_page ); $page_links = paginate_links( array( 'base' => add_query_arg( array( $tab_name => 'all', 'paged' => '%#%', 'item-type' => 'taxonomy', 'item-object' => $taxonomy_name, ) ), 'format' => '', 'prev_text' => '<span aria-label="' . esc_attr__( 'Previous page' ) . '">' . __( '«' ) . '</span>', 'next_text' => '<span aria-label="' . esc_attr__( 'Next page' ) . '">' . __( '»' ) . '</span>', /* translators: Hidden accessibility text. */ 'before_page_number' => '<span class="screen-reader-text">' . __( 'Page' ) . '</span> ', 'total' => $num_pages, 'current' => $pagenum, ) ); $db_fields = false; if ( is_taxonomy_hierarchical( $taxonomy_name ) ) { $db_fields = array( 'parent' => 'parent', 'id' => 'term_id', ); } $walker = new Walker_Nav_Menu_Checklist( $db_fields ); $current_tab = 'most-used'; if ( isset( $_REQUEST[ $tab_name ] ) && in_array( $_REQUEST[ $tab_name ], array( 'all', 'most-used', 'search' ), true ) ) { $current_tab = $_REQUEST[ $tab_name ]; } if ( ! empty( $_REQUEST[ "quick-search-taxonomy-{$taxonomy_name}" ] ) ) { $current_tab = 'search'; } $removed_args = array( 'action', 'customlink-tab', 'edit-menu-item', 'menu-item', 'page-tab', '_wpnonce', ); $most_used_url = ''; $view_all_url = ''; $search_url = ''; if ( $nav_menu_selected_id ) { $most_used_url = add_query_arg( $tab_name, 'most-used', remove_query_arg( $removed_args ) ); $view_all_url = add_query_arg( $tab_name, 'all', remove_query_arg( $removed_args ) ); $search_url = add_query_arg( $tab_name, 'search', remove_query_arg( $removed_args ) ); } ?> <div id="<?php echo esc_attr( "taxonomy-{$taxonomy_name}" ); ?>" class="taxonomydiv"> <ul id="<?php echo esc_attr( "taxonomy-{$taxonomy_name}-tabs" ); ?>" class="taxonomy-tabs add-menu-item-tabs"> <li <?php echo ( 'most-used' === $current_tab ? ' class="tabs"' : '' ); ?>> <a class="nav-tab-link" data-type="<?php echo esc_attr( "tabs-panel-{$taxonomy_name}-pop" ); ?>" href="<?php echo esc_url( $most_used_url . "#tabs-panel-{$taxonomy_name}-pop" ); ?>" > <?php echo esc_html( $taxonomy->labels->most_used ); ?> </a> </li> <li <?php echo ( 'all' === $current_tab ? ' class="tabs"' : '' ); ?>> <a class="nav-tab-link" data-type="<?php echo esc_attr( "tabs-panel-{$taxonomy_name}-all" ); ?>" href="<?php echo esc_url( $view_all_url . "#tabs-panel-{$taxonomy_name}-all" ); ?>" > <?php _e( 'View All' ); ?> </a> </li> <li <?php echo ( 'search' === $current_tab ? ' class="tabs"' : '' ); ?>> <a class="nav-tab-link" data-type="<?php echo esc_attr( "tabs-panel-search-taxonomy-{$taxonomy_name}" ); ?>" href="<?php echo esc_url( $search_url . "#tabs-panel-search-taxonomy-{$taxonomy_name}" ); ?>" > <?php _e( 'Search' ); ?> </a> </li> </ul><!-- .taxonomy-tabs --> <div id="<?php echo esc_attr( "tabs-panel-{$taxonomy_name}-pop" ); ?>" class="tabs-panel <?php echo ( 'most-used' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" role="region" aria-label="<?php echo esc_attr( $taxonomy->labels->most_used ); ?>" tabindex="0" > <ul id="<?php echo esc_attr( "{$taxonomy_name}checklist-pop" ); ?>" class="categorychecklist form-no-clear" > <?php $popular_terms = get_terms( array( 'taxonomy' => $taxonomy_name, 'orderby' => 'count', 'order' => 'DESC', 'number' => 10, 'hierarchical' => false, ) ); $args['walker'] = $walker; echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $popular_terms ), 0, (object) $args ); ?> </ul> </div><!-- /.tabs-panel --> <div id="<?php echo esc_attr( "tabs-panel-{$taxonomy_name}-all" ); ?>" class="tabs-panel tabs-panel-view-all <?php echo ( 'all' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" role="region" aria-label="<?php echo esc_attr( $taxonomy->labels->all_items ); ?>" tabindex="0" > <?php if ( ! empty( $page_links ) ) : ?> <div class="add-menu-item-pagelinks"> <?php echo $page_links; ?> </div> <?php endif; ?> <ul id="<?php echo esc_attr( "{$taxonomy_name}checklist" ); ?>" data-wp-lists="<?php echo esc_attr( "list:{$taxonomy_name}" ); ?>" class="categorychecklist form-no-clear" > <?php $args['walker'] = $walker; echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $terms ), 0, (object) $args ); ?> </ul> <?php if ( ! empty( $page_links ) ) : ?> <div class="add-menu-item-pagelinks"> <?php echo $page_links; ?> </div> <?php endif; ?> </div><!-- /.tabs-panel --> <div id="<?php echo esc_attr( "tabs-panel-search-taxonomy-{$taxonomy_name}" ); ?>" class="tabs-panel <?php echo ( 'search' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" role="region" aria-label="<?php echo esc_attr( $taxonomy->labels->search_items ); ?>" tabindex="0"> <?php if ( isset( $_REQUEST[ "quick-search-taxonomy-{$taxonomy_name}" ] ) ) { $searched = esc_attr( $_REQUEST[ "quick-search-taxonomy-{$taxonomy_name}" ] ); $search_results = get_terms( array( 'taxonomy' => $taxonomy_name, 'name__like' => $searched, 'fields' => 'all', 'orderby' => 'count', 'order' => 'DESC', 'hierarchical' => false, ) ); } else { $searched = ''; $search_results = array(); } ?> <p class="quick-search-wrap"> <label for="<?php echo esc_attr( "quick-search-taxonomy-{$taxonomy_name}" ); ?>" class="screen-reader-text"> <?php /* translators: Hidden accessibility text. */ _e( 'Search' ); ?> </label> <input type="search" class="quick-search" value="<?php echo $searched; ?>" name="<?php echo esc_attr( "quick-search-taxonomy-{$taxonomy_name}" ); ?>" id="<?php echo esc_attr( "quick-search-taxonomy-{$taxonomy_name}" ); ?>" /> <span class="spinner"></span> <?php submit_button( __( 'Search' ), 'small quick-search-submit hide-if-js', 'submit', false, array( 'id' => "submit-quick-search-taxonomy-{$taxonomy_name}" ) ); ?> </p> <ul id="<?php echo esc_attr( "{$taxonomy_name}-search-checklist" ); ?>" data-wp-lists="<?php echo esc_attr( "list:{$taxonomy_name}" ); ?>" class="categorychecklist form-no-clear" > <?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?> <?php $args['walker'] = $walker; echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $search_results ), 0, (object) $args ); ?> <?php elseif ( is_wp_error( $search_results ) ) : ?> <li><?php echo $search_results->get_error_message(); ?></li> <?php elseif ( ! empty( $searched ) ) : ?> <li><?php _e( 'No results found.' ); ?></li> <?php endif; ?> </ul> </div><!-- /.tabs-panel --> <p class="button-controls wp-clearfix" data-items-type="<?php echo esc_attr( "taxonomy-{$taxonomy_name}" ); ?>"> <span class="list-controls hide-if-no-js"> <input type="checkbox"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> id="<?php echo esc_attr( $tab_name ); ?>" class="select-all" /> <label for="<?php echo esc_attr( $tab_name ); ?>"><?php _e( 'Select All' ); ?></label> </span> <span class="add-to-menu"> <input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-taxonomy-menu-item" id="<?php echo esc_attr( "submit-taxonomy-{$taxonomy_name}" ); ?>" /> <span class="spinner"></span> </span> </p> </div><!-- /.taxonomydiv --> <?php } /** * Save posted nav menu item data. * * @since 3.0.0 * * @param int $menu_id The menu ID for which to save this item. Value of 0 makes a draft, orphaned menu item. Default 0. * @param array[] $menu_data The unsanitized POSTed menu item data. * @return int[] The database IDs of the items saved */ function wp_save_nav_menu_items( $menu_id = 0, $menu_data = array() ) { $menu_id = (int) $menu_id; $items_saved = array(); if ( 0 === $menu_id || is_nav_menu( $menu_id ) ) { // Loop through all the menu items' POST values. foreach ( (array) $menu_data as $_possible_db_id => $_item_object_data ) { if ( // Checkbox is not checked. empty( $_item_object_data['menu-item-object-id'] ) && ( // And item type either isn't set. ! isset( $_item_object_data['menu-item-type'] ) || // Or URL is the default. in_array( $_item_object_data['menu-item-url'], array( 'https://', 'http://', '' ), true ) || // Or it's not a custom menu item (but not the custom home page). ! ( 'custom' === $_item_object_data['menu-item-type'] && ! isset( $_item_object_data['menu-item-db-id'] ) ) || // Or it *is* a custom menu item that already exists. ! empty( $_item_object_data['menu-item-db-id'] ) ) ) { // Then this potential menu item is not getting added to this menu. continue; } // If this possible menu item doesn't actually have a menu database ID yet. if ( empty( $_item_object_data['menu-item-db-id'] ) || ( 0 > $_possible_db_id ) || $_possible_db_id !== (int) $_item_object_data['menu-item-db-id'] ) { $_actual_db_id = 0; } else { $_actual_db_id = (int) $_item_object_data['menu-item-db-id']; } $args = array( 'menu-item-db-id' => ( isset( $_item_object_data['menu-item-db-id'] ) ? $_item_object_data['menu-item-db-id'] : '' ), 'menu-item-object-id' => ( isset( $_item_object_data['menu-item-object-id'] ) ? $_item_object_data['menu-item-object-id'] : '' ), 'menu-item-object' => ( isset( $_item_object_data['menu-item-object'] ) ? $_item_object_data['menu-item-object'] : '' ), 'menu-item-parent-id' => ( isset( $_item_object_data['menu-item-parent-id'] ) ? $_item_object_data['menu-item-parent-id'] : '' ), 'menu-item-position' => ( isset( $_item_object_data['menu-item-position'] ) ? $_item_object_data['menu-item-position'] : '' ), 'menu-item-type' => ( isset( $_item_object_data['menu-item-type'] ) ? $_item_object_data['menu-item-type'] : '' ), 'menu-item-title' => ( isset( $_item_object_data['menu-item-title'] ) ? $_item_object_data['menu-item-title'] : '' ), 'menu-item-url' => ( isset( $_item_object_data['menu-item-url'] ) ? $_item_object_data['menu-item-url'] : '' ), 'menu-item-description' => ( isset( $_item_object_data['menu-item-description'] ) ? $_item_object_data['menu-item-description'] : '' ), 'menu-item-attr-title' => ( isset( $_item_object_data['menu-item-attr-title'] ) ? $_item_object_data['menu-item-attr-title'] : '' ), 'menu-item-target' => ( isset( $_item_object_data['menu-item-target'] ) ? $_item_object_data['menu-item-target'] : '' ), 'menu-item-classes' => ( isset( $_item_object_data['menu-item-classes'] ) ? $_item_object_data['menu-item-classes'] : '' ), 'menu-item-xfn' => ( isset( $_item_object_data['menu-item-xfn'] ) ? $_item_object_data['menu-item-xfn'] : '' ), ); $items_saved[] = wp_update_nav_menu_item( $menu_id, $_actual_db_id, $args ); } } return $items_saved; } /** * Adds custom arguments to some of the meta box object types. * * @since 3.0.0 * * @access private * * @param object $data_object The post type or taxonomy meta-object. * @return object The post type or taxonomy object. */ function _wp_nav_menu_meta_box_object( $data_object = null ) { if ( isset( $data_object->name ) ) { if ( 'page' === $data_object->name ) { $data_object->_default_query = array( 'orderby' => 'menu_order title', 'post_status' => 'publish', ); // Posts should show only published items. } elseif ( 'post' === $data_object->name ) { $data_object->_default_query = array( 'post_status' => 'publish', ); // Categories should be in reverse chronological order. } elseif ( 'category' === $data_object->name ) { $data_object->_default_query = array( 'orderby' => 'id', 'order' => 'DESC', ); // Custom post types should show only published items. } else { $data_object->_default_query = array( 'post_status' => 'publish', ); } } return $data_object; } /** * Returns the menu formatted to edit. * * @since 3.0.0 * * @param int $menu_id Optional. The ID of the menu to format. Default 0. * @return string|WP_Error|null The menu formatted to edit or error object on failure. * Null if the `$menu_id` parameter is not supplied or the term does not exist. */ function wp_get_nav_menu_to_edit( $menu_id = 0 ) { $menu = wp_get_nav_menu_object( $menu_id ); // If the menu exists, get its items. if ( is_nav_menu( $menu ) ) { $menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'post_status' => 'any' ) ); $result = '<div id="menu-instructions" class="post-body-plain'; $result .= ( ! empty( $menu_items ) ) ? ' menu-instructions-inactive">' : '">'; $result .= '<p>' . __( 'Add menu items from the column on the left.' ) . '</p>'; $result .= '</div>'; if ( empty( $menu_items ) ) { return $result . ' <ul class="menu" id="menu-to-edit"> </ul>'; } /** * Filters the Walker class used when adding nav menu items. * * @since 3.0.0 * * @param string $class The walker class to use. Default 'Walker_Nav_Menu_Edit'. * @param int $menu_id ID of the menu being rendered. */ $walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $menu_id ); if ( class_exists( $walker_class_name ) ) { $walker = new $walker_class_name(); } else { return new WP_Error( 'menu_walker_not_exist', sprintf( /* translators: %s: Walker class name. */ __( 'The Walker class named %s does not exist.' ), '<strong>' . $walker_class_name . '</strong>' ) ); } $some_pending_menu_items = false; $some_invalid_menu_items = false; foreach ( (array) $menu_items as $menu_item ) { if ( isset( $menu_item->post_status ) && 'draft' === $menu_item->post_status ) { $some_pending_menu_items = true; } if ( ! empty( $menu_item->_invalid ) ) { $some_invalid_menu_items = true; } } if ( $some_pending_menu_items ) { $message = __( 'Click Save Menu to make pending menu items public.' ); $notice_args = array( 'type' => 'info', 'additional_classes' => array( 'notice-alt', 'inline' ), ); $result .= wp_get_admin_notice( $message, $notice_args ); } if ( $some_invalid_menu_items ) { $message = __( 'There are some invalid menu items. Please check or delete them.' ); $notice_args = array( 'type' => 'error', 'additional_classes' => array( 'notice-alt', 'inline' ), ); $result .= wp_get_admin_notice( $message, $notice_args ); } $result .= '<ul class="menu" id="menu-to-edit"> '; $result .= walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $menu_items ), 0, (object) array( 'walker' => $walker ) ); $result .= ' </ul> '; return $result; } elseif ( is_wp_error( $menu ) ) { return $menu; } return null; } /** * Returns the columns for the nav menus page. * * @since 3.0.0 * * @return string[] Array of column titles keyed by their column name. */ function wp_nav_menu_manage_columns() { return array( '_title' => __( 'Show advanced menu properties' ), 'cb' => '<input type="checkbox" />', 'link-target' => __( 'Link Target' ), 'title-attribute' => __( 'Title Attribute' ), 'css-classes' => __( 'CSS Classes' ), 'xfn' => __( 'Link Relationship (XFN)' ), 'description' => __( 'Description' ), ); } /** * Deletes orphaned draft menu items * * @access private * @since 3.0.0 * * @global wpdb $wpdb WordPress database abstraction object. */ function _wp_delete_orphaned_draft_menu_items() { global $wpdb; $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS ); // Delete orphaned draft menu items. $menu_items_to_delete = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts AS p LEFT JOIN $wpdb->postmeta AS m ON p.ID = m.post_id WHERE post_type = 'nav_menu_item' AND post_status = 'draft' AND meta_key = '_menu_item_orphaned' AND meta_value < %d", $delete_timestamp ) ); foreach ( (array) $menu_items_to_delete as $menu_item_id ) { wp_delete_post( $menu_item_id, true ); } } /** * Saves nav menu items. * * @since 3.6.0 * * @param int|string $nav_menu_selected_id ID, slug, or name of the currently-selected menu. * @param string $nav_menu_selected_title Title of the currently-selected menu. * @return string[] The menu updated messages. */ function wp_nav_menu_update_menu_items( $nav_menu_selected_id, $nav_menu_selected_title ) { $unsorted_menu_items = wp_get_nav_menu_items( $nav_menu_selected_id, array( 'orderby' => 'ID', 'output' => ARRAY_A, 'output_key' => 'ID', 'post_status' => 'draft,publish', ) ); $messages = array(); $menu_items = array(); // Index menu items by DB ID. foreach ( $unsorted_menu_items as $_item ) { $menu_items[ $_item->db_id ] = $_item; } $post_fields = array( 'menu-item-db-id', 'menu-item-object-id', 'menu-item-object', 'menu-item-parent-id', 'menu-item-position', 'menu-item-type', 'menu-item-title', 'menu-item-url', 'menu-item-description', 'menu-item-attr-title', 'menu-item-target', 'menu-item-classes', 'menu-item-xfn', ); wp_defer_term_counting( true ); // Loop through all the menu items' POST variables. if ( ! empty( $_POST['menu-item-db-id'] ) ) { foreach ( (array) $_POST['menu-item-db-id'] as $_key => $k ) { // Menu item title can't be blank. if ( ! isset( $_POST['menu-item-title'][ $_key ] ) || '' === $_POST['menu-item-title'][ $_key ] ) { continue; } $args = array(); foreach ( $post_fields as $field ) { $args[ $field ] = isset( $_POST[ $field ][ $_key ] ) ? $_POST[ $field ][ $_key ] : ''; } $menu_item_db_id = wp_update_nav_menu_item( $nav_menu_selected_id, ( (int) $_POST['menu-item-db-id'][ $_key ] !== $_key ? 0 : $_key ), $args ); if ( is_wp_error( $menu_item_db_id ) ) { $messages[] = wp_get_admin_notice( $menu_item_db_id->get_error_message(), array( 'id' => 'message', 'additional_classes' => array( 'error' ), ) ); } else { unset( $menu_items[ $menu_item_db_id ] ); } } } // Remove menu items from the menu that weren't in $_POST. if ( ! empty( $menu_items ) ) { foreach ( array_keys( $menu_items ) as $menu_item_id ) { if ( is_nav_menu_item( $menu_item_id ) ) { wp_delete_post( $menu_item_id ); } } } // Store 'auto-add' pages. $auto_add = ! empty( $_POST['auto-add-pages'] ); $nav_menu_option = (array) get_option( 'nav_menu_options' ); if ( ! isset( $nav_menu_option['auto_add'] ) ) { $nav_menu_option['auto_add'] = array(); } if ( $auto_add ) { if ( ! in_array( $nav_menu_selected_id, $nav_menu_option['auto_add'], true ) ) { $nav_menu_option['auto_add'][] = $nav_menu_selected_id; } } else { $key = array_search( $nav_menu_selected_id, $nav_menu_option['auto_add'], true ); if ( false !== $key ) { unset( $nav_menu_option['auto_add'][ $key ] ); } } // Remove non-existent/deleted menus. $nav_menu_option['auto_add'] = array_intersect( $nav_menu_option['auto_add'], wp_get_nav_menus( array( 'fields' => 'ids' ) ) ); update_option( 'nav_menu_options', $nav_menu_option, false ); wp_defer_term_counting( false ); /** This action is documented in wp-includes/nav-menu.php */ do_action( 'wp_update_nav_menu', $nav_menu_selected_id ); /* translators: %s: Nav menu title. */ $message = sprintf( __( '%s has been updated.' ), '<strong>' . $nav_menu_selected_title . '</strong>' ); $notice_args = array( 'id' => 'message', 'dismissible' => true, 'additional_classes' => array( 'updated' ), ); $messages[] = wp_get_admin_notice( $message, $notice_args ); unset( $menu_items, $unsorted_menu_items ); return $messages; } /** * If a JSON blob of navigation menu data is in POST data, expand it and inject * it into `$_POST` to avoid PHP `max_input_vars` limitations. See #14134. * * @ignore * @since 4.5.3 * @access private */ function _wp_expand_nav_menu_post_data() { if ( ! isset( $_POST['nav-menu-data'] ) ) { return; } $data = json_decode( stripslashes( $_POST['nav-menu-data'] ) ); if ( ! is_null( $data ) && $data ) { foreach ( $data as $post_input_data ) { /* * For input names that are arrays (e.g. `menu-item-db-id[3][4][5]`), * derive the array path keys via regex and set the value in $_POST. */ preg_match( '#([^\[]*)(\[(.+)\])?#', $post_input_data->name, $matches ); $array_bits = array( $matches[1] ); if ( isset( $matches[3] ) ) { $array_bits = array_merge( $array_bits, explode( '][', $matches[3] ) ); } $new_post_data = array(); // Build the new array value from leaf to trunk. for ( $i = count( $array_bits ) - 1; $i >= 0; $i-- ) { if ( count( $array_bits ) - 1 === $i ) { $new_post_data[ $array_bits[ $i ] ] = wp_slash( $post_input_data->value ); } else { $new_post_data = array( $array_bits[ $i ] => $new_post_data ); } } $_POST = array_replace_recursive( $_POST, $new_post_data ); } } } PK U�g\�2<�Om Om plugin.phpnu �[��� <?php /** * WordPress Plugin Administration API * * @package WordPress * @subpackage Administration */ /** * Parses the plugin contents to retrieve plugin's metadata. * * All plugin headers must be on their own line. Plugin description must not have * any newlines, otherwise only parts of the description will be displayed. * The below is formatted for printing. * * /* * Plugin Name: Name of the plugin. * Plugin URI: The home page of the plugin. * Description: Plugin description. * Author: Plugin author's name. * Author URI: Link to the author's website. * Version: Plugin version. * Text Domain: Optional. Unique identifier, should be same as the one used in * load_plugin_textdomain(). * Domain Path: Optional. Only useful if the translations are located in a * folder above the plugin's base path. For example, if .mo files are * located in the locale folder then Domain Path will be "/locale/" and * must have the first slash. Defaults to the base folder the plugin is * located in. * Network: Optional. Specify "Network: true" to require that a plugin is activated * across all sites in an installation. This will prevent a plugin from being * activated on a single site when Multisite is enabled. * Requires at least: Optional. Specify the minimum required WordPress version. * Requires PHP: Optional. Specify the minimum required PHP version. * * / # Remove the space to close comment. * * The first 8 KB of the file will be pulled in and if the plugin data is not * within that first 8 KB, then the plugin author should correct their plugin * and move the plugin data headers to the top. * * The plugin file is assumed to have permissions to allow for scripts to read * the file. This is not checked however and the file is only opened for * reading. * * @since 1.5.0 * @since 5.3.0 Added support for `Requires at least` and `Requires PHP` headers. * @since 5.8.0 Added support for `Update URI` header. * @since 6.5.0 Added support for `Requires Plugins` header. * * @param string $plugin_file Absolute path to the main plugin file. * @param bool $markup Optional. If the returned data should have HTML markup applied. * Default true. * @param bool $translate Optional. If the returned data should be translated. Default true. * @return array { * Plugin data. Values will be empty if not supplied by the plugin. * * @type string $Name Name of the plugin. Should be unique. * @type string $PluginURI Plugin URI. * @type string $Version Plugin version. * @type string $Description Plugin description. * @type string $Author Plugin author's name. * @type string $AuthorURI Plugin author's website address (if set). * @type string $TextDomain Plugin textdomain. * @type string $DomainPath Plugin's relative directory path to .mo files. * @type bool $Network Whether the plugin can only be activated network-wide. * @type string $RequiresWP Minimum required version of WordPress. * @type string $RequiresPHP Minimum required version of PHP. * @type string $UpdateURI ID of the plugin for update purposes, should be a URI. * @type string $RequiresPlugins Comma separated list of dot org plugin slugs. * @type string $Title Title of the plugin and link to the plugin's site (if set). * @type string $AuthorName Plugin author's name. * } */ function get_plugin_data( $plugin_file, $markup = true, $translate = true ) { $default_headers = array( 'Name' => 'Plugin Name', 'PluginURI' => 'Plugin URI', 'Version' => 'Version', 'Description' => 'Description', 'Author' => 'Author', 'AuthorURI' => 'Author URI', 'TextDomain' => 'Text Domain', 'DomainPath' => 'Domain Path', 'Network' => 'Network', 'RequiresWP' => 'Requires at least', 'RequiresPHP' => 'Requires PHP', 'UpdateURI' => 'Update URI', 'RequiresPlugins' => 'Requires Plugins', // Site Wide Only is deprecated in favor of Network. '_sitewide' => 'Site Wide Only', ); $plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' ); // Site Wide Only is the old header for Network. if ( ! $plugin_data['Network'] && $plugin_data['_sitewide'] ) { /* translators: 1: Site Wide Only: true, 2: Network: true */ _deprecated_argument( __FUNCTION__, '3.0.0', sprintf( __( 'The %1$s plugin header is deprecated. Use %2$s instead.' ), '<code>Site Wide Only: true</code>', '<code>Network: true</code>' ) ); $plugin_data['Network'] = $plugin_data['_sitewide']; } $plugin_data['Network'] = ( 'true' === strtolower( $plugin_data['Network'] ) ); unset( $plugin_data['_sitewide'] ); // If no text domain is defined fall back to the plugin slug. if ( ! $plugin_data['TextDomain'] ) { $plugin_slug = dirname( plugin_basename( $plugin_file ) ); if ( '.' !== $plugin_slug && ! str_contains( $plugin_slug, '/' ) ) { $plugin_data['TextDomain'] = $plugin_slug; } } if ( $markup || $translate ) { $plugin_data = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup, $translate ); } else { $plugin_data['Title'] = $plugin_data['Name']; $plugin_data['AuthorName'] = $plugin_data['Author']; } return $plugin_data; } /** * Sanitizes plugin data, optionally adds markup, optionally translates. * * @since 2.7.0 * * @see get_plugin_data() * * @access private * * @param string $plugin_file Path to the main plugin file. * @param array $plugin_data An array of plugin data. See get_plugin_data(). * @param bool $markup Optional. If the returned data should have HTML markup applied. * Default true. * @param bool $translate Optional. If the returned data should be translated. Default true. * @return array Plugin data. Values will be empty if not supplied by the plugin. * See get_plugin_data() for the list of possible values. */ function _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup = true, $translate = true ) { // Sanitize the plugin filename to a WP_PLUGIN_DIR relative path. $plugin_file = plugin_basename( $plugin_file ); // Translate fields. if ( $translate ) { $textdomain = $plugin_data['TextDomain']; if ( $textdomain ) { if ( ! is_textdomain_loaded( $textdomain ) ) { if ( $plugin_data['DomainPath'] ) { load_plugin_textdomain( $textdomain, false, dirname( $plugin_file ) . $plugin_data['DomainPath'] ); } else { load_plugin_textdomain( $textdomain, false, dirname( $plugin_file ) ); } } } elseif ( 'hello.php' === basename( $plugin_file ) ) { $textdomain = 'default'; } if ( $textdomain ) { foreach ( array( 'Name', 'PluginURI', 'Description', 'Author', 'AuthorURI', 'Version' ) as $field ) { if ( ! empty( $plugin_data[ $field ] ) ) { // phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain $plugin_data[ $field ] = translate( $plugin_data[ $field ], $textdomain ); } } } } // Sanitize fields. $allowed_tags_in_links = array( 'abbr' => array( 'title' => true ), 'acronym' => array( 'title' => true ), 'code' => true, 'em' => true, 'strong' => true, ); $allowed_tags = $allowed_tags_in_links; $allowed_tags['a'] = array( 'href' => true, 'title' => true, ); /* * Name is marked up inside <a> tags. Don't allow these. * Author is too, but some plugins have used <a> here (omitting Author URI). */ $plugin_data['Name'] = wp_kses( $plugin_data['Name'], $allowed_tags_in_links ); $plugin_data['Author'] = wp_kses( $plugin_data['Author'], $allowed_tags ); $plugin_data['Description'] = wp_kses( $plugin_data['Description'], $allowed_tags ); $plugin_data['Version'] = wp_kses( $plugin_data['Version'], $allowed_tags ); $plugin_data['PluginURI'] = esc_url( $plugin_data['PluginURI'] ); $plugin_data['AuthorURI'] = esc_url( $plugin_data['AuthorURI'] ); $plugin_data['Title'] = $plugin_data['Name']; $plugin_data['AuthorName'] = $plugin_data['Author']; // Apply markup. if ( $markup ) { if ( $plugin_data['PluginURI'] && $plugin_data['Name'] ) { $plugin_data['Title'] = '<a href="' . $plugin_data['PluginURI'] . '">' . $plugin_data['Name'] . '</a>'; } if ( $plugin_data['AuthorURI'] && $plugin_data['Author'] ) { $plugin_data['Author'] = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>'; } $plugin_data['Description'] = wptexturize( $plugin_data['Description'] ); if ( $plugin_data['Author'] ) { $plugin_data['Description'] .= sprintf( /* translators: %s: Plugin author. */ ' <cite>' . __( 'By %s.' ) . '</cite>', $plugin_data['Author'] ); } } return $plugin_data; } /** * Gets a list of a plugin's files. * * @since 2.8.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return string[] Array of file names relative to the plugin root. */ function get_plugin_files( $plugin ) { $plugin_file = WP_PLUGIN_DIR . '/' . $plugin; $dir = dirname( $plugin_file ); $plugin_files = array( plugin_basename( $plugin_file ) ); if ( is_dir( $dir ) && WP_PLUGIN_DIR !== $dir ) { /** * Filters the array of excluded directories and files while scanning the folder. * * @since 4.9.0 * * @param string[] $exclusions Array of excluded directories and files. */ $exclusions = (array) apply_filters( 'plugin_files_exclusions', array( 'CVS', 'node_modules', 'vendor', 'bower_components' ) ); $list_files = list_files( $dir, 100, $exclusions ); $list_files = array_map( 'plugin_basename', $list_files ); $plugin_files = array_merge( $plugin_files, $list_files ); $plugin_files = array_values( array_unique( $plugin_files ) ); } return $plugin_files; } /** * Checks the plugins directory and retrieve all plugin files with plugin data. * * WordPress only supports plugin files in the base plugins directory * (wp-content/plugins) and in one directory above the plugins directory * (wp-content/plugins/my-plugin). The file it looks for has the plugin data * and must be found in those two locations. It is recommended to keep your * plugin files in their own directories. * * The file with the plugin data is the file that will be included and therefore * needs to have the main execution for the plugin. This does not mean * everything must be contained in the file and it is recommended that the file * be split for maintainability. Keep everything in one file for extreme * optimization purposes. * * @since 1.5.0 * * @param string $plugin_folder Optional. Relative path to single plugin folder. * @return array[] Array of arrays of plugin data, keyed by plugin file name. See get_plugin_data(). */ function get_plugins( $plugin_folder = '' ) { $cache_plugins = wp_cache_get( 'plugins', 'plugins' ); if ( ! $cache_plugins ) { $cache_plugins = array(); } if ( isset( $cache_plugins[ $plugin_folder ] ) ) { return $cache_plugins[ $plugin_folder ]; } $wp_plugins = array(); $plugin_root = WP_PLUGIN_DIR; if ( ! empty( $plugin_folder ) ) { $plugin_root .= $plugin_folder; } // Files in wp-content/plugins directory. $plugins_dir = @opendir( $plugin_root ); $plugin_files = array(); if ( $plugins_dir ) { while ( ( $file = readdir( $plugins_dir ) ) !== false ) { if ( str_starts_with( $file, '.' ) ) { continue; } if ( is_dir( $plugin_root . '/' . $file ) ) { $plugins_subdir = @opendir( $plugin_root . '/' . $file ); if ( $plugins_subdir ) { while ( ( $subfile = readdir( $plugins_subdir ) ) !== false ) { if ( str_starts_with( $subfile, '.' ) ) { continue; } if ( str_ends_with( $subfile, '.php' ) ) { $plugin_files[] = "$file/$subfile"; } } closedir( $plugins_subdir ); } } elseif ( str_ends_with( $file, '.php' ) ) { $plugin_files[] = $file; } } closedir( $plugins_dir ); } if ( empty( $plugin_files ) ) { return $wp_plugins; } foreach ( $plugin_files as $plugin_file ) { if ( ! is_readable( "$plugin_root/$plugin_file" ) ) { continue; } // Do not apply markup/translate as it will be cached. $plugin_data = get_plugin_data( "$plugin_root/$plugin_file", false, false ); if ( empty( $plugin_data['Name'] ) ) { continue; } $wp_plugins[ plugin_basename( $plugin_file ) ] = $plugin_data; } uasort( $wp_plugins, '_sort_uname_callback' ); $cache_plugins[ $plugin_folder ] = $wp_plugins; wp_cache_set( 'plugins', $cache_plugins, 'plugins' ); return $wp_plugins; } /** * Checks the mu-plugins directory and retrieve all mu-plugin files with any plugin data. * * WordPress only includes mu-plugin files in the base mu-plugins directory (wp-content/mu-plugins). * * @since 3.0.0 * @return array[] Array of arrays of mu-plugin data, keyed by plugin file name. See get_plugin_data(). */ function get_mu_plugins() { $wp_plugins = array(); $plugin_files = array(); if ( ! is_dir( WPMU_PLUGIN_DIR ) ) { return $wp_plugins; } // Files in wp-content/mu-plugins directory. $plugins_dir = @opendir( WPMU_PLUGIN_DIR ); if ( $plugins_dir ) { while ( ( $file = readdir( $plugins_dir ) ) !== false ) { if ( str_ends_with( $file, '.php' ) ) { $plugin_files[] = $file; } } } else { return $wp_plugins; } closedir( $plugins_dir ); if ( empty( $plugin_files ) ) { return $wp_plugins; } foreach ( $plugin_files as $plugin_file ) { if ( ! is_readable( WPMU_PLUGIN_DIR . "/$plugin_file" ) ) { continue; } // Do not apply markup/translate as it will be cached. $plugin_data = get_plugin_data( WPMU_PLUGIN_DIR . "/$plugin_file", false, false ); if ( empty( $plugin_data['Name'] ) ) { $plugin_data['Name'] = $plugin_file; } $wp_plugins[ $plugin_file ] = $plugin_data; } if ( isset( $wp_plugins['index.php'] ) && filesize( WPMU_PLUGIN_DIR . '/index.php' ) <= 30 ) { // Silence is golden. unset( $wp_plugins['index.php'] ); } uasort( $wp_plugins, '_sort_uname_callback' ); return $wp_plugins; } /** * Declares a callback to sort array by a 'Name' key. * * @since 3.1.0 * * @access private * * @param array $a array with 'Name' key. * @param array $b array with 'Name' key. * @return int Return 0 or 1 based on two string comparison. */ function _sort_uname_callback( $a, $b ) { return strnatcasecmp( $a['Name'], $b['Name'] ); } /** * Checks the wp-content directory and retrieve all drop-ins with any plugin data. * * @since 3.0.0 * @return array[] Array of arrays of dropin plugin data, keyed by plugin file name. See get_plugin_data(). */ function get_dropins() { $dropins = array(); $plugin_files = array(); $_dropins = _get_dropins(); // Files in wp-content directory. $plugins_dir = @opendir( WP_CONTENT_DIR ); if ( $plugins_dir ) { while ( ( $file = readdir( $plugins_dir ) ) !== false ) { if ( isset( $_dropins[ $file ] ) ) { $plugin_files[] = $file; } } } else { return $dropins; } closedir( $plugins_dir ); if ( empty( $plugin_files ) ) { return $dropins; } foreach ( $plugin_files as $plugin_file ) { if ( ! is_readable( WP_CONTENT_DIR . "/$plugin_file" ) ) { continue; } // Do not apply markup/translate as it will be cached. $plugin_data = get_plugin_data( WP_CONTENT_DIR . "/$plugin_file", false, false ); if ( empty( $plugin_data['Name'] ) ) { $plugin_data['Name'] = $plugin_file; } $dropins[ $plugin_file ] = $plugin_data; } uksort( $dropins, 'strnatcasecmp' ); return $dropins; } /** * Returns drop-in plugins that WordPress uses. * * Includes Multisite drop-ins only when is_multisite() * * @since 3.0.0 * * @return array[] { * Key is file name. The value is an array of data about the drop-in. * * @type array ...$0 { * Data about the drop-in. * * @type string $0 The purpose of the drop-in. * @type string|true $1 Name of the constant that must be true for the drop-in * to be used, or true if no constant is required. * } * } */ function _get_dropins() { $dropins = array( 'advanced-cache.php' => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE 'db.php' => array( __( 'Custom database class.' ), true ), // Auto on load. 'db-error.php' => array( __( 'Custom database error message.' ), true ), // Auto on error. 'install.php' => array( __( 'Custom installation script.' ), true ), // Auto on installation. 'maintenance.php' => array( __( 'Custom maintenance message.' ), true ), // Auto on maintenance. 'object-cache.php' => array( __( 'External object cache.' ), true ), // Auto on load. 'php-error.php' => array( __( 'Custom PHP error message.' ), true ), // Auto on error. 'fatal-error-handler.php' => array( __( 'Custom PHP fatal error handler.' ), true ), // Auto on error. ); if ( is_multisite() ) { $dropins['sunrise.php'] = array( __( 'Executed before Multisite is loaded.' ), 'SUNRISE' ); // SUNRISE $dropins['blog-deleted.php'] = array( __( 'Custom site deleted message.' ), true ); // Auto on deleted blog. $dropins['blog-inactive.php'] = array( __( 'Custom site inactive message.' ), true ); // Auto on inactive blog. $dropins['blog-suspended.php'] = array( __( 'Custom site suspended message.' ), true ); // Auto on archived or spammed blog. } return $dropins; } /** * Determines whether a plugin is active. * * Only plugins installed in the plugins/ folder can be active. * * Plugins in the mu-plugins/ folder can't be "activated," so this function will * return false for those plugins. * * For more information on this and similar theme functions, check out * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ * Conditional Tags} article in the Theme Developer Handbook. * * @since 2.5.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return bool True, if in the active plugins list. False, not in the list. */ function is_plugin_active( $plugin ) { return in_array( $plugin, (array) get_option( 'active_plugins', array() ), true ) || is_plugin_active_for_network( $plugin ); } /** * Determines whether the plugin is inactive. * * Reverse of is_plugin_active(). Used as a callback. * * For more information on this and similar theme functions, check out * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ * Conditional Tags} article in the Theme Developer Handbook. * * @since 3.1.0 * * @see is_plugin_active() * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return bool True if inactive. False if active. */ function is_plugin_inactive( $plugin ) { return ! is_plugin_active( $plugin ); } /** * Determines whether the plugin is active for the entire network. * * Only plugins installed in the plugins/ folder can be active. * * Plugins in the mu-plugins/ folder can't be "activated," so this function will * return false for those plugins. * * For more information on this and similar theme functions, check out * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ * Conditional Tags} article in the Theme Developer Handbook. * * @since 3.0.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return bool True if active for the network, otherwise false. */ function is_plugin_active_for_network( $plugin ) { if ( ! is_multisite() ) { return false; } $plugins = get_site_option( 'active_sitewide_plugins' ); if ( isset( $plugins[ $plugin ] ) ) { return true; } return false; } /** * Checks for "Network: true" in the plugin header to see if this should * be activated only as a network wide plugin. The plugin would also work * when Multisite is not enabled. * * Checks for "Site Wide Only: true" for backward compatibility. * * @since 3.0.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return bool True if plugin is network only, false otherwise. */ function is_network_only_plugin( $plugin ) { $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ); if ( $plugin_data ) { return $plugin_data['Network']; } return false; } /** * Attempts activation of plugin in a "sandbox" and redirects on success. * * A plugin that is already activated will not attempt to be activated again. * * The way it works is by setting the redirection to the error before trying to * include the plugin file. If the plugin fails, then the redirection will not * be overwritten with the success message. Also, the options will not be * updated and the activation hook will not be called on plugin error. * * It should be noted that in no way the below code will actually prevent errors * within the file. The code should not be used elsewhere to replicate the * "sandbox", which uses redirection to work. * {@source 13 1} * * If any errors are found or text is outputted, then it will be captured to * ensure that the success redirection will update the error redirection. * * @since 2.5.0 * @since 5.2.0 Test for WordPress version and PHP version compatibility. * * @param string $plugin Path to the plugin file relative to the plugins directory. * @param string $redirect Optional. URL to redirect to. * @param bool $network_wide Optional. Whether to enable the plugin for all sites in the network * or just the current site. Multisite only. Default false. * @param bool $silent Optional. Whether to prevent calling activation hooks. Default false. * @return null|WP_Error Null on success, WP_Error on invalid file. */ function activate_plugin( $plugin, $redirect = '', $network_wide = false, $silent = false ) { $plugin = plugin_basename( trim( $plugin ) ); if ( is_multisite() && ( $network_wide || is_network_only_plugin( $plugin ) ) ) { $network_wide = true; $current = get_site_option( 'active_sitewide_plugins', array() ); $_GET['networkwide'] = 1; // Back compat for plugins looking for this value. } else { $current = get_option( 'active_plugins', array() ); } $valid = validate_plugin( $plugin ); if ( is_wp_error( $valid ) ) { return $valid; } $requirements = validate_plugin_requirements( $plugin ); if ( is_wp_error( $requirements ) ) { return $requirements; } if ( $network_wide && ! isset( $current[ $plugin ] ) || ! $network_wide && ! in_array( $plugin, $current, true ) ) { if ( ! empty( $redirect ) ) { // We'll override this later if the plugin can be included without fatal error. wp_redirect( add_query_arg( '_error_nonce', wp_create_nonce( 'plugin-activation-error_' . $plugin ), $redirect ) ); } ob_start(); // Load the plugin to test whether it throws any errors. plugin_sandbox_scrape( $plugin ); if ( ! $silent ) { /** * Fires before a plugin is activated. * * If a plugin is silently activated (such as during an update), * this hook does not fire. * * @since 2.9.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @param bool $network_wide Whether to enable the plugin for all sites in the network * or just the current site. Multisite only. Default false. */ do_action( 'activate_plugin', $plugin, $network_wide ); /** * Fires as a specific plugin is being activated. * * This hook is the "activation" hook used internally by register_activation_hook(). * The dynamic portion of the hook name, `$plugin`, refers to the plugin basename. * * If a plugin is silently activated (such as during an update), this hook does not fire. * * @since 2.0.0 * * @param bool $network_wide Whether to enable the plugin for all sites in the network * or just the current site. Multisite only. Default false. */ do_action( "activate_{$plugin}", $network_wide ); } if ( $network_wide ) { $current = get_site_option( 'active_sitewide_plugins', array() ); $current[ $plugin ] = time(); update_site_option( 'active_sitewide_plugins', $current ); } else { $current = get_option( 'active_plugins', array() ); $current[] = $plugin; sort( $current ); update_option( 'active_plugins', $current ); } if ( ! $silent ) { /** * Fires after a plugin has been activated. * * If a plugin is silently activated (such as during an update), * this hook does not fire. * * @since 2.9.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @param bool $network_wide Whether to enable the plugin for all sites in the network * or just the current site. Multisite only. Default false. */ do_action( 'activated_plugin', $plugin, $network_wide ); } if ( ob_get_length() > 0 ) { $output = ob_get_clean(); return new WP_Error( 'unexpected_output', __( 'The plugin generated unexpected output.' ), $output ); } ob_end_clean(); } return null; } /** * Deactivates a single plugin or multiple plugins. * * The deactivation hook is disabled by the plugin upgrader by using the $silent * parameter. * * @since 2.5.0 * * @param string|string[] $plugins Single plugin or list of plugins to deactivate. * @param bool $silent Prevent calling deactivation hooks. Default false. * @param bool|null $network_wide Whether to deactivate the plugin for all sites in the network. * A value of null will deactivate plugins for both the network * and the current site. Multisite only. Default null. */ function deactivate_plugins( $plugins, $silent = false, $network_wide = null ) { if ( is_multisite() ) { $network_current = get_site_option( 'active_sitewide_plugins', array() ); } $current = get_option( 'active_plugins', array() ); $do_blog = false; $do_network = false; foreach ( (array) $plugins as $plugin ) { $plugin = plugin_basename( trim( $plugin ) ); if ( ! is_plugin_active( $plugin ) ) { continue; } $network_deactivating = ( false !== $network_wide ) && is_plugin_active_for_network( $plugin ); if ( ! $silent ) { /** * Fires before a plugin is deactivated. * * If a plugin is silently deactivated (such as during an update), * this hook does not fire. * * @since 2.9.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @param bool $network_deactivating Whether the plugin is deactivated for all sites in the network * or just the current site. Multisite only. Default false. */ do_action( 'deactivate_plugin', $plugin, $network_deactivating ); } if ( false !== $network_wide ) { if ( is_plugin_active_for_network( $plugin ) ) { $do_network = true; unset( $network_current[ $plugin ] ); } elseif ( $network_wide ) { continue; } } if ( true !== $network_wide ) { $key = array_search( $plugin, $current, true ); if ( false !== $key ) { $do_blog = true; unset( $current[ $key ] ); } } if ( $do_blog && wp_is_recovery_mode() ) { list( $extension ) = explode( '/', $plugin ); wp_paused_plugins()->delete( $extension ); } if ( ! $silent ) { /** * Fires as a specific plugin is being deactivated. * * This hook is the "deactivation" hook used internally by register_deactivation_hook(). * The dynamic portion of the hook name, `$plugin`, refers to the plugin basename. * * If a plugin is silently deactivated (such as during an update), this hook does not fire. * * @since 2.0.0 * * @param bool $network_deactivating Whether the plugin is deactivated for all sites in the network * or just the current site. Multisite only. Default false. */ do_action( "deactivate_{$plugin}", $network_deactivating ); /** * Fires after a plugin is deactivated. * * If a plugin is silently deactivated (such as during an update), * this hook does not fire. * * @since 2.9.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @param bool $network_deactivating Whether the plugin is deactivated for all sites in the network * or just the current site. Multisite only. Default false. */ do_action( 'deactivated_plugin', $plugin, $network_deactivating ); } } if ( $do_blog ) { update_option( 'active_plugins', $current ); } if ( $do_network ) { update_site_option( 'active_sitewide_plugins', $network_current ); } } /** * Activates multiple plugins. * * When WP_Error is returned, it does not mean that one of the plugins had * errors. It means that one or more of the plugin file paths were invalid. * * The execution will be halted as soon as one of the plugins has an error. * * @since 2.6.0 * * @param string|string[] $plugins Single plugin or list of plugins to activate. * @param string $redirect Redirect to page after successful activation. * @param bool $network_wide Whether to enable the plugin for all sites in the network. * Default false. * @param bool $silent Prevent calling activation hooks. Default false. * @return true|WP_Error True when finished or WP_Error if there were errors during a plugin activation. */ function activate_plugins( $plugins, $redirect = '', $network_wide = false, $silent = false ) { if ( ! is_array( $plugins ) ) { $plugins = array( $plugins ); } $errors = array(); foreach ( $plugins as $plugin ) { if ( ! empty( $redirect ) ) { $redirect = add_query_arg( 'plugin', $plugin, $redirect ); } $result = activate_plugin( $plugin, $redirect, $network_wide, $silent ); if ( is_wp_error( $result ) ) { $errors[ $plugin ] = $result; } } if ( ! empty( $errors ) ) { return new WP_Error( 'plugins_invalid', __( 'One of the plugins is invalid.' ), $errors ); } return true; } /** * Removes directory and files of a plugin for a list of plugins. * * @since 2.6.0 * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * * @param string[] $plugins List of plugin paths to delete, relative to the plugins directory. * @param string $deprecated Not used. * @return bool|null|WP_Error True on success, false if `$plugins` is empty, `WP_Error` on failure. * `null` if filesystem credentials are required to proceed. */ function delete_plugins( $plugins, $deprecated = '' ) { global $wp_filesystem; if ( empty( $plugins ) ) { return false; } $checked = array(); foreach ( $plugins as $plugin ) { $checked[] = 'checked[]=' . $plugin; } $url = wp_nonce_url( 'plugins.php?action=delete-selected&verify-delete=1&' . implode( '&', $checked ), 'bulk-plugins' ); ob_start(); $credentials = request_filesystem_credentials( $url ); $data = ob_get_clean(); if ( false === $credentials ) { if ( ! empty( $data ) ) { require_once ABSPATH . 'wp-admin/admin-header.php'; echo $data; require_once ABSPATH . 'wp-admin/admin-footer.php'; exit; } return; } if ( ! WP_Filesystem( $credentials ) ) { ob_start(); // Failed to connect. Error and request again. request_filesystem_credentials( $url, '', true ); $data = ob_get_clean(); if ( ! empty( $data ) ) { require_once ABSPATH . 'wp-admin/admin-header.php'; echo $data; require_once ABSPATH . 'wp-admin/admin-footer.php'; exit; } return; } if ( ! is_object( $wp_filesystem ) ) { return new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) ); } if ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) { return new WP_Error( 'fs_error', __( 'Filesystem error.' ), $wp_filesystem->errors ); } // Get the base plugin folder. $plugins_dir = $wp_filesystem->wp_plugins_dir(); if ( empty( $plugins_dir ) ) { return new WP_Error( 'fs_no_plugins_dir', __( 'Unable to locate WordPress plugin directory.' ) ); } $plugins_dir = trailingslashit( $plugins_dir ); $plugin_translations = wp_get_installed_translations( 'plugins' ); $errors = array(); foreach ( $plugins as $plugin_file ) { // Run Uninstall hook. if ( is_uninstallable_plugin( $plugin_file ) ) { uninstall_plugin( $plugin_file ); } /** * Fires immediately before a plugin deletion attempt. * * @since 4.4.0 * * @param string $plugin_file Path to the plugin file relative to the plugins directory. */ do_action( 'delete_plugin', $plugin_file ); $this_plugin_dir = trailingslashit( dirname( $plugins_dir . $plugin_file ) ); /* * If plugin is in its own directory, recursively delete the directory. * Base check on if plugin includes directory separator AND that it's not the root plugin folder. */ if ( strpos( $plugin_file, '/' ) && $this_plugin_dir !== $plugins_dir ) { $deleted = $wp_filesystem->delete( $this_plugin_dir, true ); } else { $deleted = $wp_filesystem->delete( $plugins_dir . $plugin_file ); } /** * Fires immediately after a plugin deletion attempt. * * @since 4.4.0 * * @param string $plugin_file Path to the plugin file relative to the plugins directory. * @param bool $deleted Whether the plugin deletion was successful. */ do_action( 'deleted_plugin', $plugin_file, $deleted ); if ( ! $deleted ) { $errors[] = $plugin_file; continue; } $plugin_slug = dirname( $plugin_file ); if ( 'hello.php' === $plugin_file ) { $plugin_slug = 'hello-dolly'; } // Remove language files, silently. if ( '.' !== $plugin_slug && ! empty( $plugin_translations[ $plugin_slug ] ) ) { $translations = $plugin_translations[ $plugin_slug ]; foreach ( $translations as $translation => $data ) { $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.po' ); $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.mo' ); $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.l10n.php' ); $json_translation_files = glob( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '-*.json' ); if ( $json_translation_files ) { array_map( array( $wp_filesystem, 'delete' ), $json_translation_files ); } } } } // Remove deleted plugins from the plugin updates list. $current = get_site_transient( 'update_plugins' ); if ( $current ) { // Don't remove the plugins that weren't deleted. $deleted = array_diff( $plugins, $errors ); foreach ( $deleted as $plugin_file ) { unset( $current->response[ $plugin_file ] ); } set_site_transient( 'update_plugins', $current ); } if ( ! empty( $errors ) ) { if ( 1 === count( $errors ) ) { /* translators: %s: Plugin filename. */ $message = __( 'Could not fully remove the plugin %s.' ); } else { /* translators: %s: Comma-separated list of plugin filenames. */ $message = __( 'Could not fully remove the plugins %s.' ); } return new WP_Error( 'could_not_remove_plugin', sprintf( $message, implode( ', ', $errors ) ) ); } return true; } /** * Validates active plugins. * * Validate all active plugins, deactivates invalid and * returns an array of deactivated ones. * * @since 2.5.0 * @return WP_Error[] Array of plugin errors keyed by plugin file name. */ function validate_active_plugins() { $plugins = get_option( 'active_plugins', array() ); // Validate vartype: array. if ( ! is_array( $plugins ) ) { update_option( 'active_plugins', array() ); $plugins = array(); } if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) { $network_plugins = (array) get_site_option( 'active_sitewide_plugins', array() ); $plugins = array_merge( $plugins, array_keys( $network_plugins ) ); } if ( empty( $plugins ) ) { return array(); } $invalid = array(); // Invalid plugins get deactivated. foreach ( $plugins as $plugin ) { $result = validate_plugin( $plugin ); if ( is_wp_error( $result ) ) { $invalid[ $plugin ] = $result; deactivate_plugins( $plugin, true ); } } return $invalid; } /** * Validates the plugin path. * * Checks that the main plugin file exists and is a valid plugin. See validate_file(). * * @since 2.5.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return int|WP_Error 0 on success, WP_Error on failure. */ function validate_plugin( $plugin ) { if ( validate_file( $plugin ) ) { return new WP_Error( 'plugin_invalid', __( 'Invalid plugin path.' ) ); } if ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin ) ) { return new WP_Error( 'plugin_not_found', __( 'Plugin file does not exist.' ) ); } $installed_plugins = get_plugins(); if ( ! isset( $installed_plugins[ $plugin ] ) ) { return new WP_Error( 'no_plugin_header', __( 'The plugin does not have a valid header.' ) ); } return 0; } /** * Validates the plugin requirements for WordPress version and PHP version. * * Uses the information from `Requires at least`, `Requires PHP` and `Requires Plugins` headers * defined in the plugin's main PHP file. * * @since 5.2.0 * @since 5.3.0 Added support for reading the headers from the plugin's * main PHP file, with `readme.txt` as a fallback. * @since 5.8.0 Removed support for using `readme.txt` as a fallback. * @since 6.5.0 Added support for the 'Requires Plugins' header. * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return true|WP_Error True if requirements are met, WP_Error on failure. */ function validate_plugin_requirements( $plugin ) { $plugin_headers = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ); $requirements = array( 'requires' => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '', 'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '', 'requires_plugins' => ! empty( $plugin_headers['RequiresPlugins'] ) ? $plugin_headers['RequiresPlugins'] : '', ); $compatible_wp = is_wp_version_compatible( $requirements['requires'] ); $compatible_php = is_php_version_compatible( $requirements['requires_php'] ); $php_update_message = '</p><p>' . sprintf( /* translators: %s: URL to Update PHP page. */ __( '<a href="%s">Learn more about updating PHP</a>.' ), esc_url( wp_get_update_php_url() ) ); $annotation = wp_get_update_php_annotation(); if ( $annotation ) { $php_update_message .= '</p><p><em>' . $annotation . '</em>'; } if ( ! $compatible_wp && ! $compatible_php ) { return new WP_Error( 'plugin_wp_php_incompatible', '<p>' . sprintf( /* translators: 1: Current WordPress version, 2: Current PHP version, 3: Plugin name, 4: Required WordPress version, 5: Required PHP version. */ _x( '<strong>Error:</strong> Current versions of WordPress (%1$s) and PHP (%2$s) do not meet minimum requirements for %3$s. The plugin requires WordPress %4$s and PHP %5$s.', 'plugin' ), get_bloginfo( 'version' ), PHP_VERSION, $plugin_headers['Name'], $requirements['requires'], $requirements['requires_php'] ) . $php_update_message . '</p>' ); } elseif ( ! $compatible_php ) { return new WP_Error( 'plugin_php_incompatible', '<p>' . sprintf( /* translators: 1: Current PHP version, 2: Plugin name, 3: Required PHP version. */ _x( '<strong>Error:</strong> Current PHP version (%1$s) does not meet minimum requirements for %2$s. The plugin requires PHP %3$s.', 'plugin' ), PHP_VERSION, $plugin_headers['Name'], $requirements['requires_php'] ) . $php_update_message . '</p>' ); } elseif ( ! $compatible_wp ) { return new WP_Error( 'plugin_wp_incompatible', '<p>' . sprintf( /* translators: 1: Current WordPress version, 2: Plugin name, 3: Required WordPress version. */ _x( '<strong>Error:</strong> Current WordPress version (%1$s) does not meet minimum requirements for %2$s. The plugin requires WordPress %3$s.', 'plugin' ), get_bloginfo( 'version' ), $plugin_headers['Name'], $requirements['requires'] ) . '</p>' ); } WP_Plugin_Dependencies::initialize(); if ( WP_Plugin_Dependencies::has_unmet_dependencies( $plugin ) ) { $dependency_names = WP_Plugin_Dependencies::get_dependency_names( $plugin ); $unmet_dependencies = array(); $unmet_dependency_names = array(); foreach ( $dependency_names as $dependency => $dependency_name ) { $dependency_file = WP_Plugin_Dependencies::get_dependency_filepath( $dependency ); if ( false === $dependency_file ) { $unmet_dependencies['not_installed'][ $dependency ] = $dependency_name; $unmet_dependency_names[] = $dependency_name; } elseif ( is_plugin_inactive( $dependency_file ) ) { $unmet_dependencies['inactive'][ $dependency ] = $dependency_name; $unmet_dependency_names[] = $dependency_name; } } $error_message = sprintf( /* translators: 1: Plugin name, 2: Number of plugins, 3: A comma-separated list of plugin names. */ _n( '<strong>Error:</strong> %1$s requires %2$d plugin to be installed and activated: %3$s.', '<strong>Error:</strong> %1$s requires %2$d plugins to be installed and activated: %3$s.', count( $unmet_dependency_names ) ), $plugin_headers['Name'], count( $unmet_dependency_names ), implode( wp_get_list_item_separator(), $unmet_dependency_names ) ); if ( is_multisite() ) { if ( current_user_can( 'manage_network_plugins' ) ) { $error_message .= ' ' . sprintf( /* translators: %s: Link to the plugins page. */ __( '<a href="%s">Manage plugins</a>.' ), esc_url( network_admin_url( 'plugins.php' ) ) ); } else { $error_message .= ' ' . __( 'Please contact your network administrator.' ); } } else { $error_message .= ' ' . sprintf( /* translators: %s: Link to the plugins page. */ __( '<a href="%s">Manage plugins</a>.' ), esc_url( admin_url( 'plugins.php' ) ) ); } return new WP_Error( 'plugin_missing_dependencies', "<p>{$error_message}</p>", $unmet_dependencies ); } /** * Filters the plugin requirement validation response. * * If a plugin fails due to a Core-provided validation (incompatible WP, PHP versions), this * filter will not fire. A WP_Error response will already be returned. * * This filter is intended to add additional validation steps by site administrators. * * @since 6.9.0 * * @param bool|WP_Error $met_requirements True if the plugin meets requirements, WP_Error if not. * @param string $plugin Path to the plugin file relative to the plugins directory. */ return apply_filters( 'validate_plugin_requirements', true, $plugin ); } /** * Determines whether the plugin can be uninstalled. * * @since 2.7.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return bool Whether plugin can be uninstalled. */ function is_uninstallable_plugin( $plugin ) { $file = plugin_basename( $plugin ); $uninstallable_plugins = (array) get_option( 'uninstall_plugins' ); if ( isset( $uninstallable_plugins[ $file ] ) || file_exists( WP_PLUGIN_DIR . '/' . dirname( $file ) . '/uninstall.php' ) ) { return true; } return false; } /** * Uninstalls a single plugin. * * Calls the uninstall hook, if it is available. * * @since 2.7.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return true|void True if a plugin's uninstall.php file has been found and included. * Void otherwise. */ function uninstall_plugin( $plugin ) { $file = plugin_basename( $plugin ); $uninstallable_plugins = (array) get_option( 'uninstall_plugins' ); /** * Fires in uninstall_plugin() immediately before the plugin is uninstalled. * * @since 4.5.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. * @param array $uninstallable_plugins Uninstallable plugins. */ do_action( 'pre_uninstall_plugin', $plugin, $uninstallable_plugins ); if ( file_exists( WP_PLUGIN_DIR . '/' . dirname( $file ) . '/uninstall.php' ) ) { if ( isset( $uninstallable_plugins[ $file ] ) ) { unset( $uninstallable_plugins[ $file ] ); update_option( 'uninstall_plugins', $uninstallable_plugins ); } unset( $uninstallable_plugins ); define( 'WP_UNINSTALL_PLUGIN', $file ); wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $file ); include_once WP_PLUGIN_DIR . '/' . dirname( $file ) . '/uninstall.php'; return true; } if ( isset( $uninstallable_plugins[ $file ] ) ) { $callable = $uninstallable_plugins[ $file ]; unset( $uninstallable_plugins[ $file ] ); update_option( 'uninstall_plugins', $uninstallable_plugins ); unset( $uninstallable_plugins ); wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $file ); include_once WP_PLUGIN_DIR . '/' . $file; add_action( "uninstall_{$file}", $callable ); /** * Fires in uninstall_plugin() once the plugin has been uninstalled. * * The action concatenates the 'uninstall_' prefix with the basename of the * plugin passed to uninstall_plugin() to create a dynamically-named action. * * @since 2.7.0 */ do_action( "uninstall_{$file}" ); } } // // Menu. // /** * Adds a top-level menu page. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 1.5.0 * * @global array $menu * @global array $admin_page_hooks * @global array $_registered_pages * @global array $_parent_pages * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by. Should be unique for this menu page and only * include lowercase alphanumeric, dashes, and underscores characters to be compatible * with sanitize_key(). * @param callable $callback Optional. The function to be called to output the content for this page. * @param string $icon_url Optional. The URL to the icon to be used for this menu. * * Pass a base64-encoded SVG using a data URI, which will be colored to match * the color scheme. This should begin with 'data:image/svg+xml;base64,'. * * Pass the name of a Dashicons helper class to use a font icon, * e.g. 'dashicons-chart-pie'. * * Pass 'none' to leave div.wp-menu-image empty so an icon can be added via CSS. * @param int|float $position Optional. The position in the menu order this item should appear. * @return string The resulting page's hook_suffix. */ function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $icon_url = '', $position = null ) { global $menu, $admin_page_hooks, $_registered_pages, $_parent_pages; $menu_slug = plugin_basename( $menu_slug ); $admin_page_hooks[ $menu_slug ] = sanitize_title( $menu_title ); $hookname = get_plugin_page_hookname( $menu_slug, '' ); if ( ! empty( $callback ) && ! empty( $hookname ) && current_user_can( $capability ) ) { add_action( $hookname, $callback ); } if ( empty( $icon_url ) ) { $icon_url = 'dashicons-admin-generic'; $icon_class = 'menu-icon-generic '; } else { $icon_url = set_url_scheme( $icon_url ); $icon_class = ''; } $new_menu = array( $menu_title, $capability, $menu_slug, $page_title, 'menu-top ' . $icon_class . $hookname, $hookname, $icon_url ); if ( null !== $position && ! is_numeric( $position ) ) { _doing_it_wrong( __FUNCTION__, sprintf( /* translators: %s: add_menu_page() */ __( 'The seventh parameter passed to %s should be numeric representing menu position.' ), '<code>add_menu_page()</code>' ), '6.0.0' ); $position = null; } if ( null === $position || ! is_numeric( $position ) ) { $menu[] = $new_menu; } elseif ( isset( $menu[ (string) $position ] ) ) { $collision_avoider = base_convert( substr( md5( $menu_slug . $menu_title ), -4 ), 16, 10 ) * 0.00001; $position = (string) ( $position + $collision_avoider ); $menu[ $position ] = $new_menu; } else { /* * Cast menu position to a string. * * This allows for floats to be passed as the position. PHP will normally cast a float to an * integer value, this ensures the float retains its mantissa (positive fractional part). * * A string containing an integer value, eg "10", is treated as a numeric index. */ $position = (string) $position; $menu[ $position ] = $new_menu; } $_registered_pages[ $hookname ] = true; // No parent as top level. $_parent_pages[ $menu_slug ] = false; return $hookname; } /** * Adds a submenu page. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 1.5.0 * @since 5.3.0 Added the `$position` parameter. * * @global array $submenu * @global array $menu * @global array $_wp_real_parent_file * @global bool $_wp_submenu_nopriv * @global array $_registered_pages * @global array $_parent_pages * * @param string $parent_slug The slug name for the parent menu (or the file name of a standard * WordPress admin page). * @param string $page_title The text to be displayed in the title tags of the page when the menu * is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by. Should be unique for this menu * and only include lowercase alphanumeric, dashes, and underscores characters * to be compatible with sanitize_key(). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int|float $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { global $submenu, $menu, $_wp_real_parent_file, $_wp_submenu_nopriv, $_registered_pages, $_parent_pages; $menu_slug = plugin_basename( $menu_slug ); $parent_slug = plugin_basename( $parent_slug ); if ( isset( $_wp_real_parent_file[ $parent_slug ] ) ) { $parent_slug = $_wp_real_parent_file[ $parent_slug ]; } if ( ! current_user_can( $capability ) ) { $_wp_submenu_nopriv[ $parent_slug ][ $menu_slug ] = true; return false; } /* * If the parent doesn't already have a submenu, add a link to the parent * as the first item in the submenu. If the submenu file is the same as the * parent file someone is trying to link back to the parent manually. In * this case, don't automatically add a link back to avoid duplication. */ if ( ! isset( $submenu[ $parent_slug ] ) && $menu_slug !== $parent_slug ) { foreach ( (array) $menu as $parent_menu ) { if ( $parent_menu[2] === $parent_slug && current_user_can( $parent_menu[1] ) ) { $submenu[ $parent_slug ][] = array_slice( $parent_menu, 0, 4 ); } } } $new_sub_menu = array( $menu_title, $capability, $menu_slug, $page_title ); if ( null !== $position && ! is_numeric( $position ) ) { _doing_it_wrong( __FUNCTION__, sprintf( /* translators: %s: add_submenu_page() */ __( 'The seventh parameter passed to %s should be numeric representing menu position.' ), '<code>add_submenu_page()</code>' ), '5.3.0' ); $position = null; } if ( null === $position || ( ! isset( $submenu[ $parent_slug ] ) || $position >= count( $submenu[ $parent_slug ] ) ) ) { $submenu[ $parent_slug ][] = $new_sub_menu; } else { // Test for a negative position. $position = max( $position, 0 ); if ( 0 === $position ) { // For negative or `0` positions, prepend the submenu. array_unshift( $submenu[ $parent_slug ], $new_sub_menu ); } else { $position = absint( $position ); // Grab all of the items before the insertion point. $before_items = array_slice( $submenu[ $parent_slug ], 0, $position, true ); // Grab all of the items after the insertion point. $after_items = array_slice( $submenu[ $parent_slug ], $position, null, true ); // Add the new item. $before_items[] = $new_sub_menu; // Merge the items. $submenu[ $parent_slug ] = array_merge( $before_items, $after_items ); } } // Sort the parent array. ksort( $submenu[ $parent_slug ] ); $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug ); if ( ! empty( $callback ) && ! empty( $hookname ) ) { add_action( $hookname, $callback ); } $_registered_pages[ $hookname ] = true; /* * Backward-compatibility for plugins using add_management_page(). * See wp-admin/admin.php for redirect from edit.php to tools.php. */ if ( 'tools.php' === $parent_slug ) { $_registered_pages[ get_plugin_page_hookname( $menu_slug, 'edit.php' ) ] = true; } // No parent as top level. $_parent_pages[ $menu_slug ] = $parent_slug; return $hookname; } /** * Adds a submenu page to the Tools main menu. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 1.5.0 * @since 5.3.0 Added the `$position` parameter. * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_management_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { return add_submenu_page( 'tools.php', $page_title, $menu_title, $capability, $menu_slug, $callback, $position ); } /** * Adds a submenu page to the Settings main menu. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 1.5.0 * @since 5.3.0 Added the `$position` parameter. * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_options_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { return add_submenu_page( 'options-general.php', $page_title, $menu_title, $capability, $menu_slug, $callback, $position ); } /** * Adds a submenu page to the Appearance main menu. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 2.0.0 * @since 5.3.0 Added the `$position` parameter. * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_theme_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { return add_submenu_page( 'themes.php', $page_title, $menu_title, $capability, $menu_slug, $callback, $position ); } /** * Adds a submenu page to the Plugins main menu. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 3.0.0 * @since 5.3.0 Added the `$position` parameter. * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_plugins_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { return add_submenu_page( 'plugins.php', $page_title, $menu_title, $capability, $menu_slug, $callback, $position ); } /** * Adds a submenu page to the Users/Profile main menu. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 2.1.3 * @since 5.3.0 Added the `$position` parameter. * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_users_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { if ( current_user_can( 'edit_users' ) ) { $parent = 'users.php'; } else { $parent = 'profile.php'; } return add_submenu_page( $parent, $page_title, $menu_title, $capability, $menu_slug, $callback, $position ); } /** * Adds a submenu page to the Dashboard main menu. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 2.7.0 * @since 5.3.0 Added the `$position` parameter. * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_dashboard_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { return add_submenu_page( 'index.php', $page_title, $menu_title, $capability, $menu_slug, $callback, $position ); } /** * Adds a submenu page to the Posts main menu. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 2.7.0 * @since 5.3.0 Added the `$position` parameter. * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_posts_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { return add_submenu_page( 'edit.php', $page_title, $menu_title, $capability, $menu_slug, $callback, $position ); } /** * Adds a submenu page to the Media main menu. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 2.7.0 * @since 5.3.0 Added the `$position` parameter. * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_media_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { return add_submenu_page( 'upload.php', $page_title, $menu_title, $capability, $menu_slug, $callback, $position ); } /** * Adds a submenu page to the Links main menu. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 2.7.0 * @since 5.3.0 Added the `$position` parameter. * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_links_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { return add_submenu_page( 'link-manager.php', $page_title, $menu_title, $capability, $menu_slug, $callback, $position ); } /** * Adds a submenu page to the Pages main menu. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 2.7.0 * @since 5.3.0 Added the `$position` parameter. * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_pages_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { return add_submenu_page( 'edit.php?post_type=page', $page_title, $menu_title, $capability, $menu_slug, $callback, $position ); } /** * Adds a submenu page to the Comments main menu. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 2.7.0 * @since 5.3.0 Added the `$position` parameter. * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param int $position Optional. The position in the menu order this item should appear. * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required. */ function add_comments_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { return add_submenu_page( 'edit-comments.php', $page_title, $menu_title, $capability, $menu_slug, $callback, $position ); } /** * Removes a top-level admin menu. * * Example usage: * * - `remove_menu_page( 'tools.php' )` * - `remove_menu_page( 'plugin_menu_slug' )` * * @since 3.1.0 * * @global array $menu * * @param string $menu_slug The slug of the menu. * @return array|false The removed menu on success, false if not found. */ function remove_menu_page( $menu_slug ) { global $menu; foreach ( $menu as $i => $item ) { if ( $menu_slug === $item[2] ) { unset( $menu[ $i ] ); return $item; } } return false; } /** * Removes an admin submenu. * * Example usage: * * - `remove_submenu_page( 'themes.php', 'nav-menus.php' )` * - `remove_submenu_page( 'tools.php', 'plugin_submenu_slug' )` * - `remove_submenu_page( 'plugin_menu_slug', 'plugin_submenu_slug' )` * * @since 3.1.0 * * @global array $submenu * * @param string $menu_slug The slug for the parent menu. * @param string $submenu_slug The slug of the submenu. * @return array|false The removed submenu on success, false if not found. */ function remove_submenu_page( $menu_slug, $submenu_slug ) { global $submenu; if ( ! isset( $submenu[ $menu_slug ] ) ) { return false; } foreach ( $submenu[ $menu_slug ] as $i => $item ) { if ( $submenu_slug === $item[2] ) { unset( $submenu[ $menu_slug ][ $i ] ); return $item; } } return false; } /** * Gets the URL to access a particular menu page based on the slug it was registered with. * * If the slug hasn't been registered properly, no URL will be returned. * * @since 3.0.0 * * @global array $_parent_pages * * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param bool $display Optional. Whether or not to display the URL. Default true. * @return string The menu page URL. */ function menu_page_url( $menu_slug, $display = true ) { global $_parent_pages; if ( isset( $_parent_pages[ $menu_slug ] ) ) { $parent_slug = $_parent_pages[ $menu_slug ]; if ( $parent_slug && ! isset( $_parent_pages[ $parent_slug ] ) ) { $url = admin_url( add_query_arg( 'page', $menu_slug, $parent_slug ) ); } else { $url = admin_url( 'admin.php?page=' . $menu_slug ); } } else { $url = ''; } $url = esc_url( $url ); if ( $display ) { echo $url; } return $url; } // // Pluggable Menu Support -- Private. // /** * Gets the parent file of the current admin page. * * @since 1.5.0 * * @global string $parent_file * @global array $menu * @global array $submenu * @global string $pagenow The filename of the current screen. * @global string $typenow The post type of the current screen. * @global string $plugin_page * @global array $_wp_real_parent_file * @global array $_wp_menu_nopriv * @global array $_wp_submenu_nopriv * * @param string $parent_page Optional. The slug name for the parent menu (or the file name * of a standard WordPress admin page). Default empty string. * @return string The parent file of the current admin page. */ function get_admin_page_parent( $parent_page = '' ) { global $parent_file, $menu, $submenu, $pagenow, $typenow, $plugin_page, $_wp_real_parent_file, $_wp_menu_nopriv, $_wp_submenu_nopriv; if ( ! empty( $parent_page ) && 'admin.php' !== $parent_page ) { if ( isset( $_wp_real_parent_file[ $parent_page ] ) ) { $parent_page = $_wp_real_parent_file[ $parent_page ]; } return $parent_page; } if ( 'admin.php' === $pagenow && isset( $plugin_page ) ) { foreach ( (array) $menu as $parent_menu ) { if ( $parent_menu[2] === $plugin_page ) { $parent_file = $plugin_page; if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) { $parent_file = $_wp_real_parent_file[ $parent_file ]; } return $parent_file; } } if ( isset( $_wp_menu_nopriv[ $plugin_page ] ) ) { $parent_file = $plugin_page; if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) { $parent_file = $_wp_real_parent_file[ $parent_file ]; } return $parent_file; } } if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $pagenow ][ $plugin_page ] ) ) { $parent_file = $pagenow; if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) { $parent_file = $_wp_real_parent_file[ $parent_file ]; } return $parent_file; } foreach ( array_keys( (array) $submenu ) as $parent_page ) { foreach ( $submenu[ $parent_page ] as $submenu_array ) { if ( isset( $_wp_real_parent_file[ $parent_page ] ) ) { $parent_page = $_wp_real_parent_file[ $parent_page ]; } if ( ! empty( $typenow ) && "$pagenow?post_type=$typenow" === $submenu_array[2] ) { $parent_file = $parent_page; return $parent_page; } elseif ( empty( $typenow ) && $pagenow === $submenu_array[2] && ( empty( $parent_file ) || ! str_contains( $parent_file, '?' ) ) ) { $parent_file = $parent_page; return $parent_page; } elseif ( isset( $plugin_page ) && $plugin_page === $submenu_array[2] ) { $parent_file = $parent_page; return $parent_page; } } } if ( empty( $parent_file ) ) { $parent_file = ''; } return ''; } /** * Gets the title of the current admin page. * * @since 1.5.0 * * @global string $title The title of the current screen. * @global array $menu * @global array $submenu * @global string $pagenow The filename of the current screen. * @global string $typenow The post type of the current screen. * @global string $plugin_page * * @return string The title of the current admin page. */ function get_admin_page_title() { global $title, $menu, $submenu, $pagenow, $typenow, $plugin_page; if ( ! empty( $title ) ) { return $title; } $hook = get_plugin_page_hook( $plugin_page, $pagenow ); $parent = get_admin_page_parent(); $parent1 = $parent; if ( empty( $parent ) ) { foreach ( (array) $menu as $menu_array ) { if ( isset( $menu_array[3] ) ) { if ( $menu_array[2] === $pagenow ) { $title = $menu_array[3]; return $menu_array[3]; } elseif ( isset( $plugin_page ) && $plugin_page === $menu_array[2] && $hook === $menu_array[5] ) { $title = $menu_array[3]; return $menu_array[3]; } } else { $title = $menu_array[0]; return $title; } } } else { foreach ( array_keys( $submenu ) as $parent ) { foreach ( $submenu[ $parent ] as $submenu_array ) { if ( isset( $plugin_page ) && $plugin_page === $submenu_array[2] && ( $pagenow === $parent || $plugin_page === $parent || $plugin_page === $hook || 'admin.php' === $pagenow && $parent1 !== $submenu_array[2] || ! empty( $typenow ) && "$pagenow?post_type=$typenow" === $parent ) ) { $title = $submenu_array[3]; return $submenu_array[3]; } if ( $submenu_array[2] !== $pagenow || isset( $_GET['page'] ) ) { // Not the current page. continue; } if ( isset( $submenu_array[3] ) ) { $title = $submenu_array[3]; return $submenu_array[3]; } else { $title = $submenu_array[0]; return $title; } } } if ( empty( $title ) ) { foreach ( $menu as $menu_array ) { if ( isset( $plugin_page ) && $plugin_page === $menu_array[2] && 'admin.php' === $pagenow && $parent1 === $menu_array[2] ) { $title = $menu_array[3]; return $menu_array[3]; } } } } return $title; } /** * Gets the hook attached to the administrative page of a plugin. * * @since 1.5.0 * * @param string $plugin_page The slug name of the plugin page. * @param string $parent_page The slug name for the parent menu (or the file name of a standard * WordPress admin page). * @return string|null Hook attached to the plugin page, null otherwise. */ function get_plugin_page_hook( $plugin_page, $parent_page ) { $hook = get_plugin_page_hookname( $plugin_page, $parent_page ); if ( has_action( $hook ) ) { return $hook; } else { return null; } } /** * Gets the hook name for the administrative page of a plugin. * * @since 1.5.0 * * @global array $admin_page_hooks * * @param string $plugin_page The slug name of the plugin page. * @param string $parent_page The slug name for the parent menu (or the file name of a standard * WordPress admin page). * @return string Hook name for the plugin page. */ function get_plugin_page_hookname( $plugin_page, $parent_page ) { global $admin_page_hooks; $parent = get_admin_page_parent( $parent_page ); $page_type = 'admin'; if ( empty( $parent_page ) || 'admin.php' === $parent_page || isset( $admin_page_hooks[ $plugin_page ] ) ) { if ( isset( $admin_page_hooks[ $plugin_page ] ) ) { $page_type = 'toplevel'; } elseif ( isset( $admin_page_hooks[ $parent ] ) ) { $page_type = $admin_page_hooks[ $parent ]; } } elseif ( isset( $admin_page_hooks[ $parent ] ) ) { $page_type = $admin_page_hooks[ $parent ]; } $plugin_name = preg_replace( '!\.php!', '', $plugin_page ); return $page_type . '_page_' . $plugin_name; } /** * Determines whether the current user can access the current admin page. * * @since 1.5.0 * * @global string $pagenow The filename of the current screen. * @global array $menu * @global array $submenu * @global array $_wp_menu_nopriv * @global array $_wp_submenu_nopriv * @global string $plugin_page * @global array $_registered_pages * * @return bool True if the current user can access the admin page, false otherwise. */ function user_can_access_admin_page() { global $pagenow, $menu, $submenu, $_wp_menu_nopriv, $_wp_submenu_nopriv, $plugin_page, $_registered_pages; $parent = get_admin_page_parent(); if ( ! isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $parent ][ $pagenow ] ) ) { return false; } if ( isset( $plugin_page ) ) { if ( isset( $_wp_submenu_nopriv[ $parent ][ $plugin_page ] ) ) { return false; } $hookname = get_plugin_page_hookname( $plugin_page, $parent ); if ( ! isset( $_registered_pages[ $hookname ] ) ) { return false; } } if ( empty( $parent ) ) { if ( isset( $_wp_menu_nopriv[ $pagenow ] ) ) { return false; } if ( isset( $_wp_submenu_nopriv[ $pagenow ][ $pagenow ] ) ) { return false; } if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $pagenow ][ $plugin_page ] ) ) { return false; } if ( isset( $plugin_page ) && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) { return false; } foreach ( array_keys( $_wp_submenu_nopriv ) as $key ) { if ( isset( $_wp_submenu_nopriv[ $key ][ $pagenow ] ) ) { return false; } if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $key ][ $plugin_page ] ) ) { return false; } } return true; } if ( isset( $plugin_page ) && $plugin_page === $parent && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) { return false; } if ( isset( $submenu[ $parent ] ) ) { foreach ( $submenu[ $parent ] as $submenu_array ) { if ( isset( $plugin_page ) && $submenu_array[2] === $plugin_page ) { return current_user_can( $submenu_array[1] ); } elseif ( $submenu_array[2] === $pagenow ) { return current_user_can( $submenu_array[1] ); } } } foreach ( $menu as $menu_array ) { if ( $menu_array[2] === $parent ) { return current_user_can( $menu_array[1] ); } } return true; } /* Allowed list functions */ /** * Refreshes the value of the allowed options list available via the 'allowed_options' hook. * * See the {@see 'allowed_options'} filter. * * @since 2.7.0 * @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`. * Please consider writing more inclusive code. * * @global array $new_allowed_options * * @param array $options * @return array */ function option_update_filter( $options ) { global $new_allowed_options; if ( is_array( $new_allowed_options ) ) { $options = add_allowed_options( $new_allowed_options, $options ); } return $options; } /** * Adds an array of options to the list of allowed options. * * @since 5.5.0 * * @global array $allowed_options * * @param array $new_options * @param string|array $options * @return array */ function add_allowed_options( $new_options, $options = '' ) { if ( '' === $options ) { global $allowed_options; } else { $allowed_options = $options; } foreach ( $new_options as $page => $keys ) { foreach ( $keys as $key ) { if ( ! isset( $allowed_options[ $page ] ) || ! is_array( $allowed_options[ $page ] ) ) { $allowed_options[ $page ] = array(); $allowed_options[ $page ][] = $key; } else { $pos = array_search( $key, $allowed_options[ $page ], true ); if ( false === $pos ) { $allowed_options[ $page ][] = $key; } } } } return $allowed_options; } /** * Removes a list of options from the allowed options list. * * @since 5.5.0 * * @global array $allowed_options * * @param array $del_options * @param string|array $options * @return array */ function remove_allowed_options( $del_options, $options = '' ) { if ( '' === $options ) { global $allowed_options; } else { $allowed_options = $options; } foreach ( $del_options as $page => $keys ) { foreach ( $keys as $key ) { if ( isset( $allowed_options[ $page ] ) && is_array( $allowed_options[ $page ] ) ) { $pos = array_search( $key, $allowed_options[ $page ], true ); if ( false !== $pos ) { unset( $allowed_options[ $page ][ $pos ] ); } } } } return $allowed_options; } /** * Outputs nonce, action, and option_page fields for a settings page. * * @since 2.7.0 * * @param string $option_group A settings group name. This should match the group name * used in register_setting(). */ function settings_fields( $option_group ) { echo "<input type='hidden' name='option_page' value='" . esc_attr( $option_group ) . "' />"; echo '<input type="hidden" name="action" value="update" />'; wp_nonce_field( "$option_group-options" ); } /** * Clears the plugins cache used by get_plugins() and by default, the plugin updates cache. * * @since 3.7.0 * * @param bool $clear_update_cache Whether to clear the plugin updates cache. Default true. */ function wp_clean_plugins_cache( $clear_update_cache = true ) { if ( $clear_update_cache ) { delete_site_transient( 'update_plugins' ); } wp_cache_delete( 'plugins', 'plugins' ); } /** * Loads a given plugin attempt to generate errors. * * @since 3.0.0 * @since 4.4.0 Function was moved into the `wp-admin/includes/plugin.php` file. * * @param string $plugin Path to the plugin file relative to the plugins directory. */ function plugin_sandbox_scrape( $plugin ) { if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) { define( 'WP_SANDBOX_SCRAPING', true ); } wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin ); include_once WP_PLUGIN_DIR . '/' . $plugin; } /** * Declares a helper function for adding content to the Privacy Policy Guide. * * Plugins and themes should suggest text for inclusion in the site's privacy policy. * The suggested text should contain information about any functionality that affects user privacy, * and will be shown on the Privacy Policy Guide screen. * * A plugin or theme can use this function multiple times as long as it will help to better present * the suggested policy content. For example modular plugins such as WooCommerse or Jetpack * can add or remove suggested content depending on the modules/extensions that are enabled. * For more information see the Plugin Handbook: * https://developer.wordpress.org/plugins/privacy/suggesting-text-for-the-site-privacy-policy/. * * The HTML contents of the `$policy_text` supports use of a specialized `.privacy-policy-tutorial` * CSS class which can be used to provide supplemental information. Any content contained within * HTML elements that have the `.privacy-policy-tutorial` CSS class applied will be omitted * from the clipboard when the section content is copied. * * Intended for use with the `'admin_init'` action. * * @since 4.9.6 * * @param string $plugin_name The name of the plugin or theme that is suggesting content * for the site's privacy policy. * @param string $policy_text The suggested content for inclusion in the policy. */ function wp_add_privacy_policy_content( $plugin_name, $policy_text ) { if ( ! is_admin() ) { _doing_it_wrong( __FUNCTION__, sprintf( /* translators: %s: admin_init */ __( 'The suggested privacy policy content should be added only in wp-admin by using the %s (or later) action.' ), '<code>admin_init</code>' ), '4.9.7' ); return; } elseif ( ! doing_action( 'admin_init' ) && ! did_action( 'admin_init' ) ) { _doing_it_wrong( __FUNCTION__, sprintf( /* translators: %s: admin_init */ __( 'The suggested privacy policy content should be added by using the %s (or later) action. Please see the inline documentation.' ), '<code>admin_init</code>' ), '4.9.7' ); return; } if ( ! class_exists( 'WP_Privacy_Policy_Content' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-policy-content.php'; } WP_Privacy_Policy_Content::add( $plugin_name, $policy_text ); } /** * Determines whether a plugin is technically active but was paused while * loading. * * For more information on this and similar theme functions, check out * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ * Conditional Tags} article in the Theme Developer Handbook. * * @since 5.2.0 * * @global WP_Paused_Extensions_Storage $_paused_plugins * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return bool True, if in the list of paused plugins. False, if not in the list. */ function is_plugin_paused( $plugin ) { if ( ! isset( $GLOBALS['_paused_plugins'] ) ) { return false; } if ( ! is_plugin_active( $plugin ) ) { return false; } list( $plugin ) = explode( '/', $plugin ); return array_key_exists( $plugin, $GLOBALS['_paused_plugins'] ); } /** * Gets the error that was recorded for a paused plugin. * * @since 5.2.0 * * @global WP_Paused_Extensions_Storage $_paused_plugins * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return array|false Array of error information as returned by `error_get_last()`, * or false if none was recorded. */ function wp_get_plugin_error( $plugin ) { if ( ! isset( $GLOBALS['_paused_plugins'] ) ) { return false; } list( $plugin ) = explode( '/', $plugin ); if ( ! array_key_exists( $plugin, $GLOBALS['_paused_plugins'] ) ) { return false; } return $GLOBALS['_paused_plugins'][ $plugin ]; } /** * Tries to resume a single plugin. * * If a redirect was provided, we first ensure the plugin does not throw fatal * errors anymore. * * The way it works is by setting the redirection to the error before trying to * include the plugin file. If the plugin fails, then the redirection will not * be overwritten with the success message and the plugin will not be resumed. * * @since 5.2.0 * * @param string $plugin Single plugin to resume. * @param string $redirect Optional. URL to redirect to. Default empty string. * @return true|WP_Error True on success, false if `$plugin` was not paused, * `WP_Error` on failure. */ function resume_plugin( $plugin, $redirect = '' ) { /* * We'll override this later if the plugin could be resumed without * creating a fatal error. */ if ( ! empty( $redirect ) ) { wp_redirect( add_query_arg( '_error_nonce', wp_create_nonce( 'plugin-resume-error_' . $plugin ), $redirect ) ); // Load the plugin to test whether it throws a fatal error. ob_start(); plugin_sandbox_scrape( $plugin ); ob_clean(); } list( $extension ) = explode( '/', $plugin ); $result = wp_paused_plugins()->delete( $extension ); if ( ! $result ) { return new WP_Error( 'could_not_resume_plugin', __( 'Could not resume the plugin.' ) ); } return true; } /** * Renders an admin notice in case some plugins have been paused due to errors. * * @since 5.2.0 * * @global string $pagenow The filename of the current screen. * @global WP_Paused_Extensions_Storage $_paused_plugins */ function paused_plugins_notice() { if ( 'plugins.php' === $GLOBALS['pagenow'] ) { return; } if ( ! current_user_can( 'resume_plugins' ) ) { return; } if ( ! isset( $GLOBALS['_paused_plugins'] ) || empty( $GLOBALS['_paused_plugins'] ) ) { return; } $message = sprintf( '<strong>%s</strong><br>%s</p><p><a href="%s">%s</a>', __( 'One or more plugins failed to load properly.' ), __( 'You can find more details and make changes on the Plugins screen.' ), esc_url( admin_url( 'plugins.php?plugin_status=paused' ) ), __( 'Go to the Plugins screen' ) ); wp_admin_notice( $message, array( 'type' => 'error' ) ); } /** * Renders an admin notice when a plugin was deactivated during an update. * * Displays an admin notice in case a plugin has been deactivated during an * upgrade due to incompatibility with the current version of WordPress. * * @since 5.8.0 * @access private * * @global string $pagenow The filename of the current screen. * @global string $wp_version The WordPress version string. */ function deactivated_plugins_notice() { if ( 'plugins.php' === $GLOBALS['pagenow'] ) { return; } if ( ! current_user_can( 'activate_plugins' ) ) { return; } $blog_deactivated_plugins = get_option( 'wp_force_deactivated_plugins' ); $site_deactivated_plugins = array(); if ( false === $blog_deactivated_plugins ) { // Option not in database, add an empty array to avoid extra DB queries on subsequent loads. update_option( 'wp_force_deactivated_plugins', array(), false ); } if ( is_multisite() ) { $site_deactivated_plugins = get_site_option( 'wp_force_deactivated_plugins' ); if ( false === $site_deactivated_plugins ) { // Option not in database, add an empty array to avoid extra DB queries on subsequent loads. update_site_option( 'wp_force_deactivated_plugins', array() ); } } if ( empty( $blog_deactivated_plugins ) && empty( $site_deactivated_plugins ) ) { // No deactivated plugins. return; } $deactivated_plugins = array_merge( $blog_deactivated_plugins, $site_deactivated_plugins ); foreach ( $deactivated_plugins as $plugin ) { if ( ! empty( $plugin['version_compatible'] ) && ! empty( $plugin['version_deactivated'] ) ) { $explanation = sprintf( /* translators: 1: Name of deactivated plugin, 2: Plugin version deactivated, 3: Current WP version, 4: Compatible plugin version. */ __( '%1$s %2$s was deactivated due to incompatibility with WordPress %3$s, please upgrade to %1$s %4$s or later.' ), $plugin['plugin_name'], $plugin['version_deactivated'], $GLOBALS['wp_version'], $plugin['version_compatible'] ); } else { $explanation = sprintf( /* translators: 1: Name of deactivated plugin, 2: Plugin version deactivated, 3: Current WP version. */ __( '%1$s %2$s was deactivated due to incompatibility with WordPress %3$s.' ), $plugin['plugin_name'], ! empty( $plugin['version_deactivated'] ) ? $plugin['version_deactivated'] : '', $GLOBALS['wp_version'], $plugin['version_compatible'] ); } $message = sprintf( '<strong>%s</strong><br>%s</p><p><a href="%s">%s</a>', sprintf( /* translators: %s: Name of deactivated plugin. */ __( '%s plugin deactivated during WordPress upgrade.' ), $plugin['plugin_name'] ), $explanation, esc_url( admin_url( 'plugins.php?plugin_status=inactive' ) ), __( 'Go to the Plugins screen' ) ); wp_admin_notice( $message, array( 'type' => 'warning' ) ); } // Empty the options. update_option( 'wp_force_deactivated_plugins', array(), false ); if ( is_multisite() ) { update_site_option( 'wp_force_deactivated_plugins', array() ); } } PK U�g\yp�* �* widgets.phpnu �[��� <?php /** * WordPress Widgets Administration API * * @package WordPress * @subpackage Administration */ /** * Display list of the available widgets. * * @since 2.5.0 * * @global array $wp_registered_widgets * @global array $wp_registered_widget_controls */ function wp_list_widgets() { global $wp_registered_widgets, $wp_registered_widget_controls; $sort = $wp_registered_widgets; usort( $sort, '_sort_name_callback' ); $done = array(); foreach ( $sort as $widget ) { if ( in_array( $widget['callback'], $done, true ) ) { // We already showed this multi-widget. continue; } $sidebar = is_active_widget( $widget['callback'], $widget['id'], false, false ); $done[] = $widget['callback']; if ( ! isset( $widget['params'][0] ) ) { $widget['params'][0] = array(); } $args = array( 'widget_id' => $widget['id'], 'widget_name' => $widget['name'], '_display' => 'template', ); if ( isset( $wp_registered_widget_controls[ $widget['id'] ]['id_base'] ) && isset( $widget['params'][0]['number'] ) ) { $id_base = $wp_registered_widget_controls[ $widget['id'] ]['id_base']; $args['_temp_id'] = "$id_base-__i__"; $args['_multi_num'] = next_widget_id_number( $id_base ); $args['_add'] = 'multi'; } else { $args['_add'] = 'single'; if ( $sidebar ) { $args['_hide'] = '1'; } } $control_args = array( 0 => $args, 1 => $widget['params'][0], ); $sidebar_args = wp_list_widget_controls_dynamic_sidebar( $control_args ); wp_widget_control( ...$sidebar_args ); } } /** * Callback to sort array by a 'name' key. * * @since 3.1.0 * @access private * * @param array $a First array. * @param array $b Second array. * @return int */ function _sort_name_callback( $a, $b ) { return strnatcasecmp( $a['name'], $b['name'] ); } /** * Show the widgets and their settings for a sidebar. * Used in the admin widget config screen. * * @since 2.5.0 * * @param string $sidebar Sidebar ID. * @param string $sidebar_name Optional. Sidebar name. Default empty. */ function wp_list_widget_controls( $sidebar, $sidebar_name = '' ) { add_filter( 'dynamic_sidebar_params', 'wp_list_widget_controls_dynamic_sidebar' ); $description = wp_sidebar_description( $sidebar ); echo '<div id="' . esc_attr( $sidebar ) . '" class="widgets-sortables">'; if ( $sidebar_name ) { $add_to = sprintf( /* translators: %s: Widgets sidebar name. */ __( 'Add to: %s' ), $sidebar_name ); ?> <div class="sidebar-name" data-add-to="<?php echo esc_attr( $add_to ); ?>"> <button type="button" class="handlediv hide-if-no-js" aria-expanded="true"> <span class="screen-reader-text"><?php echo esc_html( $sidebar_name ); ?></span> <span class="toggle-indicator" aria-hidden="true"></span> </button> <h2><?php echo esc_html( $sidebar_name ); ?> <span class="spinner"></span></h2> </div> <?php } if ( ! empty( $description ) ) { ?> <div class="sidebar-description"> <p class="description"><?php echo $description; ?></p> </div> <?php } dynamic_sidebar( $sidebar ); echo '</div>'; } /** * Retrieves the widget control arguments. * * @since 2.5.0 * * @global array $wp_registered_widgets * * @param array $params * @return array */ function wp_list_widget_controls_dynamic_sidebar( $params ) { global $wp_registered_widgets; static $i = 0; ++$i; $widget_id = $params[0]['widget_id']; $id = isset( $params[0]['_temp_id'] ) ? $params[0]['_temp_id'] : $widget_id; $hidden = isset( $params[0]['_hide'] ) ? ' style="display:none;"' : ''; $params[0]['before_widget'] = "<div id='widget-{$i}_{$id}' class='widget'$hidden>"; $params[0]['after_widget'] = '</div>'; $params[0]['before_title'] = '%BEG_OF_TITLE%'; // Deprecated. $params[0]['after_title'] = '%END_OF_TITLE%'; // Deprecated. if ( is_callable( $wp_registered_widgets[ $widget_id ]['callback'] ) ) { $wp_registered_widgets[ $widget_id ]['_callback'] = $wp_registered_widgets[ $widget_id ]['callback']; $wp_registered_widgets[ $widget_id ]['callback'] = 'wp_widget_control'; } return $params; } /** * @global array $wp_registered_widgets * * @param string $id_base * @return int */ function next_widget_id_number( $id_base ) { global $wp_registered_widgets; $number = 1; foreach ( $wp_registered_widgets as $widget_id => $widget ) { if ( preg_match( '/' . preg_quote( $id_base, '/' ) . '-([0-9]+)$/', $widget_id, $matches ) ) { $number = max( $number, $matches[1] ); } } ++$number; return $number; } /** * Meta widget used to display the control form for a widget. * * Called from dynamic_sidebar(). * * @since 2.5.0 * * @global array $wp_registered_widgets * @global array $wp_registered_widget_controls * @global array $sidebars_widgets * * @param array $sidebar_args * @return array */ function wp_widget_control( $sidebar_args ) { global $wp_registered_widgets, $wp_registered_widget_controls, $sidebars_widgets; $widget_id = $sidebar_args['widget_id']; $sidebar_id = isset( $sidebar_args['id'] ) ? $sidebar_args['id'] : false; $key = $sidebar_id ? array_search( $widget_id, $sidebars_widgets[ $sidebar_id ], true ) : '-1'; // Position of widget in sidebar. $control = isset( $wp_registered_widget_controls[ $widget_id ] ) ? $wp_registered_widget_controls[ $widget_id ] : array(); $widget = $wp_registered_widgets[ $widget_id ]; $id_format = $widget['id']; $widget_number = isset( $control['params'][0]['number'] ) ? $control['params'][0]['number'] : ''; $id_base = isset( $control['id_base'] ) ? $control['id_base'] : $widget_id; $width = isset( $control['width'] ) ? $control['width'] : ''; $height = isset( $control['height'] ) ? $control['height'] : ''; $multi_number = isset( $sidebar_args['_multi_num'] ) ? $sidebar_args['_multi_num'] : ''; $add_new = isset( $sidebar_args['_add'] ) ? $sidebar_args['_add'] : ''; $before_form = isset( $sidebar_args['before_form'] ) ? $sidebar_args['before_form'] : '<form method="post">'; $after_form = isset( $sidebar_args['after_form'] ) ? $sidebar_args['after_form'] : '</form>'; $before_widget_content = isset( $sidebar_args['before_widget_content'] ) ? $sidebar_args['before_widget_content'] : '<div class="widget-content">'; $after_widget_content = isset( $sidebar_args['after_widget_content'] ) ? $sidebar_args['after_widget_content'] : '</div>'; $query_arg = array( 'editwidget' => $widget['id'] ); if ( $add_new ) { $query_arg['addnew'] = 1; if ( $multi_number ) { $query_arg['num'] = $multi_number; $query_arg['base'] = $id_base; } } else { $query_arg['sidebar'] = $sidebar_id; $query_arg['key'] = $key; } /* * We aren't showing a widget control, we're outputting a template * for a multi-widget control. */ if ( isset( $sidebar_args['_display'] ) && 'template' === $sidebar_args['_display'] && $widget_number ) { // number == -1 implies a template where id numbers are replaced by a generic '__i__'. $control['params'][0]['number'] = -1; // With id_base widget ID's are constructed like {$id_base}-{$id_number}. if ( isset( $control['id_base'] ) ) { $id_format = $control['id_base'] . '-__i__'; } } $wp_registered_widgets[ $widget_id ]['callback'] = $wp_registered_widgets[ $widget_id ]['_callback']; unset( $wp_registered_widgets[ $widget_id ]['_callback'] ); $widget_title = esc_html( strip_tags( $sidebar_args['widget_name'] ) ); $has_form = 'noform'; echo $sidebar_args['before_widget']; ?> <div class="widget-top"> <div class="widget-title-action"> <button type="button" class="widget-action hide-if-no-js" aria-expanded="false"> <span class="screen-reader-text edit"> <?php /* translators: Hidden accessibility text. %s: Widget title. */ printf( __( 'Edit widget: %s' ), $widget_title ); ?> </span> <span class="screen-reader-text add"> <?php /* translators: Hidden accessibility text. %s: Widget title. */ printf( __( 'Add widget: %s' ), $widget_title ); ?> </span> <span class="toggle-indicator" aria-hidden="true"></span> </button> <a class="widget-control-edit hide-if-js" href="<?php echo esc_url( add_query_arg( $query_arg ) ); ?>"> <span class="edit"><?php _ex( 'Edit', 'widget' ); ?></span> <span class="add"><?php _ex( 'Add', 'widget' ); ?></span> <span class="screen-reader-text"><?php echo $widget_title; ?></span> </a> </div> <div class="widget-title"><h3><?php echo $widget_title; ?><span class="in-widget-title"></span></h3></div> </div> <div class="widget-inside"> <?php echo $before_form; ?> <?php echo $before_widget_content; ?> <?php if ( isset( $control['callback'] ) ) { $has_form = call_user_func_array( $control['callback'], $control['params'] ); } else { echo "\t\t<p>" . __( 'There are no options for this widget.' ) . "</p>\n"; } $noform_class = ''; if ( 'noform' === $has_form ) { $noform_class = ' widget-control-noform'; } ?> <?php echo $after_widget_content; ?> <input type="hidden" name="widget-id" class="widget-id" value="<?php echo esc_attr( $id_format ); ?>" /> <input type="hidden" name="id_base" class="id_base" value="<?php echo esc_attr( $id_base ); ?>" /> <input type="hidden" name="widget-width" class="widget-width" value="<?php echo esc_attr( $width ); ?>" /> <input type="hidden" name="widget-height" class="widget-height" value="<?php echo esc_attr( $height ); ?>" /> <input type="hidden" name="widget_number" class="widget_number" value="<?php echo esc_attr( $widget_number ); ?>" /> <input type="hidden" name="multi_number" class="multi_number" value="<?php echo esc_attr( $multi_number ); ?>" /> <input type="hidden" name="add_new" class="add_new" value="<?php echo esc_attr( $add_new ); ?>" /> <div class="widget-control-actions"> <div class="alignleft"> <button type="button" class="button-link button-link-delete widget-control-remove"><?php _e( 'Delete' ); ?></button> <span class="widget-control-close-wrapper"> | <button type="button" class="button-link widget-control-close"><?php _e( 'Done' ); ?></button> </span> </div> <div class="alignright<?php echo $noform_class; ?>"> <?php submit_button( __( 'Save' ), 'primary widget-control-save right', 'savewidget', false, array( 'id' => 'widget-' . esc_attr( $id_format ) . '-savewidget' ) ); ?> <span class="spinner"></span> </div> <br class="clear" /> </div> <?php echo $after_form; ?> </div> <div class="widget-description"> <?php $widget_description = wp_widget_description( $widget_id ); echo ( $widget_description ) ? "$widget_description\n" : "$widget_title\n"; ?> </div> <?php echo $sidebar_args['after_widget']; return $sidebar_args; } /** * @param string $classes * @return string */ function wp_widgets_access_body_class( $classes ) { return "$classes widgets_access "; } PK U�g\,d��H �H class-wp-community-events.phpnu �[��� <?php /** * Administration: Community Events class. * * @package WordPress * @subpackage Administration * @since 4.8.0 */ /** * Class WP_Community_Events. * * A client for api.wordpress.org/events. * * @since 4.8.0 */ #[AllowDynamicProperties] class WP_Community_Events { /** * ID for a WordPress user account. * * @since 4.8.0 * * @var int */ protected $user_id = 0; /** * Stores location data for the user. * * @since 4.8.0 * * @var false|array */ protected $user_location = false; /** * Constructor for WP_Community_Events. * * @since 4.8.0 * * @param int $user_id WP user ID. * @param false|array $user_location { * Stored location data for the user. false to pass no location. * * @type string $description The name of the location * @type string $latitude The latitude in decimal degrees notation, without the degree * symbol. e.g.: 47.615200. * @type string $longitude The longitude in decimal degrees notation, without the degree * symbol. e.g.: -122.341100. * @type string $country The ISO 3166-1 alpha-2 country code. e.g.: BR * } */ public function __construct( $user_id, $user_location = false ) { $this->user_id = absint( $user_id ); $this->user_location = $user_location; } /** * Gets data about events near a particular location. * * Cached events will be immediately returned if the `user_location` property * is set for the current user, and cached events exist for that location. * * Otherwise, this method sends a request to the w.org Events API with location * data. The API will send back a recognized location based on the data, along * with nearby events. * * The browser's request for events is proxied with this method, rather * than having the browser make the request directly to api.wordpress.org, * because it allows results to be cached server-side and shared with other * users and sites in the network. This makes the process more efficient, * since increasing the number of visits that get cached data means users * don't have to wait as often; if the user's browser made the request * directly, it would also need to make a second request to WP in order to * pass the data for caching. Having WP make the request also introduces * the opportunity to anonymize the IP before sending it to w.org, which * mitigates possible privacy concerns. * * @since 4.8.0 * @since 5.5.2 Response no longer contains formatted date field. They're added * in `wp.communityEvents.populateDynamicEventFields()` now. * * @param string $location_search Optional. City name to help determine the location. * e.g., "Seattle". Default empty string. * @param string $timezone Optional. Timezone to help determine the location. * Default empty string. * @return array|WP_Error A WP_Error on failure; an array with location and events on * success. */ public function get_events( $location_search = '', $timezone = '' ) { $cached_events = $this->get_cached_events(); if ( ! $location_search && $cached_events ) { return $cached_events; } // Include an unmodified $wp_version. require ABSPATH . WPINC . '/version.php'; $api_url = 'http://api.wordpress.org/events/1.0/'; $request_args = $this->get_request_args( $location_search, $timezone ); $request_args['user-agent'] = 'WordPress/' . $wp_version . '; ' . home_url( '/' ); if ( wp_http_supports( array( 'ssl' ) ) ) { $api_url = set_url_scheme( $api_url, 'https' ); } $response = wp_remote_get( $api_url, $request_args ); $response_code = wp_remote_retrieve_response_code( $response ); $response_body = json_decode( wp_remote_retrieve_body( $response ), true ); $response_error = null; if ( is_wp_error( $response ) ) { $response_error = $response; } elseif ( 200 !== $response_code ) { $response_error = new WP_Error( 'api-error', /* translators: %d: Numeric HTTP status code, e.g. 400, 403, 500, 504, etc. */ sprintf( __( 'Invalid API response code (%d).' ), $response_code ) ); } elseif ( ! isset( $response_body['location'], $response_body['events'] ) ) { $response_error = new WP_Error( 'api-invalid-response', isset( $response_body['error'] ) ? $response_body['error'] : __( 'Unknown API error.' ) ); } if ( is_wp_error( $response_error ) ) { return $response_error; } else { $expiration = false; if ( isset( $response_body['ttl'] ) ) { $expiration = $response_body['ttl']; unset( $response_body['ttl'] ); } /* * The IP in the response is usually the same as the one that was sent * in the request, but in some cases it is different. In those cases, * it's important to reset it back to the IP from the request. * * For example, if the IP sent in the request is private (e.g., 192.168.1.100), * then the API will ignore that and use the corresponding public IP instead, * and the public IP will get returned. If the public IP were saved, though, * then get_cached_events() would always return `false`, because the transient * would be generated based on the public IP when saving the cache, but generated * based on the private IP when retrieving the cache. */ if ( ! empty( $response_body['location']['ip'] ) ) { $response_body['location']['ip'] = $request_args['body']['ip']; } /* * The API doesn't return a description for latitude/longitude requests, * but the description is already saved in the user location, so that * one can be used instead. */ if ( $this->coordinates_match( $request_args['body'], $response_body['location'] ) && empty( $response_body['location']['description'] ) ) { $response_body['location']['description'] = $this->user_location['description']; } /* * Store the raw response, because events will expire before the cache does. * The response will need to be processed every page load. */ $this->cache_events( $response_body, $expiration ); $response_body['events'] = $this->trim_events( $response_body['events'] ); return $response_body; } } /** * Builds an array of args to use in an HTTP request to the w.org Events API. * * @since 4.8.0 * * @param string $search Optional. City search string. Default empty string. * @param string $timezone Optional. Timezone string. Default empty string. * @return array The request args. */ protected function get_request_args( $search = '', $timezone = '' ) { $args = array( 'number' => 5, // Get more than three in case some get trimmed out. 'ip' => self::get_unsafe_client_ip(), ); /* * Include the minimal set of necessary arguments, in order to increase the * chances of a cache-hit on the API side. */ if ( empty( $search ) && isset( $this->user_location['latitude'], $this->user_location['longitude'] ) ) { $args['latitude'] = $this->user_location['latitude']; $args['longitude'] = $this->user_location['longitude']; } else { $args['locale'] = get_user_locale( $this->user_id ); if ( $timezone ) { $args['timezone'] = $timezone; } if ( $search ) { $args['location'] = $search; } } // Wrap the args in an array compatible with the second parameter of `wp_remote_get()`. return array( 'body' => $args, ); } /** * Determines the user's actual IP address and attempts to partially * anonymize an IP address by converting it to a network ID. * * Geolocating the network ID usually returns a similar location as the * actual IP, but provides some privacy for the user. * * $_SERVER['REMOTE_ADDR'] cannot be used in all cases, such as when the user * is making their request through a proxy, or when the web server is behind * a proxy. In those cases, $_SERVER['REMOTE_ADDR'] is set to the proxy address rather * than the user's actual address. * * Modified from https://stackoverflow.com/a/2031935/450127, MIT license. * Modified from https://github.com/geertw/php-ip-anonymizer, MIT license. * * SECURITY WARNING: This function is _NOT_ intended to be used in * circumstances where the authenticity of the IP address matters. This does * _NOT_ guarantee that the returned address is valid or accurate, and it can * be easily spoofed. * * @since 4.8.0 * * @return string|false The anonymized address on success; the given address * or false on failure. */ public static function get_unsafe_client_ip() { $client_ip = false; // In order of preference, with the best ones for this purpose first. $address_headers = array( 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR', ); foreach ( $address_headers as $header ) { if ( array_key_exists( $header, $_SERVER ) ) { /* * HTTP_X_FORWARDED_FOR can contain a chain of comma-separated * addresses. The first one is the original client. It can't be * trusted for authenticity, but we don't need to for this purpose. */ $address_chain = explode( ',', $_SERVER[ $header ] ); $client_ip = trim( $address_chain[0] ); break; } } if ( ! $client_ip ) { return false; } $anon_ip = wp_privacy_anonymize_ip( $client_ip, true ); if ( '0.0.0.0' === $anon_ip || '::' === $anon_ip ) { return false; } return $anon_ip; } /** * Test if two pairs of latitude/longitude coordinates match each other. * * @since 4.8.0 * * @param array $a The first pair, with indexes 'latitude' and 'longitude'. * @param array $b The second pair, with indexes 'latitude' and 'longitude'. * @return bool True if they match, false if they don't. */ protected function coordinates_match( $a, $b ) { if ( ! isset( $a['latitude'], $a['longitude'], $b['latitude'], $b['longitude'] ) ) { return false; } return $a['latitude'] === $b['latitude'] && $a['longitude'] === $b['longitude']; } /** * Generates a transient key based on user location. * * This could be reduced to a one-liner in the calling functions, but it's * intentionally a separate function because it's called from multiple * functions, and having it abstracted keeps the logic consistent and DRY, * which is less prone to errors. * * @since 4.8.0 * * @param array $location Should contain 'latitude' and 'longitude' indexes. * @return string|false Transient key on success, false on failure. */ protected function get_events_transient_key( $location ) { $key = false; if ( isset( $location['ip'] ) ) { $key = 'community-events-' . md5( $location['ip'] ); } elseif ( isset( $location['latitude'], $location['longitude'] ) ) { $key = 'community-events-' . md5( $location['latitude'] . $location['longitude'] ); } return $key; } /** * Caches an array of events data from the Events API. * * @since 4.8.0 * * @param array $events Response body from the API request. * @param int|false $expiration Optional. Amount of time to cache the events. Defaults to false. * @return bool true if events were cached; false if not. */ protected function cache_events( $events, $expiration = false ) { $set = false; $transient_key = $this->get_events_transient_key( $events['location'] ); $cache_expiration = $expiration ? absint( $expiration ) : HOUR_IN_SECONDS * 12; if ( $transient_key ) { $set = set_site_transient( $transient_key, $events, $cache_expiration ); } return $set; } /** * Gets cached events. * * @since 4.8.0 * @since 5.5.2 Response no longer contains formatted date field. They're added * in `wp.communityEvents.populateDynamicEventFields()` now. * * @return array|false An array containing `location` and `events` items * on success, false on failure. */ public function get_cached_events() { $transient_key = $this->get_events_transient_key( $this->user_location ); if ( ! $transient_key ) { return false; } $cached_response = get_site_transient( $transient_key ); if ( isset( $cached_response['events'] ) ) { $cached_response['events'] = $this->trim_events( $cached_response['events'] ); } return $cached_response; } /** * Adds formatted date and time items for each event in an API response. * * This has to be called after the data is pulled from the cache, because * the cached events are shared by all users. If it was called before storing * the cache, then all users would see the events in the localized data/time * of the user who triggered the cache refresh, rather than their own. * * @since 4.8.0 * @deprecated 5.5.2 No longer used in core. * * @param array $response_body The response which contains the events. * @return array The response with dates and times formatted. */ protected function format_event_data_time( $response_body ) { _deprecated_function( __METHOD__, '5.5.2' ); if ( isset( $response_body['events'] ) ) { foreach ( $response_body['events'] as $key => $event ) { $timestamp = strtotime( $event['date'] ); /* * The `date_format` option is not used because it's important * in this context to keep the day of the week in the formatted date, * so that users can tell at a glance if the event is on a day they * are available, without having to open the link. */ /* translators: Date format for upcoming events on the dashboard. Include the day of the week. See https://www.php.net/manual/datetime.format.php */ $formatted_date = date_i18n( __( 'l, M j, Y' ), $timestamp ); $formatted_time = date_i18n( get_option( 'time_format' ), $timestamp ); if ( isset( $event['end_date'] ) ) { $end_timestamp = strtotime( $event['end_date'] ); $formatted_end_date = date_i18n( __( 'l, M j, Y' ), $end_timestamp ); if ( 'meetup' !== $event['type'] && $formatted_end_date !== $formatted_date ) { /* translators: Upcoming events month format. See https://www.php.net/manual/datetime.format.php */ $start_month = date_i18n( _x( 'F', 'upcoming events month format' ), $timestamp ); $end_month = date_i18n( _x( 'F', 'upcoming events month format' ), $end_timestamp ); if ( $start_month === $end_month ) { $formatted_date = sprintf( /* translators: Date string for upcoming events. 1: Month, 2: Starting day, 3: Ending day, 4: Year. */ __( '%1$s %2$d–%3$d, %4$d' ), $start_month, /* translators: Upcoming events day format. See https://www.php.net/manual/datetime.format.php */ date_i18n( _x( 'j', 'upcoming events day format' ), $timestamp ), date_i18n( _x( 'j', 'upcoming events day format' ), $end_timestamp ), /* translators: Upcoming events year format. See https://www.php.net/manual/datetime.format.php */ date_i18n( _x( 'Y', 'upcoming events year format' ), $timestamp ) ); } else { $formatted_date = sprintf( /* translators: Date string for upcoming events. 1: Starting month, 2: Starting day, 3: Ending month, 4: Ending day, 5: Year. */ __( '%1$s %2$d – %3$s %4$d, %5$d' ), $start_month, date_i18n( _x( 'j', 'upcoming events day format' ), $timestamp ), $end_month, date_i18n( _x( 'j', 'upcoming events day format' ), $end_timestamp ), date_i18n( _x( 'Y', 'upcoming events year format' ), $timestamp ) ); } $formatted_date = wp_maybe_decline_date( $formatted_date, 'F j, Y' ); } } $response_body['events'][ $key ]['formatted_date'] = $formatted_date; $response_body['events'][ $key ]['formatted_time'] = $formatted_time; } } return $response_body; } /** * Prepares the event list for presentation. * * Discards expired events, and makes WordCamps "sticky." Attendees need more * advanced notice about WordCamps than they do for meetups, so camps should * appear in the list sooner. If a WordCamp is coming up, the API will "stick" * it in the response, even if it wouldn't otherwise appear. When that happens, * the event will be at the end of the list, and will need to be moved into a * higher position, so that it doesn't get trimmed off. * * @since 4.8.0 * @since 4.9.7 Stick a WordCamp to the final list. * @since 5.5.2 Accepts and returns only the events, rather than an entire HTTP response. * @since 6.0.0 Decode HTML entities from the event title. * * @param array $events The events that will be prepared. * @return array The response body with events trimmed. */ protected function trim_events( array $events ) { $future_events = array(); foreach ( $events as $event ) { /* * The API's `date` and `end_date` fields are in the _event's_ local timezone, but UTC is needed so * it can be converted to the _user's_ local time. */ $end_time = (int) $event['end_unix_timestamp']; if ( time() < $end_time ) { // Decode HTML entities from the event title. $event['title'] = html_entity_decode( $event['title'], ENT_QUOTES, 'UTF-8' ); array_push( $future_events, $event ); } } $future_wordcamps = array_filter( $future_events, static function ( $wordcamp ) { return 'wordcamp' === $wordcamp['type']; } ); $future_wordcamps = array_values( $future_wordcamps ); // Remove gaps in indices. $trimmed_events = array_slice( $future_events, 0, 3 ); $trimmed_event_types = wp_list_pluck( $trimmed_events, 'type' ); // Make sure the soonest upcoming WordCamp is pinned in the list. if ( $future_wordcamps && ! in_array( 'wordcamp', $trimmed_event_types, true ) ) { array_pop( $trimmed_events ); array_push( $trimmed_events, $future_wordcamps[0] ); } return $trimmed_events; } /** * Logs responses to Events API requests. * * @since 4.8.0 * @deprecated 4.9.0 Use a plugin instead. See #41217 for an example. * * @param string $message A description of what occurred. * @param array $details Details that provide more context for the * log entry. */ protected function maybe_log_events_response( $message, $details ) { _deprecated_function( __METHOD__, '4.9.0' ); if ( ! WP_DEBUG_LOG ) { return; } error_log( sprintf( '%s: %s. Details: %s', __METHOD__, trim( $message, '.' ), wp_json_encode( $details ) ) ); } } PK U�g\Փ�r r update-core.phpnu �[��� <?php /** * WordPress core upgrade functionality. * * Note: Newly introduced functions and methods cannot be used here. * All functions must be present in the previous version being upgraded from * as this file is used there too. * * @package WordPress * @subpackage Administration * @since 2.7.0 */ /** * Stores files to be deleted. * * Bundled theme files should not be included in this list. * * @since 2.7.0 * * @global string[] $_old_files * @var string[] * @name $_old_files */ global $_old_files; $_old_files = array( // 2.0 'wp-admin/import-b2.php', 'wp-admin/import-blogger.php', 'wp-admin/import-greymatter.php', 'wp-admin/import-livejournal.php', 'wp-admin/import-mt.php', 'wp-admin/import-rss.php', 'wp-admin/import-textpattern.php', 'wp-admin/quicktags.js', 'wp-images/fade-butt.png', 'wp-images/get-firefox.png', 'wp-images/header-shadow.png', 'wp-images/smilies', 'wp-images/wp-small.png', 'wp-images/wpminilogo.png', 'wp.php', // 2.1 'wp-admin/edit-form-ajax-cat.php', 'wp-admin/execute-pings.php', 'wp-admin/inline-uploading.php', 'wp-admin/link-categories.php', 'wp-admin/list-manipulation.js', 'wp-admin/list-manipulation.php', 'wp-includes/comment-functions.php', 'wp-includes/feed-functions.php', 'wp-includes/functions-compat.php', 'wp-includes/functions-formatting.php', 'wp-includes/functions-post.php', 'wp-includes/js/dbx-key.js', 'wp-includes/links.php', 'wp-includes/pluggable-functions.php', 'wp-includes/template-functions-author.php', 'wp-includes/template-functions-category.php', 'wp-includes/template-functions-general.php', 'wp-includes/template-functions-links.php', 'wp-includes/template-functions-post.php', 'wp-includes/wp-l10n.php', // 2.2 'wp-admin/cat-js.php', 'wp-includes/js/autosave-js.php', 'wp-includes/js/list-manipulation-js.php', 'wp-includes/js/wp-ajax-js.php', // 2.3 'wp-admin/admin-db.php', 'wp-admin/cat.js', 'wp-admin/categories.js', 'wp-admin/custom-fields.js', 'wp-admin/dbx-admin-key.js', 'wp-admin/edit-comments.js', 'wp-admin/install-rtl.css', 'wp-admin/install.css', 'wp-admin/upgrade-schema.php', 'wp-admin/upload-functions.php', 'wp-admin/upload-rtl.css', 'wp-admin/upload.css', 'wp-admin/upload.js', 'wp-admin/users.js', 'wp-admin/widgets-rtl.css', 'wp-admin/widgets.css', 'wp-admin/xfn.js', 'wp-includes/js/tinymce/license.html', // 2.5 'wp-admin/css/upload.css', 'wp-admin/images/box-bg-left.gif', 'wp-admin/images/box-bg-right.gif', 'wp-admin/images/box-bg.gif', 'wp-admin/images/box-butt-left.gif', 'wp-admin/images/box-butt-right.gif', 'wp-admin/images/box-butt.gif', 'wp-admin/images/box-head-left.gif', 'wp-admin/images/box-head-right.gif', 'wp-admin/images/box-head.gif', 'wp-admin/images/heading-bg.gif', 'wp-admin/images/login-bkg-bottom.gif', 'wp-admin/images/login-bkg-tile.gif', 'wp-admin/images/notice.gif', 'wp-admin/images/toggle.gif', 'wp-admin/includes/upload.php', 'wp-admin/js/dbx-admin-key.js', 'wp-admin/js/link-cat.js', 'wp-admin/profile-update.php', 'wp-admin/templates.php', 'wp-includes/js/dbx.js', 'wp-includes/js/fat.js', 'wp-includes/js/list-manipulation.js', 'wp-includes/js/tinymce/langs/en.js', 'wp-includes/js/tinymce/plugins/directionality/images', 'wp-includes/js/tinymce/plugins/directionality/langs', 'wp-includes/js/tinymce/plugins/paste/images', 'wp-includes/js/tinymce/plugins/paste/jscripts', 'wp-includes/js/tinymce/plugins/paste/langs', 'wp-includes/js/tinymce/plugins/wordpress/images', 'wp-includes/js/tinymce/plugins/wordpress/langs', 'wp-includes/js/tinymce/plugins/wordpress/wordpress.css', 'wp-includes/js/tinymce/plugins/wphelp', // 2.5.1 'wp-includes/js/tinymce/tiny_mce_gzip.php', // 2.6 'wp-admin/bookmarklet.php', 'wp-includes/js/jquery/jquery.dimensions.min.js', 'wp-includes/js/tinymce/plugins/wordpress/popups.css', 'wp-includes/js/wp-ajax.js', // 2.7 'wp-admin/css/press-this-ie-rtl.css', 'wp-admin/css/press-this-ie.css', 'wp-admin/css/upload-rtl.css', 'wp-admin/edit-form.php', 'wp-admin/images/comment-pill.gif', 'wp-admin/images/comment-stalk-classic.gif', 'wp-admin/images/comment-stalk-fresh.gif', 'wp-admin/images/comment-stalk-rtl.gif', 'wp-admin/images/del.png', 'wp-admin/images/gear.png', 'wp-admin/images/media-button-gallery.gif', 'wp-admin/images/media-buttons.gif', 'wp-admin/images/postbox-bg.gif', 'wp-admin/images/tab.png', 'wp-admin/images/tail.gif', 'wp-admin/js/forms.js', 'wp-admin/js/upload.js', 'wp-admin/link-import.php', 'wp-includes/images/audio.png', 'wp-includes/images/css.png', 'wp-includes/images/default.png', 'wp-includes/images/doc.png', 'wp-includes/images/exe.png', 'wp-includes/images/html.png', 'wp-includes/images/js.png', 'wp-includes/images/pdf.png', 'wp-includes/images/swf.png', 'wp-includes/images/tar.png', 'wp-includes/images/text.png', 'wp-includes/images/video.png', 'wp-includes/images/zip.png', 'wp-includes/js/tinymce/tiny_mce_config.php', 'wp-includes/js/tinymce/tiny_mce_ext.js', // 2.8 'wp-admin/js/users.js', 'wp-includes/js/swfupload/swfupload_f9.swf', 'wp-includes/js/tinymce/plugins/autosave', 'wp-includes/js/tinymce/plugins/paste/css', 'wp-includes/js/tinymce/utils/mclayer.js', 'wp-includes/js/tinymce/wordpress.css', // 2.9 'wp-admin/js/page.dev.js', 'wp-admin/js/page.js', 'wp-admin/js/set-post-thumbnail-handler.dev.js', 'wp-admin/js/set-post-thumbnail-handler.js', 'wp-admin/js/slug.dev.js', 'wp-admin/js/slug.js', 'wp-includes/gettext.php', 'wp-includes/js/tinymce/plugins/wordpress/js', 'wp-includes/streams.php', // MU 'README.txt', 'htaccess.dist', 'index-install.php', 'wp-admin/css/mu-rtl.css', 'wp-admin/css/mu.css', 'wp-admin/images/site-admin.png', 'wp-admin/includes/mu.php', 'wp-admin/wpmu-admin.php', 'wp-admin/wpmu-blogs.php', 'wp-admin/wpmu-edit.php', 'wp-admin/wpmu-options.php', 'wp-admin/wpmu-themes.php', 'wp-admin/wpmu-upgrade-site.php', 'wp-admin/wpmu-users.php', 'wp-includes/images/wordpress-mu.png', 'wp-includes/wpmu-default-filters.php', 'wp-includes/wpmu-functions.php', 'wpmu-settings.php', // 3.0 'wp-admin/categories.php', 'wp-admin/edit-category-form.php', 'wp-admin/edit-page-form.php', 'wp-admin/edit-pages.php', 'wp-admin/images/admin-header-footer.png', 'wp-admin/images/browse-happy.gif', 'wp-admin/images/ico-add.png', 'wp-admin/images/ico-close.png', 'wp-admin/images/ico-edit.png', 'wp-admin/images/ico-viewpage.png', 'wp-admin/images/fav-top.png', 'wp-admin/images/screen-options-left.gif', 'wp-admin/images/wp-logo-vs.gif', 'wp-admin/images/wp-logo.gif', 'wp-admin/import', 'wp-admin/js/wp-gears.dev.js', 'wp-admin/js/wp-gears.js', 'wp-admin/options-misc.php', 'wp-admin/page-new.php', 'wp-admin/page.php', 'wp-admin/rtl.css', 'wp-admin/rtl.dev.css', 'wp-admin/update-links.php', 'wp-admin/wp-admin.css', 'wp-admin/wp-admin.dev.css', 'wp-includes/js/codepress', 'wp-includes/js/jquery/autocomplete.dev.js', 'wp-includes/js/jquery/autocomplete.js', 'wp-includes/js/jquery/interface.js', // Following file added back in 5.1, see #45645. //'wp-includes/js/tinymce/wp-tinymce.js', // 3.1 'wp-admin/edit-attachment-rows.php', 'wp-admin/edit-link-categories.php', 'wp-admin/edit-link-category-form.php', 'wp-admin/edit-post-rows.php', 'wp-admin/images/button-grad-active-vs.png', 'wp-admin/images/button-grad-vs.png', 'wp-admin/images/fav-arrow-vs-rtl.gif', 'wp-admin/images/fav-arrow-vs.gif', 'wp-admin/images/fav-top-vs.gif', 'wp-admin/images/list-vs.png', 'wp-admin/images/screen-options-right-up.gif', 'wp-admin/images/screen-options-right.gif', 'wp-admin/images/visit-site-button-grad-vs.gif', 'wp-admin/images/visit-site-button-grad.gif', 'wp-admin/link-category.php', 'wp-admin/sidebar.php', 'wp-includes/classes.php', 'wp-includes/js/tinymce/blank.htm', 'wp-includes/js/tinymce/plugins/media/img', 'wp-includes/js/tinymce/plugins/safari', // 3.2 'wp-admin/images/logo-login.gif', 'wp-admin/images/star.gif', 'wp-admin/js/list-table.dev.js', 'wp-admin/js/list-table.js', 'wp-includes/default-embeds.php', // 3.3 'wp-admin/css/colors-classic-rtl.css', 'wp-admin/css/colors-classic-rtl.dev.css', 'wp-admin/css/colors-fresh-rtl.css', 'wp-admin/css/colors-fresh-rtl.dev.css', 'wp-admin/css/dashboard-rtl.dev.css', 'wp-admin/css/dashboard.dev.css', 'wp-admin/css/global-rtl.css', 'wp-admin/css/global-rtl.dev.css', 'wp-admin/css/global.css', 'wp-admin/css/global.dev.css', 'wp-admin/css/install-rtl.dev.css', 'wp-admin/css/login-rtl.dev.css', 'wp-admin/css/login.dev.css', 'wp-admin/css/ms.css', 'wp-admin/css/ms.dev.css', 'wp-admin/css/nav-menu-rtl.css', 'wp-admin/css/nav-menu-rtl.dev.css', 'wp-admin/css/nav-menu.css', 'wp-admin/css/nav-menu.dev.css', 'wp-admin/css/plugin-install-rtl.css', 'wp-admin/css/plugin-install-rtl.dev.css', 'wp-admin/css/plugin-install.css', 'wp-admin/css/plugin-install.dev.css', 'wp-admin/css/press-this-rtl.dev.css', 'wp-admin/css/press-this.dev.css', 'wp-admin/css/theme-editor-rtl.css', 'wp-admin/css/theme-editor-rtl.dev.css', 'wp-admin/css/theme-editor.css', 'wp-admin/css/theme-editor.dev.css', 'wp-admin/css/theme-install-rtl.css', 'wp-admin/css/theme-install-rtl.dev.css', 'wp-admin/css/theme-install.css', 'wp-admin/css/theme-install.dev.css', 'wp-admin/css/widgets-rtl.dev.css', 'wp-admin/css/widgets.dev.css', 'wp-admin/includes/internal-linking.php', 'wp-includes/images/admin-bar-sprite-rtl.png', 'wp-includes/js/jquery/ui.button.js', 'wp-includes/js/jquery/ui.core.js', 'wp-includes/js/jquery/ui.dialog.js', 'wp-includes/js/jquery/ui.draggable.js', 'wp-includes/js/jquery/ui.droppable.js', 'wp-includes/js/jquery/ui.mouse.js', 'wp-includes/js/jquery/ui.position.js', 'wp-includes/js/jquery/ui.resizable.js', 'wp-includes/js/jquery/ui.selectable.js', 'wp-includes/js/jquery/ui.sortable.js', 'wp-includes/js/jquery/ui.tabs.js', 'wp-includes/js/jquery/ui.widget.js', 'wp-includes/js/l10n.dev.js', 'wp-includes/js/l10n.js', 'wp-includes/js/tinymce/plugins/wplink/css', 'wp-includes/js/tinymce/plugins/wplink/img', 'wp-includes/js/tinymce/plugins/wplink/js', // Don't delete, yet: 'wp-rss.php', // Don't delete, yet: 'wp-rdf.php', // Don't delete, yet: 'wp-rss2.php', // Don't delete, yet: 'wp-commentsrss2.php', // Don't delete, yet: 'wp-atom.php', // Don't delete, yet: 'wp-feed.php', // 3.4 'wp-admin/images/gray-star.png', 'wp-admin/images/logo-login.png', 'wp-admin/images/star.png', 'wp-admin/index-extra.php', 'wp-admin/network/index-extra.php', 'wp-admin/user/index-extra.php', 'wp-includes/css/editor-buttons.css', 'wp-includes/css/editor-buttons.dev.css', 'wp-includes/js/tinymce/plugins/paste/blank.htm', 'wp-includes/js/tinymce/plugins/wordpress/css', 'wp-includes/js/tinymce/plugins/wordpress/editor_plugin.dev.js', 'wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin.dev.js', 'wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin.dev.js', 'wp-includes/js/tinymce/plugins/wpgallery/editor_plugin.dev.js', 'wp-includes/js/tinymce/plugins/wplink/editor_plugin.dev.js', // Don't delete, yet: 'wp-pass.php', // Don't delete, yet: 'wp-register.php', // 3.5 'wp-admin/gears-manifest.php', 'wp-admin/includes/manifest.php', 'wp-admin/images/archive-link.png', 'wp-admin/images/blue-grad.png', 'wp-admin/images/button-grad-active.png', 'wp-admin/images/button-grad.png', 'wp-admin/images/ed-bg-vs.gif', 'wp-admin/images/ed-bg.gif', 'wp-admin/images/fade-butt.png', 'wp-admin/images/fav-arrow-rtl.gif', 'wp-admin/images/fav-arrow.gif', 'wp-admin/images/fav-vs.png', 'wp-admin/images/fav.png', 'wp-admin/images/gray-grad.png', 'wp-admin/images/loading-publish.gif', 'wp-admin/images/logo-ghost.png', 'wp-admin/images/logo.gif', 'wp-admin/images/menu-arrow-frame-rtl.png', 'wp-admin/images/menu-arrow-frame.png', 'wp-admin/images/menu-arrows.gif', 'wp-admin/images/menu-bits-rtl-vs.gif', 'wp-admin/images/menu-bits-rtl.gif', 'wp-admin/images/menu-bits-vs.gif', 'wp-admin/images/menu-bits.gif', 'wp-admin/images/menu-dark-rtl-vs.gif', 'wp-admin/images/menu-dark-rtl.gif', 'wp-admin/images/menu-dark-vs.gif', 'wp-admin/images/menu-dark.gif', 'wp-admin/images/required.gif', 'wp-admin/images/screen-options-toggle-vs.gif', 'wp-admin/images/screen-options-toggle.gif', 'wp-admin/images/toggle-arrow-rtl.gif', 'wp-admin/images/toggle-arrow.gif', 'wp-admin/images/upload-classic.png', 'wp-admin/images/upload-fresh.png', 'wp-admin/images/white-grad-active.png', 'wp-admin/images/white-grad.png', 'wp-admin/images/widgets-arrow-vs.gif', 'wp-admin/images/widgets-arrow.gif', 'wp-admin/images/wpspin_dark.gif', 'wp-includes/images/upload.png', 'wp-includes/js/prototype.js', 'wp-includes/js/scriptaculous', 'wp-admin/css/wp-admin-rtl.dev.css', 'wp-admin/css/wp-admin.dev.css', 'wp-admin/css/media-rtl.dev.css', 'wp-admin/css/media.dev.css', 'wp-admin/css/colors-classic.dev.css', 'wp-admin/css/customize-controls-rtl.dev.css', 'wp-admin/css/customize-controls.dev.css', 'wp-admin/css/ie-rtl.dev.css', 'wp-admin/css/ie.dev.css', 'wp-admin/css/install.dev.css', 'wp-admin/css/colors-fresh.dev.css', 'wp-includes/js/customize-base.dev.js', 'wp-includes/js/json2.dev.js', 'wp-includes/js/comment-reply.dev.js', 'wp-includes/js/customize-preview.dev.js', 'wp-includes/js/wplink.dev.js', 'wp-includes/js/tw-sack.dev.js', 'wp-includes/js/wp-list-revisions.dev.js', 'wp-includes/js/autosave.dev.js', 'wp-includes/js/admin-bar.dev.js', 'wp-includes/js/quicktags.dev.js', 'wp-includes/js/wp-ajax-response.dev.js', 'wp-includes/js/wp-pointer.dev.js', 'wp-includes/js/hoverIntent.dev.js', 'wp-includes/js/colorpicker.dev.js', 'wp-includes/js/wp-lists.dev.js', 'wp-includes/js/customize-loader.dev.js', 'wp-includes/js/jquery/jquery.table-hotkeys.dev.js', 'wp-includes/js/jquery/jquery.color.dev.js', 'wp-includes/js/jquery/jquery.color.js', 'wp-includes/js/jquery/jquery.hotkeys.dev.js', 'wp-includes/js/jquery/jquery.form.dev.js', 'wp-includes/js/jquery/suggest.dev.js', 'wp-admin/js/xfn.dev.js', 'wp-admin/js/set-post-thumbnail.dev.js', 'wp-admin/js/comment.dev.js', 'wp-admin/js/theme.dev.js', 'wp-admin/js/cat.dev.js', 'wp-admin/js/password-strength-meter.dev.js', 'wp-admin/js/user-profile.dev.js', 'wp-admin/js/theme-preview.dev.js', 'wp-admin/js/post.dev.js', 'wp-admin/js/media-upload.dev.js', 'wp-admin/js/word-count.dev.js', 'wp-admin/js/plugin-install.dev.js', 'wp-admin/js/edit-comments.dev.js', 'wp-admin/js/media-gallery.dev.js', 'wp-admin/js/custom-fields.dev.js', 'wp-admin/js/custom-background.dev.js', 'wp-admin/js/common.dev.js', 'wp-admin/js/inline-edit-tax.dev.js', 'wp-admin/js/gallery.dev.js', 'wp-admin/js/utils.dev.js', 'wp-admin/js/widgets.dev.js', 'wp-admin/js/wp-fullscreen.dev.js', 'wp-admin/js/nav-menu.dev.js', 'wp-admin/js/dashboard.dev.js', 'wp-admin/js/link.dev.js', 'wp-admin/js/user-suggest.dev.js', 'wp-admin/js/postbox.dev.js', 'wp-admin/js/tags.dev.js', 'wp-admin/js/image-edit.dev.js', 'wp-admin/js/media.dev.js', 'wp-admin/js/customize-controls.dev.js', 'wp-admin/js/inline-edit-post.dev.js', 'wp-admin/js/categories.dev.js', 'wp-admin/js/editor.dev.js', 'wp-includes/js/plupload/handlers.dev.js', 'wp-includes/js/plupload/wp-plupload.dev.js', 'wp-includes/js/swfupload/handlers.dev.js', 'wp-includes/js/jcrop/jquery.Jcrop.dev.js', 'wp-includes/js/jcrop/jquery.Jcrop.js', 'wp-includes/js/jcrop/jquery.Jcrop.css', 'wp-includes/js/imgareaselect/jquery.imgareaselect.dev.js', 'wp-includes/css/wp-pointer.dev.css', 'wp-includes/css/editor.dev.css', 'wp-includes/css/jquery-ui-dialog.dev.css', 'wp-includes/css/admin-bar-rtl.dev.css', 'wp-includes/css/admin-bar.dev.css', 'wp-includes/js/jquery/ui/jquery.effects.clip.min.js', 'wp-includes/js/jquery/ui/jquery.effects.scale.min.js', 'wp-includes/js/jquery/ui/jquery.effects.blind.min.js', 'wp-includes/js/jquery/ui/jquery.effects.core.min.js', 'wp-includes/js/jquery/ui/jquery.effects.shake.min.js', 'wp-includes/js/jquery/ui/jquery.effects.fade.min.js', 'wp-includes/js/jquery/ui/jquery.effects.explode.min.js', 'wp-includes/js/jquery/ui/jquery.effects.slide.min.js', 'wp-includes/js/jquery/ui/jquery.effects.drop.min.js', 'wp-includes/js/jquery/ui/jquery.effects.highlight.min.js', 'wp-includes/js/jquery/ui/jquery.effects.bounce.min.js', 'wp-includes/js/jquery/ui/jquery.effects.pulsate.min.js', 'wp-includes/js/jquery/ui/jquery.effects.transfer.min.js', 'wp-includes/js/jquery/ui/jquery.effects.fold.min.js', 'wp-admin/js/utils.js', // Added back in 5.3 [45448], see #43895. // 'wp-admin/options-privacy.php', 'wp-app.php', 'wp-includes/class-wp-atom-server.php', // 3.5.2 'wp-includes/js/swfupload/swfupload-all.js', // 3.6 'wp-admin/js/revisions-js.php', 'wp-admin/images/screenshots', 'wp-admin/js/categories.js', 'wp-admin/js/categories.min.js', 'wp-admin/js/custom-fields.js', 'wp-admin/js/custom-fields.min.js', // 3.7 'wp-admin/js/cat.js', 'wp-admin/js/cat.min.js', // 3.8 'wp-includes/js/thickbox/tb-close-2x.png', 'wp-includes/js/thickbox/tb-close.png', 'wp-includes/images/wpmini-blue-2x.png', 'wp-includes/images/wpmini-blue.png', 'wp-admin/css/colors-fresh.css', 'wp-admin/css/colors-classic.css', 'wp-admin/css/colors-fresh.min.css', 'wp-admin/css/colors-classic.min.css', 'wp-admin/js/about.min.js', 'wp-admin/js/about.js', 'wp-admin/images/arrows-dark-vs-2x.png', 'wp-admin/images/wp-logo-vs.png', 'wp-admin/images/arrows-dark-vs.png', 'wp-admin/images/wp-logo.png', 'wp-admin/images/arrows-pr.png', 'wp-admin/images/arrows-dark.png', 'wp-admin/images/press-this.png', 'wp-admin/images/press-this-2x.png', 'wp-admin/images/arrows-vs-2x.png', 'wp-admin/images/welcome-icons.png', 'wp-admin/images/wp-logo-2x.png', 'wp-admin/images/stars-rtl-2x.png', 'wp-admin/images/arrows-dark-2x.png', 'wp-admin/images/arrows-pr-2x.png', 'wp-admin/images/menu-shadow-rtl.png', 'wp-admin/images/arrows-vs.png', 'wp-admin/images/about-search-2x.png', 'wp-admin/images/bubble_bg-rtl-2x.gif', 'wp-admin/images/wp-badge-2x.png', 'wp-admin/images/wordpress-logo-2x.png', 'wp-admin/images/bubble_bg-rtl.gif', 'wp-admin/images/wp-badge.png', 'wp-admin/images/menu-shadow.png', 'wp-admin/images/about-globe-2x.png', 'wp-admin/images/welcome-icons-2x.png', 'wp-admin/images/stars-rtl.png', 'wp-admin/images/wp-logo-vs-2x.png', 'wp-admin/images/about-updates-2x.png', // 3.9 'wp-admin/css/colors.css', 'wp-admin/css/colors.min.css', 'wp-admin/css/colors-rtl.css', 'wp-admin/css/colors-rtl.min.css', // Following files added back in 4.5, see #36083. // 'wp-admin/css/media-rtl.min.css', // 'wp-admin/css/media.min.css', // 'wp-admin/css/farbtastic-rtl.min.css', 'wp-admin/images/lock-2x.png', 'wp-admin/images/lock.png', 'wp-admin/js/theme-preview.js', 'wp-admin/js/theme-install.min.js', 'wp-admin/js/theme-install.js', 'wp-admin/js/theme-preview.min.js', 'wp-includes/js/plupload/plupload.html4.js', 'wp-includes/js/plupload/plupload.html5.js', 'wp-includes/js/plupload/changelog.txt', 'wp-includes/js/plupload/plupload.silverlight.js', 'wp-includes/js/plupload/plupload.flash.js', // Added back in 4.9 [41328], see #41755. // 'wp-includes/js/plupload/plupload.js', 'wp-includes/js/tinymce/plugins/spellchecker', 'wp-includes/js/tinymce/plugins/inlinepopups', 'wp-includes/js/tinymce/plugins/media/js', 'wp-includes/js/tinymce/plugins/media/css', 'wp-includes/js/tinymce/plugins/wordpress/img', 'wp-includes/js/tinymce/plugins/wpdialogs/js', 'wp-includes/js/tinymce/plugins/wpeditimage/img', 'wp-includes/js/tinymce/plugins/wpeditimage/js', 'wp-includes/js/tinymce/plugins/wpeditimage/css', 'wp-includes/js/tinymce/plugins/wpgallery/img', 'wp-includes/js/tinymce/plugins/paste/js', 'wp-includes/js/tinymce/themes/advanced', 'wp-includes/js/tinymce/tiny_mce.js', 'wp-includes/js/tinymce/mark_loaded_src.js', 'wp-includes/js/tinymce/wp-tinymce-schema.js', 'wp-includes/js/tinymce/plugins/media/editor_plugin.js', 'wp-includes/js/tinymce/plugins/media/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/media/media.htm', 'wp-includes/js/tinymce/plugins/wpview/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wpview/editor_plugin.js', 'wp-includes/js/tinymce/plugins/directionality/editor_plugin.js', 'wp-includes/js/tinymce/plugins/directionality/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wordpress/editor_plugin.js', 'wp-includes/js/tinymce/plugins/wordpress/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin.js', 'wp-includes/js/tinymce/plugins/wpeditimage/editimage.html', 'wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin.js', 'wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/fullscreen/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/fullscreen/fullscreen.htm', 'wp-includes/js/tinymce/plugins/fullscreen/editor_plugin.js', 'wp-includes/js/tinymce/plugins/wplink/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wplink/editor_plugin.js', 'wp-includes/js/tinymce/plugins/wpgallery/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wpgallery/editor_plugin.js', 'wp-includes/js/tinymce/plugins/tabfocus/editor_plugin.js', 'wp-includes/js/tinymce/plugins/tabfocus/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/paste/editor_plugin.js', 'wp-includes/js/tinymce/plugins/paste/pasteword.htm', 'wp-includes/js/tinymce/plugins/paste/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/paste/pastetext.htm', 'wp-includes/js/tinymce/langs/wp-langs.php', // 4.1 'wp-includes/js/jquery/ui/jquery.ui.accordion.min.js', 'wp-includes/js/jquery/ui/jquery.ui.autocomplete.min.js', 'wp-includes/js/jquery/ui/jquery.ui.button.min.js', 'wp-includes/js/jquery/ui/jquery.ui.core.min.js', 'wp-includes/js/jquery/ui/jquery.ui.datepicker.min.js', 'wp-includes/js/jquery/ui/jquery.ui.dialog.min.js', 'wp-includes/js/jquery/ui/jquery.ui.draggable.min.js', 'wp-includes/js/jquery/ui/jquery.ui.droppable.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-blind.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-bounce.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-clip.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-drop.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-explode.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-fade.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-fold.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-highlight.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-pulsate.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-scale.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-shake.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-slide.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-transfer.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect.min.js', 'wp-includes/js/jquery/ui/jquery.ui.menu.min.js', 'wp-includes/js/jquery/ui/jquery.ui.mouse.min.js', 'wp-includes/js/jquery/ui/jquery.ui.position.min.js', 'wp-includes/js/jquery/ui/jquery.ui.progressbar.min.js', 'wp-includes/js/jquery/ui/jquery.ui.resizable.min.js', 'wp-includes/js/jquery/ui/jquery.ui.selectable.min.js', 'wp-includes/js/jquery/ui/jquery.ui.slider.min.js', 'wp-includes/js/jquery/ui/jquery.ui.sortable.min.js', 'wp-includes/js/jquery/ui/jquery.ui.spinner.min.js', 'wp-includes/js/jquery/ui/jquery.ui.tabs.min.js', 'wp-includes/js/jquery/ui/jquery.ui.tooltip.min.js', 'wp-includes/js/jquery/ui/jquery.ui.widget.min.js', 'wp-includes/js/tinymce/skins/wordpress/images/dashicon-no-alt.png', // 4.3 'wp-admin/js/wp-fullscreen.js', 'wp-admin/js/wp-fullscreen.min.js', 'wp-includes/js/tinymce/wp-mce-help.php', 'wp-includes/js/tinymce/plugins/wpfullscreen', // 4.5 'wp-includes/theme-compat/comments-popup.php', // 4.6 'wp-admin/includes/class-wp-automatic-upgrader.php', // Wrong file name, see #37628. // 4.8 'wp-includes/js/tinymce/plugins/wpembed', 'wp-includes/js/tinymce/plugins/media/moxieplayer.swf', 'wp-includes/js/tinymce/skins/lightgray/fonts/readme.md', 'wp-includes/js/tinymce/skins/lightgray/fonts/tinymce-small.json', 'wp-includes/js/tinymce/skins/lightgray/fonts/tinymce.json', 'wp-includes/js/tinymce/skins/lightgray/skin.ie7.min.css', // 4.9 'wp-admin/css/press-this-editor-rtl.css', 'wp-admin/css/press-this-editor-rtl.min.css', 'wp-admin/css/press-this-editor.css', 'wp-admin/css/press-this-editor.min.css', 'wp-admin/css/press-this-rtl.css', 'wp-admin/css/press-this-rtl.min.css', 'wp-admin/css/press-this.css', 'wp-admin/css/press-this.min.css', 'wp-admin/includes/class-wp-press-this.php', 'wp-admin/js/bookmarklet.js', 'wp-admin/js/bookmarklet.min.js', 'wp-admin/js/press-this.js', 'wp-admin/js/press-this.min.js', 'wp-includes/js/mediaelement/background.png', 'wp-includes/js/mediaelement/bigplay.png', 'wp-includes/js/mediaelement/bigplay.svg', 'wp-includes/js/mediaelement/controls.png', 'wp-includes/js/mediaelement/controls.svg', 'wp-includes/js/mediaelement/flashmediaelement.swf', 'wp-includes/js/mediaelement/froogaloop.min.js', 'wp-includes/js/mediaelement/jumpforward.png', 'wp-includes/js/mediaelement/loading.gif', 'wp-includes/js/mediaelement/silverlightmediaelement.xap', 'wp-includes/js/mediaelement/skipback.png', 'wp-includes/js/plupload/plupload.flash.swf', 'wp-includes/js/plupload/plupload.full.min.js', 'wp-includes/js/plupload/plupload.silverlight.xap', 'wp-includes/js/swfupload/plugins', 'wp-includes/js/swfupload/swfupload.swf', // 4.9.2 'wp-includes/js/mediaelement/lang', 'wp-includes/js/mediaelement/mediaelement-flash-audio-ogg.swf', 'wp-includes/js/mediaelement/mediaelement-flash-audio.swf', 'wp-includes/js/mediaelement/mediaelement-flash-video-hls.swf', 'wp-includes/js/mediaelement/mediaelement-flash-video-mdash.swf', 'wp-includes/js/mediaelement/mediaelement-flash-video.swf', 'wp-includes/js/mediaelement/renderers/dailymotion.js', 'wp-includes/js/mediaelement/renderers/dailymotion.min.js', 'wp-includes/js/mediaelement/renderers/facebook.js', 'wp-includes/js/mediaelement/renderers/facebook.min.js', 'wp-includes/js/mediaelement/renderers/soundcloud.js', 'wp-includes/js/mediaelement/renderers/soundcloud.min.js', 'wp-includes/js/mediaelement/renderers/twitch.js', 'wp-includes/js/mediaelement/renderers/twitch.min.js', // 5.0 'wp-includes/js/codemirror/jshint.js', // 5.1 'wp-includes/js/tinymce/wp-tinymce.js.gz', // 5.3 'wp-includes/js/wp-a11y.js', // Moved to: wp-includes/js/dist/a11y.js 'wp-includes/js/wp-a11y.min.js', // Moved to: wp-includes/js/dist/a11y.min.js // 5.4 'wp-admin/js/wp-fullscreen-stub.js', 'wp-admin/js/wp-fullscreen-stub.min.js', // 5.5 'wp-admin/css/ie.css', 'wp-admin/css/ie.min.css', 'wp-admin/css/ie-rtl.css', 'wp-admin/css/ie-rtl.min.css', // 5.6 'wp-includes/js/jquery/ui/position.min.js', 'wp-includes/js/jquery/ui/widget.min.js', // 5.7 'wp-includes/blocks/classic/block.json', // 5.8 'wp-admin/images/freedoms.png', 'wp-admin/images/privacy.png', 'wp-admin/images/about-badge.svg', 'wp-admin/images/about-color-palette.svg', 'wp-admin/images/about-color-palette-vert.svg', 'wp-admin/images/about-header-brushes.svg', 'wp-includes/block-patterns/large-header.php', 'wp-includes/block-patterns/heading-paragraph.php', 'wp-includes/block-patterns/quote.php', 'wp-includes/block-patterns/text-three-columns-buttons.php', 'wp-includes/block-patterns/two-buttons.php', 'wp-includes/block-patterns/two-images.php', 'wp-includes/block-patterns/three-buttons.php', 'wp-includes/block-patterns/text-two-columns-with-images.php', 'wp-includes/block-patterns/text-two-columns.php', 'wp-includes/block-patterns/large-header-button.php', 'wp-includes/blocks/subhead', 'wp-includes/css/dist/editor/editor-styles.css', 'wp-includes/css/dist/editor/editor-styles.min.css', 'wp-includes/css/dist/editor/editor-styles-rtl.css', 'wp-includes/css/dist/editor/editor-styles-rtl.min.css', // 5.9 'wp-includes/blocks/heading/editor.css', 'wp-includes/blocks/heading/editor.min.css', 'wp-includes/blocks/heading/editor-rtl.css', 'wp-includes/blocks/heading/editor-rtl.min.css', 'wp-includes/blocks/query-title/editor.css', 'wp-includes/blocks/query-title/editor.min.css', 'wp-includes/blocks/query-title/editor-rtl.css', 'wp-includes/blocks/query-title/editor-rtl.min.css', /* * Restored in WordPress 6.7 * * 'wp-includes/blocks/tag-cloud/editor.css', * 'wp-includes/blocks/tag-cloud/editor.min.css', * 'wp-includes/blocks/tag-cloud/editor-rtl.css', * 'wp-includes/blocks/tag-cloud/editor-rtl.min.css', */ // 6.1 'wp-includes/blocks/post-comments.php', 'wp-includes/blocks/post-comments', 'wp-includes/blocks/comments-query-loop', // 6.3 'wp-includes/images/wlw', 'wp-includes/wlwmanifest.xml', 'wp-includes/random_compat', // 6.4 'wp-includes/navigation-fallback.php', 'wp-includes/blocks/navigation/view-modal.min.js', 'wp-includes/blocks/navigation/view-modal.js', // 6.5 'wp-includes/ID3/license.commercial.txt', 'wp-includes/blocks/query/style-rtl.min.css', 'wp-includes/blocks/query/style.min.css', 'wp-includes/blocks/query/style-rtl.css', 'wp-includes/blocks/query/style.css', 'wp-admin/images/about-header-privacy.svg', 'wp-admin/images/about-header-about.svg', 'wp-admin/images/about-header-credits.svg', 'wp-admin/images/about-header-freedoms.svg', 'wp-admin/images/about-header-contribute.svg', 'wp-admin/images/about-header-background.svg', // 6.6 'wp-includes/blocks/block/editor.css', 'wp-includes/blocks/block/editor.min.css', 'wp-includes/blocks/block/editor-rtl.css', 'wp-includes/blocks/block/editor-rtl.min.css', /* * 6.7 * * WordPress 6.7 included a SimplePie upgrade that included a major * refactoring of the file structure and library. The old files are * split in to two sections to account for this: files and directories. * * See https://core.trac.wordpress.org/changeset/59141 */ // 6.7 - files 'wp-includes/js/dist/interactivity-router.asset.php', 'wp-includes/js/dist/interactivity-router.js', 'wp-includes/js/dist/interactivity-router.min.js', 'wp-includes/js/dist/interactivity-router.min.asset.php', 'wp-includes/js/dist/interactivity.js', 'wp-includes/js/dist/interactivity.min.js', 'wp-includes/js/dist/vendor/react-dom.min.js.LICENSE.txt', 'wp-includes/js/dist/vendor/react.min.js.LICENSE.txt', 'wp-includes/js/dist/vendor/wp-polyfill-importmap.js', 'wp-includes/js/dist/vendor/wp-polyfill-importmap.min.js', 'wp-includes/sodium_compat/src/Core/Base64/Common.php', 'wp-includes/SimplePie/Author.php', 'wp-includes/SimplePie/Cache.php', 'wp-includes/SimplePie/Caption.php', 'wp-includes/SimplePie/Category.php', 'wp-includes/SimplePie/Copyright.php', 'wp-includes/SimplePie/Core.php', 'wp-includes/SimplePie/Credit.php', 'wp-includes/SimplePie/Enclosure.php', 'wp-includes/SimplePie/Exception.php', 'wp-includes/SimplePie/File.php', 'wp-includes/SimplePie/gzdecode.php', 'wp-includes/SimplePie/IRI.php', 'wp-includes/SimplePie/Item.php', 'wp-includes/SimplePie/Locator.php', 'wp-includes/SimplePie/Misc.php', 'wp-includes/SimplePie/Parser.php', 'wp-includes/SimplePie/Rating.php', 'wp-includes/SimplePie/Registry.php', 'wp-includes/SimplePie/Restriction.php', 'wp-includes/SimplePie/Sanitize.php', 'wp-includes/SimplePie/Source.php', // 6.7 - directories 'wp-includes/SimplePie/Cache/', 'wp-includes/SimplePie/Content/', 'wp-includes/SimplePie/Decode/', 'wp-includes/SimplePie/HTTP/', 'wp-includes/SimplePie/Net/', 'wp-includes/SimplePie/Parse/', 'wp-includes/SimplePie/XML/', // 6.8 'wp-includes/blocks/post-content/editor.css', 'wp-includes/blocks/post-content/editor.min.css', 'wp-includes/blocks/post-content/editor-rtl.css', 'wp-includes/blocks/post-content/editor-rtl.min.css', 'wp-includes/blocks/post-template/editor.css', 'wp-includes/blocks/post-template/editor.min.css', 'wp-includes/blocks/post-template/editor-rtl.css', 'wp-includes/blocks/post-template/editor-rtl.min.css', 'wp-includes/js/dist/undo-manager.js', 'wp-includes/js/dist/undo-manager.min.js', 'wp-includes/js/dist/fields.min.js', 'wp-includes/js/dist/fields.js', // 6.9 'wp-includes/blocks/post-author/editor.css', 'wp-includes/blocks/post-author/editor.min.css', 'wp-includes/blocks/post-author/editor-rtl.css', 'wp-includes/blocks/post-author/editor-rtl.min.css', 'wp-includes/SimplePie/src/Decode', 'wp-includes/SimplePie/src/Core.php', ); /** * Stores Requests files to be preloaded and deleted. * * For classes/interfaces, use the class/interface name * as the array key. * * All other files/directories should not have a key. * * @since 6.2.0 * * @global string[] $_old_requests_files * @var string[] * @name $_old_requests_files */ global $_old_requests_files; $_old_requests_files = array( // Interfaces. 'Requests_Auth' => 'wp-includes/Requests/Auth.php', 'Requests_Hooker' => 'wp-includes/Requests/Hooker.php', 'Requests_Proxy' => 'wp-includes/Requests/Proxy.php', 'Requests_Transport' => 'wp-includes/Requests/Transport.php', // Classes. 'Requests_Auth_Basic' => 'wp-includes/Requests/Auth/Basic.php', 'Requests_Cookie_Jar' => 'wp-includes/Requests/Cookie/Jar.php', 'Requests_Exception_HTTP' => 'wp-includes/Requests/Exception/HTTP.php', 'Requests_Exception_Transport' => 'wp-includes/Requests/Exception/Transport.php', 'Requests_Exception_HTTP_304' => 'wp-includes/Requests/Exception/HTTP/304.php', 'Requests_Exception_HTTP_305' => 'wp-includes/Requests/Exception/HTTP/305.php', 'Requests_Exception_HTTP_306' => 'wp-includes/Requests/Exception/HTTP/306.php', 'Requests_Exception_HTTP_400' => 'wp-includes/Requests/Exception/HTTP/400.php', 'Requests_Exception_HTTP_401' => 'wp-includes/Requests/Exception/HTTP/401.php', 'Requests_Exception_HTTP_402' => 'wp-includes/Requests/Exception/HTTP/402.php', 'Requests_Exception_HTTP_403' => 'wp-includes/Requests/Exception/HTTP/403.php', 'Requests_Exception_HTTP_404' => 'wp-includes/Requests/Exception/HTTP/404.php', 'Requests_Exception_HTTP_405' => 'wp-includes/Requests/Exception/HTTP/405.php', 'Requests_Exception_HTTP_406' => 'wp-includes/Requests/Exception/HTTP/406.php', 'Requests_Exception_HTTP_407' => 'wp-includes/Requests/Exception/HTTP/407.php', 'Requests_Exception_HTTP_408' => 'wp-includes/Requests/Exception/HTTP/408.php', 'Requests_Exception_HTTP_409' => 'wp-includes/Requests/Exception/HTTP/409.php', 'Requests_Exception_HTTP_410' => 'wp-includes/Requests/Exception/HTTP/410.php', 'Requests_Exception_HTTP_411' => 'wp-includes/Requests/Exception/HTTP/411.php', 'Requests_Exception_HTTP_412' => 'wp-includes/Requests/Exception/HTTP/412.php', 'Requests_Exception_HTTP_413' => 'wp-includes/Requests/Exception/HTTP/413.php', 'Requests_Exception_HTTP_414' => 'wp-includes/Requests/Exception/HTTP/414.php', 'Requests_Exception_HTTP_415' => 'wp-includes/Requests/Exception/HTTP/415.php', 'Requests_Exception_HTTP_416' => 'wp-includes/Requests/Exception/HTTP/416.php', 'Requests_Exception_HTTP_417' => 'wp-includes/Requests/Exception/HTTP/417.php', 'Requests_Exception_HTTP_418' => 'wp-includes/Requests/Exception/HTTP/418.php', 'Requests_Exception_HTTP_428' => 'wp-includes/Requests/Exception/HTTP/428.php', 'Requests_Exception_HTTP_429' => 'wp-includes/Requests/Exception/HTTP/429.php', 'Requests_Exception_HTTP_431' => 'wp-includes/Requests/Exception/HTTP/431.php', 'Requests_Exception_HTTP_500' => 'wp-includes/Requests/Exception/HTTP/500.php', 'Requests_Exception_HTTP_501' => 'wp-includes/Requests/Exception/HTTP/501.php', 'Requests_Exception_HTTP_502' => 'wp-includes/Requests/Exception/HTTP/502.php', 'Requests_Exception_HTTP_503' => 'wp-includes/Requests/Exception/HTTP/503.php', 'Requests_Exception_HTTP_504' => 'wp-includes/Requests/Exception/HTTP/504.php', 'Requests_Exception_HTTP_505' => 'wp-includes/Requests/Exception/HTTP/505.php', 'Requests_Exception_HTTP_511' => 'wp-includes/Requests/Exception/HTTP/511.php', 'Requests_Exception_HTTP_Unknown' => 'wp-includes/Requests/Exception/HTTP/Unknown.php', 'Requests_Exception_Transport_cURL' => 'wp-includes/Requests/Exception/Transport/cURL.php', 'Requests_Proxy_HTTP' => 'wp-includes/Requests/Proxy/HTTP.php', 'Requests_Response_Headers' => 'wp-includes/Requests/Response/Headers.php', 'Requests_Transport_cURL' => 'wp-includes/Requests/Transport/cURL.php', 'Requests_Transport_fsockopen' => 'wp-includes/Requests/Transport/fsockopen.php', 'Requests_Utility_CaseInsensitiveDictionary' => 'wp-includes/Requests/Utility/CaseInsensitiveDictionary.php', 'Requests_Utility_FilteredIterator' => 'wp-includes/Requests/Utility/FilteredIterator.php', 'Requests_Cookie' => 'wp-includes/Requests/Cookie.php', 'Requests_Exception' => 'wp-includes/Requests/Exception.php', 'Requests_Hooks' => 'wp-includes/Requests/Hooks.php', 'Requests_IDNAEncoder' => 'wp-includes/Requests/IDNAEncoder.php', 'Requests_IPv6' => 'wp-includes/Requests/IPv6.php', 'Requests_IRI' => 'wp-includes/Requests/IRI.php', 'Requests_Response' => 'wp-includes/Requests/Response.php', 'Requests_SSL' => 'wp-includes/Requests/SSL.php', 'Requests_Session' => 'wp-includes/Requests/Session.php', // Directories. 'wp-includes/Requests/Auth/', 'wp-includes/Requests/Cookie/', 'wp-includes/Requests/Exception/HTTP/', 'wp-includes/Requests/Exception/Transport/', 'wp-includes/Requests/Exception/', 'wp-includes/Requests/Proxy/', 'wp-includes/Requests/Response/', 'wp-includes/Requests/Transport/', 'wp-includes/Requests/Utility/', ); /** * Stores new files in wp-content to copy * * The contents of this array indicate any new bundled plugins/themes which * should be installed with the WordPress Upgrade. These items will not be * re-installed in future upgrades, this behavior is controlled by the * introduced version present here being older than the current installed version. * * The content of this array should follow the following format: * Filename (relative to wp-content) => Introduced version * Directories should be noted by suffixing it with a trailing slash (/) * * @since 3.2.0 * @since 4.7.0 New themes were not automatically installed for 4.4-4.6 on * upgrade. New themes are now installed again. To disable new * themes from being installed on upgrade, explicitly define * CORE_UPGRADE_SKIP_NEW_BUNDLED as true. * @global string[] $_new_bundled_files * @var string[] * @name $_new_bundled_files */ global $_new_bundled_files; $_new_bundled_files = array( 'plugins/akismet/' => '2.0', 'themes/twentyten/' => '3.0', 'themes/twentyeleven/' => '3.2', 'themes/twentytwelve/' => '3.5', 'themes/twentythirteen/' => '3.6', 'themes/twentyfourteen/' => '3.8', 'themes/twentyfifteen/' => '4.1', 'themes/twentysixteen/' => '4.4', 'themes/twentyseventeen/' => '4.7', 'themes/twentynineteen/' => '5.0', 'themes/twentytwenty/' => '5.3', 'themes/twentytwentyone/' => '5.6', 'themes/twentytwentytwo/' => '5.9', 'themes/twentytwentythree/' => '6.1', 'themes/twentytwentyfour/' => '6.4', 'themes/twentytwentyfive/' => '6.7', ); /** * Upgrades the core of WordPress. * * This will create a .maintenance file at the base of the WordPress directory * to ensure that people can not access the website, when the files are being * copied to their locations. * * The files in the `$_old_files` list will be removed and the new files * copied from the zip file after the database is upgraded. * * The files in the `$_new_bundled_files` list will be added to the installation * if the version is greater than or equal to the old version being upgraded. * * The steps for the upgrader for after the new release is downloaded and * unzipped is: * * 1. Test unzipped location for select files to ensure that unzipped worked. * 2. Create the .maintenance file in current WordPress base. * 3. Copy new WordPress directory over old WordPress files. * 4. Upgrade WordPress to new version. * 1. Copy all files/folders other than wp-content * 2. Copy any language files to `WP_LANG_DIR` (which may differ from `WP_CONTENT_DIR` * 3. Copy any new bundled themes/plugins to their respective locations * 5. Delete new WordPress directory path. * 6. Delete .maintenance file. * 7. Remove old files. * 8. Delete 'update_core' option. * * There are several areas of failure. For instance if PHP times out before step * 6, then you will not be able to access any portion of your site. Also, since * the upgrade will not continue where it left off, you will not be able to * automatically remove old files and remove the 'update_core' option. This * isn't that bad. * * If the copy of the new WordPress over the old fails, then the worse is that * the new WordPress directory will remain. * * If it is assumed that every file will be copied over, including plugins and * themes, then if you edit the default theme, you should rename it, so that * your changes remain. * * @since 2.7.0 * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * @global string[] $_old_files * @global string[] $_old_requests_files * @global string[] $_new_bundled_files * @global wpdb $wpdb WordPress database abstraction object. * @global string $wp_version The WordPress version string. * * @param string $from New release unzipped path. * @param string $to Path to old WordPress installation. * @return string|WP_Error New WordPress version on success, WP_Error on failure. */ function update_core( $from, $to ) { global $wp_filesystem, $_old_files, $_old_requests_files, $_new_bundled_files, $wpdb; /* * Give core update script an additional 300 seconds (5 minutes) * to finish updating large files when running on slower servers. */ if ( function_exists( 'set_time_limit' ) ) { set_time_limit( 300 ); } /* * Merge the old Requests files and directories into the `$_old_files`. * Then preload these Requests files first, before the files are deleted * and replaced to ensure the code is in memory if needed. */ $_old_files = array_merge( $_old_files, array_values( $_old_requests_files ) ); _preload_old_requests_classes_and_interfaces( $to ); /** * Filters feedback messages displayed during the core update process. * * The filter is first evaluated after the zip file for the latest version * has been downloaded and unzipped. It is evaluated five more times during * the process: * * 1. Before WordPress begins the core upgrade process. * 2. Before Maintenance Mode is enabled. * 3. Before WordPress begins copying over the necessary files. * 4. Before Maintenance Mode is disabled. * 5. Before the database is upgraded. * * @since 2.5.0 * * @param string $feedback The core update feedback messages. */ apply_filters( 'update_feedback', __( 'Verifying the unpacked files…' ) ); // Confidence check the unzipped distribution. $distro = ''; $roots = array( '/wordpress/', '/wordpress-mu/' ); foreach ( $roots as $root ) { if ( $wp_filesystem->exists( $from . $root . 'readme.html' ) && $wp_filesystem->exists( $from . $root . 'wp-includes/version.php' ) ) { $distro = $root; break; } } if ( ! $distro ) { $wp_filesystem->delete( $from, true ); return new WP_Error( 'insane_distro', __( 'The update could not be unpacked' ) ); } /* * Import $wp_version, $required_php_version, $required_php_extensions, and $required_mysql_version from the new version. * DO NOT globalize any variables imported from `version-current.php` in this function. * * BC Note: $wp_filesystem->wp_content_dir() returned unslashed pre-2.8. */ $versions_file = trailingslashit( $wp_filesystem->wp_content_dir() ) . 'upgrade/version-current.php'; if ( ! $wp_filesystem->copy( $from . $distro . 'wp-includes/version.php', $versions_file ) ) { $wp_filesystem->delete( $from, true ); return new WP_Error( 'copy_failed_for_version_file', __( 'The update cannot be installed because some files could not be copied. This is usually due to inconsistent file permissions.' ), 'wp-includes/version.php' ); } $wp_filesystem->chmod( $versions_file, FS_CHMOD_FILE ); /* * `wp_opcache_invalidate()` only exists in WordPress 5.5 or later, * so don't run it when upgrading from older versions. */ if ( function_exists( 'wp_opcache_invalidate' ) ) { wp_opcache_invalidate( $versions_file ); } require WP_CONTENT_DIR . '/upgrade/version-current.php'; $wp_filesystem->delete( $versions_file ); $php_version = PHP_VERSION; $mysql_version = $wpdb->db_version(); $old_wp_version = $GLOBALS['wp_version']; // The version of WordPress we're updating from. /* * Note: str_contains() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ $development_build = ( false !== strpos( $old_wp_version . $wp_version, '-' ) ); // A dash in the version indicates a development release. $php_compat = version_compare( $php_version, $required_php_version, '>=' ); if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) ) { $mysql_compat = true; } else { $mysql_compat = version_compare( $mysql_version, $required_mysql_version, '>=' ); } if ( ! $mysql_compat || ! $php_compat ) { $wp_filesystem->delete( $from, true ); } $php_update_message = ''; if ( function_exists( 'wp_get_update_php_url' ) ) { $php_update_message = '</p><p>' . sprintf( /* translators: %s: URL to Update PHP page. */ __( '<a href="%s">Learn more about updating PHP</a>.' ), esc_url( wp_get_update_php_url() ) ); if ( function_exists( 'wp_get_update_php_annotation' ) ) { $annotation = wp_get_update_php_annotation(); if ( $annotation ) { $php_update_message .= '</p><p><em>' . $annotation . '</em>'; } } } if ( ! $mysql_compat && ! $php_compat ) { return new WP_Error( 'php_mysql_not_compatible', sprintf( /* translators: 1: WordPress version number, 2: Minimum required PHP version number, 3: Minimum required MySQL version number, 4: Current PHP version number, 5: Current MySQL version number. */ __( 'The update cannot be installed because WordPress %1$s requires PHP version %2$s or higher and MySQL version %3$s or higher. You are running PHP version %4$s and MySQL version %5$s.' ), $wp_version, $required_php_version, $required_mysql_version, $php_version, $mysql_version ) . $php_update_message ); } elseif ( ! $php_compat ) { return new WP_Error( 'php_not_compatible', sprintf( /* translators: 1: WordPress version number, 2: Minimum required PHP version number, 3: Current PHP version number. */ __( 'The update cannot be installed because WordPress %1$s requires PHP version %2$s or higher. You are running version %3$s.' ), $wp_version, $required_php_version, $php_version ) . $php_update_message ); } elseif ( ! $mysql_compat ) { return new WP_Error( 'mysql_not_compatible', sprintf( /* translators: 1: WordPress version number, 2: Minimum required MySQL version number, 3: Current MySQL version number. */ __( 'The update cannot be installed because WordPress %1$s requires MySQL version %2$s or higher. You are running version %3$s.' ), $wp_version, $required_mysql_version, $mysql_version ) ); } if ( isset( $required_php_extensions ) && is_array( $required_php_extensions ) ) { $missing_extensions = new WP_Error(); foreach ( $required_php_extensions as $extension ) { if ( extension_loaded( $extension ) ) { continue; } $missing_extensions->add( "php_not_compatible_{$extension}", sprintf( /* translators: 1: WordPress version number, 2: The PHP extension name needed. */ __( 'The update cannot be installed because WordPress %1$s requires the %2$s PHP extension.' ), $wp_version, $extension ) ); } // Add a warning when required PHP extensions are missing. if ( ! empty( $missing_extensions->errors ) ) { return $missing_extensions; } } /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', __( 'Preparing to install the latest version…' ) ); /* * Don't copy wp-content, we'll deal with that below. * We also copy version.php last so failed updates report their old version. */ $skip = array( 'wp-content', 'wp-includes/version.php' ); $check_is_writable = array(); // Check to see which files don't really need updating - only available for 3.7 and higher. if ( function_exists( 'get_core_checksums' ) ) { // Find the local version of the working directory. $working_dir_local = WP_CONTENT_DIR . '/upgrade/' . basename( $from ) . $distro; $checksums = get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); if ( is_array( $checksums ) && isset( $checksums[ $wp_version ] ) ) { $checksums = $checksums[ $wp_version ]; // Compat code for 3.7-beta2. } if ( is_array( $checksums ) ) { foreach ( $checksums as $file => $checksum ) { /* * Note: str_starts_with() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ if ( 'wp-content' === substr( $file, 0, 10 ) ) { continue; } if ( ! file_exists( ABSPATH . $file ) ) { continue; } if ( ! file_exists( $working_dir_local . $file ) ) { continue; } if ( '.' === dirname( $file ) && in_array( pathinfo( $file, PATHINFO_EXTENSION ), array( 'html', 'txt' ), true ) ) { continue; } if ( md5_file( ABSPATH . $file ) === $checksum ) { $skip[] = $file; } else { $check_is_writable[ $file ] = ABSPATH . $file; } } } } // If we're using the direct method, we can predict write failures that are due to permissions. if ( $check_is_writable && 'direct' === $wp_filesystem->method ) { $files_writable = array_filter( $check_is_writable, array( $wp_filesystem, 'is_writable' ) ); if ( $files_writable !== $check_is_writable ) { $files_not_writable = array_diff_key( $check_is_writable, $files_writable ); foreach ( $files_not_writable as $relative_file_not_writable => $file_not_writable ) { // If the writable check failed, chmod file to 0644 and try again, same as copy_dir(). $wp_filesystem->chmod( $file_not_writable, FS_CHMOD_FILE ); if ( $wp_filesystem->is_writable( $file_not_writable ) ) { unset( $files_not_writable[ $relative_file_not_writable ] ); } } // Store package-relative paths (the key) of non-writable files in the WP_Error object. $error_data = version_compare( $old_wp_version, '3.7-beta2', '>' ) ? array_keys( $files_not_writable ) : ''; if ( $files_not_writable ) { return new WP_Error( 'files_not_writable', __( 'The update cannot be installed because your site is unable to copy some files. This is usually due to inconsistent file permissions.' ), implode( ', ', $error_data ) ); } } } /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', __( 'Enabling Maintenance mode…' ) ); // Create maintenance file to signal that we are upgrading. $maintenance_string = '<?php $upgrading = ' . time() . '; ?>'; $maintenance_file = $to . '.maintenance'; $wp_filesystem->delete( $maintenance_file ); $wp_filesystem->put_contents( $maintenance_file, $maintenance_string, FS_CHMOD_FILE ); /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', __( 'Copying the required files…' ) ); // Copy new versions of WP files into place. $result = copy_dir( $from . $distro, $to, $skip ); if ( is_wp_error( $result ) ) { $result = new WP_Error( $result->get_error_code(), $result->get_error_message(), substr( $result->get_error_data(), strlen( $to ) ) ); } // Since we know the core files have copied over, we can now copy the version file. if ( ! is_wp_error( $result ) ) { if ( ! $wp_filesystem->copy( $from . $distro . 'wp-includes/version.php', $to . 'wp-includes/version.php', true /* overwrite */ ) ) { $wp_filesystem->delete( $from, true ); $result = new WP_Error( 'copy_failed_for_version_file', __( 'The update cannot be installed because your site is unable to copy some files. This is usually due to inconsistent file permissions.' ), 'wp-includes/version.php' ); } $wp_filesystem->chmod( $to . 'wp-includes/version.php', FS_CHMOD_FILE ); /* * `wp_opcache_invalidate()` only exists in WordPress 5.5 or later, * so don't run it when upgrading from older versions. */ if ( function_exists( 'wp_opcache_invalidate' ) ) { wp_opcache_invalidate( $to . 'wp-includes/version.php' ); } } // Check to make sure everything copied correctly, ignoring the contents of wp-content. $skip = array( 'wp-content' ); $failed = array(); if ( isset( $checksums ) && is_array( $checksums ) ) { foreach ( $checksums as $file => $checksum ) { /* * Note: str_starts_with() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ if ( 'wp-content' === substr( $file, 0, 10 ) ) { continue; } if ( ! file_exists( $working_dir_local . $file ) ) { continue; } if ( '.' === dirname( $file ) && in_array( pathinfo( $file, PATHINFO_EXTENSION ), array( 'html', 'txt' ), true ) ) { $skip[] = $file; continue; } if ( file_exists( ABSPATH . $file ) && md5_file( ABSPATH . $file ) === $checksum ) { $skip[] = $file; } else { $failed[] = $file; } } } // Some files didn't copy properly. if ( ! empty( $failed ) ) { $total_size = 0; foreach ( $failed as $file ) { if ( file_exists( $working_dir_local . $file ) ) { $total_size += filesize( $working_dir_local . $file ); } } /* * If we don't have enough free space, it isn't worth trying again. * Unlikely to be hit due to the check in unzip_file(). */ $available_space = function_exists( 'disk_free_space' ) ? @disk_free_space( ABSPATH ) : false; if ( $available_space && $total_size >= $available_space ) { $result = new WP_Error( 'disk_full', __( 'There is not enough free disk space to complete the update.' ) ); } else { $result = copy_dir( $from . $distro, $to, $skip ); if ( is_wp_error( $result ) ) { $result = new WP_Error( $result->get_error_code() . '_retry', $result->get_error_message(), substr( $result->get_error_data(), strlen( $to ) ) ); } } } /* * Custom content directory needs updating now. * Copy languages. */ if ( ! is_wp_error( $result ) && $wp_filesystem->is_dir( $from . $distro . 'wp-content/languages' ) ) { if ( WP_LANG_DIR !== ABSPATH . WPINC . '/languages' || @is_dir( WP_LANG_DIR ) ) { $lang_dir = WP_LANG_DIR; } else { $lang_dir = WP_CONTENT_DIR . '/languages'; } /* * Note: str_starts_with() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ // Check if the language directory exists first. if ( ! @is_dir( $lang_dir ) && 0 === strpos( $lang_dir, ABSPATH ) ) { // If it's within the ABSPATH we can handle it here, otherwise they're out of luck. $wp_filesystem->mkdir( $to . str_replace( ABSPATH, '', $lang_dir ), FS_CHMOD_DIR ); clearstatcache(); // For FTP, need to clear the stat cache. } if ( @is_dir( $lang_dir ) ) { $wp_lang_dir = $wp_filesystem->find_folder( $lang_dir ); if ( $wp_lang_dir ) { $result = copy_dir( $from . $distro . 'wp-content/languages/', $wp_lang_dir ); if ( is_wp_error( $result ) ) { $result = new WP_Error( $result->get_error_code() . '_languages', $result->get_error_message(), substr( $result->get_error_data(), strlen( $wp_lang_dir ) ) ); } } } } /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', __( 'Disabling Maintenance mode…' ) ); // Remove maintenance file, we're done with potential site-breaking changes. $wp_filesystem->delete( $maintenance_file ); /* * 3.5 -> 3.5+ - an empty twentytwelve directory was created upon upgrade to 3.5 for some users, * preventing installation of Twenty Twelve. */ if ( '3.5' === $old_wp_version ) { if ( is_dir( WP_CONTENT_DIR . '/themes/twentytwelve' ) && ! file_exists( WP_CONTENT_DIR . '/themes/twentytwelve/style.css' ) ) { $wp_filesystem->delete( $wp_filesystem->wp_themes_dir() . 'twentytwelve/' ); } } /* * Copy new bundled plugins & themes. * This gives us the ability to install new plugins & themes bundled with * future versions of WordPress whilst avoiding the re-install upon upgrade issue. * $development_build controls us overwriting bundled themes and plugins when a non-stable release is being updated. */ if ( ! is_wp_error( $result ) && ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) ) { foreach ( (array) $_new_bundled_files as $file => $introduced_version ) { // If a $development_build or if $introduced version is greater than what the site was previously running. if ( $development_build || version_compare( $introduced_version, $old_wp_version, '>' ) ) { $directory = ( '/' === $file[ strlen( $file ) - 1 ] ); list( $type, $filename ) = explode( '/', $file, 2 ); // Check to see if the bundled items exist before attempting to copy them. if ( ! $wp_filesystem->exists( $from . $distro . 'wp-content/' . $file ) ) { continue; } if ( 'plugins' === $type ) { $dest = $wp_filesystem->wp_plugins_dir(); } elseif ( 'themes' === $type ) { // Back-compat, ::wp_themes_dir() did not return trailingslash'd pre-3.2. $dest = trailingslashit( $wp_filesystem->wp_themes_dir() ); } else { continue; } if ( ! $directory ) { if ( ! $development_build && $wp_filesystem->exists( $dest . $filename ) ) { continue; } if ( ! $wp_filesystem->copy( $from . $distro . 'wp-content/' . $file, $dest . $filename, FS_CHMOD_FILE ) ) { $result = new WP_Error( "copy_failed_for_new_bundled_$type", __( 'Could not copy file.' ), $dest . $filename ); } } else { if ( ! $development_build && $wp_filesystem->is_dir( $dest . $filename ) ) { continue; } $wp_filesystem->mkdir( $dest . $filename, FS_CHMOD_DIR ); $_result = copy_dir( $from . $distro . 'wp-content/' . $file, $dest . $filename ); /* * If an error occurs partway through this final step, * keep the error flowing through, but keep the process going. */ if ( is_wp_error( $_result ) ) { if ( ! is_wp_error( $result ) ) { $result = new WP_Error(); } $result->add( $_result->get_error_code() . "_$type", $_result->get_error_message(), substr( $_result->get_error_data(), strlen( $dest ) ) ); } } } } // End foreach. } // Handle $result error from the above blocks. if ( is_wp_error( $result ) ) { $wp_filesystem->delete( $from, true ); return $result; } // Remove old files. foreach ( $_old_files as $old_file ) { $old_file = $to . $old_file; if ( ! $wp_filesystem->exists( $old_file ) ) { continue; } // If the file isn't deleted, try writing an empty string to the file instead. if ( ! $wp_filesystem->delete( $old_file, true ) && $wp_filesystem->is_file( $old_file ) ) { $wp_filesystem->put_contents( $old_file, '' ); } } // Remove any Genericons example.html's from the filesystem. _upgrade_422_remove_genericons(); // Deactivate the REST API plugin if its version is 2.0 Beta 4 or lower. _upgrade_440_force_deactivate_incompatible_plugins(); // Deactivate incompatible plugins. _upgrade_core_deactivate_incompatible_plugins(); // Upgrade DB with separate request. /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', __( 'Upgrading database…' ) ); $db_upgrade_url = admin_url( 'upgrade.php?step=upgrade_db' ); wp_remote_post( $db_upgrade_url, array( 'timeout' => 60 ) ); // Clear the cache to prevent an update_option() from saving a stale db_version to the cache. wp_cache_flush(); // Not all cache back ends listen to 'flush'. wp_cache_delete( 'alloptions', 'options' ); // Remove working directory. $wp_filesystem->delete( $from, true ); // Force refresh of update information. if ( function_exists( 'delete_site_transient' ) ) { delete_site_transient( 'update_core' ); } else { delete_option( 'update_core' ); } /** * Fires after WordPress core has been successfully updated. * * @since 3.3.0 * * @param string $wp_version The current WordPress version. */ do_action( '_core_updated_successfully', $wp_version ); // Clear the option that blocks auto-updates after failures, now that we've been successful. if ( function_exists( 'delete_site_option' ) ) { delete_site_option( 'auto_core_update_failed' ); } return $wp_version; } /** * Preloads old Requests classes and interfaces. * * This function preloads the old Requests code into memory before the * upgrade process deletes the files. Why? Requests code is loaded into * memory via an autoloader, meaning when a class or interface is needed * If a request is in process, Requests could attempt to access code. If * the file is not there, a fatal error could occur. If the file was * replaced, the new code is not compatible with the old, resulting in * a fatal error. Preloading ensures the code is in memory before the * code is updated. * * @since 6.2.0 * * @global string[] $_old_requests_files Requests files to be preloaded. * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * @global string $wp_version The WordPress version string. * * @param string $to Path to old WordPress installation. */ function _preload_old_requests_classes_and_interfaces( $to ) { global $_old_requests_files, $wp_filesystem, $wp_version; /* * Requests was introduced in WordPress 4.6. * * Skip preloading if the website was previously using * an earlier version of WordPress. */ if ( version_compare( $wp_version, '4.6', '<' ) ) { return; } if ( ! defined( 'REQUESTS_SILENCE_PSR0_DEPRECATIONS' ) ) { define( 'REQUESTS_SILENCE_PSR0_DEPRECATIONS', true ); } foreach ( $_old_requests_files as $name => $file ) { // Skip files that aren't interfaces or classes. if ( is_int( $name ) ) { continue; } // Skip if it's already loaded. if ( class_exists( $name ) || interface_exists( $name ) ) { continue; } // Skip if the file is missing. if ( ! $wp_filesystem->is_file( $to . $file ) ) { continue; } require_once $to . $file; } } /** * Redirect to the About WordPress page after a successful upgrade. * * This function is only needed when the existing installation is older than 3.4.0. * * @since 3.3.0 * * @global string $wp_version The WordPress version string. * @global string $pagenow The filename of the current screen. * @global string $action * * @param string $new_version */ function _redirect_to_about_wordpress( $new_version ) { global $wp_version, $pagenow, $action; if ( version_compare( $wp_version, '3.4-RC1', '>=' ) ) { return; } // Ensure we only run this on the update-core.php page. The Core_Upgrader may be used in other contexts. if ( 'update-core.php' !== $pagenow ) { return; } if ( 'do-core-upgrade' !== $action && 'do-core-reinstall' !== $action ) { return; } // Load the updated default text localization domain for new strings. load_default_textdomain(); // See do_core_upgrade(). show_message( __( 'WordPress updated successfully.' ) ); // self_admin_url() won't exist when upgrading from <= 3.0, so relative URLs are intentional. show_message( '<span class="hide-if-no-js">' . sprintf( /* translators: 1: WordPress version, 2: URL to About screen. */ __( 'Welcome to WordPress %1$s. You will be redirected to the About WordPress screen. If not, click <a href="%2$s">here</a>.' ), $new_version, 'about.php?updated' ) . '</span>' ); show_message( '<span class="hide-if-js">' . sprintf( /* translators: 1: WordPress version, 2: URL to About screen. */ __( 'Welcome to WordPress %1$s. <a href="%2$s">Learn more</a>.' ), $new_version, 'about.php?updated' ) . '</span>' ); echo '</div>'; ?> <script type="text/javascript"> window.location = 'about.php?updated'; </script> <?php // Include admin-footer.php and exit. require_once ABSPATH . 'wp-admin/admin-footer.php'; exit; } /** * Cleans up Genericons example files. * * @since 4.2.2 * * @global string[] $wp_theme_directories * @global WP_Filesystem_Base $wp_filesystem */ function _upgrade_422_remove_genericons() { global $wp_theme_directories, $wp_filesystem; // A list of the affected files using the filesystem absolute paths. $affected_files = array(); // Themes. foreach ( $wp_theme_directories as $directory ) { $affected_theme_files = _upgrade_422_find_genericons_files_in_folder( $directory ); $affected_files = array_merge( $affected_files, $affected_theme_files ); } // Plugins. $affected_plugin_files = _upgrade_422_find_genericons_files_in_folder( WP_PLUGIN_DIR ); $affected_files = array_merge( $affected_files, $affected_plugin_files ); foreach ( $affected_files as $file ) { $gen_dir = $wp_filesystem->find_folder( trailingslashit( dirname( $file ) ) ); if ( empty( $gen_dir ) ) { continue; } // The path when the file is accessed via WP_Filesystem may differ in the case of FTP. $remote_file = $gen_dir . basename( $file ); if ( ! $wp_filesystem->exists( $remote_file ) ) { continue; } if ( ! $wp_filesystem->delete( $remote_file, false, 'f' ) ) { $wp_filesystem->put_contents( $remote_file, '' ); } } } /** * Recursively find Genericons example files in a given folder. * * @ignore * @since 4.2.2 * * @param string $directory Directory path. Expects trailingslashed. * @return string[] */ function _upgrade_422_find_genericons_files_in_folder( $directory ) { $directory = trailingslashit( $directory ); $files = array(); if ( file_exists( "{$directory}example.html" ) /* * Note: str_contains() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ && false !== strpos( file_get_contents( "{$directory}example.html" ), '<title>Genericons</title>' ) ) { $files[] = "{$directory}example.html"; } $dirs = glob( $directory . '*', GLOB_ONLYDIR ); $dirs = array_filter( $dirs, static function ( $dir ) { /* * Skip any node_modules directories. * * Note: str_contains() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ return false === strpos( $dir, 'node_modules' ); } ); if ( $dirs ) { foreach ( $dirs as $dir ) { $files = array_merge( $files, _upgrade_422_find_genericons_files_in_folder( $dir ) ); } } return $files; } /** * @ignore * @since 4.4.0 */ function _upgrade_440_force_deactivate_incompatible_plugins() { if ( defined( 'REST_API_VERSION' ) && version_compare( REST_API_VERSION, '2.0-beta4', '<=' ) ) { deactivate_plugins( array( 'rest-api/plugin.php' ), true ); } } /** * @access private * @ignore * @since 5.8.0 * @since 5.9.0 The minimum compatible version of Gutenberg is 11.9. * @since 6.1.1 The minimum compatible version of Gutenberg is 14.1. * @since 6.4.0 The minimum compatible version of Gutenberg is 16.5. * @since 6.5.0 The minimum compatible version of Gutenberg is 17.6. */ function _upgrade_core_deactivate_incompatible_plugins() { if ( defined( 'GUTENBERG_VERSION' ) && version_compare( GUTENBERG_VERSION, '17.6', '<' ) ) { $deactivated_gutenberg['gutenberg'] = array( 'plugin_name' => 'Gutenberg', 'version_deactivated' => GUTENBERG_VERSION, 'version_compatible' => '17.6', ); if ( is_plugin_active_for_network( 'gutenberg/gutenberg.php' ) ) { $deactivated_plugins = get_site_option( 'wp_force_deactivated_plugins', array() ); $deactivated_plugins = array_merge( $deactivated_plugins, $deactivated_gutenberg ); update_site_option( 'wp_force_deactivated_plugins', $deactivated_plugins ); } else { $deactivated_plugins = get_option( 'wp_force_deactivated_plugins', array() ); $deactivated_plugins = array_merge( $deactivated_plugins, $deactivated_gutenberg ); update_option( 'wp_force_deactivated_plugins', $deactivated_plugins, false ); } deactivate_plugins( array( 'gutenberg/gutenberg.php' ), true ); } } PK U�g\�:�'P P class-theme-upgrader-skin.phpnu �[��� <?php /** * Upgrader API: Theme_Upgrader_Skin class * * @package WordPress * @subpackage Upgrader * @since 4.6.0 */ /** * Theme Upgrader Skin for WordPress Theme Upgrades. * * @since 2.8.0 * @since 4.6.0 Moved to its own file from wp-admin/includes/class-wp-upgrader-skins.php. * * @see WP_Upgrader_Skin */ class Theme_Upgrader_Skin extends WP_Upgrader_Skin { /** * Holds the theme slug in the Theme Directory. * * @since 2.8.0 * * @var string */ public $theme = ''; /** * Constructor. * * Sets up the theme upgrader skin. * * @since 2.8.0 * * @param array $args Optional. The theme upgrader skin arguments to * override default options. Default empty array. */ public function __construct( $args = array() ) { $defaults = array( 'url' => '', 'theme' => '', 'nonce' => '', 'title' => __( 'Update Theme' ), ); $args = wp_parse_args( $args, $defaults ); $this->theme = $args['theme']; parent::__construct( $args ); } /** * Performs an action following a single theme update. * * @since 2.8.0 */ public function after() { $this->decrement_update_count( 'theme' ); $update_actions = array(); $theme_info = $this->upgrader->theme_info(); if ( $theme_info ) { $name = $theme_info->display( 'Name' ); $stylesheet = $this->upgrader->result['destination_name']; $template = $theme_info->get_template(); $activate_link = add_query_arg( array( 'action' => 'activate', 'template' => urlencode( $template ), 'stylesheet' => urlencode( $stylesheet ), ), admin_url( 'themes.php' ) ); $activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $stylesheet ); $customize_url = add_query_arg( array( 'theme' => urlencode( $stylesheet ), 'return' => urlencode( admin_url( 'themes.php' ) ), ), admin_url( 'customize.php' ) ); if ( get_stylesheet() === $stylesheet ) { if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { $update_actions['preview'] = sprintf( '<a href="%s" class="hide-if-no-customize load-customize">' . '<span aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>', esc_url( $customize_url ), __( 'Customize' ), /* translators: Hidden accessibility text. %s: Theme name. */ sprintf( __( 'Customize “%s”' ), $name ) ); } } elseif ( current_user_can( 'switch_themes' ) ) { if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { $update_actions['preview'] = sprintf( '<a href="%s" class="hide-if-no-customize load-customize">' . '<span aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>', esc_url( $customize_url ), __( 'Live Preview' ), /* translators: Hidden accessibility text. %s: Theme name. */ sprintf( __( 'Live Preview “%s”' ), $name ) ); } $update_actions['activate'] = sprintf( '<a href="%s" class="activatelink">' . '<span aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>', esc_url( $activate_link ), _x( 'Activate', 'theme' ), /* translators: Hidden accessibility text. %s: Theme name. */ sprintf( _x( 'Activate “%s”', 'theme' ), $name ) ); } if ( ! $this->result || is_wp_error( $this->result ) || is_network_admin() ) { unset( $update_actions['preview'], $update_actions['activate'] ); } } $update_actions['themes_page'] = sprintf( '<a href="%s" target="_parent">%s</a>', self_admin_url( 'themes.php' ), __( 'Go to Themes page' ) ); /** * Filters the list of action links available following a single theme update. * * @since 2.8.0 * * @param string[] $update_actions Array of theme action links. * @param string $theme Theme directory name. */ $update_actions = apply_filters( 'update_theme_complete_actions', $update_actions, $this->theme ); if ( ! empty( $update_actions ) ) { $this->feedback( implode( ' | ', (array) $update_actions ) ); } } } PK U�g\4C�iC+ C+ translation-install.phpnu �[��� <?php /** * WordPress Translation Installation Administration API * * @package WordPress * @subpackage Administration */ /** * Retrieve translations from WordPress Translation API. * * @since 4.0.0 * * @param string $type Type of translations. Accepts 'plugins', 'themes', 'core'. * @param array|object $args Translation API arguments. Optional. * @return array|WP_Error { * On success an associative array of translations, WP_Error on failure. * * @type array $translations { * List of translations, each an array of data. * * @type array ...$0 { * @type string $language Language code. * @type string $version WordPress version. * @type string $updated Date the translation was last updated, in MySQL datetime format. * @type string $english_name English name of the language. * @type string $native_name Native name of the language. * @type string $package URL to download the translation package. * @type string[] $iso Array of ISO language codes. * @type array $strings Array of translated strings used in the installation process. * } * } * } */ function translations_api( $type, $args = null ) { if ( ! in_array( $type, array( 'plugins', 'themes', 'core' ), true ) ) { return new WP_Error( 'invalid_type', __( 'Invalid translation type.' ) ); } /** * Allows a plugin to override the WordPress.org Translation Installation API entirely. * * @since 4.0.0 * * @param false|array $result The result array. Default false. * @param string $type The type of translations being requested. * @param object $args Translation API arguments. */ $res = apply_filters( 'translations_api', false, $type, $args ); if ( false === $res ) { $url = 'http://api.wordpress.org/translations/' . $type . '/1.0/'; $http_url = $url; $ssl = wp_http_supports( array( 'ssl' ) ); if ( $ssl ) { $url = set_url_scheme( $url, 'https' ); } $options = array( 'timeout' => 3, 'body' => array( 'wp_version' => wp_get_wp_version(), 'locale' => get_locale(), 'version' => $args['version'], // Version of plugin, theme or core. ), ); if ( 'core' !== $type ) { $options['body']['slug'] = $args['slug']; // Plugin or theme slug. } $request = wp_remote_post( $url, $options ); if ( $ssl && is_wp_error( $request ) ) { wp_trigger_error( __FUNCTION__, sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), __( 'https://wordpress.org/support/forums/' ) ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE ); $request = wp_remote_post( $http_url, $options ); } if ( is_wp_error( $request ) ) { $res = new WP_Error( 'translations_api_failed', sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), __( 'https://wordpress.org/support/forums/' ) ), $request->get_error_message() ); } else { $res = json_decode( wp_remote_retrieve_body( $request ), true ); if ( ! is_object( $res ) && ! is_array( $res ) ) { $res = new WP_Error( 'translations_api_failed', sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), __( 'https://wordpress.org/support/forums/' ) ), wp_remote_retrieve_body( $request ) ); } } } /** * Filters the Translation Installation API response results. * * @since 4.0.0 * * @param array|WP_Error $res { * On success an associative array of translations, WP_Error on failure. * * @type array $translations { * List of translations, each an array of data. * * @type array ...$0 { * @type string $language Language code. * @type string $version WordPress version. * @type string $updated Date the translation was last updated, in MySQL datetime format. * @type string $english_name English name of the language. * @type string $native_name Native name of the language. * @type string $package URL to download the translation package. * @type string[] $iso Array of ISO language codes. * @type array $strings Array of translated strings used in the installation process. * } * } * } * @param string $type The type of translations being requested. * @param object $args Translation API arguments. */ return apply_filters( 'translations_api_result', $res, $type, $args ); } /** * Get available translations from the WordPress.org API. * * @since 4.0.0 * * @see translations_api() * * @return array { * Array of translations keyed by the language code, each an associative array of data. * If the API response results in an error, an empty array will be returned. * * @type array ...$0 { * @type string $language Language code. * @type string $version WordPress version. * @type string $updated Date the translation was last updated, in MySQL datetime format. * @type string $english_name English name of the language. * @type string $native_name Native name of the language. * @type string $package URL to download the translation package. * @type string[] $iso Array of ISO language codes. * @type array $strings Array of translated strings used in the installation process. * } * } */ function wp_get_available_translations() { if ( ! wp_installing() ) { $translations = get_site_transient( 'available_translations' ); if ( false !== $translations ) { return $translations; } } $api = translations_api( 'core', array( 'version' => wp_get_wp_version() ) ); if ( is_wp_error( $api ) || empty( $api['translations'] ) ) { return array(); } $translations = array(); // Key the array with the language code. foreach ( $api['translations'] as $translation ) { $translations[ $translation['language'] ] = $translation; } if ( ! defined( 'WP_INSTALLING' ) ) { set_site_transient( 'available_translations', $translations, 3 * HOUR_IN_SECONDS ); } return $translations; } /** * Output the select form for the language selection on the installation screen. * * @since 4.0.0 * * @global string $wp_local_package Locale code of the package. * * @param array[] $languages Array of available languages (populated via the Translation API). */ function wp_install_language_form( $languages ) { global $wp_local_package; $installed_languages = get_available_languages(); echo "<label class='screen-reader-text' for='language'>Select a default language</label>\n"; echo "<select size='14' name='language' id='language'>\n"; echo '<option value="" lang="en" selected="selected" data-continue="Continue" data-installed="1">English (United States)</option>'; echo "\n"; if ( ! empty( $wp_local_package ) && isset( $languages[ $wp_local_package ] ) ) { if ( isset( $languages[ $wp_local_package ] ) ) { $language = $languages[ $wp_local_package ]; printf( '<option value="%s" lang="%s" data-continue="%s"%s>%s</option>' . "\n", esc_attr( $language['language'] ), esc_attr( current( $language['iso'] ) ), esc_attr( $language['strings']['continue'] ? $language['strings']['continue'] : 'Continue' ), in_array( $language['language'], $installed_languages, true ) ? ' data-installed="1"' : '', esc_html( $language['native_name'] ) ); unset( $languages[ $wp_local_package ] ); } } foreach ( $languages as $language ) { printf( '<option value="%s" lang="%s" data-continue="%s"%s>%s</option>' . "\n", esc_attr( $language['language'] ), esc_attr( current( $language['iso'] ) ), esc_attr( $language['strings']['continue'] ? $language['strings']['continue'] : 'Continue' ), in_array( $language['language'], $installed_languages, true ) ? ' data-installed="1"' : '', esc_html( $language['native_name'] ) ); } echo "</select>\n"; echo '<p class="step"><span class="spinner"></span><input id="language-continue" type="submit" class="button button-primary button-large" value="Continue" /></p>'; } /** * Download a language pack. * * @since 4.0.0 * * @see wp_get_available_translations() * * @param string $download Language code to download. * @return string|false Returns the language code if successfully downloaded * (or already installed), or false on failure. */ function wp_download_language_pack( $download ) { // Check if the translation is already installed. if ( in_array( $download, get_available_languages(), true ) ) { return $download; } if ( ! wp_is_file_mod_allowed( 'download_language_pack' ) ) { return false; } // Confirm the translation is one we can download. $translations = wp_get_available_translations(); if ( ! $translations ) { return false; } foreach ( $translations as $translation ) { if ( $translation['language'] === $download ) { $translation_to_load = true; break; } } if ( empty( $translation_to_load ) ) { return false; } $translation = (object) $translation; require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; $skin = new Automatic_Upgrader_Skin(); $upgrader = new Language_Pack_Upgrader( $skin ); $translation->type = 'core'; $result = $upgrader->upgrade( $translation, array( 'clear_update_cache' => false ) ); if ( ! $result || is_wp_error( $result ) ) { return false; } return $translation->language; } /** * Check if WordPress has access to the filesystem without asking for * credentials. * * @since 4.0.0 * * @return bool Returns true on success, false on failure. */ function wp_can_install_language_pack() { if ( ! wp_is_file_mod_allowed( 'can_install_language_pack' ) ) { return false; } require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; $skin = new Automatic_Upgrader_Skin(); $upgrader = new Language_Pack_Upgrader( $skin ); $upgrader->init(); $check = $upgrader->fs_connect( array( WP_CONTENT_DIR, WP_LANG_DIR ) ); if ( ! $check || is_wp_error( $check ) ) { return false; } return true; } PK U�g\�[��% �% menu.phpnu �[��� <?php /** * Build Administration Menu. * * @package WordPress * @subpackage Administration */ if ( is_network_admin() ) { /** * Fires before the administration menu loads in the Network Admin. * * The hook fires before menus and sub-menus are removed based on user privileges. * * @since 3.1.0 * @access private */ do_action( '_network_admin_menu' ); } elseif ( is_user_admin() ) { /** * Fires before the administration menu loads in the User Admin. * * The hook fires before menus and sub-menus are removed based on user privileges. * * @since 3.1.0 * @access private */ do_action( '_user_admin_menu' ); } else { /** * Fires before the administration menu loads in the admin. * * The hook fires before menus and sub-menus are removed based on user privileges. * * @since 2.2.0 * @access private */ do_action( '_admin_menu' ); } // Create list of page plugin hook names. foreach ( $menu as $menu_page ) { $pos = strpos( $menu_page[2], '?' ); if ( false !== $pos ) { // Handle post_type=post|page|foo pages. $hook_name = substr( $menu_page[2], 0, $pos ); $hook_args = substr( $menu_page[2], $pos + 1 ); wp_parse_str( $hook_args, $hook_args ); // Set the hook name to be the post type. if ( isset( $hook_args['post_type'] ) ) { $hook_name = $hook_args['post_type']; } else { $hook_name = basename( $hook_name, '.php' ); } unset( $hook_args ); } else { $hook_name = basename( $menu_page[2], '.php' ); } $hook_name = sanitize_title( $hook_name ); if ( isset( $compat[ $hook_name ] ) ) { $hook_name = $compat[ $hook_name ]; } elseif ( ! $hook_name ) { continue; } $admin_page_hooks[ $menu_page[2] ] = $hook_name; } unset( $menu_page, $compat ); $_wp_submenu_nopriv = array(); $_wp_menu_nopriv = array(); // Loop over submenus and remove pages for which the user does not have privs. foreach ( $submenu as $parent => $sub ) { foreach ( $sub as $index => $data ) { if ( ! current_user_can( $data[1] ) ) { unset( $submenu[ $parent ][ $index ] ); $_wp_submenu_nopriv[ $parent ][ $data[2] ] = true; } } unset( $index, $data ); if ( empty( $submenu[ $parent ] ) ) { unset( $submenu[ $parent ] ); } } unset( $sub, $parent ); /* * Loop over the top-level menu. * Menus for which the original parent is not accessible due to lack of privileges * will have the next submenu in line be assigned as the new menu parent. */ foreach ( $menu as $id => $data ) { if ( empty( $submenu[ $data[2] ] ) ) { continue; } $subs = $submenu[ $data[2] ]; $first_sub = reset( $subs ); $old_parent = $data[2]; $new_parent = $first_sub[2]; /* * If the first submenu is not the same as the assigned parent, * make the first submenu the new parent. */ if ( $new_parent !== $old_parent ) { $_wp_real_parent_file[ $old_parent ] = $new_parent; $menu[ $id ][2] = $new_parent; foreach ( $submenu[ $old_parent ] as $index => $data ) { $submenu[ $new_parent ][ $index ] = $submenu[ $old_parent ][ $index ]; unset( $submenu[ $old_parent ][ $index ] ); } unset( $submenu[ $old_parent ], $index ); if ( isset( $_wp_submenu_nopriv[ $old_parent ] ) ) { $_wp_submenu_nopriv[ $new_parent ] = $_wp_submenu_nopriv[ $old_parent ]; } } } unset( $id, $data, $subs, $first_sub, $old_parent, $new_parent ); if ( is_network_admin() ) { /** * Fires before the administration menu loads in the Network Admin. * * @since 3.1.0 * * @param string $context Empty context. */ do_action( 'network_admin_menu', '' ); } elseif ( is_user_admin() ) { /** * Fires before the administration menu loads in the User Admin. * * @since 3.1.0 * * @param string $context Empty context. */ do_action( 'user_admin_menu', '' ); } else { /** * Fires before the administration menu loads in the admin. * * @since 1.5.0 * * @param string $context Empty context. */ do_action( 'admin_menu', '' ); } /* * Remove menus that have no accessible submenus and require privileges * that the user does not have. Run re-parent loop again. */ foreach ( $menu as $id => $data ) { if ( ! current_user_can( $data[1] ) ) { $_wp_menu_nopriv[ $data[2] ] = true; } /* * If there is only one submenu and it is has same destination as the parent, * remove the submenu. */ if ( ! empty( $submenu[ $data[2] ] ) && 1 === count( $submenu[ $data[2] ] ) ) { $subs = $submenu[ $data[2] ]; $first_sub = reset( $subs ); if ( $data[2] === $first_sub[2] ) { unset( $submenu[ $data[2] ] ); } } // If submenu is empty... if ( empty( $submenu[ $data[2] ] ) ) { // And user doesn't have privs, remove menu. if ( isset( $_wp_menu_nopriv[ $data[2] ] ) ) { unset( $menu[ $id ] ); } } } unset( $id, $data, $subs, $first_sub ); /** * Adds a CSS class to a string. * * @since 2.7.0 * * @param string $class_to_add The CSS class to add. * @param string $classes The string to add the CSS class to. * @return string The string with the CSS class added. */ function add_cssclass( $class_to_add, $classes ) { if ( empty( $classes ) ) { return $class_to_add; } return $classes . ' ' . $class_to_add; } /** * Adds CSS classes for top-level administration menu items. * * The list of added classes includes `.menu-top-first` and `.menu-top-last`. * * @since 2.7.0 * * @param array $menu The array of administration menu items. * @return array The array of administration menu items with the CSS classes added. */ function add_menu_classes( $menu ) { $first_item = false; $last_order = false; $items_count = count( $menu ); $i = 0; foreach ( $menu as $order => $top ) { ++$i; if ( 0 === $order ) { // Dashboard is always shown/single. $menu[0][4] = add_cssclass( 'menu-top-first', $top[4] ); $last_order = 0; continue; } if ( str_starts_with( $top[2], 'separator' ) && false !== $last_order ) { // If separator. $first_item = true; $classes = $menu[ $last_order ][4]; $menu[ $last_order ][4] = add_cssclass( 'menu-top-last', $classes ); continue; } if ( $first_item ) { $first_item = false; $classes = $menu[ $order ][4]; $menu[ $order ][4] = add_cssclass( 'menu-top-first', $classes ); } if ( $i === $items_count ) { // Last item. $classes = $menu[ $order ][4]; $menu[ $order ][4] = add_cssclass( 'menu-top-last', $classes ); } $last_order = $order; } /** * Filters administration menu array with classes added for top-level items. * * @since 2.7.0 * * @param array $menu Associative array of administration menu items. */ return apply_filters( 'add_menu_classes', $menu ); } uksort( $menu, 'strnatcasecmp' ); // Make it all pretty. /** * Filters whether to enable custom ordering of the administration menu. * * See the {@see 'menu_order'} filter for reordering menu items. * * @since 2.8.0 * * @param bool $custom Whether custom ordering is enabled. Default false. */ if ( apply_filters( 'custom_menu_order', false ) ) { $menu_order = array(); foreach ( $menu as $menu_item ) { $menu_order[] = $menu_item[2]; } unset( $menu_item ); $default_menu_order = $menu_order; /** * Filters the order of administration menu items. * * A truthy value must first be passed to the {@see 'custom_menu_order'} filter * for this filter to work. Use the following to enable custom menu ordering: * * add_filter( 'custom_menu_order', '__return_true' ); * * @since 2.8.0 * * @param array $menu_order An ordered array of menu items. */ $menu_order = apply_filters( 'menu_order', $menu_order ); $menu_order = array_flip( $menu_order ); $default_menu_order = array_flip( $default_menu_order ); /** * @global array $menu_order * @global array $default_menu_order * * @param array $a * @param array $b * @return int */ function sort_menu( $a, $b ) { global $menu_order, $default_menu_order; $a = $a[2]; $b = $b[2]; if ( isset( $menu_order[ $a ] ) && ! isset( $menu_order[ $b ] ) ) { return -1; } elseif ( ! isset( $menu_order[ $a ] ) && isset( $menu_order[ $b ] ) ) { return 1; } elseif ( isset( $menu_order[ $a ] ) && isset( $menu_order[ $b ] ) ) { if ( $menu_order[ $a ] === $menu_order[ $b ] ) { return 0; } return ( $menu_order[ $a ] < $menu_order[ $b ] ) ? -1 : 1; } else { return ( $default_menu_order[ $a ] <= $default_menu_order[ $b ] ) ? -1 : 1; } } usort( $menu, 'sort_menu' ); unset( $menu_order, $default_menu_order ); } // Prevent adjacent separators. $prev_menu_was_separator = false; foreach ( $menu as $id => $data ) { if ( false === stristr( $data[4], 'wp-menu-separator' ) ) { // This item is not a separator, so falsey the toggler and do nothing. $prev_menu_was_separator = false; } else { // The previous item was a separator, so unset this one. if ( true === $prev_menu_was_separator ) { unset( $menu[ $id ] ); } // This item is a separator, so truthy the toggler and move on. $prev_menu_was_separator = true; } } unset( $id, $data, $prev_menu_was_separator ); // Remove the last menu item if it is a separator. $last_menu_key = array_keys( $menu ); $last_menu_key = array_pop( $last_menu_key ); if ( ! empty( $menu ) && 'wp-menu-separator' === $menu[ $last_menu_key ][4] ) { unset( $menu[ $last_menu_key ] ); } unset( $last_menu_key ); if ( ! user_can_access_admin_page() ) { /** * Fires when access to an admin page is denied. * * @since 2.5.0 */ do_action( 'admin_page_access_denied' ); wp_die( __( 'Sorry, you are not allowed to access this page.' ), 403 ); } $menu = add_menu_classes( $menu ); PK U�g\�;`�| | noop.phpnu �[��� <?php /** * Noop functions for load-scripts.php and load-styles.php. * * @package WordPress * @subpackage Administration * @since 4.4.0 */ /** * @ignore */ function __() {} /** * @ignore */ function _x() {} /** * @ignore */ function add_filter() {} /** * @ignore */ function has_filter() { return false; } /** * @ignore */ function esc_attr() {} /** * @ignore */ function apply_filters() {} /** * @ignore */ function get_option() {} /** * @ignore */ function is_lighttpd_before_150() {} /** * @ignore */ function add_action() {} /** * @ignore */ function did_action() {} /** * @ignore */ function do_action_ref_array() {} /** * @ignore */ function get_bloginfo() {} /** * @ignore */ function is_admin() { return true; } /** * @ignore */ function site_url() {} /** * @ignore */ function admin_url() {} /** * @ignore */ function home_url() {} /** * @ignore */ function includes_url() {} /** * @ignore */ function wp_guess_url() {} function get_file( $path ) { $path = realpath( $path ); if ( ! $path || ! @is_file( $path ) ) { return ''; } return @file_get_contents( $path ); } PK U�g\X�S�� �� class-wp-comments-list-table.phpnu �[��� <?php /** * List Table API: WP_Comments_List_Table class * * @package WordPress * @subpackage Administration * @since 3.1.0 */ /** * Core class used to implement displaying comments in a list table. * * @since 3.1.0 * * @see WP_List_Table */ class WP_Comments_List_Table extends WP_List_Table { public $checkbox = true; public $pending_count = array(); public $extra_items; private $user_can; /** * Constructor. * * @since 3.1.0 * * @see WP_List_Table::__construct() for more information on default arguments. * * @global int $post_id * * @param array $args An associative array of arguments. */ public function __construct( $args = array() ) { global $post_id; $post_id = isset( $_REQUEST['p'] ) ? absint( $_REQUEST['p'] ) : 0; if ( get_option( 'show_avatars' ) ) { add_filter( 'comment_author', array( $this, 'floated_admin_avatar' ), 10, 2 ); } parent::__construct( array( 'plural' => 'comments', 'singular' => 'comment', 'ajax' => true, 'screen' => isset( $args['screen'] ) ? $args['screen'] : null, ) ); } /** * Adds avatars to comment author names. * * @since 3.1.0 * * @param string $name Comment author name. * @param int $comment_id Comment ID. * @return string Avatar with the user name. */ public function floated_admin_avatar( $name, $comment_id ) { $comment = get_comment( $comment_id ); $avatar = get_avatar( $comment, 32, 'mystery' ); return "$avatar $name"; } /** * @return bool */ public function ajax_user_can() { return current_user_can( 'edit_posts' ); } /** * @global string $mode List table view mode. * @global int $post_id * @global string $comment_status * @global string $comment_type * @global string $search */ public function prepare_items() { global $mode, $post_id, $comment_status, $comment_type, $search; if ( ! empty( $_REQUEST['mode'] ) ) { $mode = 'excerpt' === $_REQUEST['mode'] ? 'excerpt' : 'list'; set_user_setting( 'posts_list_mode', $mode ); } else { $mode = get_user_setting( 'posts_list_mode', 'list' ); } $comment_status = isset( $_REQUEST['comment_status'] ) ? $_REQUEST['comment_status'] : 'all'; if ( ! in_array( $comment_status, array( 'all', 'mine', 'moderated', 'approved', 'spam', 'trash' ), true ) ) { $comment_status = 'all'; } $comment_type = ''; if ( ! empty( $_REQUEST['comment_type'] ) && 'note' !== $_REQUEST['comment_type'] ) { $comment_type = $_REQUEST['comment_type']; } $search = ( isset( $_REQUEST['s'] ) ) ? $_REQUEST['s'] : ''; $post_type = ( isset( $_REQUEST['post_type'] ) ) ? sanitize_key( $_REQUEST['post_type'] ) : ''; $user_id = ( isset( $_REQUEST['user_id'] ) ) ? $_REQUEST['user_id'] : ''; $orderby = ( isset( $_REQUEST['orderby'] ) ) ? $_REQUEST['orderby'] : ''; $order = ( isset( $_REQUEST['order'] ) ) ? $_REQUEST['order'] : ''; $comments_per_page = $this->get_per_page( $comment_status ); $doing_ajax = wp_doing_ajax(); if ( isset( $_REQUEST['number'] ) ) { $number = (int) $_REQUEST['number']; } else { $number = $comments_per_page + min( 8, $comments_per_page ); // Grab a few extra. } $page = $this->get_pagenum(); if ( isset( $_REQUEST['start'] ) ) { $start = $_REQUEST['start']; } else { $start = ( $page - 1 ) * $comments_per_page; } if ( $doing_ajax && isset( $_REQUEST['offset'] ) ) { $start += $_REQUEST['offset']; } $status_map = array( 'mine' => '', 'moderated' => 'hold', 'approved' => 'approve', 'all' => '', ); $args = array( 'status' => isset( $status_map[ $comment_status ] ) ? $status_map[ $comment_status ] : $comment_status, 'search' => $search, 'user_id' => $user_id, 'offset' => $start, 'number' => $number, 'post_id' => $post_id, 'type' => $comment_type, 'type__not_in' => array( 'note' ), 'orderby' => $orderby, 'order' => $order, 'post_type' => $post_type, 'update_comment_post_cache' => true, ); /** * Filters the arguments for the comment query in the comments list table. * * @since 5.1.0 * * @param array $args An array of get_comments() arguments. */ $args = apply_filters( 'comments_list_table_query_args', $args ); $_comments = get_comments( $args ); if ( is_array( $_comments ) ) { $this->items = array_slice( $_comments, 0, $comments_per_page ); $this->extra_items = array_slice( $_comments, $comments_per_page ); $_comment_post_ids = array_unique( wp_list_pluck( $_comments, 'comment_post_ID' ) ); $this->pending_count = get_pending_comments_num( $_comment_post_ids ); } $total_comments = get_comments( array_merge( $args, array( 'count' => true, 'offset' => 0, 'number' => 0, 'orderby' => 'none', ) ) ); $this->set_pagination_args( array( 'total_items' => $total_comments, 'per_page' => $comments_per_page, ) ); } /** * @param string $comment_status * @return int */ public function get_per_page( $comment_status = 'all' ) { $comments_per_page = $this->get_items_per_page( 'edit_comments_per_page' ); /** * Filters the number of comments listed per page in the comments list table. * * @since 2.6.0 * * @param int $comments_per_page The number of comments to list per page. * @param string $comment_status The comment status name. Default 'All'. */ return apply_filters( 'comments_per_page', $comments_per_page, $comment_status ); } /** * @global string $comment_status */ public function no_items() { global $comment_status; if ( 'moderated' === $comment_status ) { _e( 'No comments awaiting moderation.' ); } elseif ( 'trash' === $comment_status ) { _e( 'No comments found in Trash.' ); } else { _e( 'No comments found.' ); } } /** * @global int $post_id * @global string $comment_status * @global string $comment_type */ protected function get_views() { global $post_id, $comment_status, $comment_type; $status_links = array(); $num_comments = ( $post_id ) ? wp_count_comments( $post_id ) : wp_count_comments(); $statuses = array( /* translators: %s: Number of comments. */ 'all' => _nx_noop( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', 'comments' ), // Singular not used. /* translators: %s: Number of comments. */ 'mine' => _nx_noop( 'Mine <span class="count">(%s)</span>', 'Mine <span class="count">(%s)</span>', 'comments' ), /* translators: %s: Number of comments. */ 'moderated' => _nx_noop( 'Pending <span class="count">(%s)</span>', 'Pending <span class="count">(%s)</span>', 'comments' ), /* translators: %s: Number of comments. */ 'approved' => _nx_noop( 'Approved <span class="count">(%s)</span>', 'Approved <span class="count">(%s)</span>', 'comments' ), /* translators: %s: Number of comments. */ 'spam' => _nx_noop( 'Spam <span class="count">(%s)</span>', 'Spam <span class="count">(%s)</span>', 'comments' ), /* translators: %s: Number of comments. */ 'trash' => _nx_noop( 'Trash <span class="count">(%s)</span>', 'Trash <span class="count">(%s)</span>', 'comments' ), ); if ( ! EMPTY_TRASH_DAYS ) { unset( $statuses['trash'] ); } $link = admin_url( 'edit-comments.php' ); if ( ! empty( $comment_type ) && 'all' !== $comment_type ) { $link = add_query_arg( 'comment_type', $comment_type, $link ); } foreach ( $statuses as $status => $label ) { if ( 'mine' === $status ) { $current_user_id = get_current_user_id(); $num_comments->mine = get_comments( array( 'post_id' => $post_id ? $post_id : 0, 'user_id' => $current_user_id, 'count' => true, 'orderby' => 'none', ) ); $link = add_query_arg( 'user_id', $current_user_id, $link ); } else { $link = remove_query_arg( 'user_id', $link ); } if ( ! isset( $num_comments->$status ) ) { $num_comments->$status = 10; } $link = add_query_arg( 'comment_status', $status, $link ); if ( $post_id ) { $link = add_query_arg( 'p', absint( $post_id ), $link ); } /* // I toyed with this, but decided against it. Leaving it in here in case anyone thinks it is a good idea. ~ Mark if ( !empty( $_REQUEST['s'] ) ) $link = add_query_arg( 's', esc_attr( wp_unslash( $_REQUEST['s'] ) ), $link ); */ $status_links[ $status ] = array( 'url' => esc_url( $link ), 'label' => sprintf( translate_nooped_plural( $label, $num_comments->$status ), sprintf( '<span class="%s-count">%s</span>', ( 'moderated' === $status ) ? 'pending' : $status, number_format_i18n( $num_comments->$status ) ) ), 'current' => $status === $comment_status, ); } /** * Filters the comment status links. * * @since 2.5.0 * @since 5.1.0 The 'Mine' link was added. * * @param string[] $status_links An associative array of fully-formed comment status links. Includes 'All', 'Mine', * 'Pending', 'Approved', 'Spam', and 'Trash'. */ return apply_filters( 'comment_status_links', $this->get_views_links( $status_links ) ); } /** * @global string $comment_status * * @return array */ protected function get_bulk_actions() { global $comment_status; if ( ! current_user_can( 'moderate_comments' ) ) { return array(); // Return an empty array if the user doesn't have permission } $actions = array(); if ( in_array( $comment_status, array( 'all', 'approved' ), true ) ) { $actions['unapprove'] = __( 'Unapprove' ); } if ( in_array( $comment_status, array( 'all', 'moderated' ), true ) ) { $actions['approve'] = __( 'Approve' ); } if ( in_array( $comment_status, array( 'all', 'moderated', 'approved', 'trash' ), true ) ) { $actions['spam'] = _x( 'Mark as spam', 'comment' ); } if ( 'trash' === $comment_status ) { $actions['untrash'] = __( 'Restore' ); } elseif ( 'spam' === $comment_status ) { $actions['unspam'] = _x( 'Not spam', 'comment' ); } if ( in_array( $comment_status, array( 'trash', 'spam' ), true ) || ! EMPTY_TRASH_DAYS ) { $actions['delete'] = __( 'Delete permanently' ); } else { $actions['trash'] = __( 'Move to Trash' ); } return $actions; } /** * @global string $comment_status * @global string $comment_type * * @param string $which */ protected function extra_tablenav( $which ) { global $comment_status, $comment_type; static $has_items; if ( ! isset( $has_items ) ) { $has_items = $this->has_items(); } echo '<div class="alignleft actions">'; if ( 'top' === $which ) { ob_start(); $this->comment_type_dropdown( $comment_type ); /** * Fires just before the Filter submit button for comment types. * * @since 3.5.0 */ do_action( 'restrict_manage_comments' ); $output = ob_get_clean(); if ( ! empty( $output ) && $this->has_items() ) { echo $output; submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) ); } } if ( ( 'spam' === $comment_status || 'trash' === $comment_status ) && $has_items && current_user_can( 'moderate_comments' ) ) { wp_nonce_field( 'bulk-destroy', '_destroy_nonce' ); $title = ( 'spam' === $comment_status ) ? esc_attr__( 'Empty Spam' ) : esc_attr__( 'Empty Trash' ); submit_button( $title, 'apply', 'delete_all', false ); } /** * Fires after the Filter submit button for comment types. * * @since 2.5.0 * @since 5.6.0 The `$which` parameter was added. * * @param string $comment_status The comment status name. Default 'All'. * @param string $which The location of the extra table nav markup: Either 'top' or 'bottom'. */ do_action( 'manage_comments_nav', $comment_status, $which ); echo '</div>'; } /** * @return string|false */ public function current_action() { if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) ) { return 'delete_all'; } return parent::current_action(); } /** * @global int $post_id * * @return string[] Array of column titles keyed by their column name. */ public function get_columns() { global $post_id; $columns = array(); if ( $this->checkbox ) { $columns['cb'] = '<input type="checkbox" />'; } $columns['author'] = __( 'Author' ); $columns['comment'] = _x( 'Comment', 'column name' ); if ( ! $post_id ) { /* translators: Column name or table row header. */ $columns['response'] = __( 'In response to' ); } $columns['date'] = _x( 'Submitted on', 'column name' ); return $columns; } /** * Displays a comment type drop-down for filtering on the Comments list table. * * @since 5.5.0 * @since 5.6.0 Renamed from `comment_status_dropdown()` to `comment_type_dropdown()`. * * @param string $comment_type The current comment type slug. */ protected function comment_type_dropdown( $comment_type ) { /** * Filters the comment types shown in the drop-down menu on the Comments list table. * * @since 2.7.0 * * @param string[] $comment_types Array of comment type labels keyed by their name. */ $comment_types = apply_filters( 'admin_comment_types_dropdown', array( 'comment' => __( 'Comments' ), 'pings' => __( 'Pings' ), ) ); if ( $comment_types && is_array( $comment_types ) ) { printf( '<label class="screen-reader-text" for="filter-by-comment-type">%s</label>', /* translators: Hidden accessibility text. */ __( 'Filter by comment type' ) ); echo '<select id="filter-by-comment-type" name="comment_type">'; printf( "\t<option value=''>%s</option>", __( 'All comment types' ) ); foreach ( $comment_types as $type => $label ) { if ( get_comments( array( 'count' => true, 'orderby' => 'none', 'type' => $type, ) ) ) { printf( "\t<option value='%s'%s>%s</option>\n", esc_attr( $type ), selected( $comment_type, $type, false ), esc_html( $label ) ); } } echo '</select>'; } } /** * @return array */ protected function get_sortable_columns() { return array( 'author' => array( 'comment_author', false, __( 'Author' ), __( 'Table ordered by Comment Author.' ) ), 'response' => array( 'comment_post_ID', false, _x( 'In Response To', 'column name' ), __( 'Table ordered by Post Replied To.' ) ), 'date' => 'comment_date', ); } /** * Gets the name of the default primary column. * * @since 4.3.0 * * @return string Name of the default primary column, in this case, 'comment'. */ protected function get_default_primary_column_name() { return 'comment'; } /** * Displays the comments table. * * Overrides the parent display() method to render extra comments. * * @since 3.1.0 */ public function display() { wp_nonce_field( 'fetch-list-' . get_class( $this ), '_ajax_fetch_list_nonce' ); static $has_items; if ( ! isset( $has_items ) ) { $has_items = $this->has_items(); if ( $has_items ) { $this->display_tablenav( 'top' ); } } $this->screen->render_screen_reader_content( 'heading_list' ); ?> <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>"> <?php if ( ! isset( $_GET['orderby'] ) ) { // In the initial view, Comments are ordered by comment's date but there's no column for that. echo '<caption class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Ordered by Comment Date, descending.' ) . '</caption>'; } else { $this->print_table_description(); } ?> <thead> <tr> <?php $this->print_column_headers(); ?> </tr> </thead> <tbody id="the-comment-list" data-wp-lists="list:comment"> <?php $this->display_rows_or_placeholder(); ?> </tbody> <tbody id="the-extra-comment-list" data-wp-lists="list:comment" style="display: none;"> <?php /* * Back up the items to restore after printing the extra items markup. * The extra items may be empty, which will prevent the table nav from displaying later. */ $items = $this->items; $this->items = $this->extra_items; $this->display_rows_or_placeholder(); $this->items = $items; ?> </tbody> <tfoot> <tr> <?php $this->print_column_headers( false ); ?> </tr> </tfoot> </table> <?php $this->display_tablenav( 'bottom' ); } /** * @global WP_Post $post Global post object. * @global WP_Comment $comment Global comment object. * * @param WP_Comment $item */ public function single_row( $item ) { global $post, $comment; // Restores the more descriptive, specific name for use within this method. $comment = $item; if ( $comment->comment_post_ID > 0 ) { $post = get_post( $comment->comment_post_ID ); } $edit_post_cap = $post ? 'edit_post' : 'edit_posts'; if ( ! current_user_can( $edit_post_cap, $comment->comment_post_ID ) && ( post_password_required( $comment->comment_post_ID ) || ! current_user_can( 'read_post', $comment->comment_post_ID ) ) ) { // The user has no access to the post and thus cannot see the comments. return false; } $the_comment_class = wp_get_comment_status( $comment ); if ( ! $the_comment_class ) { $the_comment_class = ''; } $the_comment_class = implode( ' ', get_comment_class( $the_comment_class, $comment, $comment->comment_post_ID ) ); $this->user_can = current_user_can( 'edit_comment', $comment->comment_ID ); echo "<tr id='comment-$comment->comment_ID' class='$the_comment_class'>"; $this->single_row_columns( $comment ); echo "</tr>\n"; unset( $GLOBALS['post'], $GLOBALS['comment'] ); } /** * Generates and displays row actions links. * * @since 4.3.0 * @since 5.9.0 Renamed `$comment` to `$item` to match parent class for PHP 8 named parameter support. * * @global string $comment_status Status for the current listed comments. * * @param WP_Comment $item The comment object. * @param string $column_name Current column name. * @param string $primary Primary column name. * @return string Row actions output for comments. An empty string * if the current column is not the primary column, * or if the current user cannot edit the comment. */ protected function handle_row_actions( $item, $column_name, $primary ) { global $comment_status; if ( $primary !== $column_name ) { return ''; } if ( ! $this->user_can ) { return ''; } // Restores the more descriptive, specific name for use within this method. $comment = $item; $the_comment_status = wp_get_comment_status( $comment ); $output = ''; $approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( 'approve-comment_' . $comment->comment_ID ) ); $del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( 'delete-comment_' . $comment->comment_ID ) ); $action_string = 'comment.php?action=%s&c=' . $comment->comment_ID . '&%s'; $approve_url = sprintf( $action_string, 'approvecomment', $approve_nonce ); $unapprove_url = sprintf( $action_string, 'unapprovecomment', $approve_nonce ); $spam_url = sprintf( $action_string, 'spamcomment', $del_nonce ); $unspam_url = sprintf( $action_string, 'unspamcomment', $del_nonce ); $trash_url = sprintf( $action_string, 'trashcomment', $del_nonce ); $untrash_url = sprintf( $action_string, 'untrashcomment', $del_nonce ); $delete_url = sprintf( $action_string, 'deletecomment', $del_nonce ); // Preorder it: Approve | Reply | Quick Edit | Edit | Spam | Trash. $actions = array( 'approve' => '', 'unapprove' => '', 'reply' => '', 'quickedit' => '', 'edit' => '', 'spam' => '', 'unspam' => '', 'trash' => '', 'untrash' => '', 'delete' => '', ); // Not looking at all comments. if ( $comment_status && 'all' !== $comment_status ) { if ( 'approved' === $the_comment_status ) { $actions['unapprove'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-u vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $unapprove_url ), "delete:the-comment-list:comment-{$comment->comment_ID}:e7e7d3:action=dim-comment&new=unapproved", esc_attr__( 'Unapprove this comment' ), __( 'Unapprove' ) ); } elseif ( 'unapproved' === $the_comment_status ) { $actions['approve'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-a vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $approve_url ), "delete:the-comment-list:comment-{$comment->comment_ID}:e7e7d3:action=dim-comment&new=approved", esc_attr__( 'Approve this comment' ), __( 'Approve' ) ); } } else { $actions['approve'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-a aria-button-if-js" aria-label="%s">%s</a>', esc_url( $approve_url ), "dim:the-comment-list:comment-{$comment->comment_ID}:unapproved:e7e7d3:e7e7d3:new=approved", esc_attr__( 'Approve this comment' ), __( 'Approve' ) ); $actions['unapprove'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-u aria-button-if-js" aria-label="%s">%s</a>', esc_url( $unapprove_url ), "dim:the-comment-list:comment-{$comment->comment_ID}:unapproved:e7e7d3:e7e7d3:new=unapproved", esc_attr__( 'Unapprove this comment' ), __( 'Unapprove' ) ); } if ( 'spam' !== $the_comment_status ) { $actions['spam'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-s vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $spam_url ), "delete:the-comment-list:comment-{$comment->comment_ID}::spam=1", esc_attr__( 'Mark this comment as spam' ), /* translators: "Mark as spam" link. */ _x( 'Spam', 'verb' ) ); } elseif ( 'spam' === $the_comment_status ) { $actions['unspam'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-z vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $unspam_url ), "delete:the-comment-list:comment-{$comment->comment_ID}:66cc66:unspam=1", esc_attr__( 'Restore this comment from the spam' ), _x( 'Not Spam', 'comment' ) ); } if ( 'trash' === $the_comment_status ) { $actions['untrash'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-z vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $untrash_url ), "delete:the-comment-list:comment-{$comment->comment_ID}:66cc66:untrash=1", esc_attr__( 'Restore this comment from the Trash' ), __( 'Restore' ) ); } if ( 'spam' === $the_comment_status || 'trash' === $the_comment_status || ! EMPTY_TRASH_DAYS ) { $actions['delete'] = sprintf( '<a href="%s" data-wp-lists="%s" class="delete vim-d vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $delete_url ), "delete:the-comment-list:comment-{$comment->comment_ID}::delete=1", esc_attr__( 'Delete this comment permanently' ), __( 'Delete Permanently' ) ); } else { $actions['trash'] = sprintf( '<a href="%s" data-wp-lists="%s" class="delete vim-d vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $trash_url ), "delete:the-comment-list:comment-{$comment->comment_ID}::trash=1", esc_attr__( 'Move this comment to the Trash' ), _x( 'Trash', 'verb' ) ); } if ( 'spam' !== $the_comment_status && 'trash' !== $the_comment_status ) { $actions['edit'] = sprintf( '<a href="%s" aria-label="%s">%s</a>', "comment.php?action=editcomment&c={$comment->comment_ID}", esc_attr__( 'Edit this comment' ), __( 'Edit' ) ); $format = '<button type="button" data-comment-id="%d" data-post-id="%d" data-action="%s" class="%s button-link" aria-expanded="false" aria-label="%s">%s</button>'; $actions['quickedit'] = sprintf( $format, $comment->comment_ID, $comment->comment_post_ID, 'edit', 'vim-q comment-inline', esc_attr__( 'Quick edit this comment inline' ), __( 'Quick Edit' ) ); $actions['reply'] = sprintf( $format, $comment->comment_ID, $comment->comment_post_ID, 'replyto', 'vim-r comment-inline', esc_attr__( 'Reply to this comment' ), __( 'Reply' ) ); } /** * Filters the action links displayed for each comment in the Comments list table. * * @since 2.6.0 * * @param string[] $actions An array of comment actions. Default actions include: * 'Approve', 'Unapprove', 'Edit', 'Reply', 'Spam', * 'Delete', and 'Trash'. * @param WP_Comment $comment The comment object. */ $actions = apply_filters( 'comment_row_actions', array_filter( $actions ), $comment ); $always_visible = false; $mode = get_user_setting( 'posts_list_mode', 'list' ); if ( 'excerpt' === $mode ) { $always_visible = true; } $output .= '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">'; $i = 0; foreach ( $actions as $action => $link ) { ++$i; if ( ( ( 'approve' === $action || 'unapprove' === $action ) && 2 === $i ) || 1 === $i ) { $separator = ''; } else { $separator = ' | '; } // Reply and quickedit need a hide-if-no-js span when not added with Ajax. if ( ( 'reply' === $action || 'quickedit' === $action ) && ! wp_doing_ajax() ) { $action .= ' hide-if-no-js'; } elseif ( ( 'untrash' === $action && 'trash' === $the_comment_status ) || ( 'unspam' === $action && 'spam' === $the_comment_status ) ) { if ( '1' === get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true ) ) { $action .= ' approve'; } else { $action .= ' unapprove'; } } $output .= "<span class='$action'>{$separator}{$link}</span>"; } $output .= '</div>'; $output .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Show more details' ) . '</span></button>'; return $output; } /** * @since 5.9.0 Renamed `$comment` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Comment $item The comment object. */ public function column_cb( $item ) { // Restores the more descriptive, specific name for use within this method. $comment = $item; if ( $this->user_can ) { ?> <input id="cb-select-<?php echo $comment->comment_ID; ?>" type="checkbox" name="delete_comments[]" value="<?php echo $comment->comment_ID; ?>" /> <label for="cb-select-<?php echo $comment->comment_ID; ?>"> <span class="screen-reader-text"> <?php /* translators: Hidden accessibility text. */ _e( 'Select comment' ); ?> </span> </label> <?php } } /** * @param WP_Comment $comment The comment object. */ public function column_comment( $comment ) { echo '<div class="comment-author">'; $this->column_author( $comment ); echo '</div>'; if ( $comment->comment_parent ) { $parent = get_comment( $comment->comment_parent ); if ( $parent ) { $parent_link = esc_url( get_comment_link( $parent ) ); $name = get_comment_author( $parent ); printf( /* translators: %s: Comment link. */ __( 'In reply to %s.' ), '<a href="' . $parent_link . '">' . $name . '</a>' ); } } comment_text( $comment ); if ( $this->user_can ) { /** This filter is documented in wp-admin/includes/comment.php */ $comment_content = apply_filters( 'comment_edit_pre', $comment->comment_content ); ?> <div id="inline-<?php echo $comment->comment_ID; ?>" class="hidden"> <textarea class="comment" rows="1" cols="1"><?php echo esc_textarea( $comment_content ); ?></textarea> <div class="author-email"><?php echo esc_html( $comment->comment_author_email ); ?></div> <div class="author"><?php echo esc_html( $comment->comment_author ); ?></div> <div class="author-url"><?php echo esc_url( $comment->comment_author_url ); ?></div> <div class="comment_status"><?php echo $comment->comment_approved; ?></div> </div> <?php } } /** * @global string $comment_status * * @param WP_Comment $comment The comment object. */ public function column_author( $comment ) { global $comment_status; $author_url = get_comment_author_url( $comment ); $author_url_display = untrailingslashit( preg_replace( '|^http(s)?://(www\.)?|i', '', $author_url ) ); if ( strlen( $author_url_display ) > 50 ) { $author_url_display = wp_html_excerpt( $author_url_display, 49, '…' ); } echo '<strong>'; comment_author( $comment ); echo '</strong><br />'; if ( ! empty( $author_url_display ) ) { // Print link to author URL, and disallow referrer information (without using target="_blank"). printf( '<a href="%s" rel="noopener noreferrer">%s</a><br />', esc_url( $author_url ), esc_html( $author_url_display ) ); } if ( $this->user_can ) { if ( ! empty( $comment->comment_author_email ) ) { /** This filter is documented in wp-includes/comment-template.php */ $email = apply_filters( 'comment_email', $comment->comment_author_email, $comment ); if ( ! empty( $email ) && '@' !== $email ) { printf( '<a href="%1$s">%2$s</a><br />', esc_url( 'mailto:' . $email ), esc_html( $email ) ); } } $author_ip = get_comment_author_IP( $comment ); if ( $author_ip ) { $author_ip_url = add_query_arg( array( 's' => $author_ip, 'mode' => 'detail', ), admin_url( 'edit-comments.php' ) ); if ( 'spam' === $comment_status ) { $author_ip_url = add_query_arg( 'comment_status', 'spam', $author_ip_url ); } printf( '<a href="%1$s">%2$s</a>', esc_url( $author_ip_url ), esc_html( $author_ip ) ); } } } /** * @param WP_Comment $comment The comment object. */ public function column_date( $comment ) { $submitted = sprintf( /* translators: 1: Comment date, 2: Comment time. */ __( '%1$s at %2$s' ), /* translators: Comment date format. See https://www.php.net/manual/datetime.format.php */ get_comment_date( __( 'Y/m/d' ), $comment ), /* translators: Comment time format. See https://www.php.net/manual/datetime.format.php */ get_comment_date( __( 'g:i a' ), $comment ) ); echo '<div class="submitted-on">'; if ( 'approved' === wp_get_comment_status( $comment ) && ! empty( $comment->comment_post_ID ) ) { printf( '<a href="%s">%s</a>', esc_url( get_comment_link( $comment ) ), $submitted ); } else { echo $submitted; } echo '</div>'; } /** * @param WP_Comment $comment The comment object. */ public function column_response( $comment ) { $post = get_post(); if ( ! $post ) { return; } if ( isset( $this->pending_count[ $post->ID ] ) ) { $pending_comments = $this->pending_count[ $post->ID ]; } else { $_pending_count_temp = get_pending_comments_num( array( $post->ID ) ); $pending_comments = $_pending_count_temp[ $post->ID ]; $this->pending_count[ $post->ID ] = $pending_comments; } if ( current_user_can( 'edit_post', $post->ID ) ) { $post_link = "<a href='" . get_edit_post_link( $post->ID ) . "' class='comments-edit-item-link'>"; $post_link .= esc_html( get_the_title( $post->ID ) ) . '</a>'; } else { $post_link = esc_html( get_the_title( $post->ID ) ); } echo '<div class="response-links">'; if ( 'attachment' === $post->post_type ) { $thumb = wp_get_attachment_image( $post->ID, array( 80, 60 ), true ); if ( $thumb ) { echo $thumb; } } echo $post_link; $post_type_object = get_post_type_object( $post->post_type ); echo "<a href='" . get_permalink( $post->ID ) . "' class='comments-view-item-link'>" . $post_type_object->labels->view_item . '</a>'; echo '<span class="post-com-count-wrapper post-com-count-', $post->ID, '">'; $this->comments_bubble( $post->ID, $pending_comments ); echo '</span> '; echo '</div>'; } /** * @since 5.9.0 Renamed `$comment` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Comment $item The comment object. * @param string $column_name The custom column's name. */ public function column_default( $item, $column_name ) { // Restores the more descriptive, specific name for use within this method. $comment = $item; /** * Fires when the default column output is displayed for a single row. * * @since 2.8.0 * * @param string $column_name The custom column's name. * @param string $comment_id The comment ID as a numeric string. */ do_action( 'manage_comments_custom_column', $column_name, $comment->comment_ID ); } } PK U�g\�칅�- �- bookmark.phpnu �[��� <?php /** * WordPress Bookmark Administration API * * @package WordPress * @subpackage Administration */ /** * Adds a link using values provided in $_POST. * * @since 2.0.0 * * @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success. */ function add_link() { return edit_link(); } /** * Updates or inserts a link using values provided in $_POST. * * @since 2.0.0 * * @param int $link_id Optional. ID of the link to edit. Default 0. * @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success. */ function edit_link( $link_id = 0 ) { if ( ! current_user_can( 'manage_links' ) ) { wp_die( '<h1>' . __( 'You need a higher level of permission.' ) . '</h1>' . '<p>' . __( 'Sorry, you are not allowed to edit the links for this site.' ) . '</p>', 403 ); } $_POST['link_url'] = esc_url( $_POST['link_url'] ); $_POST['link_name'] = esc_html( $_POST['link_name'] ); $_POST['link_image'] = esc_html( $_POST['link_image'] ); $_POST['link_rss'] = esc_url( $_POST['link_rss'] ); if ( ! isset( $_POST['link_visible'] ) || 'N' !== $_POST['link_visible'] ) { $_POST['link_visible'] = 'Y'; } if ( ! empty( $link_id ) ) { $_POST['link_id'] = $link_id; return wp_update_link( $_POST ); } else { return wp_insert_link( $_POST ); } } /** * Retrieves the default link for editing. * * @since 2.0.0 * * @return stdClass Default link object. */ function get_default_link_to_edit() { $link = new stdClass(); if ( isset( $_GET['linkurl'] ) ) { $link->link_url = esc_url( wp_unslash( $_GET['linkurl'] ) ); } else { $link->link_url = ''; } if ( isset( $_GET['name'] ) ) { $link->link_name = esc_attr( wp_unslash( $_GET['name'] ) ); } else { $link->link_name = ''; } $link->link_visible = 'Y'; return $link; } /** * Deletes a specified link from the database. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $link_id ID of the link to delete. * @return true Always true. */ function wp_delete_link( $link_id ) { global $wpdb; /** * Fires before a link is deleted. * * @since 2.0.0 * * @param int $link_id ID of the link to delete. */ do_action( 'delete_link', $link_id ); wp_delete_object_term_relationships( $link_id, 'link_category' ); $wpdb->delete( $wpdb->links, array( 'link_id' => $link_id ) ); /** * Fires after a link has been deleted. * * @since 2.2.0 * * @param int $link_id ID of the deleted link. */ do_action( 'deleted_link', $link_id ); clean_bookmark_cache( $link_id ); return true; } /** * Retrieves the link category IDs associated with the link specified. * * @since 2.1.0 * * @param int $link_id Link ID to look up. * @return int[] The IDs of the requested link's categories. */ function wp_get_link_cats( $link_id = 0 ) { $cats = wp_get_object_terms( $link_id, 'link_category', array( 'fields' => 'ids' ) ); return array_unique( $cats ); } /** * Retrieves link data based on its ID. * * @since 2.0.0 * * @param int|stdClass $link Link ID or object to retrieve. * @return object Link object for editing. */ function get_link_to_edit( $link ) { return get_bookmark( $link, OBJECT, 'edit' ); } /** * Inserts a link into the database, or updates an existing link. * * Runs all the necessary sanitizing, provides default values if arguments are missing, * and finally saves the link. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param array $linkdata { * Elements that make up the link to insert. * * @type int $link_id Optional. The ID of the existing link if updating. * @type string $link_url The URL the link points to. * @type string $link_name The title of the link. * @type string $link_image Optional. A URL of an image. * @type string $link_target Optional. The target element for the anchor tag. * @type string $link_description Optional. A short description of the link. * @type string $link_visible Optional. 'Y' means visible, anything else means not. * @type int $link_owner Optional. A user ID. * @type int $link_rating Optional. A rating for the link. * @type string $link_rel Optional. A relationship of the link to you. * @type string $link_notes Optional. An extended description of or notes on the link. * @type string $link_rss Optional. A URL of an associated RSS feed. * @type int $link_category Optional. The term ID of the link category. * If empty, uses default link category. * } * @param bool $wp_error Optional. Whether to return a WP_Error object on failure. Default false. * @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success. */ function wp_insert_link( $linkdata, $wp_error = false ) { global $wpdb; $defaults = array( 'link_id' => 0, 'link_name' => '', 'link_url' => '', 'link_rating' => 0, ); $parsed_args = wp_parse_args( $linkdata, $defaults ); $parsed_args = wp_unslash( sanitize_bookmark( $parsed_args, 'db' ) ); $link_id = $parsed_args['link_id']; $link_name = $parsed_args['link_name']; $link_url = $parsed_args['link_url']; $update = false; if ( ! empty( $link_id ) ) { $update = true; } if ( '' === trim( $link_name ) ) { if ( '' !== trim( $link_url ) ) { $link_name = $link_url; } else { return 0; } } if ( '' === trim( $link_url ) ) { return 0; } $link_rating = ( ! empty( $parsed_args['link_rating'] ) ) ? $parsed_args['link_rating'] : 0; $link_image = ( ! empty( $parsed_args['link_image'] ) ) ? $parsed_args['link_image'] : ''; $link_target = ( ! empty( $parsed_args['link_target'] ) ) ? $parsed_args['link_target'] : ''; $link_visible = ( ! empty( $parsed_args['link_visible'] ) ) ? $parsed_args['link_visible'] : 'Y'; $link_owner = ( ! empty( $parsed_args['link_owner'] ) ) ? $parsed_args['link_owner'] : get_current_user_id(); $link_notes = ( ! empty( $parsed_args['link_notes'] ) ) ? $parsed_args['link_notes'] : ''; $link_description = ( ! empty( $parsed_args['link_description'] ) ) ? $parsed_args['link_description'] : ''; $link_rss = ( ! empty( $parsed_args['link_rss'] ) ) ? $parsed_args['link_rss'] : ''; $link_rel = ( ! empty( $parsed_args['link_rel'] ) ) ? $parsed_args['link_rel'] : ''; $link_category = ( ! empty( $parsed_args['link_category'] ) ) ? $parsed_args['link_category'] : array(); $link_updated = gmdate( 'Y-m-d H:i:s', current_time( 'timestamp', 0 ) ); // Make sure we set a valid category. if ( ! is_array( $link_category ) || 0 === count( $link_category ) ) { $link_category = array( get_option( 'default_link_category' ) ); } if ( $update ) { if ( false === $wpdb->update( $wpdb->links, compact( 'link_url', 'link_name', 'link_image', 'link_target', 'link_description', 'link_visible', 'link_owner', 'link_rating', 'link_rel', 'link_notes', 'link_rss', 'link_updated' ), compact( 'link_id' ) ) ) { if ( $wp_error ) { return new WP_Error( 'db_update_error', __( 'Could not update link in the database.' ), $wpdb->last_error ); } else { return 0; } } } else { if ( false === $wpdb->insert( $wpdb->links, compact( 'link_url', 'link_name', 'link_image', 'link_target', 'link_description', 'link_visible', 'link_owner', 'link_rating', 'link_rel', 'link_notes', 'link_rss', 'link_updated' ) ) ) { if ( $wp_error ) { return new WP_Error( 'db_insert_error', __( 'Could not insert link into the database.' ), $wpdb->last_error ); } else { return 0; } } $link_id = (int) $wpdb->insert_id; } wp_set_link_cats( $link_id, $link_category ); if ( $update ) { /** * Fires after a link was updated in the database. * * @since 2.0.0 * * @param int $link_id ID of the link that was updated. */ do_action( 'edit_link', $link_id ); } else { /** * Fires after a link was added to the database. * * @since 2.0.0 * * @param int $link_id ID of the link that was added. */ do_action( 'add_link', $link_id ); } clean_bookmark_cache( $link_id ); return $link_id; } /** * Updates link with the specified link categories. * * @since 2.1.0 * * @param int $link_id ID of the link to update. * @param int[] $link_categories Array of link category IDs to add the link to. */ function wp_set_link_cats( $link_id = 0, $link_categories = array() ) { // If $link_categories isn't already an array, make it one: if ( ! is_array( $link_categories ) || 0 === count( $link_categories ) ) { $link_categories = array( get_option( 'default_link_category' ) ); } $link_categories = array_map( 'intval', $link_categories ); $link_categories = array_unique( $link_categories ); wp_set_object_terms( $link_id, $link_categories, 'link_category' ); clean_bookmark_cache( $link_id ); } /** * Updates a link in the database. * * @since 2.0.0 * * @param array $linkdata Link data to update. See wp_insert_link() for accepted arguments. * @return int|WP_Error Value 0 or WP_Error on failure. The updated link ID on success. */ function wp_update_link( $linkdata ) { $link_id = (int) $linkdata['link_id']; $link = get_bookmark( $link_id, ARRAY_A ); // Escape data pulled from DB. $link = wp_slash( $link ); // Passed link category list overwrites existing category list if not empty. if ( isset( $linkdata['link_category'] ) && is_array( $linkdata['link_category'] ) && count( $linkdata['link_category'] ) > 0 ) { $link_cats = $linkdata['link_category']; } else { $link_cats = $link['link_category']; } // Merge old and new fields with new fields overwriting old ones. $linkdata = array_merge( $link, $linkdata ); $linkdata['link_category'] = $link_cats; return wp_insert_link( $linkdata ); } /** * Outputs the 'disabled' message for the WordPress Link Manager. * * @since 3.5.0 * @access private * * @global string $pagenow The filename of the current screen. */ function wp_link_manager_disabled_message() { global $pagenow; if ( ! in_array( $pagenow, array( 'link-manager.php', 'link-add.php', 'link.php' ), true ) ) { return; } add_filter( 'pre_option_link_manager_enabled', '__return_true', 100 ); $really_can_manage_links = current_user_can( 'manage_links' ); remove_filter( 'pre_option_link_manager_enabled', '__return_true', 100 ); if ( $really_can_manage_links ) { $plugins = get_plugins(); if ( empty( $plugins['link-manager/link-manager.php'] ) ) { if ( current_user_can( 'install_plugins' ) ) { $install_url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=link-manager' ), 'install-plugin_link-manager' ); wp_die( sprintf( /* translators: %s: A link to install the Link Manager plugin. */ __( 'If you are looking to use the link manager, please install the <a href="%s">Link Manager plugin</a>.' ), esc_url( $install_url ) ) ); } } elseif ( is_plugin_inactive( 'link-manager/link-manager.php' ) ) { if ( current_user_can( 'activate_plugins' ) ) { $activate_url = wp_nonce_url( self_admin_url( 'plugins.php?action=activate&plugin=link-manager/link-manager.php' ), 'activate-plugin_link-manager/link-manager.php' ); wp_die( sprintf( /* translators: %s: A link to activate the Link Manager plugin. */ __( 'Please activate the <a href="%s">Link Manager plugin</a> to use the link manager.' ), esc_url( $activate_url ) ) ); } } } wp_die( __( 'Sorry, you are not allowed to edit the links for this site.' ) ); } PK U�g\�U�� �� class-wp-posts-list-table.phpnu �[��� <?php /** * List Table API: WP_Posts_List_Table class * * @package WordPress * @subpackage Administration * @since 3.1.0 */ /** * Core class used to implement displaying posts in a list table. * * @since 3.1.0 * * @see WP_List_Table */ class WP_Posts_List_Table extends WP_List_Table { /** * Whether the items should be displayed hierarchically or linearly. * * @since 3.1.0 * @var bool */ protected $hierarchical_display; /** * Holds the number of pending comments for each post. * * @since 3.1.0 * @var array */ protected $comment_pending_count; /** * Holds the number of posts for this user. * * @since 3.1.0 * @var int */ private $user_posts_count; /** * Holds the number of posts which are sticky. * * @since 3.1.0 * @var int */ private $sticky_posts_count = 0; private $is_trash; /** * Current level for output. * * @since 4.3.0 * @var int */ protected $current_level = 0; /** * Constructor. * * @since 3.1.0 * * @see WP_List_Table::__construct() for more information on default arguments. * * @global WP_Post_Type $post_type_object Global post type object. * @global wpdb $wpdb WordPress database abstraction object. * * @param array $args An associative array of arguments. */ public function __construct( $args = array() ) { global $post_type_object, $wpdb; parent::__construct( array( 'plural' => 'posts', 'screen' => isset( $args['screen'] ) ? $args['screen'] : null, ) ); $post_type = $this->screen->post_type; $post_type_object = get_post_type_object( $post_type ); $exclude_states = get_post_stati( array( 'show_in_admin_all_list' => false, ) ); $this->user_posts_count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( 1 ) FROM $wpdb->posts WHERE post_type = %s AND post_status NOT IN ( '" . implode( "','", $exclude_states ) . "' ) AND post_author = %d", $post_type, get_current_user_id() ) ); if ( $this->user_posts_count && ! current_user_can( $post_type_object->cap->edit_others_posts ) && empty( $_REQUEST['post_status'] ) && empty( $_REQUEST['all_posts'] ) && empty( $_REQUEST['author'] ) && empty( $_REQUEST['show_sticky'] ) ) { $_GET['author'] = get_current_user_id(); } $sticky_posts = get_option( 'sticky_posts' ); if ( 'post' === $post_type && $sticky_posts ) { $sticky_posts = implode( ', ', array_map( 'absint', (array) $sticky_posts ) ); $this->sticky_posts_count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( 1 ) FROM $wpdb->posts WHERE post_type = %s AND post_status NOT IN ('trash', 'auto-draft') AND ID IN ($sticky_posts)", $post_type ) ); } } /** * Sets whether the table layout should be hierarchical or not. * * @since 4.2.0 * * @param bool $display Whether the table layout should be hierarchical. */ public function set_hierarchical_display( $display ) { $this->hierarchical_display = $display; } /** * @return bool */ public function ajax_user_can() { return current_user_can( get_post_type_object( $this->screen->post_type )->cap->edit_posts ); } /** * @global string $mode List table view mode. * @global array $avail_post_stati * @global WP_Query $wp_query WordPress Query object. * @global int $per_page */ public function prepare_items() { global $mode, $avail_post_stati, $wp_query, $per_page; if ( ! empty( $_REQUEST['mode'] ) ) { $mode = 'excerpt' === $_REQUEST['mode'] ? 'excerpt' : 'list'; set_user_setting( 'posts_list_mode', $mode ); } else { $mode = get_user_setting( 'posts_list_mode', 'list' ); } // Is going to call wp(). $avail_post_stati = wp_edit_posts_query(); $this->set_hierarchical_display( is_post_type_hierarchical( $this->screen->post_type ) && 'menu_order title' === $wp_query->query['orderby'] ); $post_type = $this->screen->post_type; $per_page = $this->get_items_per_page( 'edit_' . $post_type . '_per_page' ); /** This filter is documented in wp-admin/includes/post.php */ $per_page = apply_filters( 'edit_posts_per_page', $per_page, $post_type ); if ( $this->hierarchical_display ) { $total_items = $wp_query->post_count; } elseif ( $wp_query->found_posts || $this->get_pagenum() === 1 ) { $total_items = $wp_query->found_posts; } else { $post_counts = (array) wp_count_posts( $post_type, 'readable' ); if ( isset( $_REQUEST['post_status'] ) && in_array( $_REQUEST['post_status'], $avail_post_stati, true ) ) { $total_items = $post_counts[ $_REQUEST['post_status'] ]; } elseif ( isset( $_REQUEST['show_sticky'] ) && $_REQUEST['show_sticky'] ) { $total_items = $this->sticky_posts_count; } elseif ( isset( $_GET['author'] ) && get_current_user_id() === (int) $_GET['author'] ) { $total_items = $this->user_posts_count; } else { $total_items = array_sum( $post_counts ); // Subtract post types that are not included in the admin all list. foreach ( get_post_stati( array( 'show_in_admin_all_list' => false ) ) as $state ) { $total_items -= $post_counts[ $state ]; } } } $this->is_trash = isset( $_REQUEST['post_status'] ) && 'trash' === $_REQUEST['post_status']; $this->set_pagination_args( array( 'total_items' => $total_items, 'per_page' => $per_page, ) ); } /** * @return bool */ public function has_items() { return have_posts(); } /** */ public function no_items() { if ( isset( $_REQUEST['post_status'] ) && 'trash' === $_REQUEST['post_status'] ) { echo get_post_type_object( $this->screen->post_type )->labels->not_found_in_trash; } else { echo get_post_type_object( $this->screen->post_type )->labels->not_found; } } /** * Determines if the current view is the "All" view. * * @since 4.2.0 * * @return bool Whether the current view is the "All" view. */ protected function is_base_request() { $vars = $_GET; unset( $vars['paged'] ); if ( empty( $vars ) ) { return true; } elseif ( 1 === count( $vars ) && ! empty( $vars['post_type'] ) ) { return $this->screen->post_type === $vars['post_type']; } return 1 === count( $vars ) && ! empty( $vars['mode'] ); } /** * Creates a link to edit.php with params. * * @since 4.4.0 * * @param string[] $args Associative array of URL parameters for the link. * @param string $link_text Link text. * @param string $css_class Optional. Class attribute. Default empty string. * @return string The formatted link string. */ protected function get_edit_link( $args, $link_text, $css_class = '' ) { $url = add_query_arg( $args, 'edit.php' ); $class_html = ''; $aria_current = ''; if ( ! empty( $css_class ) ) { $class_html = sprintf( ' class="%s"', esc_attr( $css_class ) ); if ( 'current' === $css_class ) { $aria_current = ' aria-current="page"'; } } return sprintf( '<a href="%s"%s%s>%s</a>', esc_url( $url ), $class_html, $aria_current, $link_text ); } /** * @global array $locked_post_status This seems to be deprecated. * @global array $avail_post_stati * @return array */ protected function get_views() { global $locked_post_status, $avail_post_stati; $post_type = $this->screen->post_type; if ( ! empty( $locked_post_status ) ) { return array(); } $status_links = array(); $num_posts = wp_count_posts( $post_type, 'readable' ); $total_posts = array_sum( (array) $num_posts ); $class = ''; $current_user_id = get_current_user_id(); $all_args = array( 'post_type' => $post_type ); $mine = ''; // Subtract post types that are not included in the admin all list. foreach ( get_post_stati( array( 'show_in_admin_all_list' => false ) ) as $state ) { $total_posts -= $num_posts->$state; } if ( $this->user_posts_count && $this->user_posts_count !== $total_posts ) { if ( isset( $_GET['author'] ) && ( $current_user_id === (int) $_GET['author'] ) ) { $class = 'current'; } $mine_args = array( 'post_type' => $post_type, 'author' => $current_user_id, ); $mine_inner_html = sprintf( /* translators: %s: Number of posts. */ _nx( 'Mine <span class="count">(%s)</span>', 'Mine <span class="count">(%s)</span>', $this->user_posts_count, 'posts' ), number_format_i18n( $this->user_posts_count ) ); $mine = array( 'url' => esc_url( add_query_arg( $mine_args, 'edit.php' ) ), 'label' => $mine_inner_html, 'current' => isset( $_GET['author'] ) && ( $current_user_id === (int) $_GET['author'] ), ); $all_args['all_posts'] = 1; $class = ''; } $all_inner_html = sprintf( /* translators: %s: Number of posts. */ _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_posts, 'posts' ), number_format_i18n( $total_posts ) ); $status_links['all'] = array( 'url' => esc_url( add_query_arg( $all_args, 'edit.php' ) ), 'label' => $all_inner_html, 'current' => empty( $class ) && ( $this->is_base_request() || isset( $_REQUEST['all_posts'] ) ), ); if ( $mine ) { $status_links['mine'] = $mine; } foreach ( get_post_stati( array( 'show_in_admin_status_list' => true ), 'objects' ) as $status ) { $class = ''; $status_name = $status->name; if ( ! in_array( $status_name, $avail_post_stati, true ) || empty( $num_posts->$status_name ) ) { continue; } if ( isset( $_REQUEST['post_status'] ) && $status_name === $_REQUEST['post_status'] ) { $class = 'current'; } $status_args = array( 'post_status' => $status_name, 'post_type' => $post_type, ); $status_label = sprintf( translate_nooped_plural( $status->label_count, $num_posts->$status_name ), number_format_i18n( $num_posts->$status_name ) ); $status_links[ $status_name ] = array( 'url' => esc_url( add_query_arg( $status_args, 'edit.php' ) ), 'label' => $status_label, 'current' => isset( $_REQUEST['post_status'] ) && $status_name === $_REQUEST['post_status'], ); } if ( ! empty( $this->sticky_posts_count ) ) { $class = ! empty( $_REQUEST['show_sticky'] ) ? 'current' : ''; $sticky_args = array( 'post_type' => $post_type, 'show_sticky' => 1, ); $sticky_inner_html = sprintf( /* translators: %s: Number of posts. */ _nx( 'Sticky <span class="count">(%s)</span>', 'Sticky <span class="count">(%s)</span>', $this->sticky_posts_count, 'posts' ), number_format_i18n( $this->sticky_posts_count ) ); $sticky_link = array( 'sticky' => array( 'url' => esc_url( add_query_arg( $sticky_args, 'edit.php' ) ), 'label' => $sticky_inner_html, 'current' => ! empty( $_REQUEST['show_sticky'] ), ), ); // Sticky comes after Publish, or if not listed, after All. $split = 1 + array_search( ( isset( $status_links['publish'] ) ? 'publish' : 'all' ), array_keys( $status_links ), true ); $status_links = array_merge( array_slice( $status_links, 0, $split ), $sticky_link, array_slice( $status_links, $split ) ); } return $this->get_views_links( $status_links ); } /** * @return array */ protected function get_bulk_actions() { $actions = array(); $post_type_obj = get_post_type_object( $this->screen->post_type ); if ( current_user_can( $post_type_obj->cap->edit_posts ) ) { if ( $this->is_trash ) { $actions['untrash'] = __( 'Restore' ); } else { $actions['edit'] = __( 'Edit' ); } } if ( current_user_can( $post_type_obj->cap->delete_posts ) ) { if ( $this->is_trash || ! EMPTY_TRASH_DAYS ) { $actions['delete'] = __( 'Delete permanently' ); } else { $actions['trash'] = __( 'Move to Trash' ); } } return $actions; } /** * Displays a categories drop-down for filtering on the Posts list table. * * @since 4.6.0 * * @global int $cat Currently selected category. * * @param string $post_type Post type slug. */ protected function categories_dropdown( $post_type ) { global $cat; /** * Filters whether to remove the 'Categories' drop-down from the post list table. * * @since 4.6.0 * * @param bool $disable Whether to disable the categories drop-down. Default false. * @param string $post_type Post type slug. */ if ( false !== apply_filters( 'disable_categories_dropdown', false, $post_type ) ) { return; } if ( is_object_in_taxonomy( $post_type, 'category' ) ) { $dropdown_options = array( 'show_option_all' => get_taxonomy( 'category' )->labels->all_items, 'hide_empty' => 0, 'hierarchical' => 1, 'show_count' => 0, 'orderby' => 'name', 'selected' => $cat, ); echo '<label class="screen-reader-text" for="cat">' . get_taxonomy( 'category' )->labels->filter_by_item . '</label>'; wp_dropdown_categories( $dropdown_options ); } } /** * Displays a formats drop-down for filtering items. * * @since 5.2.0 * * @param string $post_type Post type slug. */ protected function formats_dropdown( $post_type ) { /** * Filters whether to remove the 'Formats' drop-down from the post list table. * * @since 5.2.0 * @since 5.5.0 The `$post_type` parameter was added. * * @param bool $disable Whether to disable the drop-down. Default false. * @param string $post_type Post type slug. */ if ( apply_filters( 'disable_formats_dropdown', false, $post_type ) ) { return; } // Return if the post type doesn't have post formats or if we're in the Trash. if ( ! is_object_in_taxonomy( $post_type, 'post_format' ) || $this->is_trash ) { return; } // Make sure the dropdown shows only formats with a post count greater than 0. $used_post_formats = get_terms( array( 'taxonomy' => 'post_format', 'hide_empty' => true, ) ); // Return if there are no posts using formats. if ( ! $used_post_formats ) { return; } $displayed_post_format = isset( $_GET['post_format'] ) ? $_GET['post_format'] : ''; ?> <label for="filter-by-format" class="screen-reader-text"> <?php /* translators: Hidden accessibility text. */ _e( 'Filter by post format' ); ?> </label> <select name="post_format" id="filter-by-format"> <option<?php selected( $displayed_post_format, '' ); ?> value=""><?php _e( 'All formats' ); ?></option> <?php foreach ( $used_post_formats as $used_post_format ) { // Post format slug. $slug = str_replace( 'post-format-', '', $used_post_format->slug ); // Pretty, translated version of the post format slug. $pretty_name = get_post_format_string( $slug ); // Skip the standard post format. if ( 'standard' === $slug ) { continue; } ?> <option<?php selected( $displayed_post_format, $slug ); ?> value="<?php echo esc_attr( $slug ); ?>"><?php echo esc_html( $pretty_name ); ?></option> <?php } ?> </select> <?php } /** * @param string $which */ protected function extra_tablenav( $which ) { ?> <div class="alignleft actions"> <?php if ( 'top' === $which ) { ob_start(); $this->months_dropdown( $this->screen->post_type ); $this->categories_dropdown( $this->screen->post_type ); $this->formats_dropdown( $this->screen->post_type ); /** * Fires before the Filter button on the Posts and Pages list tables. * * The Filter button allows sorting by date and/or category on the * Posts list table, and sorting by date on the Pages list table. * * @since 2.1.0 * @since 4.4.0 The `$post_type` parameter was added. * @since 4.6.0 The `$which` parameter was added. * * @param string $post_type The post type slug. * @param string $which The location of the extra table nav markup: * 'top' or 'bottom' for WP_Posts_List_Table, * 'bar' for WP_Media_List_Table. */ do_action( 'restrict_manage_posts', $this->screen->post_type, $which ); $output = ob_get_clean(); if ( ! empty( $output ) ) { echo $output; submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) ); } } if ( $this->is_trash && $this->has_items() && current_user_can( get_post_type_object( $this->screen->post_type )->cap->edit_others_posts ) ) { submit_button( __( 'Empty Trash' ), 'apply', 'delete_all', false ); } ?> </div> <?php /** * Fires immediately following the closing "actions" div in the tablenav for the posts * list table. * * @since 4.4.0 * * @param string $which The location of the extra table nav markup: 'top' or 'bottom'. */ do_action( 'manage_posts_extra_tablenav', $which ); } /** * @return string */ public function current_action() { if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) ) { return 'delete_all'; } return parent::current_action(); } /** * @global string $mode List table view mode. * * @return array */ protected function get_table_classes() { global $mode; $mode_class = esc_attr( 'table-view-' . $mode ); return array( 'widefat', 'fixed', 'striped', $mode_class, is_post_type_hierarchical( $this->screen->post_type ) ? 'pages' : 'posts', ); } /** * @return string[] Array of column titles keyed by their column name. */ public function get_columns() { $post_type = $this->screen->post_type; $posts_columns = array(); $posts_columns['cb'] = '<input type="checkbox" />'; /* translators: Posts screen column name. */ $posts_columns['title'] = _x( 'Title', 'column name' ); if ( post_type_supports( $post_type, 'author' ) ) { $posts_columns['author'] = __( 'Author' ); } $taxonomies = get_object_taxonomies( $post_type, 'objects' ); $taxonomies = wp_filter_object_list( $taxonomies, array( 'show_admin_column' => true ), 'and', 'name' ); /** * Filters the taxonomy columns in the Posts list table. * * The dynamic portion of the hook name, `$post_type`, refers to the post * type slug. * * Possible hook names include: * * - `manage_taxonomies_for_post_columns` * - `manage_taxonomies_for_page_columns` * * @since 3.5.0 * * @param string[] $taxonomies Array of taxonomy names to show columns for. * @param string $post_type The post type. */ $taxonomies = apply_filters( "manage_taxonomies_for_{$post_type}_columns", $taxonomies, $post_type ); $taxonomies = array_filter( $taxonomies, 'taxonomy_exists' ); foreach ( $taxonomies as $taxonomy ) { if ( 'category' === $taxonomy ) { $column_key = 'categories'; } elseif ( 'post_tag' === $taxonomy ) { $column_key = 'tags'; } else { $column_key = 'taxonomy-' . $taxonomy; } $posts_columns[ $column_key ] = get_taxonomy( $taxonomy )->labels->name; } $post_status = ! empty( $_REQUEST['post_status'] ) ? $_REQUEST['post_status'] : 'all'; if ( post_type_supports( $post_type, 'comments' ) && ! in_array( $post_status, array( 'pending', 'draft', 'future' ), true ) ) { $posts_columns['comments'] = sprintf( '<span class="vers comment-grey-bubble" title="%1$s" aria-hidden="true"></span><span class="screen-reader-text">%2$s</span>', esc_attr__( 'Comments' ), /* translators: Hidden accessibility text. */ __( 'Comments' ) ); } $posts_columns['date'] = __( 'Date' ); if ( 'page' === $post_type ) { /** * Filters the columns displayed in the Pages list table. * * @since 2.5.0 * * @param string[] $posts_columns An associative array of column headings. */ $posts_columns = apply_filters( 'manage_pages_columns', $posts_columns ); } else { /** * Filters the columns displayed in the Posts list table. * * @since 1.5.0 * * @param string[] $posts_columns An associative array of column headings. * @param string $post_type The post type slug. */ $posts_columns = apply_filters( 'manage_posts_columns', $posts_columns, $post_type ); } /** * Filters the columns displayed in the Posts list table for a specific post type. * * The dynamic portion of the hook name, `$post_type`, refers to the post type slug. * * Possible hook names include: * * - `manage_post_posts_columns` * - `manage_page_posts_columns` * * @since 3.0.0 * * @param string[] $posts_columns An associative array of column headings. */ return apply_filters( "manage_{$post_type}_posts_columns", $posts_columns ); } /** * @return array */ protected function get_sortable_columns() { $post_type = $this->screen->post_type; if ( 'page' === $post_type ) { if ( isset( $_GET['orderby'] ) ) { $title_orderby_text = __( 'Table ordered by Title.' ); } else { $title_orderby_text = __( 'Table ordered by Hierarchical Menu Order and Title.' ); } $sortables = array( 'title' => array( 'title', false, __( 'Title' ), $title_orderby_text, 'asc' ), 'parent' => array( 'parent', false ), 'comments' => array( 'comment_count', false, __( 'Comments' ), __( 'Table ordered by Comments.' ) ), 'date' => array( 'date', true, __( 'Date' ), __( 'Table ordered by Date.' ) ), ); } else { $sortables = array( 'title' => array( 'title', false, __( 'Title' ), __( 'Table ordered by Title.' ) ), 'parent' => array( 'parent', false ), 'comments' => array( 'comment_count', false, __( 'Comments' ), __( 'Table ordered by Comments.' ) ), 'date' => array( 'date', true, __( 'Date' ), __( 'Table ordered by Date.' ), 'desc' ), ); } // Custom Post Types: there's a filter for that, see get_column_info(). return $sortables; } /** * Generates the list table rows. * * @since 3.1.0 * * @global WP_Query $wp_query WordPress Query object. * @global int $per_page * * @param array $posts * @param int $level */ public function display_rows( $posts = array(), $level = 0 ) { global $wp_query, $per_page; if ( empty( $posts ) ) { $posts = $wp_query->posts; } add_filter( 'the_title', 'esc_html' ); if ( $this->hierarchical_display ) { $this->_display_rows_hierarchical( $posts, $this->get_pagenum(), $per_page ); } else { $this->_display_rows( $posts, $level ); } } /** * @param array $posts * @param int $level */ private function _display_rows( $posts, $level = 0 ) { $post_type = $this->screen->post_type; // Create array of post IDs. $post_ids = array(); foreach ( $posts as $a_post ) { $post_ids[] = $a_post->ID; } if ( post_type_supports( $post_type, 'comments' ) ) { $this->comment_pending_count = get_pending_comments_num( $post_ids ); } update_post_author_caches( $posts ); foreach ( $posts as $post ) { $this->single_row( $post, $level ); } } /** * @global wpdb $wpdb WordPress database abstraction object. * @global WP_Post $post Global post object. * @param array $pages * @param int $pagenum * @param int $per_page */ private function _display_rows_hierarchical( $pages, $pagenum = 1, $per_page = 20 ) { global $wpdb; $level = 0; if ( ! $pages ) { $pages = get_pages( array( 'sort_column' => 'menu_order' ) ); if ( ! $pages ) { return; } } /* * Arrange pages into two parts: top level pages and children_pages. * children_pages is two dimensional array. Example: * children_pages[10][] contains all sub-pages whose parent is 10. * It only takes O( N ) to arrange this and it takes O( 1 ) for subsequent lookup operations * If searching, ignore hierarchy and treat everything as top level */ if ( empty( $_REQUEST['s'] ) ) { $top_level_pages = array(); $children_pages = array(); foreach ( $pages as $page ) { // Catch and repair bad pages. if ( $page->post_parent === $page->ID ) { $page->post_parent = 0; $wpdb->update( $wpdb->posts, array( 'post_parent' => 0 ), array( 'ID' => $page->ID ) ); clean_post_cache( $page ); } if ( $page->post_parent > 0 ) { $children_pages[ $page->post_parent ][] = $page; } else { $top_level_pages[] = $page; } } $pages = &$top_level_pages; } $count = 0; $start = ( $pagenum - 1 ) * $per_page; $end = $start + $per_page; $to_display = array(); foreach ( $pages as $page ) { if ( $count >= $end ) { break; } if ( $count >= $start ) { $to_display[ $page->ID ] = $level; } ++$count; if ( isset( $children_pages ) ) { $this->_page_rows( $children_pages, $count, $page->ID, $level + 1, $pagenum, $per_page, $to_display ); } } // If it is the last pagenum and there are orphaned pages, display them with paging as well. if ( isset( $children_pages ) && $count < $end ) { foreach ( $children_pages as $orphans ) { foreach ( $orphans as $op ) { if ( $count >= $end ) { break; } if ( $count >= $start ) { $to_display[ $op->ID ] = 0; } ++$count; } } } $ids = array_keys( $to_display ); _prime_post_caches( $ids ); $_posts = array_map( 'get_post', $ids ); update_post_author_caches( $_posts ); if ( ! isset( $GLOBALS['post'] ) ) { $GLOBALS['post'] = reset( $ids ); } foreach ( $to_display as $page_id => $level ) { echo "\t"; $this->single_row( $page_id, $level ); } } /** * Displays the nested hierarchy of sub-pages together with paging * support, based on a top level page ID. * * @since 3.1.0 (Standalone function exists since 2.6.0) * @since 4.2.0 Added the `$to_display` parameter. * * @param array $children_pages * @param int $count * @param int $parent_page * @param int $level * @param int $pagenum * @param int $per_page * @param array $to_display List of pages to be displayed. Passed by reference. */ private function _page_rows( &$children_pages, &$count, $parent_page, $level, $pagenum, $per_page, &$to_display ) { if ( ! isset( $children_pages[ $parent_page ] ) ) { return; } $start = ( $pagenum - 1 ) * $per_page; $end = $start + $per_page; foreach ( $children_pages[ $parent_page ] as $page ) { if ( $count >= $end ) { break; } // If the page starts in a subtree, print the parents. if ( $count === $start && $page->post_parent > 0 ) { $my_parents = array(); $my_parent = $page->post_parent; while ( $my_parent ) { // Get the ID from the list or the attribute if my_parent is an object. $parent_id = $my_parent; if ( is_object( $my_parent ) ) { $parent_id = $my_parent->ID; } $my_parent = get_post( $parent_id ); $my_parents[] = $my_parent; if ( ! $my_parent->post_parent ) { break; } $my_parent = $my_parent->post_parent; } $num_parents = count( $my_parents ); while ( $my_parent = array_pop( $my_parents ) ) { $to_display[ $my_parent->ID ] = $level - $num_parents; --$num_parents; } } if ( $count >= $start ) { $to_display[ $page->ID ] = $level; } ++$count; $this->_page_rows( $children_pages, $count, $page->ID, $level + 1, $pagenum, $per_page, $to_display ); } unset( $children_pages[ $parent_page ] ); // Required in order to keep track of orphans. } /** * Handles the checkbox column output. * * @since 4.3.0 * @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Post $item The current WP_Post object. */ public function column_cb( $item ) { // Restores the more descriptive, specific name for use within this method. $post = $item; $show = current_user_can( 'edit_post', $post->ID ); /** * Filters whether to show the bulk edit checkbox for a post in its list table. * * By default the checkbox is only shown if the current user can edit the post. * * @since 5.7.0 * * @param bool $show Whether to show the checkbox. * @param WP_Post $post The current WP_Post object. */ if ( apply_filters( 'wp_list_table_show_post_checkbox', $show, $post ) ) : ?> <input id="cb-select-<?php the_ID(); ?>" type="checkbox" name="post[]" value="<?php the_ID(); ?>" /> <label for="cb-select-<?php the_ID(); ?>"> <span class="screen-reader-text"> <?php /* translators: %s: Post title. */ printf( __( 'Select %s' ), _draft_or_post_title() ); ?> </span> </label> <div class="locked-indicator"> <span class="locked-indicator-icon" aria-hidden="true"></span> <span class="screen-reader-text"> <?php printf( /* translators: Hidden accessibility text. %s: Post title. */ __( '“%s” is locked' ), _draft_or_post_title() ); ?> </span> </div> <?php endif; } /** * @since 4.3.0 * * @param WP_Post $post * @param string $classes * @param string $data * @param string $primary */ protected function _column_title( $post, $classes, $data, $primary ) { echo '<td class="' . $classes . ' page-title" ', $data, '>'; echo $this->column_title( $post ); echo $this->handle_row_actions( $post, 'title', $primary ); echo '</td>'; } /** * Handles the title column output. * * @since 4.3.0 * * @global string $mode List table view mode. * * @param WP_Post $post The current WP_Post object. */ public function column_title( $post ) { global $mode; if ( $this->hierarchical_display ) { if ( 0 === $this->current_level && (int) $post->post_parent > 0 ) { // Sent level 0 by accident, by default, or because we don't know the actual level. $find_main_page = (int) $post->post_parent; while ( $find_main_page > 0 ) { $parent = get_post( $find_main_page ); if ( is_null( $parent ) ) { break; } ++$this->current_level; $find_main_page = (int) $parent->post_parent; if ( ! isset( $parent_name ) ) { /** This filter is documented in wp-includes/post-template.php */ $parent_name = apply_filters( 'the_title', $parent->post_title, $parent->ID ); } } } } $can_edit_post = current_user_can( 'edit_post', $post->ID ); if ( $can_edit_post && 'trash' !== $post->post_status ) { $lock_holder = wp_check_post_lock( $post->ID ); if ( $lock_holder ) { $lock_holder = get_userdata( $lock_holder ); $locked_avatar = get_avatar( $lock_holder->ID, 18 ); /* translators: %s: User's display name. */ $locked_text = esc_html( sprintf( __( '%s is currently editing' ), $lock_holder->display_name ) ); } else { $locked_avatar = ''; $locked_text = ''; } echo '<div class="locked-info"><span class="locked-avatar">' . $locked_avatar . '</span> <span class="locked-text">' . $locked_text . "</span></div>\n"; } $pad = str_repeat( '— ', $this->current_level ); echo '<strong>'; $title = _draft_or_post_title(); if ( $can_edit_post && 'trash' !== $post->post_status ) { printf( '<a class="row-title" href="%s" aria-label="%s">%s%s</a>', get_edit_post_link( $post->ID ), /* translators: %s: Post title. */ esc_attr( sprintf( __( '“%s” (Edit)' ), $title ) ), $pad, $title ); } else { printf( '<span>%s%s</span>', $pad, $title ); } _post_states( $post ); if ( isset( $parent_name ) ) { $post_type_object = get_post_type_object( $post->post_type ); echo ' | ' . $post_type_object->labels->parent_item_colon . ' ' . esc_html( $parent_name ); } echo "</strong>\n"; if ( 'excerpt' === $mode && ! is_post_type_hierarchical( $this->screen->post_type ) && current_user_can( 'read_post', $post->ID ) ) { if ( post_password_required( $post ) ) { echo '<span class="protected-post-excerpt">' . esc_html( get_the_excerpt() ) . '</span>'; } else { echo esc_html( get_the_excerpt() ); } } /** This filter is documented in wp-admin/includes/class-wp-posts-list-table.php */ $quick_edit_enabled = apply_filters( 'quick_edit_enabled_for_post_type', true, $post->post_type ); if ( $quick_edit_enabled ) { get_inline_data( $post ); } } /** * Handles the post date column output. * * @since 4.3.0 * * @global string $mode List table view mode. * * @param WP_Post $post The current WP_Post object. */ public function column_date( $post ) { global $mode; if ( '0000-00-00 00:00:00' === $post->post_date ) { $t_time = __( 'Unpublished' ); $time_diff = 0; } else { $t_time = sprintf( /* translators: 1: Post date, 2: Post time. */ __( '%1$s at %2$s' ), /* translators: Post date format. See https://www.php.net/manual/datetime.format.php */ get_the_time( __( 'Y/m/d' ), $post ), /* translators: Post time format. See https://www.php.net/manual/datetime.format.php */ get_the_time( __( 'g:i a' ), $post ) ); $time = get_post_timestamp( $post ); $time_diff = time() - $time; } if ( 'publish' === $post->post_status ) { $status = __( 'Published' ); } elseif ( 'future' === $post->post_status ) { if ( $time_diff > 0 ) { $status = '<strong class="error-message">' . __( 'Missed schedule' ) . '</strong>'; } else { $status = __( 'Scheduled' ); } } else { $status = __( 'Last Modified' ); } /** * Filters the status text of the post. * * @since 4.8.0 * * @param string $status The status text. * @param WP_Post $post Post object. * @param string $column_name The column name. * @param string $mode The list display mode ('excerpt' or 'list'). */ $status = apply_filters( 'post_date_column_status', $status, $post, 'date', $mode ); if ( $status ) { echo $status . '<br />'; } /** * Filters the published, scheduled, or unpublished time of the post. * * @since 2.5.1 * @since 5.5.0 Removed the difference between 'excerpt' and 'list' modes. * The published time and date are both displayed now, * which is equivalent to the previous 'excerpt' mode. * * @param string $t_time The published time. * @param WP_Post $post Post object. * @param string $column_name The column name. * @param string $mode The list display mode ('excerpt' or 'list'). */ echo apply_filters( 'post_date_column_time', $t_time, $post, 'date', $mode ); } /** * Handles the comments column output. * * @since 4.3.0 * * @param WP_Post $post The current WP_Post object. */ public function column_comments( $post ) { ?> <div class="post-com-count-wrapper"> <?php $pending_comments = isset( $this->comment_pending_count[ $post->ID ] ) ? $this->comment_pending_count[ $post->ID ] : 0; $this->comments_bubble( $post->ID, $pending_comments ); ?> </div> <?php } /** * Handles the post author column output. * * @since 4.3.0 * @since 6.8.0 Added fallback text when author's name is unknown. * * @param WP_Post $post The current WP_Post object. */ public function column_author( $post ) { $author = get_the_author(); if ( ! empty( $author ) ) { $args = array( 'post_type' => $post->post_type, 'author' => get_the_author_meta( 'ID' ), ); echo $this->get_edit_link( $args, esc_html( $author ) ); } else { echo '<span aria-hidden="true">—</span><span class="screen-reader-text">' . __( '(no author)' ) . '</span>'; } } /** * Handles the default column output. * * @since 4.3.0 * @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Post $item The current WP_Post object. * @param string $column_name The current column name. */ public function column_default( $item, $column_name ) { // Restores the more descriptive, specific name for use within this method. $post = $item; if ( 'categories' === $column_name ) { $taxonomy = 'category'; } elseif ( 'tags' === $column_name ) { $taxonomy = 'post_tag'; } elseif ( str_starts_with( $column_name, 'taxonomy-' ) ) { $taxonomy = substr( $column_name, 9 ); } else { $taxonomy = false; } if ( $taxonomy ) { $taxonomy_object = get_taxonomy( $taxonomy ); $terms = get_the_terms( $post->ID, $taxonomy ); if ( is_array( $terms ) ) { $term_links = array(); foreach ( $terms as $t ) { $posts_in_term_qv = array(); if ( 'post' !== $post->post_type ) { $posts_in_term_qv['post_type'] = $post->post_type; } if ( $taxonomy_object->query_var ) { $posts_in_term_qv[ $taxonomy_object->query_var ] = $t->slug; } else { $posts_in_term_qv['taxonomy'] = $taxonomy; $posts_in_term_qv['term'] = $t->slug; } $label = esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) ); $term_links[] = $this->get_edit_link( $posts_in_term_qv, $label ); } /** * Filters the links in `$taxonomy` column of edit.php. * * @since 5.2.0 * * @param string[] $term_links Array of term editing links. * @param string $taxonomy Taxonomy name. * @param WP_Term[] $terms Array of term objects appearing in the post row. */ $term_links = apply_filters( 'post_column_taxonomy_links', $term_links, $taxonomy, $terms ); echo implode( wp_get_list_item_separator(), $term_links ); } else { echo '<span aria-hidden="true">—</span><span class="screen-reader-text">' . $taxonomy_object->labels->no_terms . '</span>'; } return; } if ( is_post_type_hierarchical( $post->post_type ) ) { /** * Fires in each custom column on the Posts list table. * * This hook only fires if the current post type is hierarchical, * such as pages. * * @since 2.5.0 * * @param string $column_name The name of the column to display. * @param int $post_id The current post ID. */ do_action( 'manage_pages_custom_column', $column_name, $post->ID ); } else { /** * Fires in each custom column in the Posts list table. * * This hook only fires if the current post type is non-hierarchical, * such as posts. * * @since 1.5.0 * * @param string $column_name The name of the column to display. * @param int $post_id The current post ID. */ do_action( 'manage_posts_custom_column', $column_name, $post->ID ); } /** * Fires for each custom column of a specific post type in the Posts list table. * * The dynamic portion of the hook name, `$post->post_type`, refers to the post type. * * Possible hook names include: * * - `manage_post_posts_custom_column` * - `manage_page_posts_custom_column` * * @since 3.1.0 * * @param string $column_name The name of the column to display. * @param int $post_id The current post ID. */ do_action( "manage_{$post->post_type}_posts_custom_column", $column_name, $post->ID ); } /** * @global WP_Post $post Global post object. * * @param int|WP_Post $post * @param int $level */ public function single_row( $post, $level = 0 ) { $global_post = get_post(); $post = get_post( $post ); $this->current_level = $level; $GLOBALS['post'] = $post; setup_postdata( $post ); $classes = 'iedit author-' . ( get_current_user_id() === (int) $post->post_author ? 'self' : 'other' ); $lock_holder = wp_check_post_lock( $post->ID ); if ( $lock_holder ) { $classes .= ' wp-locked'; } if ( $post->post_parent ) { $count = count( get_post_ancestors( $post->ID ) ); $classes .= ' level-' . $count; } else { $classes .= ' level-0'; } ?> <tr id="post-<?php echo $post->ID; ?>" class="<?php echo implode( ' ', get_post_class( $classes, $post->ID ) ); ?>"> <?php $this->single_row_columns( $post ); ?> </tr> <?php $GLOBALS['post'] = $global_post; } /** * Gets the name of the default primary column. * * @since 4.3.0 * * @return string Name of the default primary column, in this case, 'title'. */ protected function get_default_primary_column_name() { return 'title'; } /** * Generates and displays row action links. * * @since 4.3.0 * @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Post $item Post being acted upon. * @param string $column_name Current column name. * @param string $primary Primary column name. * @return string Row actions output for posts, or an empty string * if the current column is not the primary column. */ protected function handle_row_actions( $item, $column_name, $primary ) { if ( $primary !== $column_name ) { return ''; } // Restores the more descriptive, specific name for use within this method. $post = $item; $post_type_object = get_post_type_object( $post->post_type ); $can_edit_post = current_user_can( 'edit_post', $post->ID ); $actions = array(); $title = _draft_or_post_title(); if ( $can_edit_post && 'trash' !== $post->post_status ) { $actions['edit'] = sprintf( '<a href="%s" aria-label="%s">%s</a>', get_edit_post_link( $post->ID ), /* translators: %s: Post title. */ esc_attr( sprintf( __( 'Edit “%s”' ), $title ) ), __( 'Edit' ) ); /** * Filters whether Quick Edit should be enabled for the given post type. * * @since 6.4.0 * * @param bool $enable Whether to enable the Quick Edit functionality. Default true. * @param string $post_type Post type name. */ $quick_edit_enabled = apply_filters( 'quick_edit_enabled_for_post_type', true, $post->post_type ); if ( $quick_edit_enabled && 'wp_block' !== $post->post_type ) { $actions['inline hide-if-no-js'] = sprintf( '<button type="button" class="button-link editinline" aria-label="%s" aria-expanded="false">%s</button>', /* translators: %s: Post title. */ esc_attr( sprintf( __( 'Quick edit “%s” inline' ), $title ) ), __( 'Quick Edit' ) ); } } if ( current_user_can( 'delete_post', $post->ID ) ) { if ( 'trash' === $post->post_status ) { $actions['untrash'] = sprintf( '<a href="%s" aria-label="%s">%s</a>', wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&action=untrash', $post->ID ) ), 'untrash-post_' . $post->ID ), /* translators: %s: Post title. */ esc_attr( sprintf( __( 'Restore “%s” from the Trash' ), $title ) ), __( 'Restore' ) ); } elseif ( EMPTY_TRASH_DAYS ) { $actions['trash'] = sprintf( '<a href="%s" class="submitdelete" aria-label="%s">%s</a>', get_delete_post_link( $post->ID ), /* translators: %s: Post title. */ esc_attr( sprintf( __( 'Move “%s” to the Trash' ), $title ) ), _x( 'Trash', 'verb' ) ); } if ( 'trash' === $post->post_status || ! EMPTY_TRASH_DAYS ) { $actions['delete'] = sprintf( '<a href="%s" class="submitdelete" aria-label="%s">%s</a>', get_delete_post_link( $post->ID, '', true ), /* translators: %s: Post title. */ esc_attr( sprintf( __( 'Delete “%s” permanently' ), $title ) ), __( 'Delete Permanently' ) ); } } if ( is_post_type_viewable( $post_type_object ) ) { if ( in_array( $post->post_status, array( 'pending', 'draft', 'future' ), true ) ) { if ( $can_edit_post ) { $preview_link = get_preview_post_link( $post ); $actions['view'] = sprintf( '<a href="%s" rel="bookmark" aria-label="%s">%s</a>', esc_url( $preview_link ), /* translators: %s: Post title. */ esc_attr( sprintf( __( 'Preview “%s”' ), $title ) ), __( 'Preview' ) ); } } elseif ( 'trash' !== $post->post_status ) { $actions['view'] = sprintf( '<a href="%s" rel="bookmark" aria-label="%s">%s</a>', get_permalink( $post->ID ), /* translators: %s: Post title. */ esc_attr( sprintf( __( 'View “%s”' ), $title ) ), __( 'View' ) ); } } if ( 'wp_block' === $post->post_type ) { $actions['export'] = sprintf( '<button type="button" class="wp-list-reusable-blocks__export button-link" data-id="%s" aria-label="%s">%s</button>', $post->ID, /* translators: %s: Post title. */ esc_attr( sprintf( __( 'Export “%s” as JSON' ), $title ) ), __( 'Export as JSON' ) ); } if ( is_post_type_hierarchical( $post->post_type ) ) { /** * Filters the array of row action links on the Pages list table. * * The filter is evaluated only for hierarchical post types. * * @since 2.8.0 * * @param string[] $actions An array of row action links. Defaults are * 'Edit', 'Quick Edit', 'Restore', 'Trash', * 'Delete Permanently', 'Preview', and 'View'. * @param WP_Post $post The post object. */ $actions = apply_filters( 'page_row_actions', $actions, $post ); } else { /** * Filters the array of row action links on the Posts list table. * * The filter is evaluated only for non-hierarchical post types. * * @since 2.8.0 * * @param string[] $actions An array of row action links. Defaults are * 'Edit', 'Quick Edit', 'Restore', 'Trash', * 'Delete Permanently', 'Preview', and 'View'. * @param WP_Post $post The post object. */ $actions = apply_filters( 'post_row_actions', $actions, $post ); } return $this->row_actions( $actions ); } /** * Outputs the hidden row displayed when inline editing * * @since 3.1.0 * * @global string $mode List table view mode. */ public function inline_edit() { global $mode; $screen = $this->screen; $post = get_default_post_to_edit( $screen->post_type ); $post_type_object = get_post_type_object( $screen->post_type ); $taxonomy_names = get_object_taxonomies( $screen->post_type ); $hierarchical_taxonomies = array(); $flat_taxonomies = array(); foreach ( $taxonomy_names as $taxonomy_name ) { $taxonomy = get_taxonomy( $taxonomy_name ); $show_in_quick_edit = $taxonomy->show_in_quick_edit; /** * Filters whether the current taxonomy should be shown in the Quick Edit panel. * * @since 4.2.0 * * @param bool $show_in_quick_edit Whether to show the current taxonomy in Quick Edit. * @param string $taxonomy_name Taxonomy name. * @param string $post_type Post type of current Quick Edit post. */ if ( ! apply_filters( 'quick_edit_show_taxonomy', $show_in_quick_edit, $taxonomy_name, $screen->post_type ) ) { continue; } if ( $taxonomy->hierarchical ) { $hierarchical_taxonomies[] = $taxonomy; } else { $flat_taxonomies[] = $taxonomy; } } $m = ( isset( $mode ) && 'excerpt' === $mode ) ? 'excerpt' : 'list'; $can_publish = current_user_can( $post_type_object->cap->publish_posts ); $core_columns = array( 'cb' => true, 'date' => true, 'title' => true, 'categories' => true, 'tags' => true, 'comments' => true, 'author' => true, ); ?> <form method="get"> <table style="display: none"><tbody id="inlineedit"> <?php $hclass = count( $hierarchical_taxonomies ) ? 'post' : 'page'; $inline_edit_classes = "inline-edit-row inline-edit-row-$hclass"; $bulk_edit_classes = "bulk-edit-row bulk-edit-row-$hclass bulk-edit-{$screen->post_type}"; $quick_edit_classes = "quick-edit-row quick-edit-row-$hclass inline-edit-{$screen->post_type}"; $bulk = 0; while ( $bulk < 2 ) : $classes = $inline_edit_classes . ' '; $classes .= $bulk ? $bulk_edit_classes : $quick_edit_classes; ?> <tr id="<?php echo $bulk ? 'bulk-edit' : 'inline-edit'; ?>" class="<?php echo $classes; ?>" style="display: none"> <td colspan="<?php echo $this->get_column_count(); ?>" class="colspanchange"> <div class="inline-edit-wrapper" role="region" aria-labelledby="<?php echo $bulk ? 'bulk' : 'quick'; ?>-edit-legend"> <fieldset class="inline-edit-col-left"> <legend class="inline-edit-legend" id="<?php echo $bulk ? 'bulk' : 'quick'; ?>-edit-legend"><?php echo $bulk ? __( 'Bulk Edit' ) : __( 'Quick Edit' ); ?></legend> <div class="inline-edit-col"> <?php if ( post_type_supports( $screen->post_type, 'title' ) ) : ?> <?php if ( $bulk ) : ?> <div id="bulk-title-div"> <div id="bulk-titles"></div> </div> <?php else : // $bulk ?> <label> <span class="title"><?php _e( 'Title' ); ?></span> <span class="input-text-wrap"><input type="text" name="post_title" class="ptitle" value="" /></span> </label> <?php if ( is_post_type_viewable( $screen->post_type ) ) : ?> <label> <span class="title"><?php _e( 'Slug' ); ?></span> <span class="input-text-wrap"><input type="text" name="post_name" value="" autocomplete="off" spellcheck="false" /></span> </label> <?php endif; // is_post_type_viewable() ?> <?php endif; // $bulk ?> <?php endif; // post_type_supports( ... 'title' ) ?> <?php if ( ! $bulk ) : ?> <fieldset class="inline-edit-date"> <legend><span class="title"><?php _e( 'Date' ); ?></span></legend> <?php touch_time( 1, 1, 0, 1 ); ?> </fieldset> <br class="clear" /> <?php endif; // $bulk ?> <?php if ( post_type_supports( $screen->post_type, 'author' ) ) { $authors_dropdown = ''; if ( current_user_can( $post_type_object->cap->edit_others_posts ) ) { $dropdown_name = 'post_author'; $dropdown_class = 'authors'; if ( wp_is_large_user_count() ) { $authors_dropdown = sprintf( '<select name="%s" class="%s hidden"></select>', esc_attr( $dropdown_name ), esc_attr( $dropdown_class ) ); } else { $users_opt = array( 'hide_if_only_one_author' => false, 'capability' => array( $post_type_object->cap->edit_posts ), 'name' => $dropdown_name, 'class' => $dropdown_class, 'multi' => 1, 'echo' => 0, 'show' => 'display_name_with_login', ); if ( $bulk ) { $users_opt['show_option_none'] = __( '— No Change —' ); } /** * Filters the arguments used to generate the Quick Edit authors drop-down. * * @since 5.6.0 * * @see wp_dropdown_users() * * @param array $users_opt An array of arguments passed to wp_dropdown_users(). * @param bool $bulk A flag to denote if it's a bulk action. */ $users_opt = apply_filters( 'quick_edit_dropdown_authors_args', $users_opt, $bulk ); $authors = wp_dropdown_users( $users_opt ); if ( $authors ) { $authors_dropdown = '<label class="inline-edit-author">'; $authors_dropdown .= '<span class="title">' . __( 'Author' ) . '</span>'; $authors_dropdown .= $authors; $authors_dropdown .= '</label>'; } } } // current_user_can( 'edit_others_posts' ) if ( ! $bulk ) { echo $authors_dropdown; } } // post_type_supports( ... 'author' ) ?> <?php if ( ! $bulk && $can_publish ) : ?> <div class="inline-edit-group wp-clearfix"> <label class="alignleft"> <span class="title"><?php _e( 'Password' ); ?></span> <span class="input-text-wrap"><input type="text" name="post_password" class="inline-edit-password-input" value="" /></span> </label> <span class="alignleft inline-edit-or"> <?php /* translators: Between password field and private checkbox on post quick edit interface. */ _e( '–OR–' ); ?> </span> <label class="alignleft inline-edit-private"> <input type="checkbox" name="keep_private" value="private" /> <span class="checkbox-title"><?php _e( 'Private' ); ?></span> </label> </div> <?php endif; ?> </div> </fieldset> <?php if ( count( $hierarchical_taxonomies ) && ! $bulk ) : ?> <fieldset class="inline-edit-col-center inline-edit-categories"> <div class="inline-edit-col"> <?php foreach ( $hierarchical_taxonomies as $taxonomy ) : ?> <span class="title inline-edit-categories-label"><?php echo esc_html( $taxonomy->labels->name ); ?></span> <input type="hidden" name="<?php echo ( 'category' === $taxonomy->name ) ? 'post_category[]' : 'tax_input[' . esc_attr( $taxonomy->name ) . '][]'; ?>" value="0" /> <ul class="cat-checklist <?php echo esc_attr( $taxonomy->name ); ?>-checklist"> <?php wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name ) ); ?> </ul> <?php endforeach; // $hierarchical_taxonomies as $taxonomy ?> </div> </fieldset> <?php endif; // count( $hierarchical_taxonomies ) && ! $bulk ?> <fieldset class="inline-edit-col-right"> <div class="inline-edit-col"> <?php if ( post_type_supports( $screen->post_type, 'author' ) && $bulk ) { echo $authors_dropdown; } ?> <?php if ( post_type_supports( $screen->post_type, 'page-attributes' ) ) : ?> <?php if ( $post_type_object->hierarchical ) : ?> <label> <span class="title"><?php _e( 'Parent' ); ?></span> <?php $dropdown_args = array( 'post_type' => $post_type_object->name, 'selected' => $post->post_parent, 'name' => 'post_parent', 'show_option_none' => __( 'Main Page (no parent)' ), 'option_none_value' => 0, 'sort_column' => 'menu_order, post_title', ); if ( $bulk ) { $dropdown_args['show_option_no_change'] = __( '— No Change —' ); $dropdown_args['id'] = 'bulk_edit_post_parent'; } /** * Filters the arguments used to generate the Quick Edit page-parent drop-down. * * @since 2.7.0 * @since 5.6.0 The `$bulk` parameter was added. * * @see wp_dropdown_pages() * * @param array $dropdown_args An array of arguments passed to wp_dropdown_pages(). * @param bool $bulk A flag to denote if it's a bulk action. */ $dropdown_args = apply_filters( 'quick_edit_dropdown_pages_args', $dropdown_args, $bulk ); wp_dropdown_pages( $dropdown_args ); ?> </label> <?php endif; // hierarchical ?> <?php if ( ! $bulk ) : ?> <label> <span class="title"><?php _e( 'Order' ); ?></span> <span class="input-text-wrap"><input type="text" name="menu_order" class="inline-edit-menu-order-input" value="<?php echo $post->menu_order; ?>" /></span> </label> <?php endif; // ! $bulk ?> <?php endif; // post_type_supports( ... 'page-attributes' ) ?> <?php if ( 0 < count( get_page_templates( null, $screen->post_type ) ) ) : ?> <label> <span class="title"><?php _e( 'Template' ); ?></span> <select name="page_template"> <?php if ( $bulk ) : ?> <option value="-1"><?php _e( '— No Change —' ); ?></option> <?php endif; // $bulk ?> <?php /** This filter is documented in wp-admin/includes/meta-boxes.php */ $default_title = apply_filters( 'default_page_template_title', __( 'Default template' ), 'quick-edit' ); ?> <option value="default"><?php echo esc_html( $default_title ); ?></option> <?php page_template_dropdown( '', $screen->post_type ); ?> </select> </label> <?php endif; ?> <?php if ( count( $flat_taxonomies ) && ! $bulk ) : ?> <?php foreach ( $flat_taxonomies as $taxonomy ) : ?> <?php if ( current_user_can( $taxonomy->cap->assign_terms ) ) : ?> <?php $taxonomy_name = esc_attr( $taxonomy->name ); ?> <div class="inline-edit-tags-wrap"> <label class="inline-edit-tags"> <span class="title"><?php echo esc_html( $taxonomy->labels->name ); ?></span> <textarea data-wp-taxonomy="<?php echo $taxonomy_name; ?>" cols="22" rows="1" name="tax_input[<?php echo esc_attr( $taxonomy->name ); ?>]" class="tax_input_<?php echo esc_attr( $taxonomy->name ); ?>" aria-describedby="inline-edit-<?php echo esc_attr( $taxonomy->name ); ?>-desc"></textarea> </label> <p class="howto" id="inline-edit-<?php echo esc_attr( $taxonomy->name ); ?>-desc"><?php echo esc_html( $taxonomy->labels->separate_items_with_commas ); ?></p> </div> <?php endif; // current_user_can( 'assign_terms' ) ?> <?php endforeach; // $flat_taxonomies as $taxonomy ?> <?php endif; // count( $flat_taxonomies ) && ! $bulk ?> <?php if ( post_type_supports( $screen->post_type, 'comments' ) || post_type_supports( $screen->post_type, 'trackbacks' ) ) : ?> <?php if ( $bulk ) : ?> <div class="inline-edit-group wp-clearfix"> <?php if ( post_type_supports( $screen->post_type, 'comments' ) ) : ?> <label class="alignleft"> <span class="title"><?php _e( 'Comments' ); ?></span> <select name="comment_status"> <option value=""><?php _e( '— No Change —' ); ?></option> <option value="open"><?php _e( 'Allow' ); ?></option> <option value="closed"><?php _e( 'Do not allow' ); ?></option> </select> </label> <?php endif; ?> <?php if ( post_type_supports( $screen->post_type, 'trackbacks' ) ) : ?> <label class="alignright"> <span class="title"><?php _e( 'Pings' ); ?></span> <select name="ping_status"> <option value=""><?php _e( '— No Change —' ); ?></option> <option value="open"><?php _e( 'Allow' ); ?></option> <option value="closed"><?php _e( 'Do not allow' ); ?></option> </select> </label> <?php endif; ?> </div> <?php else : // $bulk ?> <div class="inline-edit-group wp-clearfix"> <?php if ( post_type_supports( $screen->post_type, 'comments' ) ) : ?> <label class="alignleft"> <input type="checkbox" name="comment_status" value="open" /> <span class="checkbox-title"><?php _e( 'Allow Comments' ); ?></span> </label> <?php endif; ?> <?php if ( post_type_supports( $screen->post_type, 'trackbacks' ) ) : ?> <label class="alignleft"> <input type="checkbox" name="ping_status" value="open" /> <span class="checkbox-title"><?php _e( 'Allow Pings' ); ?></span> </label> <?php endif; ?> </div> <?php endif; // $bulk ?> <?php endif; // post_type_supports( ... comments or pings ) ?> <div class="inline-edit-group wp-clearfix"> <label class="inline-edit-status alignleft"> <span class="title"><?php _e( 'Status' ); ?></span> <select name="_status"> <?php $inline_edit_statuses = array(); if ( $bulk ) { $inline_edit_statuses['-1'] = __( '— No Change —' ); } // Contributors only get "Unpublished" and "Pending Review". if ( $can_publish ) { $inline_edit_statuses['publish'] = __( 'Published' ); $inline_edit_statuses['future'] = __( 'Scheduled' ); // There is already a checkbox for Private in Single Post Quick Edit. See #63612. if ( $bulk ) { $inline_edit_statuses['private'] = __( 'Private' ); } } $inline_edit_statuses['pending'] = __( 'Pending Review' ); $inline_edit_statuses['draft'] = __( 'Draft' ); /** * Filters the statuses available in the Quick Edit and Bulk Edit UI. * * @since 6.9.0 * * @param array<string,string> $inline_edit_statuses An array of statuses available in the Quick Edit UI. * @param string $post_type The post type slug. * @param bool $bulk A flag to denote if it's a bulk action. * @param bool $can_publish A flag to denote if the user can publish posts. */ $inline_edit_statuses = apply_filters( 'quick_edit_statuses', $inline_edit_statuses, $screen->post_type, $bulk, $can_publish ); foreach ( $inline_edit_statuses as $inline_status_value => $inline_status_text ) : ?> <option value="<?php echo esc_attr( $inline_status_value ); ?>"><?php echo esc_attr( $inline_status_text ); ?></option> <?php endforeach; ?> </select> </label> <?php if ( 'post' === $screen->post_type && $can_publish && current_user_can( $post_type_object->cap->edit_others_posts ) ) : ?> <?php if ( $bulk ) : ?> <label class="alignright"> <span class="title"><?php _e( 'Sticky' ); ?></span> <select name="sticky"> <option value="-1"><?php _e( '— No Change —' ); ?></option> <option value="sticky"><?php _e( 'Sticky' ); ?></option> <option value="unsticky"><?php _e( 'Not Sticky' ); ?></option> </select> </label> <?php else : // $bulk ?> <label class="alignleft"> <input type="checkbox" name="sticky" value="sticky" /> <span class="checkbox-title"><?php _e( 'Make this post sticky' ); ?></span> </label> <?php endif; // $bulk ?> <?php endif; // 'post' && $can_publish && current_user_can( 'edit_others_posts' ) ?> </div> <?php if ( $bulk && current_theme_supports( 'post-formats' ) && post_type_supports( $screen->post_type, 'post-formats' ) ) : ?> <?php $post_formats = get_theme_support( 'post-formats' ); ?> <label class="alignleft"> <span class="title"><?php _ex( 'Format', 'post format' ); ?></span> <select name="post_format"> <option value="-1"><?php _e( '— No Change —' ); ?></option> <option value="0"><?php echo get_post_format_string( 'standard' ); ?></option> <?php if ( is_array( $post_formats[0] ) ) : ?> <?php foreach ( $post_formats[0] as $format ) : ?> <option value="<?php echo esc_attr( $format ); ?>"><?php echo esc_html( get_post_format_string( $format ) ); ?></option> <?php endforeach; ?> <?php endif; ?> </select> </label> <?php endif; ?> </div> </fieldset> <?php list( $columns ) = $this->get_column_info(); foreach ( $columns as $column_name => $column_display_name ) { if ( isset( $core_columns[ $column_name ] ) ) { continue; } if ( $bulk ) { /** * Fires once for each column in Bulk Edit mode. * * @since 2.7.0 * * @param string $column_name Name of the column to edit. * @param string $post_type The post type slug. */ do_action( 'bulk_edit_custom_box', $column_name, $screen->post_type ); } else { /** * Fires once for each column in Quick Edit mode. * * @since 2.7.0 * * @param string $column_name Name of the column to edit. * @param string $post_type The post type slug, or current screen name if this is a taxonomy list table. * @param string $taxonomy The taxonomy name, if any. */ do_action( 'quick_edit_custom_box', $column_name, $screen->post_type, '' ); } } ?> <div class="submit inline-edit-save"> <?php if ( ! $bulk ) : ?> <?php wp_nonce_field( 'inlineeditnonce', '_inline_edit', false ); ?> <button type="button" class="button button-primary save"><?php _e( 'Update' ); ?></button> <?php else : ?> <?php submit_button( __( 'Update' ), 'primary', 'bulk_edit', false ); ?> <?php endif; ?> <button type="button" class="button cancel"><?php _e( 'Cancel' ); ?></button> <?php if ( ! $bulk ) : ?> <span class="spinner"></span> <?php endif; ?> <input type="hidden" name="post_view" value="<?php echo esc_attr( $m ); ?>" /> <input type="hidden" name="screen" value="<?php echo esc_attr( $screen->id ); ?>" /> <?php if ( ! $bulk && ! post_type_supports( $screen->post_type, 'author' ) ) : ?> <input type="hidden" name="post_author" value="<?php echo esc_attr( $post->post_author ); ?>" /> <?php endif; ?> <?php wp_admin_notice( '<p class="error"></p>', array( 'type' => 'error', 'additional_classes' => array( 'notice-alt', 'inline', 'hidden' ), 'paragraph_wrap' => false, ) ); ?> </div> </div> <!-- end of .inline-edit-wrapper --> </td></tr> <?php ++$bulk; endwhile; ?> </tbody></table> </form> <?php } } PK U�g\/f���<