File manager - Edit - /home/u291647258/domains/adiyoga.in/public_html/wp-content/uploads/includes.zip
Back
PK �Z�\����e e export.phpnu �[��� <?php /** * WordPress Export Administration API * * @package WordPress * @subpackage Administration */ /** * Version number for the export format. * * Bump this when something changes that might affect compatibility. * * @since 2.5.0 */ define( 'WXR_VERSION', '1.2' ); /** * Generates the WXR export file for download. * * Default behavior is to export all content, however, note that post content will only * be exported for post types with the `can_export` argument enabled. Any posts with the * 'auto-draft' status will be skipped. * * @since 2.1.0 * @since 5.7.0 Added the `post_modified` and `post_modified_gmt` fields to the export file. * * @global wpdb $wpdb WordPress database abstraction object. * @global WP_Post $post Global post object. * * @param array $args { * Optional. Arguments for generating the WXR export file for download. Default empty array. * * @type string $content Type of content to export. If set, only the post content of this post type * will be exported. Accepts 'all', 'post', 'page', 'attachment', or a defined * custom post. If an invalid custom post type is supplied, every post type for * which `can_export` is enabled will be exported instead. If a valid custom post * type is supplied but `can_export` is disabled, then 'posts' will be exported * instead. When 'all' is supplied, only post types with `can_export` enabled will * be exported. Default 'all'. * @type string $author Author to export content for. Only used when `$content` is 'post', 'page', or * 'attachment'. Accepts false (all) or a specific author ID. Default false (all). * @type string $category Category (slug) to export content for. Used only when `$content` is 'post'. If * set, only post content assigned to `$category` will be exported. Accepts false * or a specific category slug. Default is false (all categories). * @type string $start_date Start date to export content from. Expected date format is 'Y-m-d'. Used only * when `$content` is 'post', 'page' or 'attachment'. Default false (since the * beginning of time). * @type string $end_date End date to export content to. Expected date format is 'Y-m-d'. Used only when * `$content` is 'post', 'page' or 'attachment'. Default false (latest publish date). * @type string $status Post status to export posts for. Used only when `$content` is 'post' or 'page'. * Accepts false (all statuses except 'auto-draft'), or a specific status, i.e. * 'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', or * 'trash'. Default false (all statuses except 'auto-draft'). * } */ function export_wp( $args = array() ) { global $wpdb, $post; $defaults = array( 'content' => 'all', 'author' => false, 'category' => false, 'start_date' => false, 'end_date' => false, 'status' => false, ); $args = wp_parse_args( $args, $defaults ); /** * Fires at the beginning of an export, before any headers are sent. * * @since 2.3.0 * * @param array $args An array of export arguments. */ do_action( 'export_wp', $args ); $sitename = sanitize_key( get_bloginfo( 'name' ) ); if ( ! empty( $sitename ) ) { $sitename .= '.'; } $date = gmdate( 'Y-m-d' ); $wp_filename = $sitename . 'WordPress.' . $date . '.xml'; /** * Filters the export filename. * * @since 4.4.0 * * @param string $wp_filename The name of the file for download. * @param string $sitename The site name. * @param string $date Today's date, formatted. */ $filename = apply_filters( 'export_wp_filename', $wp_filename, $sitename, $date ); header( 'Content-Description: File Transfer' ); header( 'Content-Disposition: attachment; filename=' . $filename ); header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true ); if ( 'all' !== $args['content'] && post_type_exists( $args['content'] ) ) { $ptype = get_post_type_object( $args['content'] ); if ( ! $ptype->can_export ) { $args['content'] = 'post'; } $where = $wpdb->prepare( "{$wpdb->posts}.post_type = %s", $args['content'] ); } else { $post_types = get_post_types( array( 'can_export' => true ) ); $esses = array_fill( 0, count( $post_types ), '%s' ); // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare $where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types ); } if ( $args['status'] && ( 'post' === $args['content'] || 'page' === $args['content'] ) ) { $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_status = %s", $args['status'] ); } else { $where .= " AND {$wpdb->posts}.post_status != 'auto-draft'"; } $join = ''; if ( $args['category'] && 'post' === $args['content'] ) { $term = term_exists( $args['category'], 'category' ); if ( $term ) { $join = "INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)"; $where .= $wpdb->prepare( " AND {$wpdb->term_relationships}.term_taxonomy_id = %d", $term['term_taxonomy_id'] ); } } if ( in_array( $args['content'], array( 'post', 'page', 'attachment' ), true ) ) { if ( $args['author'] ) { $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] ); } if ( $args['start_date'] ) { $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", gmdate( 'Y-m-d', strtotime( $args['start_date'] ) ) ); } if ( $args['end_date'] ) { $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", gmdate( 'Y-m-d', strtotime( '+1 month', strtotime( $args['end_date'] ) ) ) ); } } // Grab a snapshot of post IDs, just in case it changes during the export. $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where" ); // Get IDs for the attachments of each post, unless all content is already being exported. if ( ! in_array( $args['content'], array( 'all', 'attachment' ), true ) ) { // Array to hold all additional IDs (attachments and thumbnails). $additional_ids = array(); // Create a copy of the post IDs array to avoid modifying the original array. $processing_ids = $post_ids; while ( $next_posts = array_splice( $processing_ids, 0, 20 ) ) { $posts_in = array_map( 'absint', $next_posts ); $placeholders = array_fill( 0, count( $posts_in ), '%d' ); // Create a string for the placeholders. $in_placeholder = implode( ',', $placeholders ); // Prepare the SQL statement for attachment ids. $attachment_ids = $wpdb->get_col( $wpdb->prepare( " SELECT ID FROM $wpdb->posts WHERE post_parent IN ($in_placeholder) AND post_type = 'attachment' ", $posts_in ) ); $thumbnails_ids = $wpdb->get_col( $wpdb->prepare( " SELECT meta_value FROM $wpdb->postmeta WHERE $wpdb->postmeta.post_id IN ($in_placeholder) AND $wpdb->postmeta.meta_key = '_thumbnail_id' ", $posts_in ) ); $additional_ids = array_merge( $additional_ids, $attachment_ids, $thumbnails_ids ); } // Merge the additional IDs back with the original post IDs after processing all posts $post_ids = array_unique( array_merge( $post_ids, $additional_ids ) ); } /* * Get the requested terms ready, empty unless posts filtered by category * or all content. */ $cats = array(); $tags = array(); $terms = array(); if ( isset( $term ) && $term ) { $cat = get_term( $term['term_id'], 'category' ); $cats = array( $cat->term_id => $cat ); unset( $term, $cat ); } elseif ( 'all' === $args['content'] ) { $categories = (array) get_categories( array( 'get' => 'all' ) ); $tags = (array) get_tags( array( 'get' => 'all' ) ); $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) ); $custom_terms = (array) get_terms( array( 'taxonomy' => $custom_taxonomies, 'get' => 'all', ) ); // Put categories in order with no child going before its parent. while ( $cat = array_shift( $categories ) ) { if ( ! $cat->parent || isset( $cats[ $cat->parent ] ) ) { $cats[ $cat->term_id ] = $cat; } else { $categories[] = $cat; } } // Put terms in order with no child going before its parent. while ( $t = array_shift( $custom_terms ) ) { if ( ! $t->parent || isset( $terms[ $t->parent ] ) ) { $terms[ $t->term_id ] = $t; } else { $custom_terms[] = $t; } } unset( $categories, $custom_taxonomies, $custom_terms ); } /** * Wraps given string in XML CDATA tag. * * @since 2.1.0 * * @param string|null $str String to wrap in XML CDATA tag. May be null. * @return string */ function wxr_cdata( $str ) { $str = (string) $str; if ( ! wp_is_valid_utf8( $str ) ) { $str = utf8_encode( $str ); } // $str = ent2ncr(esc_html($str)); $str = '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str ) . ']]>'; return $str; } /** * Returns the URL of the site. * * @since 2.5.0 * * @return string Site URL. */ function wxr_site_url() { if ( is_multisite() ) { // Multisite: the base URL. return network_home_url(); } else { // WordPress (single site): the site URL. return get_bloginfo_rss( 'url' ); } } /** * Outputs a cat_name XML tag from a given category object. * * @since 2.1.0 * * @param WP_Term $category Category Object. */ function wxr_cat_name( $category ) { if ( empty( $category->name ) ) { return; } echo '<wp:cat_name>' . wxr_cdata( $category->name ) . "</wp:cat_name>\n"; } /** * Outputs a category_description XML tag from a given category object. * * @since 2.1.0 * * @param WP_Term $category Category Object. */ function wxr_category_description( $category ) { if ( empty( $category->description ) ) { return; } echo '<wp:category_description>' . wxr_cdata( $category->description ) . "</wp:category_description>\n"; } /** * Outputs a tag_name XML tag from a given tag object. * * @since 2.3.0 * * @param WP_Term $tag Tag Object. */ function wxr_tag_name( $tag ) { if ( empty( $tag->name ) ) { return; } echo '<wp:tag_name>' . wxr_cdata( $tag->name ) . "</wp:tag_name>\n"; } /** * Outputs a tag_description XML tag from a given tag object. * * @since 2.3.0 * * @param WP_Term $tag Tag Object. */ function wxr_tag_description( $tag ) { if ( empty( $tag->description ) ) { return; } echo '<wp:tag_description>' . wxr_cdata( $tag->description ) . "</wp:tag_description>\n"; } /** * Outputs a term_name XML tag from a given term object. * * @since 2.9.0 * * @param WP_Term $term Term Object. */ function wxr_term_name( $term ) { if ( empty( $term->name ) ) { return; } echo '<wp:term_name>' . wxr_cdata( $term->name ) . "</wp:term_name>\n"; } /** * Outputs a term_description XML tag from a given term object. * * @since 2.9.0 * * @param WP_Term $term Term Object. */ function wxr_term_description( $term ) { if ( empty( $term->description ) ) { return; } echo "\t\t<wp:term_description>" . wxr_cdata( $term->description ) . "</wp:term_description>\n"; } /** * Outputs term meta XML tags for a given term object. * * @since 4.6.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param WP_Term $term Term object. */ function wxr_term_meta( $term ) { global $wpdb; $termmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->termmeta WHERE term_id = %d", $term->term_id ) ); foreach ( $termmeta as $meta ) { /** * Filters whether to selectively skip term meta used for WXR exports. * * Returning a truthy value from the filter will skip the current meta * object from being exported. * * @since 4.6.0 * * @param bool $skip Whether to skip the current piece of term meta. Default false. * @param string $meta_key Current meta key. * @param object $meta Current meta object. */ if ( ! apply_filters( 'wxr_export_skip_termmeta', false, $meta->meta_key, $meta ) ) { printf( "\t\t<wp:termmeta>\n\t\t\t<wp:meta_key>%s</wp:meta_key>\n\t\t\t<wp:meta_value>%s</wp:meta_value>\n\t\t</wp:termmeta>\n", wxr_cdata( $meta->meta_key ), wxr_cdata( $meta->meta_value ) ); } } } /** * Outputs list of authors with posts. * * @since 3.1.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int[] $post_ids Optional. Array of post IDs to filter the query by. */ function wxr_authors_list( ?array $post_ids = null ) { global $wpdb; if ( ! empty( $post_ids ) ) { $post_ids = array_map( 'absint', $post_ids ); $post_id_chunks = array_chunk( $post_ids, 20 ); } else { $post_id_chunks = array( array() ); } $authors = array(); foreach ( $post_id_chunks as $next_posts ) { $and = ! empty( $next_posts ) ? 'AND ID IN (' . implode( ', ', $next_posts ) . ')' : ''; $results = $wpdb->get_results( "SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_status != 'auto-draft' $and" ); foreach ( (array) $results as $result ) { $authors[] = get_userdata( $result->post_author ); } } $authors = array_filter( $authors ); $authors = array_unique( $authors, SORT_REGULAR ); // Remove duplicate authors. foreach ( $authors as $author ) { echo "\t<wp:author>"; echo '<wp:author_id>' . (int) $author->ID . '</wp:author_id>'; echo '<wp:author_login>' . wxr_cdata( $author->user_login ) . '</wp:author_login>'; echo '<wp:author_email>' . wxr_cdata( $author->user_email ) . '</wp:author_email>'; echo '<wp:author_display_name>' . wxr_cdata( $author->display_name ) . '</wp:author_display_name>'; echo '<wp:author_first_name>' . wxr_cdata( $author->first_name ) . '</wp:author_first_name>'; echo '<wp:author_last_name>' . wxr_cdata( $author->last_name ) . '</wp:author_last_name>'; echo "</wp:author>\n"; } } /** * Outputs all navigation menu terms. * * @since 3.1.0 */ function wxr_nav_menu_terms() { $nav_menus = wp_get_nav_menus(); if ( empty( $nav_menus ) || ! is_array( $nav_menus ) ) { return; } foreach ( $nav_menus as $menu ) { echo "\t<wp:term>"; echo '<wp:term_id>' . (int) $menu->term_id . '</wp:term_id>'; echo '<wp:term_taxonomy>nav_menu</wp:term_taxonomy>'; echo '<wp:term_slug>' . wxr_cdata( $menu->slug ) . '</wp:term_slug>'; wxr_term_name( $menu ); echo "</wp:term>\n"; } } /** * Outputs list of taxonomy terms, in XML tag format, associated with a post. * * @since 2.3.0 */ function wxr_post_taxonomy() { $post = get_post(); $taxonomies = get_object_taxonomies( $post->post_type ); if ( empty( $taxonomies ) ) { return; } $terms = wp_get_object_terms( $post->ID, $taxonomies ); foreach ( (array) $terms as $term ) { echo "\t\t<category domain=\"{$term->taxonomy}\" nicename=\"{$term->slug}\">" . wxr_cdata( $term->name ) . "</category>\n"; } } /** * Determines whether to selectively skip post meta used for WXR exports. * * @since 3.3.0 * * @param bool $return_me Whether to skip the current post meta. Default false. * @param string $meta_key Meta key. * @return bool */ function wxr_filter_postmeta( $return_me, $meta_key ) { if ( '_edit_lock' === $meta_key ) { $return_me = true; } return $return_me; } add_filter( 'wxr_export_skip_postmeta', 'wxr_filter_postmeta', 10, 2 ); echo '<?xml version="1.0" encoding="' . get_bloginfo( 'charset' ) . "\" ?>\n"; ?> <!-- This is a WordPress eXtended RSS file generated by WordPress as an export of your site. --> <!-- It contains information about your site's posts, pages, comments, categories, and other content. --> <!-- You may use this file to transfer that content from one site to another. --> <!-- This file is not intended to serve as a complete backup of your site. --> <!-- To import this information into a WordPress site follow these steps: --> <!-- 1. Log in to that site as an administrator. --> <!-- 2. Go to Tools: Import in the WordPress admin panel. --> <!-- 3. Install the "WordPress" importer from the list. --> <!-- 4. Activate & Run Importer. --> <!-- 5. Upload this file using the form provided on that page. --> <!-- 6. You will first be asked to map the authors in this export file to users --> <!-- on the site. For each author, you may choose to map to an --> <!-- existing user on the site or to create a new user. --> <!-- 7. WordPress will then import each of the posts, pages, comments, categories, etc. --> <!-- contained in this file into your site. --> <?php the_generator( 'export' ); ?> <rss version="2.0" xmlns:excerpt="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/excerpt/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wp="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/" > <channel> <title><?php bloginfo_rss( 'name' ); ?></title> <link><?php bloginfo_rss( 'url' ); ?></link> <description><?php bloginfo_rss( 'description' ); ?></description> <pubDate><?php echo gmdate( 'D, d M Y H:i:s +0000' ); ?></pubDate> <language><?php bloginfo_rss( 'language' ); ?></language> <wp:wxr_version><?php echo WXR_VERSION; ?></wp:wxr_version> <wp:base_site_url><?php echo wxr_site_url(); ?></wp:base_site_url> <wp:base_blog_url><?php bloginfo_rss( 'url' ); ?></wp:base_blog_url> <?php wxr_authors_list( $post_ids ); ?> <?php foreach ( $cats as $c ) : ?> <wp:category> <wp:term_id><?php echo (int) $c->term_id; ?></wp:term_id> <wp:category_nicename><?php echo wxr_cdata( $c->slug ); ?></wp:category_nicename> <wp:category_parent><?php echo wxr_cdata( $c->parent ? $cats[ $c->parent ]->slug : '' ); ?></wp:category_parent> <?php wxr_cat_name( $c ); wxr_category_description( $c ); wxr_term_meta( $c ); ?> </wp:category> <?php endforeach; ?> <?php foreach ( $tags as $t ) : ?> <wp:tag> <wp:term_id><?php echo (int) $t->term_id; ?></wp:term_id> <wp:tag_slug><?php echo wxr_cdata( $t->slug ); ?></wp:tag_slug> <?php wxr_tag_name( $t ); wxr_tag_description( $t ); wxr_term_meta( $t ); ?> </wp:tag> <?php endforeach; ?> <?php foreach ( $terms as $t ) : ?> <wp:term> <wp:term_id><?php echo (int) $t->term_id; ?></wp:term_id> <wp:term_taxonomy><?php echo wxr_cdata( $t->taxonomy ); ?></wp:term_taxonomy> <wp:term_slug><?php echo wxr_cdata( $t->slug ); ?></wp:term_slug> <wp:term_parent><?php echo wxr_cdata( $t->parent ? $terms[ $t->parent ]->slug : '' ); ?></wp:term_parent> <?php wxr_term_name( $t ); wxr_term_description( $t ); wxr_term_meta( $t ); ?> </wp:term> <?php endforeach; ?> <?php if ( 'all' === $args['content'] ) { wxr_nav_menu_terms(); } ?> <?php /** This action is documented in wp-includes/feed-rss2.php */ do_action( 'rss2_head' ); ?> <?php if ( $post_ids ) { /** * @global WP_Query $wp_query WordPress Query object. */ global $wp_query; // Fake being in the loop. $wp_query->in_the_loop = true; // Fetch 20 posts at a time rather than loading the entire table into memory. while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) { $where = 'WHERE ID IN (' . implode( ',', $next_posts ) . ')'; $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" ); // Begin Loop. foreach ( $posts as $post ) { setup_postdata( $post ); /** * Filters the post title used for WXR exports. * * @since 5.7.0 * * @param string $post_title Title of the current post. */ $title = wxr_cdata( apply_filters( 'the_title_export', $post->post_title ) ); /** * Filters the post content used for WXR exports. * * @since 2.5.0 * * @param string $post_content Content of the current post. */ $content = wxr_cdata( apply_filters( 'the_content_export', $post->post_content ) ); /** * Filters the post excerpt used for WXR exports. * * @since 2.6.0 * * @param string $post_excerpt Excerpt for the current post. */ $excerpt = wxr_cdata( apply_filters( 'the_excerpt_export', $post->post_excerpt ) ); $is_sticky = is_sticky( $post->ID ) ? 1 : 0; ?> <item> <title><?php echo $title; ?></title> <link><?php the_permalink_rss(); ?></link> <pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate> <dc:creator><?php echo wxr_cdata( get_the_author_meta( 'login' ) ); ?></dc:creator> <guid isPermaLink="false"><?php the_guid(); ?></guid> <description></description> <content:encoded><?php echo $content; ?></content:encoded> <excerpt:encoded><?php echo $excerpt; ?></excerpt:encoded> <wp:post_id><?php echo (int) $post->ID; ?></wp:post_id> <wp:post_date><?php echo wxr_cdata( $post->post_date ); ?></wp:post_date> <wp:post_date_gmt><?php echo wxr_cdata( $post->post_date_gmt ); ?></wp:post_date_gmt> <wp:post_modified><?php echo wxr_cdata( $post->post_modified ); ?></wp:post_modified> <wp:post_modified_gmt><?php echo wxr_cdata( $post->post_modified_gmt ); ?></wp:post_modified_gmt> <wp:comment_status><?php echo wxr_cdata( $post->comment_status ); ?></wp:comment_status> <wp:ping_status><?php echo wxr_cdata( $post->ping_status ); ?></wp:ping_status> <wp:post_name><?php echo wxr_cdata( $post->post_name ); ?></wp:post_name> <wp:status><?php echo wxr_cdata( $post->post_status ); ?></wp:status> <wp:post_parent><?php echo (int) $post->post_parent; ?></wp:post_parent> <wp:menu_order><?php echo (int) $post->menu_order; ?></wp:menu_order> <wp:post_type><?php echo wxr_cdata( $post->post_type ); ?></wp:post_type> <wp:post_password><?php echo wxr_cdata( $post->post_password ); ?></wp:post_password> <wp:is_sticky><?php echo (int) $is_sticky; ?></wp:is_sticky> <?php if ( 'attachment' === $post->post_type ) : ?> <wp:attachment_url><?php echo wxr_cdata( wp_get_attachment_url( $post->ID ) ); ?></wp:attachment_url> <?php endif; ?> <?php wxr_post_taxonomy(); ?> <?php $postmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) ); foreach ( $postmeta as $meta ) : /** * Filters whether to selectively skip post meta used for WXR exports. * * Returning a truthy value from the filter will skip the current meta * object from being exported. * * @since 3.3.0 * * @param bool $skip Whether to skip the current post meta. Default false. * @param string $meta_key Current meta key. * @param object $meta Current meta object. */ if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) ) { continue; } ?> <wp:postmeta> <wp:meta_key><?php echo wxr_cdata( $meta->meta_key ); ?></wp:meta_key> <wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value> </wp:postmeta> <?php endforeach; $_comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) ); $comments = array_map( 'get_comment', $_comments ); foreach ( $comments as $c ) : ?> <wp:comment> <wp:comment_id><?php echo (int) $c->comment_ID; ?></wp:comment_id> <wp:comment_author><?php echo wxr_cdata( $c->comment_author ); ?></wp:comment_author> <wp:comment_author_email><?php echo wxr_cdata( $c->comment_author_email ); ?></wp:comment_author_email> <wp:comment_author_url><?php echo sanitize_url( $c->comment_author_url ); ?></wp:comment_author_url> <wp:comment_author_IP><?php echo wxr_cdata( $c->comment_author_IP ); ?></wp:comment_author_IP> <wp:comment_date><?php echo wxr_cdata( $c->comment_date ); ?></wp:comment_date> <wp:comment_date_gmt><?php echo wxr_cdata( $c->comment_date_gmt ); ?></wp:comment_date_gmt> <wp:comment_content><?php echo wxr_cdata( $c->comment_content ); ?></wp:comment_content> <wp:comment_approved><?php echo wxr_cdata( $c->comment_approved ); ?></wp:comment_approved> <wp:comment_type><?php echo wxr_cdata( $c->comment_type ); ?></wp:comment_type> <wp:comment_parent><?php echo (int) $c->comment_parent; ?></wp:comment_parent> <wp:comment_user_id><?php echo (int) $c->user_id; ?></wp:comment_user_id> <?php $c_meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $c->comment_ID ) ); foreach ( $c_meta as $meta ) : /** * Filters whether to selectively skip comment meta used for WXR exports. * * Returning a truthy value from the filter will skip the current meta * object from being exported. * * @since 4.0.0 * * @param bool $skip Whether to skip the current comment meta. Default false. * @param string $meta_key Current meta key. * @param object $meta Current meta object. */ if ( apply_filters( 'wxr_export_skip_commentmeta', false, $meta->meta_key, $meta ) ) { continue; } ?> <wp:commentmeta> <wp:meta_key><?php echo wxr_cdata( $meta->meta_key ); ?></wp:meta_key> <wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value> </wp:commentmeta> <?php endforeach; ?> </wp:comment> <?php endforeach; ?> </item> <?php } } } ?> </channel> </rss> <?php } PK �Z�\���5�� �� update.phpnu �[��� <?php /** * WordPress Administration Update API * * @package WordPress * @subpackage Administration */ /** * Selects the first update version from the update_core option. * * @since 2.7.0 * * @return object|array|false The response from the API on success, false on failure. */ function get_preferred_from_update_core() { $updates = get_core_updates(); if ( ! is_array( $updates ) ) { return false; } if ( empty( $updates ) ) { return (object) array( 'response' => 'latest' ); } return $updates[0]; } /** * Gets available core updates. * * @since 2.7.0 * * @param array $options Set $options['dismissed'] to true to show dismissed upgrades too, * set $options['available'] to false to skip not-dismissed updates. * @return array|false Array of the update objects on success, false on failure. */ function get_core_updates( $options = array() ) { $options = array_merge( array( 'available' => true, 'dismissed' => false, ), $options ); $dismissed = get_site_option( 'dismissed_update_core' ); if ( ! is_array( $dismissed ) ) { $dismissed = array(); } $from_api = get_site_transient( 'update_core' ); if ( ! isset( $from_api->updates ) || ! is_array( $from_api->updates ) ) { return false; } $updates = $from_api->updates; $result = array(); foreach ( $updates as $update ) { if ( 'autoupdate' === $update->response ) { continue; } if ( array_key_exists( $update->current . '|' . $update->locale, $dismissed ) ) { if ( $options['dismissed'] ) { $update->dismissed = true; $result[] = $update; } } else { if ( $options['available'] ) { $update->dismissed = false; $result[] = $update; } } } return $result; } /** * Gets the best available (and enabled) Auto-Update for WordPress core. * * If there's 1.2.3 and 1.3 on offer, it'll choose 1.3 if the installation allows it, else, 1.2.3. * * @since 3.7.0 * * @return object|false The core update offering on success, false on failure. */ function find_core_auto_update() { $updates = get_site_transient( 'update_core' ); if ( ! $updates || empty( $updates->updates ) ) { return false; } require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; $auto_update = false; $upgrader = new WP_Automatic_Updater(); foreach ( $updates->updates as $update ) { if ( 'autoupdate' !== $update->response ) { continue; } if ( ! $upgrader->should_update( 'core', $update, ABSPATH ) ) { continue; } if ( ! $auto_update || version_compare( $update->current, $auto_update->current, '>' ) ) { $auto_update = $update; } } return $auto_update; } /** * Gets and caches the checksums for the given version of WordPress. * * @since 3.7.0 * * @param string $version Version string to query. * @param string $locale Locale to query. * @return array|false An array of checksums on success, false on failure. */ function get_core_checksums( $version, $locale ) { $http_url = 'http://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), '', '&' ); $url = $http_url; $ssl = wp_http_supports( array( 'ssl' ) ); if ( $ssl ) { $url = set_url_scheme( $url, 'https' ); } $options = array( 'timeout' => wp_doing_cron() ? 30 : 3, ); $response = wp_remote_get( $url, $options ); if ( $ssl && is_wp_error( $response ) ) { 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 ); $response = wp_remote_get( $http_url, $options ); } if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { return false; } $body = trim( wp_remote_retrieve_body( $response ) ); $body = json_decode( $body, true ); if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) { return false; } return $body['checksums']; } /** * Dismisses core update. * * @since 2.7.0 * * @param object $update * @return bool */ function dismiss_core_update( $update ) { $dismissed = get_site_option( 'dismissed_update_core' ); $dismissed[ $update->current . '|' . $update->locale ] = true; return update_site_option( 'dismissed_update_core', $dismissed ); } /** * Undismisses core update. * * @since 2.7.0 * * @param string $version * @param string $locale * @return bool */ function undismiss_core_update( $version, $locale ) { $dismissed = get_site_option( 'dismissed_update_core' ); $key = $version . '|' . $locale; if ( ! isset( $dismissed[ $key ] ) ) { return false; } unset( $dismissed[ $key ] ); return update_site_option( 'dismissed_update_core', $dismissed ); } /** * Finds the available update for WordPress core. * * @since 2.7.0 * * @param string $version Version string to find the update for. * @param string $locale Locale to find the update for. * @return object|false The core update offering on success, false on failure. */ function find_core_update( $version, $locale ) { $from_api = get_site_transient( 'update_core' ); if ( ! isset( $from_api->updates ) || ! is_array( $from_api->updates ) ) { return false; } $updates = $from_api->updates; foreach ( $updates as $update ) { if ( $update->current === $version && $update->locale === $locale ) { return $update; } } return false; } /** * Returns core update footer message. * * @since 2.3.0 * * @param string $msg * @return string */ function core_update_footer( $msg = '' ) { if ( ! current_user_can( 'update_core' ) ) { /* translators: %s: WordPress version. */ return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) ); } $cur = get_preferred_from_update_core(); if ( ! is_object( $cur ) ) { $cur = new stdClass(); } if ( ! isset( $cur->current ) ) { $cur->current = ''; } if ( ! isset( $cur->response ) ) { $cur->response = ''; } $is_development_version = preg_match( '/alpha|beta|RC/', wp_get_wp_version() ); if ( $is_development_version ) { return sprintf( /* translators: 1: WordPress version number, 2: URL to WordPress Updates screen. */ __( 'You are using a development version (%1$s). Cool! Please <a href="%2$s">stay updated</a>.' ), get_bloginfo( 'version', 'display' ), network_admin_url( 'update-core.php' ) ); } switch ( $cur->response ) { case 'upgrade': return sprintf( '<strong><a href="%s">%s</a></strong>', network_admin_url( 'update-core.php' ), /* translators: %s: WordPress version. */ sprintf( __( 'Get Version %s' ), $cur->current ) ); case 'latest': default: /* translators: %s: WordPress version. */ return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) ); } } /** * Returns core update notification message. * * @since 2.3.0 * * @global string $pagenow The filename of the current screen. * @return void|false */ function update_nag() { global $pagenow; if ( is_multisite() && ! current_user_can( 'update_core' ) ) { return false; } if ( 'update-core.php' === $pagenow ) { return; } $cur = get_preferred_from_update_core(); if ( ! isset( $cur->response ) || 'upgrade' !== $cur->response ) { return false; } $version_url = sprintf( /* translators: %s: WordPress version. */ esc_url( __( 'https://wordpress.org/documentation/wordpress-version/version-%s/' ) ), sanitize_title( $cur->current ) ); if ( current_user_can( 'update_core' ) ) { $msg = sprintf( /* translators: 1: URL to WordPress release notes, 2: New WordPress version, 3: URL to network admin, 4: Accessibility text. */ __( '<a href="%1$s">WordPress %2$s</a> is available! <a href="%3$s" aria-label="%4$s">Please update now</a>.' ), $version_url, $cur->current, network_admin_url( 'update-core.php' ), esc_attr__( 'Please update WordPress now' ) ); } else { $msg = sprintf( /* translators: 1: URL to WordPress release notes, 2: New WordPress version. */ __( '<a href="%1$s">WordPress %2$s</a> is available! Please notify the site administrator.' ), $version_url, $cur->current ); } wp_admin_notice( $msg, array( 'type' => 'warning', 'additional_classes' => array( 'update-nag', 'inline' ), 'paragraph_wrap' => false, ) ); } /** * Displays WordPress version and active theme in the 'At a Glance' dashboard widget. * * @since 2.5.0 */ function update_right_now_message() { $theme_name = wp_get_theme(); if ( current_user_can( 'switch_themes' ) ) { $theme_name = sprintf( '<a href="themes.php">%1$s</a>', $theme_name ); } $msg = ''; if ( current_user_can( 'update_core' ) ) { $cur = get_preferred_from_update_core(); if ( isset( $cur->response ) && 'upgrade' === $cur->response ) { $msg .= sprintf( '<a href="%s" class="button" aria-describedby="wp-version">%s</a> ', network_admin_url( 'update-core.php' ), /* translators: %s: WordPress version number, or 'Latest' string. */ sprintf( __( 'Update to %s' ), $cur->current ? $cur->current : __( 'Latest' ) ) ); } } /* translators: 1: Version number, 2: Theme name. */ $content = __( 'WordPress %1$s running %2$s theme.' ); /** * Filters the text displayed in the 'At a Glance' dashboard widget. * * Prior to 3.8.0, the widget was named 'Right Now'. * * @since 4.4.0 * * @param string $content Default text. */ $content = apply_filters( 'update_right_now_text', $content ); $msg .= sprintf( '<span id="wp-version">' . $content . '</span>', get_bloginfo( 'version', 'display' ), $theme_name ); echo "<p id='wp-version-message'>$msg</p>"; } /** * Retrieves plugins with updates available. * * @since 2.9.0 * * @return object[] */ function get_plugin_updates() { $all_plugins = get_plugins(); $upgrade_plugins = array(); $current = get_site_transient( 'update_plugins' ); foreach ( (array) $all_plugins as $plugin_file => $plugin_data ) { if ( isset( $current->response[ $plugin_file ] ) ) { $upgrade_plugins[ $plugin_file ] = (object) $plugin_data; $upgrade_plugins[ $plugin_file ]->update = $current->response[ $plugin_file ]; } } return $upgrade_plugins; } /** * Adds a callback to display update information for plugins with updates available. * * @since 2.9.0 */ function wp_plugin_update_rows() { if ( ! current_user_can( 'update_plugins' ) ) { return; } $plugins = get_site_transient( 'update_plugins' ); if ( isset( $plugins->response ) && is_array( $plugins->response ) ) { $plugins = array_keys( $plugins->response ); foreach ( $plugins as $plugin_file ) { add_action( "after_plugin_row_{$plugin_file}", 'wp_plugin_update_row', 10, 2 ); } } } /** * Displays update information for a plugin. * * @since 2.3.0 * * @param string $file Plugin basename. * @param array $plugin_data Plugin information. * @return void|false */ function wp_plugin_update_row( $file, $plugin_data ) { $current = get_site_transient( 'update_plugins' ); if ( ! isset( $current->response[ $file ] ) ) { return false; } $response = $current->response[ $file ]; $plugins_allowedtags = array( 'a' => array( 'href' => array(), 'title' => array(), ), 'abbr' => array( 'title' => array() ), 'acronym' => array( 'title' => array() ), 'code' => array(), 'em' => array(), 'strong' => array(), ); $plugin_name = wp_kses( $plugin_data['Name'], $plugins_allowedtags ); $plugin_slug = isset( $response->slug ) ? $response->slug : $response->id; if ( isset( $response->slug ) ) { $details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $plugin_slug . '§ion=changelog' ); } elseif ( isset( $response->url ) ) { $details_url = $response->url; } else { $details_url = $plugin_data['PluginURI']; } $details_url = add_query_arg( array( 'TB_iframe' => 'true', 'width' => 600, 'height' => 800, ), $details_url ); /** @var WP_Plugins_List_Table $wp_list_table */ $wp_list_table = _get_list_table( 'WP_Plugins_List_Table', array( 'screen' => get_current_screen(), ) ); if ( is_network_admin() || ! is_multisite() ) { if ( is_network_admin() ) { $active_class = is_plugin_active_for_network( $file ) ? ' active' : ''; } else { $active_class = is_plugin_active( $file ) ? ' active' : ''; } $requires_php = isset( $response->requires_php ) ? $response->requires_php : null; $compatible_php = is_php_version_compatible( $requires_php ); $notice_type = $compatible_php ? 'notice-warning' : 'notice-error'; printf( '<tr class="plugin-update-tr%s" id="%s" data-slug="%s" data-plugin="%s">' . '<td colspan="%s" class="plugin-update colspanchange">' . '<div class="update-message notice inline %s notice-alt"><p>', $active_class, esc_attr( $plugin_slug . '-update' ), esc_attr( $plugin_slug ), esc_attr( $file ), esc_attr( $wp_list_table->get_column_count() ), $notice_type ); if ( ! current_user_can( 'update_plugins' ) ) { printf( /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.' ), $plugin_name, esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Plugin name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) ), esc_attr( $response->new_version ) ); } elseif ( empty( $response->package ) ) { printf( /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this plugin.</em>' ), $plugin_name, esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Plugin name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) ), esc_attr( $response->new_version ) ); } else { if ( $compatible_php ) { printf( /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number, 5: Update URL, 6: Additional link attributes. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ), $plugin_name, esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Plugin name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) ), esc_attr( $response->new_version ), wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $file, 'upgrade-plugin_' . $file ), sprintf( 'class="update-link" aria-label="%s"', /* translators: %s: Plugin name. */ esc_attr( sprintf( _x( 'Update %s now', 'plugin' ), $plugin_name ) ) ) ); } else { printf( /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number 5: URL to Update PHP page. */ __( 'There is a new version of %1$s available, but it does not work with your version of PHP. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s">learn more about updating PHP</a>.' ), $plugin_name, esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Plugin name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) ), esc_attr( $response->new_version ), esc_url( wp_get_update_php_url() ) ); wp_update_php_annotation( '<br><em>', '</em>' ); } } /** * Fires at the end of the update message container in each * row of the plugins list table. * * The dynamic portion of the hook name, `$file`, refers to the path * of the plugin's primary file relative to the plugins directory. * * @since 2.8.0 * * @param array $plugin_data An array of plugin metadata. See get_plugin_data() * and the {@see 'plugin_row_meta'} filter for the list * of possible values. * @param object $response { * An object of metadata about the available plugin update. * * @type string $id Plugin ID, e.g. `w.org/plugins/[plugin-name]`. * @type string $slug Plugin slug. * @type string $plugin Plugin basename. * @type string $new_version New plugin version. * @type string $url Plugin URL. * @type string $package Plugin update package URL. * @type string[] $icons An array of plugin icon URLs. * @type string[] $banners An array of plugin banner URLs. * @type string[] $banners_rtl An array of plugin RTL banner URLs. * @type string $requires The version of WordPress which the plugin requires. * @type string $tested The version of WordPress the plugin is tested against. * @type string $requires_php The version of PHP which the plugin requires. * } */ do_action( "in_plugin_update_message-{$file}", $plugin_data, $response ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores echo '</p></div></td></tr>'; } } /** * Retrieves themes with updates available. * * @since 2.9.0 * * @return WP_Theme[] */ function get_theme_updates() { $current = get_site_transient( 'update_themes' ); if ( ! isset( $current->response ) ) { return array(); } $update_themes = array(); foreach ( $current->response as $stylesheet => $data ) { $update_themes[ $stylesheet ] = wp_get_theme( $stylesheet ); $update_themes[ $stylesheet ]->update = $data; } return $update_themes; } /** * Adds a callback to display update information for themes with updates available. * * @since 3.1.0 */ function wp_theme_update_rows() { if ( ! current_user_can( 'update_themes' ) ) { return; } $themes = get_site_transient( 'update_themes' ); if ( isset( $themes->response ) && is_array( $themes->response ) ) { $themes = array_keys( $themes->response ); foreach ( $themes as $theme ) { add_action( "after_theme_row_{$theme}", 'wp_theme_update_row', 10, 2 ); } } } /** * Displays update information for a theme. * * @since 3.1.0 * * @param string $theme_key Theme stylesheet. * @param WP_Theme $theme Theme object. * @return void|false */ function wp_theme_update_row( $theme_key, $theme ) { $current = get_site_transient( 'update_themes' ); if ( ! isset( $current->response[ $theme_key ] ) ) { return false; } $response = $current->response[ $theme_key ]; $details_url = add_query_arg( array( 'TB_iframe' => 'true', 'width' => 1024, 'height' => 800, ), $current->response[ $theme_key ]['url'] ); /** @var WP_MS_Themes_List_Table $wp_list_table */ $wp_list_table = _get_list_table( 'WP_MS_Themes_List_Table' ); $active = $theme->is_allowed( 'network' ) ? ' active' : ''; $requires_wp = isset( $response['requires'] ) ? $response['requires'] : null; $requires_php = isset( $response['requires_php'] ) ? $response['requires_php'] : null; $compatible_wp = is_wp_version_compatible( $requires_wp ); $compatible_php = is_php_version_compatible( $requires_php ); printf( '<tr class="plugin-update-tr%s" id="%s" data-slug="%s">' . '<td colspan="%s" class="plugin-update colspanchange">' . '<div class="update-message notice inline notice-warning notice-alt"><p>', $active, esc_attr( $theme->get_stylesheet() . '-update' ), esc_attr( $theme->get_stylesheet() ), $wp_list_table->get_column_count() ); if ( $compatible_wp && $compatible_php ) { if ( ! current_user_can( 'update_themes' ) ) { printf( /* translators: 1: Theme name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.' ), $theme['Name'], esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Theme name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) ), $response['new_version'] ); } elseif ( empty( $response['package'] ) ) { printf( /* translators: 1: Theme name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>' ), $theme['Name'], esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Theme name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) ), $response['new_version'] ); } else { printf( /* translators: 1: Theme name, 2: Details URL, 3: Additional link attributes, 4: Version number, 5: Update URL, 6: Additional link attributes. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ), $theme['Name'], esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Theme name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) ), $response['new_version'], wp_nonce_url( self_admin_url( 'update.php?action=upgrade-theme&theme=' ) . $theme_key, 'upgrade-theme_' . $theme_key ), sprintf( 'class="update-link" aria-label="%s"', /* translators: %s: Theme name. */ esc_attr( sprintf( _x( 'Update %s now', 'theme' ), $theme['Name'] ) ) ) ); } } else { if ( ! $compatible_wp && ! $compatible_php ) { printf( /* translators: %s: Theme name. */ __( 'There is a new version of %s available, but it does not work with your versions of WordPress and PHP.' ), $theme['Name'] ); if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) { printf( /* translators: 1: URL to WordPress Updates screen, 2: URL to Update PHP page. */ ' ' . __( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.' ), self_admin_url( 'update-core.php' ), esc_url( wp_get_update_php_url() ) ); wp_update_php_annotation( '</p><p><em>', '</em>' ); } elseif ( current_user_can( 'update_core' ) ) { printf( /* translators: %s: URL to WordPress Updates screen. */ ' ' . __( '<a href="%s">Please update WordPress</a>.' ), self_admin_url( 'update-core.php' ) ); } elseif ( current_user_can( 'update_php' ) ) { printf( /* translators: %s: URL to Update PHP page. */ ' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ), esc_url( wp_get_update_php_url() ) ); wp_update_php_annotation( '</p><p><em>', '</em>' ); } } elseif ( ! $compatible_wp ) { printf( /* translators: %s: Theme name. */ __( 'There is a new version of %s available, but it does not work with your version of WordPress.' ), $theme['Name'] ); if ( current_user_can( 'update_core' ) ) { printf( /* translators: %s: URL to WordPress Updates screen. */ ' ' . __( '<a href="%s">Please update WordPress</a>.' ), self_admin_url( 'update-core.php' ) ); } } elseif ( ! $compatible_php ) { printf( /* translators: %s: Theme name. */ __( 'There is a new version of %s available, but it does not work with your version of PHP.' ), $theme['Name'] ); if ( current_user_can( 'update_php' ) ) { printf( /* translators: %s: URL to Update PHP page. */ ' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ), esc_url( wp_get_update_php_url() ) ); wp_update_php_annotation( '</p><p><em>', '</em>' ); } } } /** * Fires at the end of the update message container in each * row of the themes list table. * * The dynamic portion of the hook name, `$theme_key`, refers to * the theme slug as found in the WordPress.org themes repository. * * @since 3.1.0 * * @param WP_Theme $theme The WP_Theme object. * @param array $response { * An array of metadata about the available theme update. * * @type string $new_version New theme version. * @type string $url Theme URL. * @type string $package Theme update package URL. * } */ do_action( "in_theme_update_message-{$theme_key}", $theme, $response ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores echo '</p></div></td></tr>'; } /** * Displays maintenance nag HTML message. * * @since 2.7.0 * * @global int $upgrading * * @return void|false */ function maintenance_nag() { global $upgrading; $nag = isset( $upgrading ); if ( ! $nag ) { $failed = get_site_option( 'auto_core_update_failed' ); /* * If an update failed critically, we may have copied over version.php but not other files. * In that case, if the installation claims we're running the version we attempted, nag. * This is serious enough to err on the side of nagging. * * If we simply failed to update before we tried to copy any files, then assume things are * OK if they are now running the latest. * * This flag is cleared whenever a successful update occurs using Core_Upgrader. */ $comparison = ! empty( $failed['critical'] ) ? '>=' : '>'; if ( isset( $failed['attempted'] ) && version_compare( $failed['attempted'], wp_get_wp_version(), $comparison ) ) { $nag = true; } } if ( ! $nag ) { return false; } if ( current_user_can( 'update_core' ) ) { $msg = sprintf( /* translators: %s: URL to WordPress Updates screen. */ __( 'An automated WordPress update has failed to complete - <a href="%s">please attempt the update again now</a>.' ), 'update-core.php' ); } else { $msg = __( 'An automated WordPress update has failed to complete! Please notify the site administrator.' ); } wp_admin_notice( $msg, array( 'type' => 'warning', 'additional_classes' => array( 'update-nag', 'inline' ), 'paragraph_wrap' => false, ) ); } /** * Prints the JavaScript templates for update admin notices. * * @since 4.6.0 * * Template takes one argument with four values: * * param {object} data { * Arguments for admin notice. * * @type string id ID of the notice. * @type string className Class names for the notice. * @type string message The notice's message. * @type string type The type of update the notice is for. Either 'plugin' or 'theme'. * } */ function wp_print_admin_notice_templates() { ?> <script id="tmpl-wp-updates-admin-notice" type="text/html"> <div <# if ( data.id ) { #>id="{{ data.id }}"<# } #> class="notice {{ data.className }}"><p>{{{ data.message }}}</p></div> </script> <script id="tmpl-wp-bulk-updates-admin-notice" type="text/html"> <div id="{{ data.id }}" class="{{ data.className }} notice <# if ( data.errorMessage ) { #>notice-error<# } else { #>notice-success<# } #>"> <p> <# if ( data.successMessage ) { #> {{{ data.successMessage }}} <# } #> <# if ( data.errorMessage ) { #> <button class="button-link bulk-action-errors-collapsed" aria-expanded="false"> {{{ data.errorMessage }}} <span class="screen-reader-text"> <?php /* translators: Hidden accessibility text. */ _e( 'Show more details' ); ?> </span> <span class="toggle-indicator" aria-hidden="true"></span> </button> <# } #> </p> <# if ( data.errorMessages ) { #> <ul class="bulk-action-errors hidden"> <# _.each( data.errorMessages, function( errorMessage ) { #> <li>{{ errorMessage }}</li> <# } ); #> </ul> <# } #> </div> </script> <?php } /** * Prints the JavaScript templates for update and deletion rows in list tables. * * @since 4.6.0 * * The update template takes one argument with four values: * * param {object} data { * Arguments for the update row * * @type string slug Plugin slug. * @type string plugin Plugin base name. * @type string colspan The number of table columns this row spans. * @type string content The row content. * } * * The delete template takes one argument with four values: * * param {object} data { * Arguments for the update row * * @type string slug Plugin slug. * @type string plugin Plugin base name. * @type string name Plugin name. * @type string colspan The number of table columns this row spans. * } */ function wp_print_update_row_templates() { ?> <script id="tmpl-item-update-row" type="text/template"> <tr class="plugin-update-tr update" id="{{ data.slug }}-update" data-slug="{{ data.slug }}" <# if ( data.plugin ) { #>data-plugin="{{ data.plugin }}"<# } #>> <td colspan="{{ data.colspan }}" class="plugin-update colspanchange"> {{{ data.content }}} </td> </tr> </script> <script id="tmpl-item-deleted-row" type="text/template"> <tr class="plugin-deleted-tr inactive deleted" id="{{ data.slug }}-deleted" data-slug="{{ data.slug }}" <# if ( data.plugin ) { #>data-plugin="{{ data.plugin }}"<# } #>> <td colspan="{{ data.colspan }}" class="plugin-update colspanchange"> <# if ( data.plugin ) { #> <?php printf( /* translators: %s: Plugin name. */ _x( '%s was successfully deleted.', 'plugin' ), '<strong>{{{ data.name }}}</strong>' ); ?> <# } else { #> <?php printf( /* translators: %s: Theme name. */ _x( '%s was successfully deleted.', 'theme' ), '<strong>{{{ data.name }}}</strong>' ); ?> <# } #> </td> </tr> </script> <?php } /** * Displays a notice when the user is in recovery mode. * * @since 5.2.0 */ function wp_recovery_mode_nag() { if ( ! wp_is_recovery_mode() ) { return; } $url = wp_login_url(); $url = add_query_arg( 'action', WP_Recovery_Mode::EXIT_ACTION, $url ); $url = wp_nonce_url( $url, WP_Recovery_Mode::EXIT_ACTION ); $message = sprintf( /* translators: %s: Recovery Mode exit link. */ __( 'You are in recovery mode. This means there may be an error with a theme or plugin. To exit recovery mode, log out or use the Exit button. <a href="%s">Exit Recovery Mode</a>' ), esc_url( $url ) ); wp_admin_notice( $message, array( 'type' => 'info' ) ); } /** * Checks whether auto-updates are enabled. * * @since 5.5.0 * * @param string $type The type of update being checked: Either 'theme' or 'plugin'. * @return bool True if auto-updates are enabled for `$type`, false otherwise. */ function wp_is_auto_update_enabled_for_type( $type ) { if ( ! class_exists( 'WP_Automatic_Updater' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-automatic-updater.php'; } $updater = new WP_Automatic_Updater(); $enabled = ! $updater->is_disabled(); switch ( $type ) { case 'plugin': /** * Filters whether plugins auto-update is enabled. * * @since 5.5.0 * * @param bool $enabled True if plugins auto-update is enabled, false otherwise. */ return apply_filters( 'plugins_auto_update_enabled', $enabled ); case 'theme': /** * Filters whether themes auto-update is enabled. * * @since 5.5.0 * * @param bool $enabled True if themes auto-update is enabled, false otherwise. */ return apply_filters( 'themes_auto_update_enabled', $enabled ); } return false; } /** * Checks whether auto-updates are forced for an item. * * @since 5.6.0 * * @param string $type The type of update being checked: Either 'theme' or 'plugin'. * @param bool|null $update Whether to update. The value of null is internally used * to detect whether nothing has hooked into this filter. * @param object $item The update offer. * @return bool True if auto-updates are forced for `$item`, false otherwise. */ function wp_is_auto_update_forced_for_item( $type, $update, $item ) { /** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */ return apply_filters( "auto_update_{$type}", $update, $item ); } /** * Determines the appropriate auto-update message to be displayed. * * @since 5.5.0 * * @return string The update message to be shown. */ function wp_get_auto_update_message() { $next_update_time = wp_next_scheduled( 'wp_version_check' ); // Check if the event exists. if ( false === $next_update_time ) { $message = __( 'Automatic update not scheduled. There may be a problem with WP-Cron.' ); } else { $time_to_next_update = human_time_diff( (int) $next_update_time ); // See if cron is overdue. $overdue = ( time() - $next_update_time ) > 0; if ( $overdue ) { $message = sprintf( /* translators: %s: Duration that WP-Cron has been overdue. */ __( 'Automatic update overdue by %s. There may be a problem with WP-Cron.' ), $time_to_next_update ); } else { $message = sprintf( /* translators: %s: Time until the next update. */ __( 'Automatic update scheduled in %s.' ), $time_to_next_update ); } } return $message; } PK �Z�\�5�"� � % class-wp-post-comments-list-table.phpnu �[��� <?php /** * List Table API: WP_Post_Comments_List_Table class * * @package WordPress * @subpackage Administration * @since 4.4.0 */ /** * Core class used to implement displaying post comments in a list table. * * @since 3.1.0 * * @see WP_Comments_List_Table */ class WP_Post_Comments_List_Table extends WP_Comments_List_Table { /** * @return array */ protected function get_column_info() { return array( array( 'author' => __( 'Author' ), 'comment' => _x( 'Comment', 'column name' ), ), array(), array(), 'comment', ); } /** * @return array */ protected function get_table_classes() { $classes = parent::get_table_classes(); $classes[] = 'wp-list-table'; $classes[] = 'comments-box'; return $classes; } /** * @param bool $output_empty */ public function display( $output_empty = false ) { $singular = $this->_args['singular']; wp_nonce_field( 'fetch-list-' . get_class( $this ), '_ajax_fetch_list_nonce' ); ?> <table class="<?php echo implode( ' ', $this->get_table_classes() ); ?>" style="display:none;"> <tbody id="the-comment-list" <?php if ( $singular ) { echo " data-wp-lists='list:$singular'"; } ?> > <?php if ( ! $output_empty ) { $this->display_rows_or_placeholder(); } ?> </tbody> </table> <?php } /** * @param bool $comment_status * @return int */ public function get_per_page( $comment_status = false ) { return 10; } } PK �Z�\%��a a class-bulk-upgrader-skin.phpnu �[��� <?php /** * Upgrader API: Bulk_Upgrader_Skin class * * @package WordPress * @subpackage Upgrader * @since 4.6.0 */ /** * Generic Bulk Upgrader Skin for WordPress Upgrades. * * @since 3.0.0 * @since 4.6.0 Moved to its own file from wp-admin/includes/class-wp-upgrader-skins.php. * * @see WP_Upgrader_Skin */ class Bulk_Upgrader_Skin extends WP_Upgrader_Skin { /** * Whether the bulk update process has started. * * @since 3.0.0 * @var bool */ public $in_loop = false; /** * Stores an error message about the update. * * @since 3.0.0 * @var string|false */ public $error = false; /** * Constructor. * * Sets up the generic skin for the Bulk Upgrader classes. * * @since 3.0.0 * * @param array $args */ public function __construct( $args = array() ) { $defaults = array( 'url' => '', 'nonce' => '', ); $args = wp_parse_args( $args, $defaults ); parent::__construct( $args ); } /** * Sets up the strings used in the update process. * * @since 3.0.0 */ public function add_strings() { $this->upgrader->strings['skin_upgrade_start'] = __( 'The update process is starting. This process may take a while on some hosts, so please be patient.' ); /* translators: 1: Title of an update, 2: Error message. */ $this->upgrader->strings['skin_update_failed_error'] = __( 'An error occurred while updating %1$s: %2$s' ); /* translators: %s: Title of an update. */ $this->upgrader->strings['skin_update_failed'] = __( 'The update of %s failed.' ); /* translators: %s: Title of an update. */ $this->upgrader->strings['skin_update_successful'] = __( '%s updated successfully.' ); $this->upgrader->strings['skin_upgrade_end'] = __( 'All updates have been completed.' ); } /** * Displays a message about the update. * * @since 3.0.0 * @since 5.9.0 Renamed `$string` (a PHP reserved keyword) to `$feedback` for PHP 8 named parameter support. * * @param string $feedback Message data. * @param mixed ...$args Optional text replacements. */ public function feedback( $feedback, ...$args ) { if ( isset( $this->upgrader->strings[ $feedback ] ) ) { $feedback = $this->upgrader->strings[ $feedback ]; } if ( str_contains( $feedback, '%' ) ) { if ( $args ) { $args = array_map( 'strip_tags', $args ); $args = array_map( 'esc_html', $args ); $feedback = vsprintf( $feedback, $args ); } } if ( empty( $feedback ) ) { return; } if ( $this->in_loop ) { echo "$feedback<br />\n"; } else { echo "<p>$feedback</p>\n"; } } /** * Displays the header before the update process. * * @since 3.0.0 */ public function header() { // Nothing. This will be displayed within an iframe. } /** * Displays the footer following the update process. * * @since 3.0.0 */ public function footer() { // Nothing. This will be displayed within an iframe. } /** * Displays an error message about the update. * * @since 3.0.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 ) { if ( is_string( $errors ) && isset( $this->upgrader->strings[ $errors ] ) ) { $this->error = $this->upgrader->strings[ $errors ]; } if ( is_wp_error( $errors ) ) { $messages = array(); foreach ( $errors->get_error_messages() as $emessage ) { if ( $errors->get_error_data() && is_string( $errors->get_error_data() ) ) { $messages[] = $emessage . ' ' . esc_html( strip_tags( $errors->get_error_data() ) ); } else { $messages[] = $emessage; } } $this->error = implode( ', ', $messages ); } echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js( $this->upgrader->update_current ) . '\').hide();</script>'; } /** * Displays the header before the bulk update process. * * @since 3.0.0 */ public function bulk_header() { $this->feedback( 'skin_upgrade_start' ); } /** * Displays the footer following the bulk update process. * * @since 3.0.0 */ public function bulk_footer() { $this->feedback( 'skin_upgrade_end' ); } /** * Performs an action before a bulk update. * * @since 3.0.0 * * @param string $title */ public function before( $title = '' ) { $this->in_loop = true; printf( '<h2>' . $this->upgrader->strings['skin_before_update_header'] . ' <span class="spinner waiting-' . $this->upgrader->update_current . '"></span></h2>', $title, $this->upgrader->update_current, $this->upgrader->update_count ); echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js( $this->upgrader->update_current ) . '\').css("display", "inline-block");</script>'; // This progress messages div gets moved via JavaScript when clicking on "More details.". echo '<div class="update-messages hide-if-js" id="progress-' . esc_attr( $this->upgrader->update_current ) . '"><p>'; $this->flush_output(); } /** * Performs an action following a bulk update. * * @since 3.0.0 * * @param string $title */ public function after( $title = '' ) { echo '</p></div>'; if ( $this->error || ! $this->result ) { if ( $this->error ) { $after_error_message = sprintf( $this->upgrader->strings['skin_update_failed_error'], $title, '<strong>' . $this->error . '</strong>' ); } else { $after_error_message = sprintf( $this->upgrader->strings['skin_update_failed'], $title ); } wp_admin_notice( $after_error_message, array( 'additional_classes' => array( 'error' ), ) ); echo '<script type="text/javascript">jQuery(\'#progress-' . esc_js( $this->upgrader->update_current ) . '\').show();</script>'; } if ( $this->result && ! is_wp_error( $this->result ) ) { if ( ! $this->error ) { echo '<div class="updated js-update-details" data-update-details="progress-' . esc_attr( $this->upgrader->update_current ) . '">' . '<p>' . sprintf( $this->upgrader->strings['skin_update_successful'], $title ) . ' <button type="button" class="hide-if-no-js button-link js-update-details-toggle" aria-expanded="false">' . __( 'More details.' ) . '<span class="dashicons dashicons-arrow-down" aria-hidden="true"></span></button>' . '</p></div>'; } echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js( $this->upgrader->update_current ) . '\').hide();</script>'; } $this->reset(); $this->flush_output(); } /** * Resets the properties used in the update process. * * @since 3.0.0 */ public function reset() { $this->in_loop = false; $this->error = false; } /** * Flushes all output buffers. * * @since 3.0.0 */ public function flush_output() { wp_ob_end_flush_all(); flush(); } } PK �Z�\�8. class-wp-site-icon.phpnu �[��� <?php /** * Administration API: WP_Site_Icon class * * @package WordPress * @subpackage Administration * @since 4.3.0 */ /** * Core class used to implement site icon functionality. * * @since 4.3.0 */ #[AllowDynamicProperties] class WP_Site_Icon { /** * The minimum size of the site icon. * * @since 4.3.0 * @var int */ public $min_size = 512; /** * The size to which to crop the image so that we can display it in the UI nicely. * * @since 4.3.0 * @var int */ public $page_crop = 512; /** * List of site icon sizes. * * @since 4.3.0 * @var int[] */ public $site_icon_sizes = array( /* * Square, medium sized tiles for IE11+. * * See https://msdn.microsoft.com/library/dn455106(v=vs.85).aspx */ 270, /* * App icon for Android/Chrome. * * @link https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android * @link https://developer.chrome.com/multidevice/android/installtohomescreen */ 192, /* * App icons up to iPhone 6 Plus. * * See https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/MobileHIG/IconMatrix.html */ 180, // Our regular Favicon. 32, ); /** * Registers actions and filters. * * @since 4.3.0 */ public function __construct() { add_action( 'delete_attachment', array( $this, 'delete_attachment_data' ) ); add_filter( 'get_post_metadata', array( $this, 'get_post_metadata' ), 10, 4 ); } /** * Creates an attachment 'object'. * * @since 4.3.0 * @deprecated 6.5.0 * * @param string $cropped Cropped image URL. * @param int $parent_attachment_id Attachment ID of parent image. * @return array An array with attachment object data. */ public function create_attachment_object( $cropped, $parent_attachment_id ) { _deprecated_function( __METHOD__, '6.5.0', 'wp_copy_parent_attachment_properties()' ); $parent = get_post( $parent_attachment_id ); $parent_url = wp_get_attachment_url( $parent->ID ); $url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url ); $size = wp_getimagesize( $cropped ); $image_type = ( $size ) ? $size['mime'] : 'image/jpeg'; $attachment = array( 'ID' => $parent_attachment_id, 'post_title' => wp_basename( $cropped ), 'post_content' => $url, 'post_mime_type' => $image_type, 'guid' => $url, 'context' => 'site-icon', ); return $attachment; } /** * Inserts an attachment. * * @since 4.3.0 * * @param array $attachment An array with attachment object data. * @param string $file File path of the attached image. * @return int Attachment ID. */ public function insert_attachment( $attachment, $file ) { $attachment_id = wp_insert_attachment( $attachment, $file ); $metadata = wp_generate_attachment_metadata( $attachment_id, $file ); /** * Filters the site icon attachment metadata. * * @since 4.3.0 * * @see wp_generate_attachment_metadata() * * @param array $metadata Attachment metadata. */ $metadata = apply_filters( 'site_icon_attachment_metadata', $metadata ); wp_update_attachment_metadata( $attachment_id, $metadata ); return $attachment_id; } /** * Adds additional sizes to be made when creating the site icon images. * * @since 4.3.0 * * @param array[] $sizes Array of arrays containing information for additional sizes. * @return array[] Array of arrays containing additional image sizes. */ public function additional_sizes( $sizes = array() ) { $only_crop_sizes = array(); /** * Filters the different dimensions that a site icon is saved in. * * @since 4.3.0 * * @param int[] $site_icon_sizes Array of sizes available for the Site Icon. */ $this->site_icon_sizes = apply_filters( 'site_icon_image_sizes', $this->site_icon_sizes ); // Use a natural sort of numbers. natsort( $this->site_icon_sizes ); $this->site_icon_sizes = array_reverse( $this->site_icon_sizes ); // Ensure that we only resize the image into sizes that allow cropping. foreach ( $sizes as $name => $size_array ) { if ( isset( $size_array['crop'] ) ) { $only_crop_sizes[ $name ] = $size_array; } } foreach ( $this->site_icon_sizes as $size ) { if ( $size < $this->min_size ) { $only_crop_sizes[ 'site_icon-' . $size ] = array( 'width ' => $size, 'height' => $size, 'crop' => true, ); } } return $only_crop_sizes; } /** * Adds Site Icon sizes to the array of image sizes on demand. * * @since 4.3.0 * * @param string[] $sizes Array of image size names. * @return string[] Array of image size names. */ public function intermediate_image_sizes( $sizes = array() ) { /** This filter is documented in wp-admin/includes/class-wp-site-icon.php */ $this->site_icon_sizes = apply_filters( 'site_icon_image_sizes', $this->site_icon_sizes ); foreach ( $this->site_icon_sizes as $size ) { $sizes[] = 'site_icon-' . $size; } return $sizes; } /** * Deletes the Site Icon when the image file is deleted. * * @since 4.3.0 * * @param int $post_id Attachment ID. */ public function delete_attachment_data( $post_id ) { $site_icon_id = (int) get_option( 'site_icon' ); if ( $site_icon_id && $post_id === $site_icon_id ) { delete_option( 'site_icon' ); } } /** * Adds custom image sizes when meta data for an image is requested, that happens to be used as Site Icon. * * @since 4.3.0 * * @param null|array|string $value The value get_metadata() should return a single metadata value, or an * array of values. * @param int $post_id Post ID. * @param string $meta_key Meta key. * @param bool $single Whether to return only the first value of the specified `$meta_key`. * @return array|null|string The attachment metadata value, array of values, or null. */ public function get_post_metadata( $value, $post_id, $meta_key, $single ) { if ( $single && '_wp_attachment_backup_sizes' === $meta_key ) { $site_icon_id = (int) get_option( 'site_icon' ); if ( $post_id === $site_icon_id ) { add_filter( 'intermediate_image_sizes', array( $this, 'intermediate_image_sizes' ) ); } } return $value; } } PK �Z�\�6�� � class-wp-list-table.phpnu �[��� <?php /** * Administration API: WP_List_Table class * * @package WordPress * @subpackage List_Table * @since 3.1.0 */ /** * Base class for displaying a list of items in an ajaxified HTML table. * * @since 3.1.0 */ #[AllowDynamicProperties] class WP_List_Table { /** * The current list of items. * * @since 3.1.0 * @var array */ public $items; /** * Various information about the current table. * * @since 3.1.0 * @var array */ protected $_args; /** * Various information needed for displaying the pagination. * * @since 3.1.0 * @var array */ protected $_pagination_args = array(); /** * The current screen. * * @since 3.1.0 * @var WP_Screen */ protected $screen; /** * Cached bulk actions. * * @since 3.1.0 * @var array */ private $_actions; /** * Cached pagination output. * * @since 3.1.0 * @var string */ private $_pagination; /** * The view switcher modes. * * @since 4.1.0 * @var array */ protected $modes = array(); /** * Stores the value returned by ::get_column_info(). * * @since 4.1.0 * @var array|null */ protected $_column_headers; /** * {@internal Missing Summary} * * @var array */ protected $compat_fields = array( '_args', '_pagination_args', 'screen', '_actions', '_pagination' ); /** * {@internal Missing Summary} * * @var array */ protected $compat_methods = array( 'set_pagination_args', 'get_views', 'get_bulk_actions', 'bulk_actions', 'row_actions', 'months_dropdown', 'view_switcher', 'comments_bubble', 'get_items_per_page', 'pagination', 'get_sortable_columns', 'get_column_info', 'get_table_classes', 'display_tablenav', 'extra_tablenav', 'single_row_columns', ); /** * Constructor. * * The child class should call this constructor from its own constructor to override * the default $args. * * @since 3.1.0 * * @param array|string $args { * Array or string of arguments. * * @type string $plural Plural value used for labels and the objects being listed. * This affects things such as CSS class-names and nonces used * in the list table, e.g. 'posts'. Default empty. * @type string $singular Singular label for an object being listed, e.g. 'post'. * Default empty * @type bool $ajax Whether the list table supports Ajax. This includes loading * and sorting data, for example. If true, the class will call * the _js_vars() method in the footer to provide variables * to any scripts handling Ajax events. Default false. * @type string $screen String containing the hook name used to determine the current * screen. If left null, the current screen will be automatically set. * Default null. * } */ public function __construct( $args = array() ) { $args = wp_parse_args( $args, array( 'plural' => '', 'singular' => '', 'ajax' => false, 'screen' => null, ) ); $this->screen = convert_to_screen( $args['screen'] ); add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 ); if ( ! $args['plural'] ) { $args['plural'] = $this->screen->base; } $args['plural'] = sanitize_key( $args['plural'] ); $args['singular'] = sanitize_key( $args['singular'] ); $this->_args = $args; if ( $args['ajax'] ) { // wp_enqueue_script( 'list-table' ); add_action( 'admin_footer', array( $this, '_js_vars' ) ); } if ( empty( $this->modes ) ) { $this->modes = array( 'list' => __( 'Compact view' ), 'excerpt' => __( 'Extended view' ), ); } } /** * Makes private properties readable for backward compatibility. * * @since 4.0.0 * @since 6.4.0 Getting a dynamic property is deprecated. * * @param string $name Property to get. * @return mixed Property. */ public function __get( $name ) { if ( in_array( $name, $this->compat_fields, true ) ) { return $this->$name; } wp_trigger_error( __METHOD__, "The property `{$name}` is not declared. Getting a dynamic property is " . 'deprecated since version 6.4.0! Instead, declare the property on the class.', E_USER_DEPRECATED ); return null; } /** * Makes private properties settable for backward compatibility. * * @since 4.0.0 * @since 6.4.0 Setting a dynamic property is deprecated. * * @param string $name Property to check if set. * @param mixed $value Property value. */ public function __set( $name, $value ) { if ( in_array( $name, $this->compat_fields, true ) ) { $this->$name = $value; return; } wp_trigger_error( __METHOD__, "The property `{$name}` is not declared. Setting a dynamic property is " . 'deprecated since version 6.4.0! Instead, declare the property on the class.', E_USER_DEPRECATED ); } /** * Makes private properties checkable for backward compatibility. * * @since 4.0.0 * @since 6.4.0 Checking a dynamic property is deprecated. * * @param string $name Property to check if set. * @return bool Whether the property is a back-compat property and it is set. */ public function __isset( $name ) { if ( in_array( $name, $this->compat_fields, true ) ) { return isset( $this->$name ); } wp_trigger_error( __METHOD__, "The property `{$name}` is not declared. Checking `isset()` on a dynamic property " . 'is deprecated since version 6.4.0! Instead, declare the property on the class.', E_USER_DEPRECATED ); return false; } /** * Makes private properties un-settable for backward compatibility. * * @since 4.0.0 * @since 6.4.0 Unsetting a dynamic property is deprecated. * * @param string $name Property to unset. */ public function __unset( $name ) { if ( in_array( $name, $this->compat_fields, true ) ) { unset( $this->$name ); return; } wp_trigger_error( __METHOD__, "A property `{$name}` is not declared. Unsetting a dynamic property is " . 'deprecated since version 6.4.0! Instead, declare the property on the class.', E_USER_DEPRECATED ); } /** * Makes private/protected methods readable for backward compatibility. * * @since 4.0.0 * * @param string $name Method to call. * @param array $arguments Arguments to pass when calling. * @return mixed|bool Return value of the callback, false otherwise. */ public function __call( $name, $arguments ) { if ( in_array( $name, $this->compat_methods, true ) ) { return $this->$name( ...$arguments ); } return false; } /** * Checks the current user's permissions * * @since 3.1.0 * @abstract */ public function ajax_user_can() { die( 'function WP_List_Table::ajax_user_can() must be overridden in a subclass.' ); } /** * Prepares the list of items for displaying. * * @uses WP_List_Table::set_pagination_args() * * @since 3.1.0 * @abstract */ public function prepare_items() { die( 'function WP_List_Table::prepare_items() must be overridden in a subclass.' ); } /** * Sets all the necessary pagination arguments. * * @since 3.1.0 * * @param array|string $args Array or string of arguments with information about the pagination. */ protected function set_pagination_args( $args ) { $args = wp_parse_args( $args, array( 'total_items' => 0, 'total_pages' => 0, 'per_page' => 0, ) ); if ( ! $args['total_pages'] && $args['per_page'] > 0 ) { $args['total_pages'] = (int) ceil( $args['total_items'] / $args['per_page'] ); } // Redirect if page number is invalid and headers are not already sent. if ( ! headers_sent() && ! wp_doing_ajax() && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) { wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) ); exit; } $this->_pagination_args = $args; } /** * Access the pagination args. * * @since 3.1.0 * * @param string $key Pagination argument to retrieve. Common values include 'total_items', * 'total_pages', 'per_page', or 'infinite_scroll'. * @return int Number of items that correspond to the given pagination argument. */ public function get_pagination_arg( $key ) { if ( 'page' === $key ) { return $this->get_pagenum(); } if ( isset( $this->_pagination_args[ $key ] ) ) { return $this->_pagination_args[ $key ]; } return 0; } /** * Determines whether the table has items to display or not * * @since 3.1.0 * * @return bool */ public function has_items() { return ! empty( $this->items ); } /** * Message to be displayed when there are no items * * @since 3.1.0 */ public function no_items() { _e( 'No items found.' ); } /** * Displays the search box. * * @since 3.1.0 * * @param string $text The 'submit' button label. * @param string $input_id ID attribute value for the search input field. */ public function search_box( $text, $input_id ) { if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) { return; } $input_id = $input_id . '-search-input'; if ( ! empty( $_REQUEST['orderby'] ) ) { if ( is_array( $_REQUEST['orderby'] ) ) { foreach ( $_REQUEST['orderby'] as $key => $value ) { echo '<input type="hidden" name="orderby[' . esc_attr( $key ) . ']" value="' . esc_attr( $value ) . '" />'; } } else { echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />'; } } if ( ! empty( $_REQUEST['order'] ) ) { echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />'; } if ( ! empty( $_REQUEST['post_mime_type'] ) ) { echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />'; } if ( ! empty( $_REQUEST['detached'] ) ) { echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />'; } ?> <p class="search-box"> <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label> <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" /> <?php submit_button( $text, '', '', false, array( 'id' => 'search-submit' ) ); ?> </p> <?php } /** * Generates views links. * * @since 6.1.0 * * @param array $link_data { * An array of link data. * * @type string $url The link URL. * @type string $label The link label. * @type bool $current Optional. Whether this is the currently selected view. * } * @return string[] An array of link markup. Keys match the `$link_data` input array. */ protected function get_views_links( $link_data = array() ) { if ( ! is_array( $link_data ) ) { _doing_it_wrong( __METHOD__, sprintf( /* translators: %s: The $link_data argument. */ __( 'The %s argument must be an array.' ), '<code>$link_data</code>' ), '6.1.0' ); return array( '' ); } $views_links = array(); foreach ( $link_data as $view => $link ) { if ( empty( $link['url'] ) || ! is_string( $link['url'] ) || '' === trim( $link['url'] ) ) { _doing_it_wrong( __METHOD__, sprintf( /* translators: %1$s: The argument name. %2$s: The view name. */ __( 'The %1$s argument must be a non-empty string for %2$s.' ), '<code>url</code>', '<code>' . esc_html( $view ) . '</code>' ), '6.1.0' ); continue; } if ( empty( $link['label'] ) || ! is_string( $link['label'] ) || '' === trim( $link['label'] ) ) { _doing_it_wrong( __METHOD__, sprintf( /* translators: %1$s: The argument name. %2$s: The view name. */ __( 'The %1$s argument must be a non-empty string for %2$s.' ), '<code>label</code>', '<code>' . esc_html( $view ) . '</code>' ), '6.1.0' ); continue; } $views_links[ $view ] = sprintf( '<a href="%s"%s>%s</a>', esc_url( $link['url'] ), isset( $link['current'] ) && true === $link['current'] ? ' class="current" aria-current="page"' : '', $link['label'] ); } return $views_links; } /** * Gets the list of views available on this table. * * The format is an associative array: * - `'id' => 'link'` * * @since 3.1.0 * * @return array */ protected function get_views() { return array(); } /** * Displays the list of views available on this table. * * @since 3.1.0 */ public function views() { $views = $this->get_views(); /** * Filters the list of available list table views. * * The dynamic portion of the hook name, `$this->screen->id`, refers * to the ID of the current screen. * * @since 3.1.0 * * @param string[] $views An array of available list table views. */ $views = apply_filters( "views_{$this->screen->id}", $views ); if ( empty( $views ) ) { return; } $this->screen->render_screen_reader_content( 'heading_views' ); echo "<ul class='subsubsub'>\n"; foreach ( $views as $class => $view ) { $views[ $class ] = "\t<li class='$class'>$view"; } echo implode( " |</li>\n", $views ) . "</li>\n"; echo '</ul>'; } /** * Retrieves the list of bulk actions available for this table. * * The format is an associative array where each element represents either a top level option value and label, or * an array representing an optgroup and its options. * * For a standard option, the array element key is the field value and the array element value is the field label. * * For an optgroup, the array element key is the label and the array element value is an associative array of * options as above. * * Example: * * [ * 'edit' => 'Edit', * 'delete' => 'Delete', * 'Change State' => [ * 'feature' => 'Featured', * 'sale' => 'On Sale', * ] * ] * * @since 3.1.0 * @since 5.6.0 A bulk action can now contain an array of options in order to create an optgroup. * * @return array */ protected function get_bulk_actions() { return array(); } /** * Displays the bulk actions dropdown. * * @since 3.1.0 * * @param string $which The location of the bulk actions: Either 'top' or 'bottom'. * This is designated as optional for backward compatibility. */ protected function bulk_actions( $which = '' ) { if ( is_null( $this->_actions ) ) { $this->_actions = $this->get_bulk_actions(); /** * Filters the items in the bulk actions menu of the list table. * * The dynamic portion of the hook name, `$this->screen->id`, refers * to the ID of the current screen. * * @since 3.1.0 * @since 5.6.0 A bulk action can now contain an array of options in order to create an optgroup. * * @param array $actions An array of the available bulk actions. */ $this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores $two = ''; } else { $two = '2'; } if ( empty( $this->_actions ) ) { return; } echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Select bulk action' ) . '</label>'; echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n"; echo '<option value="-1">' . __( 'Bulk actions' ) . "</option>\n"; foreach ( $this->_actions as $key => $value ) { if ( is_array( $value ) ) { echo "\t" . '<optgroup label="' . esc_attr( $key ) . '">' . "\n"; foreach ( $value as $name => $title ) { $class = ( 'edit' === $name ) ? ' class="hide-if-no-js"' : ''; echo "\t\t" . '<option value="' . esc_attr( $name ) . '"' . $class . '>' . $title . "</option>\n"; } echo "\t" . "</optgroup>\n"; } else { $class = ( 'edit' === $key ) ? ' class="hide-if-no-js"' : ''; echo "\t" . '<option value="' . esc_attr( $key ) . '"' . $class . '>' . $value . "</option>\n"; } } echo "</select>\n"; submit_button( __( 'Apply' ), 'action', 'bulk_action', false, array( 'id' => "doaction$two" ) ); echo "\n"; } /** * Gets the current action selected from the bulk actions dropdown. * * @since 3.1.0 * * @return string|false The action name. False if no action was selected. */ public function current_action() { if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) ) { return false; } if ( isset( $_REQUEST['action'] ) && '-1' !== $_REQUEST['action'] ) { return $_REQUEST['action']; } return false; } /** * Generates the required HTML for a list of row action links. * * @since 3.1.0 * * @param string[] $actions An array of action links. * @param bool $always_visible Whether the actions should be always visible. * @return string The HTML for the row actions. */ protected function row_actions( $actions, $always_visible = false ) { $action_count = count( $actions ); if ( ! $action_count ) { return ''; } $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; $separator = ( $i < $action_count ) ? ' | ' : ''; $output .= "<span class='$action'>{$link}{$separator}</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; } /** * Displays a dropdown for filtering items in the list table by month. * * @since 3.1.0 * * @global wpdb $wpdb WordPress database abstraction object. * @global WP_Locale $wp_locale WordPress date and time locale object. * * @param string $post_type The post type. */ protected function months_dropdown( $post_type ) { global $wpdb, $wp_locale; /** * Filters whether to remove the 'Months' drop-down from the post list table. * * @since 4.2.0 * * @param bool $disable Whether to disable the drop-down. Default false. * @param string $post_type The post type. */ if ( apply_filters( 'disable_months_dropdown', false, $post_type ) ) { return; } /** * Filters whether to short-circuit performing the months dropdown query. * * @since 5.7.0 * * @param object[]|false $months 'Months' drop-down results. Default false. * @param string $post_type The post type. */ $months = apply_filters( 'pre_months_dropdown_query', false, $post_type ); if ( ! is_array( $months ) ) { $extra_checks = "AND post_status != 'auto-draft'"; if ( ! isset( $_GET['post_status'] ) || 'trash' !== $_GET['post_status'] ) { $extra_checks .= " AND post_status != 'trash'"; } elseif ( isset( $_GET['post_status'] ) ) { $extra_checks = $wpdb->prepare( ' AND post_status = %s', $_GET['post_status'] ); } $months = $wpdb->get_results( $wpdb->prepare( "SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month FROM $wpdb->posts WHERE post_type = %s $extra_checks ORDER BY post_date DESC", $post_type ) ); } /** * Filters the 'Months' drop-down results. * * @since 3.7.0 * * @param object[] $months Array of the months drop-down query results. * @param string $post_type The post type. */ $months = apply_filters( 'months_dropdown_results', $months, $post_type ); $month_count = count( $months ); if ( ! $month_count || ( 1 === $month_count && 0 === (int) $months[0]->month ) ) { return; } $selected_month = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0; ?> <label for="filter-by-date" class="screen-reader-text"><?php echo get_post_type_object( $post_type )->labels->filter_by_date; ?></label> <select name="m" id="filter-by-date"> <option<?php selected( $selected_month, 0 ); ?> value="0"><?php _e( 'All dates' ); ?></option> <?php foreach ( $months as $arc_row ) { if ( 0 === (int) $arc_row->year ) { continue; } $month = zeroise( $arc_row->month, 2 ); $year = $arc_row->year; printf( "<option %s value='%s'>%s</option>\n", selected( $selected_month, $year . $month, false ), esc_attr( $year . $month ), /* translators: 1: Month name, 2: 4-digit year. */ esc_html( sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year ) ) ); } ?> </select> <?php } /** * Displays a view switcher. * * @since 3.1.0 * * @param string $current_mode */ protected function view_switcher( $current_mode ) { ?> <input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" /> <div class="view-switch"> <?php foreach ( $this->modes as $mode => $title ) { $classes = array( 'view-' . $mode ); $aria_current = ''; if ( $current_mode === $mode ) { $classes[] = 'current'; $aria_current = ' aria-current="page"'; } printf( "<a href='%s' class='%s' id='view-switch-$mode'$aria_current>" . "<span class='screen-reader-text'>%s</span>" . "</a>\n", esc_url( remove_query_arg( 'attachment-filter', add_query_arg( 'mode', $mode ) ) ), implode( ' ', $classes ), $title ); } ?> </div> <?php } /** * Displays a comment count bubble. * * @since 3.1.0 * * @param int $post_id The post ID. * @param int $pending_comments Number of pending comments. */ protected function comments_bubble( $post_id, $pending_comments ) { $post_object = get_post( $post_id ); $edit_post_cap = $post_object ? 'edit_post' : 'edit_posts'; if ( ! current_user_can( $edit_post_cap, $post_id ) && ( post_password_required( $post_id ) || ! current_user_can( 'read_post', $post_id ) ) ) { // The user has no access to the post and thus cannot see the comments. return false; } $approved_comments = get_comments_number(); $approved_comments_number = number_format_i18n( $approved_comments ); $pending_comments_number = number_format_i18n( $pending_comments ); $approved_only_phrase = sprintf( /* translators: %s: Number of comments. */ _n( '%s comment', '%s comments', $approved_comments ), $approved_comments_number ); $approved_phrase = sprintf( /* translators: %s: Number of comments. */ _n( '%s approved comment', '%s approved comments', $approved_comments ), $approved_comments_number ); $pending_phrase = sprintf( /* translators: %s: Number of comments. */ _n( '%s pending comment', '%s pending comments', $pending_comments ), $pending_comments_number ); if ( ! $approved_comments && ! $pending_comments ) { // No comments at all. printf( '<span aria-hidden="true">—</span>' . '<span class="screen-reader-text">%s</span>', __( 'No comments' ) ); } elseif ( $approved_comments && 'trash' === get_post_status( $post_id ) ) { // Don't link the comment bubble for a trashed post. printf( '<span class="post-com-count post-com-count-approved">' . '<span class="comment-count-approved" aria-hidden="true">%s</span>' . '<span class="screen-reader-text">%s</span>' . '</span>', $approved_comments_number, $pending_comments ? $approved_phrase : $approved_only_phrase ); } elseif ( $approved_comments ) { // Link the comment bubble to approved comments. printf( '<a href="%s" class="post-com-count post-com-count-approved">' . '<span class="comment-count-approved" aria-hidden="true">%s</span>' . '<span class="screen-reader-text">%s</span>' . '</a>', esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'approved', ), admin_url( 'edit-comments.php' ) ) ), $approved_comments_number, $pending_comments ? $approved_phrase : $approved_only_phrase ); } else { // Don't link the comment bubble when there are no approved comments. printf( '<span class="post-com-count post-com-count-no-comments">' . '<span class="comment-count comment-count-no-comments" aria-hidden="true">%s</span>' . '<span class="screen-reader-text">%s</span>' . '</span>', $approved_comments_number, $pending_comments ? /* translators: Hidden accessibility text. */ __( 'No approved comments' ) : /* translators: Hidden accessibility text. */ __( 'No comments' ) ); } if ( $pending_comments ) { printf( '<a href="%s" class="post-com-count post-com-count-pending">' . '<span class="comment-count-pending" aria-hidden="true">%s</span>' . '<span class="screen-reader-text">%s</span>' . '</a>', esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'moderated', ), admin_url( 'edit-comments.php' ) ) ), $pending_comments_number, $pending_phrase ); } else { printf( '<span class="post-com-count post-com-count-pending post-com-count-no-pending">' . '<span class="comment-count comment-count-no-pending" aria-hidden="true">%s</span>' . '<span class="screen-reader-text">%s</span>' . '</span>', $pending_comments_number, $approved_comments ? /* translators: Hidden accessibility text. */ __( 'No pending comments' ) : /* translators: Hidden accessibility text. */ __( 'No comments' ) ); } } /** * Gets the current page number. * * @since 3.1.0 * * @return int */ public function get_pagenum() { $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0; if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] ) { $pagenum = $this->_pagination_args['total_pages']; } return max( 1, $pagenum ); } /** * Gets the number of items to display on a single page. * * @since 3.1.0 * * @param string $option User option name. * @param int $default_value Optional. The number of items to display. Default 20. * @return int */ protected function get_items_per_page( $option, $default_value = 20 ) { $per_page = (int) get_user_option( $option ); if ( empty( $per_page ) || $per_page < 1 ) { $per_page = $default_value; } /** * Filters the number of items to be displayed on each page of the list table. * * The dynamic hook name, `$option`, refers to the `per_page` option depending * on the type of list table in use. Possible filter names include: * * - `edit_comments_per_page` * - `sites_network_per_page` * - `site_themes_network_per_page` * - `themes_network_per_page` * - `users_network_per_page` * - `edit_post_per_page` * - `edit_page_per_page` * - `edit_{$post_type}_per_page` * - `edit_post_tag_per_page` * - `edit_category_per_page` * - `edit_{$taxonomy}_per_page` * - `site_users_network_per_page` * - `users_per_page` * * @since 2.9.0 * * @param int $per_page Number of items to be displayed. Default 20. */ return (int) apply_filters( "{$option}", $per_page ); } /** * Displays the pagination. * * @since 3.1.0 * * @param string $which The location of the pagination: Either 'top' or 'bottom'. */ protected function pagination( $which ) { if ( empty( $this->_pagination_args['total_items'] ) ) { return; } $total_items = $this->_pagination_args['total_items']; $total_pages = $this->_pagination_args['total_pages']; $infinite_scroll = false; if ( isset( $this->_pagination_args['infinite_scroll'] ) ) { $infinite_scroll = $this->_pagination_args['infinite_scroll']; } if ( 'top' === $which && $total_pages > 1 ) { $this->screen->render_screen_reader_content( 'heading_pagination' ); } $output = '<span class="displaying-num">' . sprintf( /* translators: %s: Number of items. */ _n( '%s item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>'; $current = $this->get_pagenum(); $removable_query_args = wp_removable_query_args(); $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); $current_url = remove_query_arg( $removable_query_args, $current_url ); $page_links = array(); $total_pages_before = '<span class="paging-input">'; $total_pages_after = '</span></span>'; $disable_first = false; $disable_last = false; $disable_prev = false; $disable_next = false; if ( 1 === $current ) { $disable_first = true; $disable_prev = true; } if ( $total_pages === $current ) { $disable_last = true; $disable_next = true; } if ( $disable_first ) { $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">«</span>'; } else { $page_links[] = sprintf( "<a class='first-page button' href='%s'>" . "<span class='screen-reader-text'>%s</span>" . "<span aria-hidden='true'>%s</span>" . '</a>', esc_url( remove_query_arg( 'paged', $current_url ) ), /* translators: Hidden accessibility text. */ __( 'First page' ), '«' ); } if ( $disable_prev ) { $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">‹</span>'; } else { $page_links[] = sprintf( "<a class='prev-page button' href='%s'>" . "<span class='screen-reader-text'>%s</span>" . "<span aria-hidden='true'>%s</span>" . '</a>', esc_url( add_query_arg( 'paged', max( 1, $current - 1 ), $current_url ) ), /* translators: Hidden accessibility text. */ __( 'Previous page' ), '‹' ); } if ( 'bottom' === $which ) { $html_current_page = $current; $total_pages_before = sprintf( '<span class="screen-reader-text">%s</span>' . '<span id="table-paging" class="paging-input">' . '<span class="tablenav-paging-text">', /* translators: Hidden accessibility text. */ __( 'Current Page' ) ); } else { $html_current_page = sprintf( '<label for="current-page-selector" class="screen-reader-text">%s</label>' . "<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' />" . "<span class='tablenav-paging-text'>", /* translators: Hidden accessibility text. */ __( 'Current Page' ), $current, strlen( $total_pages ) ); } $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) ); $page_links[] = $total_pages_before . sprintf( /* translators: 1: Current page, 2: Total pages. */ _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after; if ( $disable_next ) { $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">›</span>'; } else { $page_links[] = sprintf( "<a class='next-page button' href='%s'>" . "<span class='screen-reader-text'>%s</span>" . "<span aria-hidden='true'>%s</span>" . '</a>', esc_url( add_query_arg( 'paged', min( $total_pages, $current + 1 ), $current_url ) ), /* translators: Hidden accessibility text. */ __( 'Next page' ), '›' ); } if ( $disable_last ) { $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">»</span>'; } else { $page_links[] = sprintf( "<a class='last-page button' href='%s'>" . "<span class='screen-reader-text'>%s</span>" . "<span aria-hidden='true'>%s</span>" . '</a>', esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ), /* translators: Hidden accessibility text. */ __( 'Last page' ), '»' ); } $pagination_links_class = 'pagination-links'; if ( ! empty( $infinite_scroll ) ) { $pagination_links_class .= ' hide-if-js'; } $output .= "\n<span class='$pagination_links_class'>" . implode( "\n", $page_links ) . '</span>'; if ( $total_pages ) { $page_class = $total_pages < 2 ? ' one-page' : ''; } else { $page_class = ' no-pages'; } $this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>"; echo $this->_pagination; } /** * Gets a list of columns. * * The format is: * - `'internal-name' => 'Title'` * * @since 3.1.0 * @abstract * * @return array */ public function get_columns() { die( 'function WP_List_Table::get_columns() must be overridden in a subclass.' ); } /** * Gets a list of sortable columns. * * The format is: * - `'internal-name' => 'orderby'` * - `'internal-name' => array( 'orderby', bool, 'abbr', 'orderby-text', 'initially-sorted-column-order' )` - * - `'internal-name' => array( 'orderby', 'asc' )` - The second element sets the initial sorting order. * - `'internal-name' => array( 'orderby', true )` - The second element makes the initial order descending. * * In the second format, passing true as second parameter will make the initial * sorting order be descending. Following parameters add a short column name to * be used as 'abbr' attribute, a translatable string for the current sorting, * and the initial order for the initial sorted column, 'asc' or 'desc' (default: false). * * @since 3.1.0 * @since 6.3.0 Added 'abbr', 'orderby-text' and 'initially-sorted-column-order'. * * @return array */ protected function get_sortable_columns() { return array(); } /** * Gets the name of the default primary column. * * @since 4.3.0 * * @return string Name of the default primary column, in this case, an empty string. */ protected function get_default_primary_column_name() { $columns = $this->get_columns(); $column = ''; if ( empty( $columns ) ) { return $column; } /* * We need a primary defined so responsive views show something, * so let's fall back to the first non-checkbox column. */ foreach ( $columns as $col => $column_name ) { if ( 'cb' === $col ) { continue; } $column = $col; break; } return $column; } /** * Gets the name of the primary column. * * Public wrapper for WP_List_Table::get_default_primary_column_name(). * * @since 4.4.0 * * @return string Name of the default primary column. */ public function get_primary_column() { return $this->get_primary_column_name(); } /** * Gets the name of the primary column. * * @since 4.3.0 * * @return string The name of the primary column. */ protected function get_primary_column_name() { $columns = get_column_headers( $this->screen ); $default = $this->get_default_primary_column_name(); /* * If the primary column doesn't exist, * fall back to the first non-checkbox column. */ if ( ! isset( $columns[ $default ] ) ) { $default = self::get_default_primary_column_name(); } /** * Filters the name of the primary column for the current list table. * * @since 4.3.0 * * @param string $default Column name default for the specific list table, e.g. 'name'. * @param string $context Screen ID for specific list table, e.g. 'plugins'. */ $column = apply_filters( 'list_table_primary_column', $default, $this->screen->id ); if ( empty( $column ) || ! isset( $columns[ $column ] ) ) { $column = $default; } return $column; } /** * Gets a list of all, hidden, and sortable columns, with filter applied. * * @since 3.1.0 * * @return array */ protected function get_column_info() { // $_column_headers is already set / cached. if ( isset( $this->_column_headers ) && is_array( $this->_column_headers ) ) { /* * Backward compatibility for `$_column_headers` format prior to WordPress 4.3. * * In WordPress 4.3 the primary column name was added as a fourth item in the * column headers property. This ensures the primary column name is included * in plugins setting the property directly in the three item format. */ if ( 4 === count( $this->_column_headers ) ) { return $this->_column_headers; } $column_headers = array( array(), array(), array(), $this->get_primary_column_name() ); foreach ( $this->_column_headers as $key => $value ) { $column_headers[ $key ] = $value; } $this->_column_headers = $column_headers; return $this->_column_headers; } $columns = get_column_headers( $this->screen ); $hidden = get_hidden_columns( $this->screen ); $sortable_columns = $this->get_sortable_columns(); /** * Filters the list table sortable columns for a specific screen. * * The dynamic portion of the hook name, `$this->screen->id`, refers * to the ID of the current screen. * * @since 3.1.0 * * @param array $sortable_columns An array of sortable columns. */ $_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns ); $sortable = array(); foreach ( $_sortable as $id => $data ) { if ( empty( $data ) ) { continue; } $data = (array) $data; // Descending initial sorting. if ( ! isset( $data[1] ) ) { $data[1] = false; } // Current sorting translatable string. if ( ! isset( $data[2] ) ) { $data[2] = ''; } // Initial view sorted column and asc/desc order, default: false. if ( ! isset( $data[3] ) ) { $data[3] = false; } // Initial order for the initial sorted column, default: false. if ( ! isset( $data[4] ) ) { $data[4] = false; } $sortable[ $id ] = $data; } $primary = $this->get_primary_column_name(); $this->_column_headers = array( $columns, $hidden, $sortable, $primary ); return $this->_column_headers; } /** * Returns the number of visible columns. * * @since 3.1.0 * * @return int */ public function get_column_count() { list ( $columns, $hidden ) = $this->get_column_info(); $hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) ); return count( $columns ) - count( $hidden ); } /** * Prints column headers, accounting for hidden and sortable columns. * * @since 3.1.0 * * @param bool $with_id Whether to set the ID attribute or not */ public function print_column_headers( $with_id = true ) { list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info(); $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); $current_url = remove_query_arg( 'paged', $current_url ); // When users click on a column header to sort by other columns. if ( isset( $_GET['orderby'] ) ) { $current_orderby = $_GET['orderby']; // In the initial view there's no orderby parameter. } else { $current_orderby = ''; } // Not in the initial view and descending order. if ( isset( $_GET['order'] ) && 'desc' === $_GET['order'] ) { $current_order = 'desc'; } else { // The initial view is not always 'asc', we'll take care of this below. $current_order = 'asc'; } if ( ! empty( $columns['cb'] ) ) { static $cb_counter = 1; $columns['cb'] = '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" /> <label for="cb-select-all-' . $cb_counter . '">' . '<span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Select All' ) . '</span>' . '</label>'; ++$cb_counter; } foreach ( $columns as $column_key => $column_display_name ) { $class = array( 'manage-column', "column-$column_key" ); $aria_sort_attr = ''; $abbr_attr = ''; $order_text = ''; if ( in_array( $column_key, $hidden, true ) ) { $class[] = 'hidden'; } if ( 'cb' === $column_key ) { $class[] = 'check-column'; } elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ), true ) ) { $class[] = 'num'; } if ( $column_key === $primary ) { $class[] = 'column-primary'; } if ( isset( $sortable[ $column_key ] ) ) { $orderby = isset( $sortable[ $column_key ][0] ) ? $sortable[ $column_key ][0] : ''; $desc_first = isset( $sortable[ $column_key ][1] ) ? $sortable[ $column_key ][1] : false; $abbr = isset( $sortable[ $column_key ][2] ) ? $sortable[ $column_key ][2] : ''; $orderby_text = isset( $sortable[ $column_key ][3] ) ? $sortable[ $column_key ][3] : ''; $initial_order = isset( $sortable[ $column_key ][4] ) ? $sortable[ $column_key ][4] : ''; /* * We're in the initial view and there's no $_GET['orderby'] then check if the * initial sorting information is set in the sortable columns and use that. */ if ( '' === $current_orderby && $initial_order ) { // Use the initially sorted column $orderby as current orderby. $current_orderby = $orderby; // Use the initially sorted column asc/desc order as initial order. $current_order = $initial_order; } /* * True in the initial view when an initial orderby is set via get_sortable_columns() * and true in the sorted views when the actual $_GET['orderby'] is equal to $orderby. */ if ( $current_orderby === $orderby ) { // The sorted column. The `aria-sort` attribute must be set only on the sorted column. if ( 'asc' === $current_order ) { $order = 'desc'; $aria_sort_attr = ' aria-sort="ascending"'; } else { $order = 'asc'; $aria_sort_attr = ' aria-sort="descending"'; } $class[] = 'sorted'; $class[] = $current_order; } else { // The other sortable columns. $order = strtolower( $desc_first ); if ( ! in_array( $order, array( 'desc', 'asc' ), true ) ) { $order = $desc_first ? 'desc' : 'asc'; } $class[] = 'sortable'; $class[] = 'desc' === $order ? 'asc' : 'desc'; /* translators: Hidden accessibility text. */ $asc_text = __( 'Sort ascending.' ); /* translators: Hidden accessibility text. */ $desc_text = __( 'Sort descending.' ); $order_text = 'asc' === $order ? $asc_text : $desc_text; } if ( '' !== $order_text ) { $order_text = ' <span class="screen-reader-text">' . $order_text . '</span>'; } // Print an 'abbr' attribute if a value is provided via get_sortable_columns(). $abbr_attr = $abbr ? ' abbr="' . esc_attr( $abbr ) . '"' : ''; $column_display_name = sprintf( '<a href="%1$s">' . '<span>%2$s</span>' . '<span class="sorting-indicators">' . '<span class="sorting-indicator asc" aria-hidden="true"></span>' . '<span class="sorting-indicator desc" aria-hidden="true"></span>' . '</span>' . '%3$s' . '</a>', esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ), $column_display_name, $order_text ); } $tag = ( 'cb' === $column_key ) ? 'td' : 'th'; $scope = ( 'th' === $tag ) ? 'scope="col"' : ''; $id = $with_id ? "id='$column_key'" : ''; $class_attr = "class='" . implode( ' ', $class ) . "'"; echo "<$tag $scope $id $class_attr $aria_sort_attr $abbr_attr>$column_display_name</$tag>"; } } /** * Print a table description with information about current sorting and order. * * For the table initial view, information about initial orderby and order * should be provided via get_sortable_columns(). * * @since 6.3.0 */ public function print_table_description() { list( $columns, $hidden, $sortable ) = $this->get_column_info(); if ( empty( $sortable ) ) { return; } // When users click on a column header to sort by other columns. if ( isset( $_GET['orderby'] ) ) { $current_orderby = $_GET['orderby']; // In the initial view there's no orderby parameter. } else { $current_orderby = ''; } // Not in the initial view and descending order. if ( isset( $_GET['order'] ) && 'desc' === $_GET['order'] ) { $current_order = 'desc'; } else { // The initial view is not always 'asc', we'll take care of this below. $current_order = 'asc'; } foreach ( array_keys( $columns ) as $column_key ) { if ( isset( $sortable[ $column_key ] ) ) { $orderby = isset( $sortable[ $column_key ][0] ) ? $sortable[ $column_key ][0] : ''; $desc_first = isset( $sortable[ $column_key ][1] ) ? $sortable[ $column_key ][1] : false; $abbr = isset( $sortable[ $column_key ][2] ) ? $sortable[ $column_key ][2] : ''; $orderby_text = isset( $sortable[ $column_key ][3] ) ? $sortable[ $column_key ][3] : ''; $initial_order = isset( $sortable[ $column_key ][4] ) ? $sortable[ $column_key ][4] : ''; if ( ! is_string( $orderby_text ) || '' === $orderby_text ) { return; } /* * We're in the initial view and there's no $_GET['orderby'] then check if the * initial sorting information is set in the sortable columns and use that. */ if ( '' === $current_orderby && $initial_order ) { // Use the initially sorted column $orderby as current orderby. $current_orderby = $orderby; // Use the initially sorted column asc/desc order as initial order. $current_order = $initial_order; } /* * True in the initial view when an initial orderby is set via get_sortable_columns() * and true in the sorted views when the actual $_GET['orderby'] is equal to $orderby. */ if ( $current_orderby === $orderby ) { /* translators: Hidden accessibility text. */ $asc_text = __( 'Ascending.' ); /* translators: Hidden accessibility text. */ $desc_text = __( 'Descending.' ); $order_text = 'asc' === $current_order ? $asc_text : $desc_text; echo '<caption class="screen-reader-text">' . $orderby_text . ' ' . $order_text . '</caption>'; return; } } } } /** * Displays the table. * * @since 3.1.0 */ public function display() { $singular = $this->_args['singular']; $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 $this->print_table_description(); ?> <thead> <tr> <?php $this->print_column_headers(); ?> </tr> </thead> <tbody id="the-list" <?php if ( $singular ) { echo " data-wp-lists='list:$singular'"; } ?> > <?php $this->display_rows_or_placeholder(); ?> </tbody> <tfoot> <tr> <?php $this->print_column_headers( false ); ?> </tr> </tfoot> </table> <?php $this->display_tablenav( 'bottom' ); } /** * Gets a list of CSS classes for the WP_List_Table table tag. * * @since 3.1.0 * * @return string[] Array of CSS classes for the table tag. */ protected function get_table_classes() { $mode = get_user_setting( 'posts_list_mode', 'list' ); $mode_class = esc_attr( 'table-view-' . $mode ); return array( 'widefat', 'fixed', 'striped', $mode_class, $this->_args['plural'] ); } /** * Generates the table navigation above or below the table * * @since 3.1.0 * @param string $which The location of the navigation: Either 'top' or 'bottom'. */ protected function display_tablenav( $which ) { if ( 'bottom' === $which && ! $this->has_items() ) { return; } if ( 'top' === $which ) { wp_nonce_field( 'bulk-' . $this->_args['plural'] ); } ?> <div class="tablenav <?php echo esc_attr( $which ); ?>"> <?php if ( $this->has_items() ) : ?> <div class="alignleft actions bulkactions"> <?php $this->bulk_actions( $which ); ?> </div> <?php endif; $this->extra_tablenav( $which ); $this->pagination( $which ); ?> <br class="clear" /> </div> <?php } /** * Displays extra controls between bulk actions and pagination. * * @since 3.1.0 * * @param string $which */ protected function extra_tablenav( $which ) {} /** * Generates the tbody element for the list table. * * @since 3.1.0 */ public function display_rows_or_placeholder() { if ( $this->has_items() ) { $this->display_rows(); } else { echo '<tr class="no-items"><td class="colspanchange" colspan="' . $this->get_column_count() . '">'; $this->no_items(); echo '</td></tr>'; } } /** * Generates the list table rows. * * @since 3.1.0 */ public function display_rows() { foreach ( $this->items as $item ) { $this->single_row( $item ); } } /** * Generates content for a single row of the table. * * @since 3.1.0 * * @param object|array $item The current item */ public function single_row( $item ) { echo '<tr>'; $this->single_row_columns( $item ); echo '</tr>'; } /** * @param object|array $item * @param string $column_name */ protected function column_default( $item, $column_name ) {} /** * @param object|array $item */ protected function column_cb( $item ) {} /** * Generates the columns for a single row of the table. * * @since 3.1.0 * * @param object|array $item The current item. */ protected function single_row_columns( $item ) { list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info(); foreach ( $columns as $column_name => $column_display_name ) { $classes = "$column_name column-$column_name"; if ( $primary === $column_name ) { $classes .= ' has-row-actions column-primary'; } if ( in_array( $column_name, $hidden, true ) ) { $classes .= ' hidden'; } /* * Comments column uses HTML in the display name with screen reader text. * Strip tags to get closer to a user-friendly string. */ $data = 'data-colname="' . esc_attr( wp_strip_all_tags( $column_display_name ) ) . '"'; $attributes = "class='$classes' $data"; if ( 'cb' === $column_name ) { echo '<th scope="row" class="check-column">'; echo $this->column_cb( $item ); echo '</th>'; } elseif ( method_exists( $this, '_column_' . $column_name ) ) { echo call_user_func( array( $this, '_column_' . $column_name ), $item, $classes, $data, $primary ); } elseif ( method_exists( $this, 'column_' . $column_name ) ) { echo "<td $attributes>"; echo call_user_func( array( $this, 'column_' . $column_name ), $item ); echo $this->handle_row_actions( $item, $column_name, $primary ); echo '</td>'; } else { echo "<td $attributes>"; echo $this->column_default( $item, $column_name ); echo $this->handle_row_actions( $item, $column_name, $primary ); echo '</td>'; } } } /** * Generates and display row actions links for the list table. * * @since 4.3.0 * * @param object|array $item The item being acted upon. * @param string $column_name Current column name. * @param string $primary Primary column name. * @return string The row actions HTML, or an empty string * if the current column is not the primary column. */ protected function handle_row_actions( $item, $column_name, $primary ) { return $column_name === $primary ? '<button type="button" class="toggle-row"><span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Show more details' ) . '</span></button>' : ''; } /** * Handles an incoming ajax request (called from admin-ajax.php) * * @since 3.1.0 */ public function ajax_response() { $this->prepare_items(); ob_start(); if ( ! empty( $_REQUEST['no_placeholder'] ) ) { $this->display_rows(); } else { $this->display_rows_or_placeholder(); } $rows = ob_get_clean(); $response = array( 'rows' => $rows ); if ( isset( $this->_pagination_args['total_items'] ) ) { $response['total_items_i18n'] = sprintf( /* translators: Number of items. */ _n( '%s item', '%s items', $this->_pagination_args['total_items'] ), number_format_i18n( $this->_pagination_args['total_items'] ) ); } if ( isset( $this->_pagination_args['total_pages'] ) ) { $response['total_pages'] = $this->_pagination_args['total_pages']; $response['total_pages_i18n'] = number_format_i18n( $this->_pagination_args['total_pages'] ); } die( wp_json_encode( $response ) ); } /** * Sends required variables to JavaScript land. * * @since 3.1.0 */ public function _js_vars() { $args = array( 'class' => get_class( $this ), 'screen' => array( 'id' => $this->screen->id, 'base' => $this->screen->base, ), ); printf( "<script type='text/javascript'>list_args = %s;</script>\n", wp_json_encode( $args, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ); } } PK �Z�\�qI�/H /H "