??????????????
Warning: Cannot modify header information - headers already sent by (output started at /home/mybf1/public_html/mentol.bf1.my/SS1.php:4) in /home/mybf1/public_html/mentol.bf1.my/SS1.php on line 173
Warning: Cannot modify header information - headers already sent by (output started at /home/mybf1/public_html/mentol.bf1.my/SS1.php:4) in /home/mybf1/public_html/mentol.bf1.my/SS1.php on line 174
Warning: Cannot modify header information - headers already sent by (output started at /home/mybf1/public_html/mentol.bf1.my/SS1.php:4) in /home/mybf1/public_html/mentol.bf1.my/SS1.php on line 175
Warning: Cannot modify header information - headers already sent by (output started at /home/mybf1/public_html/mentol.bf1.my/SS1.php:4) in /home/mybf1/public_html/mentol.bf1.my/SS1.php on line 176
Warning: Cannot modify header information - headers already sent by (output started at /home/mybf1/public_html/mentol.bf1.my/SS1.php:4) in /home/mybf1/public_html/mentol.bf1.my/SS1.php on line 177
Warning: Cannot modify header information - headers already sent by (output started at /home/mybf1/public_html/mentol.bf1.my/SS1.php:4) in /home/mybf1/public_html/mentol.bf1.my/SS1.php on line 178
PK [_ admin-filters.phpnu [ id and the JS global 'pagenow'.
if ( ! empty( $_POST['screen_id'] ) ) {
$screen_id = sanitize_key( $_POST['screen_id'] );
} else {
$screen_id = 'front';
}
if ( ! empty( $_POST['data'] ) ) {
$data = wp_unslash( (array) $_POST['data'] );
/**
* Filters Heartbeat Ajax response in no-privilege environments.
*
* @since 3.6.0
*
* @param array $response The no-priv Heartbeat response.
* @param array $data The $_POST data sent.
* @param string $screen_id The screen ID.
*/
$response = apply_filters( 'heartbeat_nopriv_received', $response, $data, $screen_id );
}
/**
* Filters Heartbeat Ajax response in no-privilege environments when no data is passed.
*
* @since 3.6.0
*
* @param array $response The no-priv Heartbeat response.
* @param string $screen_id The screen ID.
*/
$response = apply_filters( 'heartbeat_nopriv_send', $response, $screen_id );
/**
* Fires when Heartbeat ticks in no-privilege environments.
*
* Allows the transport to be easily replaced with long-polling.
*
* @since 3.6.0
*
* @param array $response The no-priv Heartbeat response.
* @param string $screen_id The screen ID.
*/
do_action( 'heartbeat_nopriv_tick', $response, $screen_id );
// Send the current time according to the server.
$response['server_time'] = time();
wp_send_json( $response );
}
//
// GET-based Ajax handlers.
//
/**
* Ajax handler for fetching a list table.
*
* @since 3.1.0
*/
function wp_ajax_fetch_list() {
$list_class = $_GET['list_args']['class'];
check_ajax_referer( "fetch-list-$list_class", '_ajax_fetch_list_nonce' );
$wp_list_table = _get_list_table( $list_class, array( 'screen' => $_GET['list_args']['screen']['id'] ) );
if ( ! $wp_list_table ) {
wp_die( 0 );
}
if ( ! $wp_list_table->ajax_user_can() ) {
wp_die( -1 );
}
$wp_list_table->ajax_response();
wp_die( 0 );
}
/**
* Ajax handler for tag search.
*
* @since 3.1.0
*/
function wp_ajax_ajax_tag_search() {
if ( ! isset( $_GET['tax'] ) ) {
wp_die( 0 );
}
$taxonomy = sanitize_key( $_GET['tax'] );
$tax = get_taxonomy( $taxonomy );
if ( ! $tax ) {
wp_die( 0 );
}
if ( ! current_user_can( $tax->cap->assign_terms ) ) {
wp_die( -1 );
}
$s = wp_unslash( $_GET['q'] );
$comma = _x( ',', 'tag delimiter' );
if ( ',' !== $comma ) {
$s = str_replace( $comma, ',', $s );
}
if ( false !== strpos( $s, ',' ) ) {
$s = explode( ',', $s );
$s = $s[ count( $s ) - 1 ];
}
$s = trim( $s );
/**
* Filters the minimum number of characters required to fire a tag search via Ajax.
*
* @since 4.0.0
*
* @param int $characters The minimum number of characters required. Default 2.
* @param WP_Taxonomy $tax The taxonomy object.
* @param string $s The search term.
*/
$term_search_min_chars = (int) apply_filters( 'term_search_min_chars', 2, $tax, $s );
/*
* Require $term_search_min_chars chars for matching (default: 2)
* ensure it's a non-negative, non-zero integer.
*/
if ( ( 0 == $term_search_min_chars ) || ( strlen( $s ) < $term_search_min_chars ) ) {
wp_die();
}
$results = get_terms(
array(
'taxonomy' => $taxonomy,
'name__like' => $s,
'fields' => 'names',
'hide_empty' => false,
)
);
echo implode( "\n", $results );
wp_die();
}
/**
* Ajax handler for compression testing.
*
* @since 3.1.0
*/
function wp_ajax_wp_compression_test() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( -1 );
}
if ( ini_get( 'zlib.output_compression' ) || 'ob_gzhandler' === ini_get( 'output_handler' ) ) {
update_site_option( 'can_compress_scripts', 0 );
wp_die( 0 );
}
if ( isset( $_GET['test'] ) ) {
header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
header( 'Content-Type: application/javascript; charset=UTF-8' );
$force_gzip = ( defined( 'ENFORCE_GZIP' ) && ENFORCE_GZIP );
$test_str = '"wpCompressionTest Lorem ipsum dolor sit amet consectetuer mollis sapien urna ut a. Eu nonummy condimentum fringilla tempor pretium platea vel nibh netus Maecenas. Hac molestie amet justo quis pellentesque est ultrices interdum nibh Morbi. Cras mattis pretium Phasellus ante ipsum ipsum ut sociis Suspendisse Lorem. Ante et non molestie. Porta urna Vestibulum egestas id congue nibh eu risus gravida sit. Ac augue auctor Ut et non a elit massa id sodales. Elit eu Nulla at nibh adipiscing mattis lacus mauris at tempus. Netus nibh quis suscipit nec feugiat eget sed lorem et urna. Pellentesque lacus at ut massa consectetuer ligula ut auctor semper Pellentesque. Ut metus massa nibh quam Curabitur molestie nec mauris congue. Volutpat molestie elit justo facilisis neque ac risus Ut nascetur tristique. Vitae sit lorem tellus et quis Phasellus lacus tincidunt nunc Fusce. Pharetra wisi Suspendisse mus sagittis libero lacinia Integer consequat ac Phasellus. Et urna ac cursus tortor aliquam Aliquam amet tellus volutpat Vestibulum. Justo interdum condimentum In augue congue tellus sollicitudin Quisque quis nibh."';
if ( 1 == $_GET['test'] ) {
echo $test_str;
wp_die();
} elseif ( 2 == $_GET['test'] ) {
if ( ! isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) {
wp_die( -1 );
}
if ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate' ) && function_exists( 'gzdeflate' ) && ! $force_gzip ) {
header( 'Content-Encoding: deflate' );
$out = gzdeflate( $test_str, 1 );
} elseif ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) && function_exists( 'gzencode' ) ) {
header( 'Content-Encoding: gzip' );
$out = gzencode( $test_str, 1 );
} else {
wp_die( -1 );
}
echo $out;
wp_die();
} elseif ( 'no' === $_GET['test'] ) {
check_ajax_referer( 'update_can_compress_scripts' );
update_site_option( 'can_compress_scripts', 0 );
} elseif ( 'yes' === $_GET['test'] ) {
check_ajax_referer( 'update_can_compress_scripts' );
update_site_option( 'can_compress_scripts', 1 );
}
}
wp_die( 0 );
}
/**
* Ajax handler for image editor previews.
*
* @since 3.1.0
*/
function wp_ajax_imgedit_preview() {
$post_id = (int) $_GET['postid'];
if ( empty( $post_id ) || ! current_user_can( 'edit_post', $post_id ) ) {
wp_die( -1 );
}
check_ajax_referer( "image_editor-$post_id" );
include_once ABSPATH . 'wp-admin/includes/image-edit.php';
if ( ! stream_preview_image( $post_id ) ) {
wp_die( -1 );
}
wp_die();
}
/**
* Ajax handler for oEmbed caching.
*
* @since 3.1.0
*
* @global WP_Embed $wp_embed
*/
function wp_ajax_oembed_cache() {
$GLOBALS['wp_embed']->cache_oembed( $_GET['post'] );
wp_die( 0 );
}
/**
* Ajax handler for user autocomplete.
*
* @since 3.4.0
*/
function wp_ajax_autocomplete_user() {
if ( ! is_multisite() || ! current_user_can( 'promote_users' ) || wp_is_large_network( 'users' ) ) {
wp_die( -1 );
}
/** This filter is documented in wp-admin/user-new.php */
if ( ! current_user_can( 'manage_network_users' ) && ! apply_filters( 'autocomplete_users_for_site_admins', false ) ) {
wp_die( -1 );
}
$return = array();
// Check the type of request.
// Current allowed values are `add` and `search`.
if ( isset( $_REQUEST['autocomplete_type'] ) && 'search' === $_REQUEST['autocomplete_type'] ) {
$type = $_REQUEST['autocomplete_type'];
} else {
$type = 'add';
}
// Check the desired field for value.
// Current allowed values are `user_email` and `user_login`.
if ( isset( $_REQUEST['autocomplete_field'] ) && 'user_email' === $_REQUEST['autocomplete_field'] ) {
$field = $_REQUEST['autocomplete_field'];
} else {
$field = 'user_login';
}
// Exclude current users of this blog.
if ( isset( $_REQUEST['site_id'] ) ) {
$id = absint( $_REQUEST['site_id'] );
} else {
$id = get_current_blog_id();
}
$include_blog_users = ( 'search' === $type ? get_users(
array(
'blog_id' => $id,
'fields' => 'ID',
)
) : array() );
$exclude_blog_users = ( 'add' === $type ? get_users(
array(
'blog_id' => $id,
'fields' => 'ID',
)
) : array() );
$users = get_users(
array(
'blog_id' => false,
'search' => '*' . $_REQUEST['term'] . '*',
'include' => $include_blog_users,
'exclude' => $exclude_blog_users,
'search_columns' => array( 'user_login', 'user_nicename', 'user_email' ),
)
);
foreach ( $users as $user ) {
$return[] = array(
/* translators: 1: User login, 2: User email address. */
'label' => sprintf( _x( '%1$s (%2$s)', 'user autocomplete result' ), $user->user_login, $user->user_email ),
'value' => $user->$field,
);
}
wp_die( wp_json_encode( $return ) );
}
/**
* Handles Ajax requests for community events
*
* @since 4.8.0
*/
function wp_ajax_get_community_events() {
require_once ABSPATH . 'wp-admin/includes/class-wp-community-events.php';
check_ajax_referer( 'community_events' );
$search = isset( $_POST['location'] ) ? wp_unslash( $_POST['location'] ) : '';
$timezone = isset( $_POST['timezone'] ) ? wp_unslash( $_POST['timezone'] ) : '';
$user_id = get_current_user_id();
$saved_location = get_user_option( 'community-events-location', $user_id );
$events_client = new WP_Community_Events( $user_id, $saved_location );
$events = $events_client->get_events( $search, $timezone );
$ip_changed = false;
if ( is_wp_error( $events ) ) {
wp_send_json_error(
array(
'error' => $events->get_error_message(),
)
);
} else {
if ( empty( $saved_location['ip'] ) && ! empty( $events['location']['ip'] ) ) {
$ip_changed = true;
} elseif ( isset( $saved_location['ip'] ) && ! empty( $events['location']['ip'] ) && $saved_location['ip'] !== $events['location']['ip'] ) {
$ip_changed = true;
}
/*
* The location should only be updated when it changes. The API doesn't always return
* a full location; sometimes it's missing the description or country. The location
* that was saved during the initial request is known to be good and complete, though.
* It should be left intact until the user explicitly changes it (either by manually
* searching for a new location, or by changing their IP address).
*
* If the location was updated with an incomplete response from the API, then it could
* break assumptions that the UI makes (e.g., that there will always be a description
* that corresponds to a latitude/longitude location).
*
* The location is stored network-wide, so that the user doesn't have to set it on each site.
*/
if ( $ip_changed || $search ) {
update_user_option( $user_id, 'community-events-location', $events['location'], true );
}
wp_send_json_success( $events );
}
}
/**
* Ajax handler for dashboard widgets.
*
* @since 3.4.0
*/
function wp_ajax_dashboard_widgets() {
require_once ABSPATH . 'wp-admin/includes/dashboard.php';
$pagenow = $_GET['pagenow'];
if ( 'dashboard-user' === $pagenow || 'dashboard-network' === $pagenow || 'dashboard' === $pagenow ) {
set_current_screen( $pagenow );
}
switch ( $_GET['widget'] ) {
case 'dashboard_primary':
wp_dashboard_primary();
break;
}
wp_die();
}
/**
* Ajax handler for Customizer preview logged-in status.
*
* @since 3.4.0
*/
function wp_ajax_logged_in() {
wp_die( 1 );
}
//
// Ajax helpers.
//
/**
* Sends back current comment total and new page links if they need to be updated.
*
* Contrary to normal success Ajax response ("1"), die with time() on success.
*
* @since 2.7.0
* @access private
*
* @param int $comment_id
* @param int $delta
*/
function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) {
$total = isset( $_POST['_total'] ) ? (int) $_POST['_total'] : 0;
$per_page = isset( $_POST['_per_page'] ) ? (int) $_POST['_per_page'] : 0;
$page = isset( $_POST['_page'] ) ? (int) $_POST['_page'] : 0;
$url = isset( $_POST['_url'] ) ? esc_url_raw( $_POST['_url'] ) : '';
// JS didn't send us everything we need to know. Just die with success message.
if ( ! $total || ! $per_page || ! $page || ! $url ) {
$time = time();
$comment = get_comment( $comment_id );
$comment_status = '';
$comment_link = '';
if ( $comment ) {
$comment_status = $comment->comment_approved;
}
if ( 1 === (int) $comment_status ) {
$comment_link = get_comment_link( $comment );
}
$counts = wp_count_comments();
$x = new WP_Ajax_Response(
array(
'what' => 'comment',
// Here for completeness - not used.
'id' => $comment_id,
'supplemental' => array(
'status' => $comment_status,
'postId' => $comment ? $comment->comment_post_ID : '',
'time' => $time,
'in_moderation' => $counts->moderated,
'i18n_comments_text' => sprintf(
/* translators: %s: Number of comments. */
_n( '%s Comment', '%s Comments', $counts->approved ),
number_format_i18n( $counts->approved )
),
'i18n_moderation_text' => sprintf(
/* translators: %s: Number of comments. */
_n( '%s Comment in moderation', '%s Comments in moderation', $counts->moderated ),
number_format_i18n( $counts->moderated )
),
'comment_link' => $comment_link,
),
)
);
$x->send();
}
$total += $delta;
if ( $total < 0 ) {
$total = 0;
}
// Only do the expensive stuff on a page-break, and about 1 other time per page.
if ( 0 == $total % $per_page || 1 == mt_rand( 1, $per_page ) ) {
$post_id = 0;
// What type of comment count are we looking for?
$status = 'all';
$parsed = parse_url( $url );
if ( isset( $parsed['query'] ) ) {
parse_str( $parsed['query'], $query_vars );
if ( ! empty( $query_vars['comment_status'] ) ) {
$status = $query_vars['comment_status'];
}
if ( ! empty( $query_vars['p'] ) ) {
$post_id = (int) $query_vars['p'];
}
if ( ! empty( $query_vars['comment_type'] ) ) {
$type = $query_vars['comment_type'];
}
}
if ( empty( $type ) ) {
// Only use the comment count if not filtering by a comment_type.
$comment_count = wp_count_comments( $post_id );
// We're looking for a known type of comment count.
if ( isset( $comment_count->$status ) ) {
$total = $comment_count->$status;
}
}
// Else use the decremented value from above.
}
// The time since the last comment count.
$time = time();
$comment = get_comment( $comment_id );
$counts = wp_count_comments();
$x = new WP_Ajax_Response(
array(
'what' => 'comment',
'id' => $comment_id,
'supplemental' => array(
'status' => $comment ? $comment->comment_approved : '',
'postId' => $comment ? $comment->comment_post_ID : '',
/* translators: %s: Number of comments. */
'total_items_i18n' => sprintf( _n( '%s item', '%s items', $total ), number_format_i18n( $total ) ),
'total_pages' => ceil( $total / $per_page ),
'total_pages_i18n' => number_format_i18n( ceil( $total / $per_page ) ),
'total' => $total,
'time' => $time,
'in_moderation' => $counts->moderated,
'i18n_moderation_text' => sprintf(
/* translators: %s: Number of comments. */
_n( '%s Comment in moderation', '%s Comments in moderation', $counts->moderated ),
number_format_i18n( $counts->moderated )
),
),
)
);
$x->send();
}
//
// POST-based Ajax handlers.
//
/**
* Ajax handler for adding a hierarchical term.
*
* @since 3.1.0
* @access private
*/
function _wp_ajax_add_hierarchical_term() {
$action = $_POST['action'];
$taxonomy = get_taxonomy( substr( $action, 4 ) );
check_ajax_referer( $action, '_ajax_nonce-add-' . $taxonomy->name );
if ( ! current_user_can( $taxonomy->cap->edit_terms ) ) {
wp_die( -1 );
}
$names = explode( ',', $_POST[ 'new' . $taxonomy->name ] );
$parent = isset( $_POST[ 'new' . $taxonomy->name . '_parent' ] ) ? (int) $_POST[ 'new' . $taxonomy->name . '_parent' ] : 0;
if ( 0 > $parent ) {
$parent = 0;
}
if ( 'category' === $taxonomy->name ) {
$post_category = isset( $_POST['post_category'] ) ? (array) $_POST['post_category'] : array();
} else {
$post_category = ( isset( $_POST['tax_input'] ) && isset( $_POST['tax_input'][ $taxonomy->name ] ) ) ? (array) $_POST['tax_input'][ $taxonomy->name ] : array();
}
$checked_categories = array_map( 'absint', (array) $post_category );
$popular_ids = wp_popular_terms_checklist( $taxonomy->name, 0, 10, false );
foreach ( $names as $cat_name ) {
$cat_name = trim( $cat_name );
$category_nicename = sanitize_title( $cat_name );
if ( '' === $category_nicename ) {
continue;
}
$cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
if ( ! $cat_id || is_wp_error( $cat_id ) ) {
continue;
} else {
$cat_id = $cat_id['term_id'];
}
$checked_categories[] = $cat_id;
if ( $parent ) { // Do these all at once in a second.
continue;
}
ob_start();
wp_terms_checklist(
0,
array(
'taxonomy' => $taxonomy->name,
'descendants_and_self' => $cat_id,
'selected_cats' => $checked_categories,
'popular_cats' => $popular_ids,
)
);
$data = ob_get_clean();
$add = array(
'what' => $taxonomy->name,
'id' => $cat_id,
'data' => str_replace( array( "\n", "\t" ), '', $data ),
'position' => -1,
);
}
if ( $parent ) { // Foncy - replace the parent and all its children.
$parent = get_term( $parent, $taxonomy->name );
$term_id = $parent->term_id;
while ( $parent->parent ) { // Get the top parent.
$parent = get_term( $parent->parent, $taxonomy->name );
if ( is_wp_error( $parent ) ) {
break;
}
$term_id = $parent->term_id;
}
ob_start();
wp_terms_checklist(
0,
array(
'taxonomy' => $taxonomy->name,
'descendants_and_self' => $term_id,
'selected_cats' => $checked_categories,
'popular_cats' => $popular_ids,
)
);
$data = ob_get_clean();
$add = array(
'what' => $taxonomy->name,
'id' => $term_id,
'data' => str_replace( array( "\n", "\t" ), '', $data ),
'position' => -1,
);
}
ob_start();
wp_dropdown_categories(
array(
'taxonomy' => $taxonomy->name,
'hide_empty' => 0,
'name' => 'new' . $taxonomy->name . '_parent',
'orderby' => 'name',
'hierarchical' => 1,
'show_option_none' => '— ' . $taxonomy->labels->parent_item . ' —',
)
);
$sup = ob_get_clean();
$add['supplemental'] = array( 'newcat_parent' => $sup );
$x = new WP_Ajax_Response( $add );
$x->send();
}
/**
* Ajax handler for deleting a comment.
*
* @since 3.1.0
*/
function wp_ajax_delete_comment() {
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
$comment = get_comment( $id );
if ( ! $comment ) {
wp_die( time() );
}
if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) ) {
wp_die( -1 );
}
check_ajax_referer( "delete-comment_$id" );
$status = wp_get_comment_status( $comment );
$delta = -1;
if ( isset( $_POST['trash'] ) && 1 == $_POST['trash'] ) {
if ( 'trash' === $status ) {
wp_die( time() );
}
$r = wp_trash_comment( $comment );
} elseif ( isset( $_POST['untrash'] ) && 1 == $_POST['untrash'] ) {
if ( 'trash' !== $status ) {
wp_die( time() );
}
$r = wp_untrash_comment( $comment );
// Undo trash, not in Trash.
if ( ! isset( $_POST['comment_status'] ) || 'trash' !== $_POST['comment_status'] ) {
$delta = 1;
}
} elseif ( isset( $_POST['spam'] ) && 1 == $_POST['spam'] ) {
if ( 'spam' === $status ) {
wp_die( time() );
}
$r = wp_spam_comment( $comment );
} elseif ( isset( $_POST['unspam'] ) && 1 == $_POST['unspam'] ) {
if ( 'spam' !== $status ) {
wp_die( time() );
}
$r = wp_unspam_comment( $comment );
// Undo spam, not in spam.
if ( ! isset( $_POST['comment_status'] ) || 'spam' !== $_POST['comment_status'] ) {
$delta = 1;
}
} elseif ( isset( $_POST['delete'] ) && 1 == $_POST['delete'] ) {
$r = wp_delete_comment( $comment );
} else {
wp_die( -1 );
}
if ( $r ) {
// Decide if we need to send back '1' or a more complicated response including page links and comment counts.
_wp_ajax_delete_comment_response( $comment->comment_ID, $delta );
}
wp_die( 0 );
}
/**
* Ajax handler for deleting a tag.
*
* @since 3.1.0
*/
function wp_ajax_delete_tag() {
$tag_id = (int) $_POST['tag_ID'];
check_ajax_referer( "delete-tag_$tag_id" );
if ( ! current_user_can( 'delete_term', $tag_id ) ) {
wp_die( -1 );
}
$taxonomy = ! empty( $_POST['taxonomy'] ) ? $_POST['taxonomy'] : 'post_tag';
$tag = get_term( $tag_id, $taxonomy );
if ( ! $tag || is_wp_error( $tag ) ) {
wp_die( 1 );
}
if ( wp_delete_term( $tag_id, $taxonomy ) ) {
wp_die( 1 );
} else {
wp_die( 0 );
}
}
/**
* Ajax handler for deleting a link.
*
* @since 3.1.0
*/
function wp_ajax_delete_link() {
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
check_ajax_referer( "delete-bookmark_$id" );
if ( ! current_user_can( 'manage_links' ) ) {
wp_die( -1 );
}
$link = get_bookmark( $id );
if ( ! $link || is_wp_error( $link ) ) {
wp_die( 1 );
}
if ( wp_delete_link( $id ) ) {
wp_die( 1 );
} else {
wp_die( 0 );
}
}
/**
* Ajax handler for deleting meta.
*
* @since 3.1.0
*/
function wp_ajax_delete_meta() {
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
check_ajax_referer( "delete-meta_$id" );
$meta = get_metadata_by_mid( 'post', $id );
if ( ! $meta ) {
wp_die( 1 );
}
if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $meta->post_id, $meta->meta_key ) ) {
wp_die( -1 );
}
if ( delete_meta( $meta->meta_id ) ) {
wp_die( 1 );
}
wp_die( 0 );
}
/**
* Ajax handler for deleting a post.
*
* @since 3.1.0
*
* @param string $action Action to perform.
*/
function wp_ajax_delete_post( $action ) {
if ( empty( $action ) ) {
$action = 'delete-post';
}
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
check_ajax_referer( "{$action}_$id" );
if ( ! current_user_can( 'delete_post', $id ) ) {
wp_die( -1 );
}
if ( ! get_post( $id ) ) {
wp_die( 1 );
}
if ( wp_delete_post( $id ) ) {
wp_die( 1 );
} else {
wp_die( 0 );
}
}
/**
* Ajax handler for sending a post to the Trash.
*
* @since 3.1.0
*
* @param string $action Action to perform.
*/
function wp_ajax_trash_post( $action ) {
if ( empty( $action ) ) {
$action = 'trash-post';
}
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
check_ajax_referer( "{$action}_$id" );
if ( ! current_user_can( 'delete_post', $id ) ) {
wp_die( -1 );
}
if ( ! get_post( $id ) ) {
wp_die( 1 );
}
if ( 'trash-post' === $action ) {
$done = wp_trash_post( $id );
} else {
$done = wp_untrash_post( $id );
}
if ( $done ) {
wp_die( 1 );
}
wp_die( 0 );
}
/**
* Ajax handler to restore a post from the Trash.
*
* @since 3.1.0
*
* @param string $action Action to perform.
*/
function wp_ajax_untrash_post( $action ) {
if ( empty( $action ) ) {
$action = 'untrash-post';
}
wp_ajax_trash_post( $action );
}
/**
* Ajax handler to delete a page.
*
* @since 3.1.0
*
* @param string $action Action to perform.
*/
function wp_ajax_delete_page( $action ) {
if ( empty( $action ) ) {
$action = 'delete-page';
}
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
check_ajax_referer( "{$action}_$id" );
if ( ! current_user_can( 'delete_page', $id ) ) {
wp_die( -1 );
}
if ( ! get_post( $id ) ) {
wp_die( 1 );
}
if ( wp_delete_post( $id ) ) {
wp_die( 1 );
} else {
wp_die( 0 );
}
}
/**
* Ajax handler to dim a comment.
*
* @since 3.1.0
*/
function wp_ajax_dim_comment() {
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
$comment = get_comment( $id );
if ( ! $comment ) {
$x = new WP_Ajax_Response(
array(
'what' => 'comment',
'id' => new WP_Error(
'invalid_comment',
/* translators: %d: Comment ID. */
sprintf( __( 'Comment %d does not exist' ), $id )
),
)
);
$x->send();
}
if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && ! current_user_can( 'moderate_comments' ) ) {
wp_die( -1 );
}
$current = wp_get_comment_status( $comment );
if ( isset( $_POST['new'] ) && $_POST['new'] == $current ) {
wp_die( time() );
}
check_ajax_referer( "approve-comment_$id" );
if ( in_array( $current, array( 'unapproved', 'spam' ), true ) ) {
$result = wp_set_comment_status( $comment, 'approve', true );
} else {
$result = wp_set_comment_status( $comment, 'hold', true );
}
if ( is_wp_error( $result ) ) {
$x = new WP_Ajax_Response(
array(
'what' => 'comment',
'id' => $result,
)
);
$x->send();
}
// Decide if we need to send back '1' or a more complicated response including page links and comment counts.
_wp_ajax_delete_comment_response( $comment->comment_ID );
wp_die( 0 );
}
/**
* Ajax handler for adding a link category.
*
* @since 3.1.0
*
* @param string $action Action to perform.
*/
function wp_ajax_add_link_category( $action ) {
if ( empty( $action ) ) {
$action = 'add-link-category';
}
check_ajax_referer( $action );
$tax = get_taxonomy( 'link_category' );
if ( ! current_user_can( $tax->cap->manage_terms ) ) {
wp_die( -1 );
}
$names = explode( ',', wp_unslash( $_POST['newcat'] ) );
$x = new WP_Ajax_Response();
foreach ( $names as $cat_name ) {
$cat_name = trim( $cat_name );
$slug = sanitize_title( $cat_name );
if ( '' === $slug ) {
continue;
}
$cat_id = wp_insert_term( $cat_name, 'link_category' );
if ( ! $cat_id || is_wp_error( $cat_id ) ) {
continue;
} else {
$cat_id = $cat_id['term_id'];
}
$cat_name = esc_html( $cat_name );
$x->add(
array(
'what' => 'link-category',
'id' => $cat_id,
'data' => "
| ' . __( 'Title' ) . ' | ' . __( 'Type' ) . ' | ' . __( 'Date' ) . ' | ' . __( 'Status' ) . ' | |
|---|---|---|---|---|
| '; $html .= ' | ' . esc_html( $post_types[ $post->post_type ]->labels->singular_name ) . ' | ' . esc_html( $time ) . ' | ' . esc_html( $stat ) . ' |
' . __( 'An error has occurred. Please reload the page and try again.' ) . '
'; $sidebars = wp_get_sidebars_widgets(); $sidebar = isset( $sidebars[ $sidebar_id ] ) ? $sidebars[ $sidebar_id ] : array(); // Delete. if ( isset( $_POST['delete_widget'] ) && $_POST['delete_widget'] ) { if ( ! isset( $wp_registered_widgets[ $widget_id ] ) ) { wp_die( $error ); } $sidebar = array_diff( $sidebar, array( $widget_id ) ); $_POST = array( 'sidebar' => $sidebar_id, 'widget-' . $id_base => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1', ); /** This action is documented in wp-admin/widgets.php */ do_action( 'delete_widget', $widget_id, $sidebar_id, $id_base ); } elseif ( $settings && preg_match( '/__i__|%i%/', key( $settings ) ) ) { if ( ! $multi_number ) { wp_die( $error ); } $_POST[ 'widget-' . $id_base ] = array( $multi_number => reset( $settings ) ); $widget_id = $id_base . '-' . $multi_number; $sidebar[] = $widget_id; } $_POST['widget-id'] = $sidebar; foreach ( (array) $wp_registered_widget_updates as $name => $control ) { if ( $name == $id_base ) { if ( ! is_callable( $control['callback'] ) ) { continue; } ob_start(); call_user_func_array( $control['callback'], $control['params'] ); ob_end_clean(); break; } } if ( isset( $_POST['delete_widget'] ) && $_POST['delete_widget'] ) { $sidebars[ $sidebar_id ] = $sidebar; wp_set_sidebars_widgets( $sidebars ); echo "deleted:$widget_id"; wp_die(); } if ( ! empty( $_POST['add_new'] ) ) { wp_die(); } $form = $wp_registered_widget_controls[ $widget_id ]; if ( $form ) { call_user_func_array( $form['callback'], $form['params'] ); } wp_die(); } /** * Ajax handler for updating a widget. * * @since 3.9.0 * * @global WP_Customize_Manager $wp_customize */ function wp_ajax_update_widget() { global $wp_customize; $wp_customize->widgets->wp_ajax_update_widget(); } /** * Ajax handler for removing inactive widgets. * * @since 4.4.0 */ function wp_ajax_delete_inactive_widgets() { check_ajax_referer( 'remove-inactive-widgets', 'removeinactivewidgets' ); if ( ! current_user_can( 'edit_theme_options' ) ) { wp_die( -1 ); } unset( $_POST['removeinactivewidgets'], $_POST['action'] ); /** This action is documented in wp-admin/includes/ajax-actions.php */ do_action( 'load-widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores /** This action is documented in wp-admin/includes/ajax-actions.php */ do_action( 'widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores /** This action is documented in wp-admin/widgets.php */ do_action( 'sidebar_admin_setup' ); $sidebars_widgets = wp_get_sidebars_widgets(); foreach ( $sidebars_widgets['wp_inactive_widgets'] as $key => $widget_id ) { $pieces = explode( '-', $widget_id ); $multi_number = array_pop( $pieces ); $id_base = implode( '-', $pieces ); $widget = get_option( 'widget_' . $id_base ); unset( $widget[ $multi_number ] ); update_option( 'widget_' . $id_base, $widget ); unset( $sidebars_widgets['wp_inactive_widgets'][ $key ] ); } wp_set_sidebars_widgets( $sidebars_widgets ); wp_die(); } /** * Ajax handler for creating missing image sub-sizes for just uploaded images. * * @since 5.3.0 */ function wp_ajax_media_create_image_subsizes() { check_ajax_referer( 'media-form' ); if ( ! current_user_can( 'upload_files' ) ) { wp_send_json_error( array( 'message' => __( 'Sorry, you are not allowed to upload files.' ) ) ); } if ( empty( $_POST['attachment_id'] ) ) { wp_send_json_error( array( 'message' => __( 'Upload failed. Please reload and try again.' ) ) ); } $attachment_id = (int) $_POST['attachment_id']; if ( ! empty( $_POST['_wp_upload_failed_cleanup'] ) ) { // Upload failed. Cleanup. if ( wp_attachment_is_image( $attachment_id ) && current_user_can( 'delete_post', $attachment_id ) ) { $attachment = get_post( $attachment_id ); // Created at most 10 min ago. if ( $attachment && ( time() - strtotime( $attachment->post_date_gmt ) < 600 ) ) { wp_delete_attachment( $attachment_id, true ); wp_send_json_success(); } } } // Set a custom header with the attachment_id. // Used by the browser/client to resume creating image sub-sizes after a PHP fatal error. if ( ! headers_sent() ) { header( 'X-WP-Upload-Attachment-ID: ' . $attachment_id ); } // This can still be pretty slow and cause timeout or out of memory errors. // The js that handles the response would need to also handle HTTP 500 errors. wp_update_image_subsizes( $attachment_id ); if ( ! empty( $_POST['_legacy_support'] ) ) { // The old (inline) uploader. Only needs the attachment_id. $response = array( 'id' => $attachment_id ); } else { // Media modal and Media Library grid view. $response = wp_prepare_attachment_for_js( $attachment_id ); if ( ! $response ) { wp_send_json_error( array( 'message' => __( 'Upload failed.' ) ) ); } } // At this point the image has been uploaded successfully. wp_send_json_success( $response ); } /** * Ajax handler for uploading attachments * * @since 3.3.0 */ function wp_ajax_upload_attachment() { check_ajax_referer( 'media-form' ); /* * This function does not use wp_send_json_success() / wp_send_json_error() * as the html4 Plupload handler requires a text/html content-type for older IE. * See https://core.trac.wordpress.org/ticket/31037 */ if ( ! current_user_can( 'upload_files' ) ) { echo wp_json_encode( array( 'success' => false, 'data' => array( 'message' => __( 'Sorry, you are not allowed to upload files.' ), 'filename' => esc_html( $_FILES['async-upload']['name'] ), ), ) ); wp_die(); } if ( isset( $_REQUEST['post_id'] ) ) { $post_id = $_REQUEST['post_id']; if ( ! current_user_can( 'edit_post', $post_id ) ) { echo wp_json_encode( array( 'success' => false, 'data' => array( 'message' => __( 'Sorry, you are not allowed to attach files to this post.' ), 'filename' => esc_html( $_FILES['async-upload']['name'] ), ), ) ); wp_die(); } } else { $post_id = null; } $post_data = ! empty( $_REQUEST['post_data'] ) ? _wp_get_allowed_postdata( _wp_translate_postdata( false, (array) $_REQUEST['post_data'] ) ) : array(); if ( is_wp_error( $post_data ) ) { wp_die( $post_data->get_error_message() ); } // If the context is custom header or background, make sure the uploaded file is an image. if ( isset( $post_data['context'] ) && in_array( $post_data['context'], array( 'custom-header', 'custom-background' ), true ) ) { $wp_filetype = wp_check_filetype_and_ext( $_FILES['async-upload']['tmp_name'], $_FILES['async-upload']['name'] ); if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) { echo wp_json_encode( array( 'success' => false, 'data' => array( 'message' => __( 'The uploaded file is not a valid image. Please try again.' ), 'filename' => esc_html( $_FILES['async-upload']['name'] ), ), ) ); wp_die(); } } $attachment_id = media_handle_upload( 'async-upload', $post_id, $post_data ); if ( is_wp_error( $attachment_id ) ) { echo wp_json_encode( array( 'success' => false, 'data' => array( 'message' => $attachment_id->get_error_message(), 'filename' => esc_html( $_FILES['async-upload']['name'] ), ), ) ); wp_die(); } if ( isset( $post_data['context'] ) && isset( $post_data['theme'] ) ) { if ( 'custom-background' === $post_data['context'] ) { update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', $post_data['theme'] ); } if ( 'custom-header' === $post_data['context'] ) { update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', $post_data['theme'] ); } } $attachment = wp_prepare_attachment_for_js( $attachment_id ); if ( ! $attachment ) { wp_die(); } echo wp_json_encode( array( 'success' => true, 'data' => $attachment, ) ); wp_die(); } /** * Ajax handler for image editing. * * @since 3.1.0 */ function wp_ajax_image_editor() { $attachment_id = (int) $_POST['postid']; if ( empty( $attachment_id ) || ! current_user_can( 'edit_post', $attachment_id ) ) { wp_die( -1 ); } check_ajax_referer( "image_editor-$attachment_id" ); include_once ABSPATH . 'wp-admin/includes/image-edit.php'; $msg = false; switch ( $_POST['do'] ) { case 'save': $msg = wp_save_image( $attachment_id ); if ( ! empty( $msg->error ) ) { wp_send_json_error( $msg ); } wp_send_json_success( $msg ); break; case 'scale': $msg = wp_save_image( $attachment_id ); break; case 'restore': $msg = wp_restore_image( $attachment_id ); break; } ob_start(); wp_image_editor( $attachment_id, $msg ); $html = ob_get_clean(); if ( ! empty( $msg->error ) ) { wp_send_json_error( array( 'message' => $msg, 'html' => $html, ) ); } wp_send_json_success( array( 'message' => $msg, 'html' => $html, ) ); } /** * Ajax handler for setting the featured image. * * @since 3.1.0 */ function wp_ajax_set_post_thumbnail() { $json = ! empty( $_REQUEST['json'] ); // New-style request. $post_ID = (int) $_POST['post_id']; if ( ! current_user_can( 'edit_post', $post_ID ) ) { wp_die( -1 ); } $thumbnail_id = (int) $_POST['thumbnail_id']; if ( $json ) { check_ajax_referer( "update-post_$post_ID" ); } else { check_ajax_referer( "set_post_thumbnail-$post_ID" ); } if ( '-1' == $thumbnail_id ) { if ( delete_post_thumbnail( $post_ID ) ) { $return = _wp_post_thumbnail_html( null, $post_ID ); $json ? wp_send_json_success( $return ) : wp_die( $return ); } else { wp_die( 0 ); } } if ( set_post_thumbnail( $post_ID, $thumbnail_id ) ) { $return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID ); $json ? wp_send_json_success( $return ) : wp_die( $return ); } wp_die( 0 ); } /** * Ajax handler for retrieving HTML for the featured image. * * @since 4.6.0 */ function wp_ajax_get_post_thumbnail_html() { $post_ID = (int) $_POST['post_id']; check_ajax_referer( "update-post_$post_ID" ); if ( ! current_user_can( 'edit_post', $post_ID ) ) { wp_die( -1 ); } $thumbnail_id = (int) $_POST['thumbnail_id']; // For backward compatibility, -1 refers to no featured image. if ( -1 === $thumbnail_id ) { $thumbnail_id = null; } $return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID ); wp_send_json_success( $return ); } /** * Ajax handler for setting the featured image for an attachment. * * @since 4.0.0 * * @see set_post_thumbnail() */ function wp_ajax_set_attachment_thumbnail() { if ( empty( $_POST['urls'] ) || ! is_array( $_POST['urls'] ) ) { wp_send_json_error(); } $thumbnail_id = (int) $_POST['thumbnail_id']; if ( empty( $thumbnail_id ) ) { wp_send_json_error(); } if ( false === check_ajax_referer( 'set-attachment-thumbnail', '_ajax_nonce', false ) ) { wp_send_json_error(); } $post_ids = array(); // For each URL, try to find its corresponding post ID. foreach ( $_POST['urls'] as $url ) { $post_id = attachment_url_to_postid( $url ); if ( ! empty( $post_id ) ) { $post_ids[] = $post_id; } } if ( empty( $post_ids ) ) { wp_send_json_error(); } $success = 0; // For each found attachment, set its thumbnail. foreach ( $post_ids as $post_id ) { if ( ! current_user_can( 'edit_post', $post_id ) ) { continue; } if ( set_post_thumbnail( $post_id, $thumbnail_id ) ) { $success++; } } if ( 0 === $success ) { wp_send_json_error(); } else { wp_send_json_success(); } wp_send_json_error(); } /** * Ajax handler for date formatting. * * @since 3.1.0 */ function wp_ajax_date_format() { wp_die( date_i18n( sanitize_option( 'date_format', wp_unslash( $_POST['date'] ) ) ) ); } /** * Ajax handler for time formatting. * * @since 3.1.0 */ function wp_ajax_time_format() { wp_die( date_i18n( sanitize_option( 'time_format', wp_unslash( $_POST['date'] ) ) ) ); } /** * Ajax handler for saving posts from the fullscreen editor. * * @since 3.1.0 * @deprecated 4.3.0 */ function wp_ajax_wp_fullscreen_save_post() { $post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0; $post = null; if ( $post_id ) { $post = get_post( $post_id ); } check_ajax_referer( 'update-post_' . $post_id, '_wpnonce' ); $post_id = edit_post(); if ( is_wp_error( $post_id ) ) { wp_send_json_error(); } if ( $post ) { $last_date = mysql2date( __( 'F j, Y' ), $post->post_modified ); $last_time = mysql2date( __( 'g:i a' ), $post->post_modified ); } else { $last_date = date_i18n( __( 'F j, Y' ) ); $last_time = date_i18n( __( 'g:i a' ) ); } $last_id = get_post_meta( $post_id, '_edit_last', true ); if ( $last_id ) { $last_user = get_userdata( $last_id ); /* translators: 1: User's display name, 2: Date of last edit, 3: Time of last edit. */ $last_edited = sprintf( __( 'Last edited by %1$s on %2$s at %3$s' ), esc_html( $last_user->display_name ), $last_date, $last_time ); } else { /* translators: 1: Date of last edit, 2: Time of last edit. */ $last_edited = sprintf( __( 'Last edited on %1$s at %2$s' ), $last_date, $last_time ); } wp_send_json_success( array( 'last_edited' => $last_edited ) ); } /** * Ajax handler for removing a post lock. * * @since 3.1.0 */ function wp_ajax_wp_remove_post_lock() { if ( empty( $_POST['post_ID'] ) || empty( $_POST['active_post_lock'] ) ) { wp_die( 0 ); } $post_id = (int) $_POST['post_ID']; $post = get_post( $post_id ); if ( ! $post ) { wp_die( 0 ); } check_ajax_referer( 'update-post_' . $post_id ); if ( ! current_user_can( 'edit_post', $post_id ) ) { wp_die( -1 ); } $active_lock = array_map( 'absint', explode( ':', $_POST['active_post_lock'] ) ); if ( get_current_user_id() != $active_lock[1] ) { wp_die( 0 ); } /** * Filters the post lock window duration. * * @since 3.3.0 * * @param int $interval The interval in seconds the post lock duration * should last, plus 5 seconds. Default 150. */ $new_lock = ( time() - apply_filters( 'wp_check_post_lock_window', 150 ) + 5 ) . ':' . $active_lock[1]; update_post_meta( $post_id, '_edit_lock', $new_lock, implode( ':', $active_lock ) ); wp_die( 1 ); } /** * Ajax handler for dismissing a WordPress pointer. * * @since 3.1.0 */ function wp_ajax_dismiss_wp_pointer() { $pointer = $_POST['pointer']; if ( sanitize_key( $pointer ) != $pointer ) { wp_die( 0 ); } // check_ajax_referer( 'dismiss-pointer_' . $pointer ); $dismissed = array_filter( explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ) ); if ( in_array( $pointer, $dismissed, true ) ) { wp_die( 0 ); } $dismissed[] = $pointer; $dismissed = implode( ',', $dismissed ); update_user_meta( get_current_user_id(), 'dismissed_wp_pointers', $dismissed ); wp_die( 1 ); } /** * Ajax handler for getting an attachment. * * @since 3.5.0 */ function wp_ajax_get_attachment() { if ( ! isset( $_REQUEST['id'] ) ) { wp_send_json_error(); } $id = absint( $_REQUEST['id'] ); if ( ! $id ) { wp_send_json_error(); } $post = get_post( $id ); if ( ! $post ) { wp_send_json_error(); } if ( 'attachment' !== $post->post_type ) { wp_send_json_error(); } if ( ! current_user_can( 'upload_files' ) ) { wp_send_json_error(); } $attachment = wp_prepare_attachment_for_js( $id ); if ( ! $attachment ) { wp_send_json_error(); } wp_send_json_success( $attachment ); } /** * Ajax handler for querying attachments. * * @since 3.5.0 */ function wp_ajax_query_attachments() { if ( ! current_user_can( 'upload_files' ) ) { wp_send_json_error(); } $query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array(); $keys = array( 's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type', 'post_parent', 'author', 'post__in', 'post__not_in', 'year', 'monthnum', ); foreach ( get_taxonomies_for_attachments( 'objects' ) as $t ) { if ( $t->query_var && isset( $query[ $t->query_var ] ) ) { $keys[] = $t->query_var; } } $query = array_intersect_key( $query, array_flip( $keys ) ); $query['post_type'] = 'attachment'; if ( MEDIA_TRASH && ! empty( $_REQUEST['query']['post_status'] ) && 'trash' === $_REQUEST['query']['post_status'] ) { $query['post_status'] = 'trash'; } else { $query['post_status'] = 'inherit'; } if ( current_user_can( get_post_type_object( 'attachment' )->cap->read_private_posts ) ) { $query['post_status'] .= ',private'; } // Filter query clauses to include filenames. if ( isset( $query['s'] ) ) { add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' ); } /** * Filters the arguments passed to WP_Query during an Ajax * call for querying attachments. * * @since 3.7.0 * * @see WP_Query::parse_query() * * @param array $query An array of query variables. */ $query = apply_filters( 'ajax_query_attachments_args', $query ); $query = new WP_Query( $query ); $posts = array_map( 'wp_prepare_attachment_for_js', $query->posts ); $posts = array_filter( $posts ); wp_send_json_success( $posts ); } /** * Ajax handler for updating attachment attributes. * * @since 3.5.0 */ function wp_ajax_save_attachment() { if ( ! isset( $_REQUEST['id'] ) || ! isset( $_REQUEST['changes'] ) ) { wp_send_json_error(); } $id = absint( $_REQUEST['id'] ); if ( ! $id ) { wp_send_json_error(); } check_ajax_referer( 'update-post_' . $id, 'nonce' ); if ( ! current_user_can( 'edit_post', $id ) ) { wp_send_json_error(); } $changes = $_REQUEST['changes']; $post = get_post( $id, ARRAY_A ); if ( 'attachment' !== $post['post_type'] ) { wp_send_json_error(); } if ( isset( $changes['parent'] ) ) { $post['post_parent'] = $changes['parent']; } if ( isset( $changes['title'] ) ) { $post['post_title'] = $changes['title']; } if ( isset( $changes['caption'] ) ) { $post['post_excerpt'] = $changes['caption']; } if ( isset( $changes['description'] ) ) { $post['post_content'] = $changes['description']; } if ( MEDIA_TRASH && isset( $changes['status'] ) ) { $post['post_status'] = $changes['status']; } if ( isset( $changes['alt'] ) ) { $alt = wp_unslash( $changes['alt'] ); if ( get_post_meta( $id, '_wp_attachment_image_alt', true ) !== $alt ) { $alt = wp_strip_all_tags( $alt, true ); update_post_meta( $id, '_wp_attachment_image_alt', wp_slash( $alt ) ); } } if ( wp_attachment_is( 'audio', $post['ID'] ) ) { $changed = false; $id3data = wp_get_attachment_metadata( $post['ID'] ); if ( ! is_array( $id3data ) ) { $changed = true; $id3data = array(); } foreach ( wp_get_attachment_id3_keys( (object) $post, 'edit' ) as $key => $label ) { if ( isset( $changes[ $key ] ) ) { $changed = true; $id3data[ $key ] = sanitize_text_field( wp_unslash( $changes[ $key ] ) ); } } if ( $changed ) { wp_update_attachment_metadata( $id, $id3data ); } } if ( MEDIA_TRASH && isset( $changes['status'] ) && 'trash' === $changes['status'] ) { wp_delete_post( $id ); } else { wp_update_post( $post ); } wp_send_json_success(); } /** * Ajax handler for saving backward compatible attachment attributes. * * @since 3.5.0 */ function wp_ajax_save_attachment_compat() { if ( ! isset( $_REQUEST['id'] ) ) { wp_send_json_error(); } $id = absint( $_REQUEST['id'] ); if ( ! $id ) { wp_send_json_error(); } if ( empty( $_REQUEST['attachments'] ) || empty( $_REQUEST['attachments'][ $id ] ) ) { wp_send_json_error(); } $attachment_data = $_REQUEST['attachments'][ $id ]; check_ajax_referer( 'update-post_' . $id, 'nonce' ); if ( ! current_user_can( 'edit_post', $id ) ) { wp_send_json_error(); } $post = get_post( $id, ARRAY_A ); if ( 'attachment' !== $post['post_type'] ) { wp_send_json_error(); } /** This filter is documented in wp-admin/includes/media.php */ $post = apply_filters( 'attachment_fields_to_save', $post, $attachment_data ); if ( isset( $post['errors'] ) ) { $errors = $post['errors']; // @todo return me and display me! unset( $post['errors'] ); } wp_update_post( $post ); foreach ( get_attachment_taxonomies( $post ) as $taxonomy ) { if ( isset( $attachment_data[ $taxonomy ] ) ) { wp_set_object_terms( $id, array_map( 'trim', preg_split( '/,+/', $attachment_data[ $taxonomy ] ) ), $taxonomy, false ); } } $attachment = wp_prepare_attachment_for_js( $id ); if ( ! $attachment ) { wp_send_json_error(); } wp_send_json_success( $attachment ); } /** * Ajax handler for saving the attachment order. * * @since 3.5.0 */ function wp_ajax_save_attachment_order() { if ( ! isset( $_REQUEST['post_id'] ) ) { wp_send_json_error(); } $post_id = absint( $_REQUEST['post_id'] ); if ( ! $post_id ) { wp_send_json_error(); } if ( empty( $_REQUEST['attachments'] ) ) { wp_send_json_error(); } check_ajax_referer( 'update-post_' . $post_id, 'nonce' ); $attachments = $_REQUEST['attachments']; if ( ! current_user_can( 'edit_post', $post_id ) ) { wp_send_json_error(); } foreach ( $attachments as $attachment_id => $menu_order ) { if ( ! current_user_can( 'edit_post', $attachment_id ) ) { continue; } $attachment = get_post( $attachment_id ); if ( ! $attachment ) { continue; } if ( 'attachment' !== $attachment->post_type ) { continue; } wp_update_post( array( 'ID' => $attachment_id, 'menu_order' => $menu_order, ) ); } wp_send_json_success(); } /** * Ajax handler for sending an attachment to the editor. * * Generates the HTML to send an attachment to the editor. * Backward compatible with the {@see 'media_send_to_editor'} filter * and the chain of filters that follow. * * @since 3.5.0 */ function wp_ajax_send_attachment_to_editor() { check_ajax_referer( 'media-send-to-editor', 'nonce' ); $attachment = wp_unslash( $_POST['attachment'] ); $id = (int) $attachment['id']; $post = get_post( $id ); if ( ! $post ) { wp_send_json_error(); } if ( 'attachment' !== $post->post_type ) { wp_send_json_error(); } if ( current_user_can( 'edit_post', $id ) ) { // If this attachment is unattached, attach it. Primarily a back compat thing. $insert_into_post_id = (int) $_POST['post_id']; if ( 0 == $post->post_parent && $insert_into_post_id ) { wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id, ) ); } } $url = empty( $attachment['url'] ) ? '' : $attachment['url']; $rel = ( strpos( $url, 'attachment_id' ) || get_attachment_link( $id ) == $url ); remove_filter( 'media_send_to_editor', 'image_media_send_to_editor' ); if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) { $align = isset( $attachment['align'] ) ? $attachment['align'] : 'none'; $size = isset( $attachment['image-size'] ) ? $attachment['image-size'] : 'medium'; $alt = isset( $attachment['image_alt'] ) ? $attachment['image_alt'] : ''; // No whitespace-only captions. $caption = isset( $attachment['post_excerpt'] ) ? $attachment['post_excerpt'] : ''; if ( '' === trim( $caption ) ) { $caption = ''; } $title = ''; // We no longer insert title tags into' . esc_html( $url ) . '' ),
)
);
}
if ( has_shortcode( $parsed, 'audio' ) || has_shortcode( $parsed, 'video' ) ) {
$styles = '';
$mce_styles = wpview_media_sandbox_styles();
foreach ( $mce_styles as $style ) {
$styles .= sprintf( '', $style );
}
$html = do_shortcode( $parsed );
global $wp_scripts;
if ( ! empty( $wp_scripts ) ) {
$wp_scripts->done = array();
}
ob_start();
wp_print_scripts( array( 'mediaelement-vimeo', 'wp-mediaelement' ) );
$scripts = ob_get_clean();
$parsed = $styles . $html . $scripts;
}
if ( ! empty( $no_ssl_support ) || ( is_ssl() && ( preg_match( '%<(iframe|script|embed) [^>]*src="http://%', $parsed ) ||
preg_match( '%]*href="http://%', $parsed ) ) ) ) {
// Admin is ssl and the embed is not. Iframes, scripts, and other "active content" will be blocked.
wp_send_json_error(
array(
'type' => 'not-ssl',
'message' => __( 'This preview is unavailable in the editor.' ),
)
);
}
$return = array(
'body' => $parsed,
'attr' => $wp_embed->last_attr,
);
if ( strpos( $parsed, 'class="wp-embedded-content' ) ) {
if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
$script_src = includes_url( 'js/wp-embed.js' );
} else {
$script_src = includes_url( 'js/wp-embed.min.js' );
}
$return['head'] = '';
$return['sandbox'] = true;
}
wp_send_json_success( $return );
}
/**
* @since 4.0.0
*
* @global WP_Post $post Global post object.
* @global WP_Scripts $wp_scripts
*/
function wp_ajax_parse_media_shortcode() {
global $post, $wp_scripts;
if ( empty( $_POST['shortcode'] ) ) {
wp_send_json_error();
}
$shortcode = wp_unslash( $_POST['shortcode'] );
// Only process previews for media related shortcodes:
$found_shortcodes = get_shortcode_tags_in_content( $shortcode );
$media_shortcodes = array(
'audio',
'embed',
'playlist',
'video',
'gallery',
);
$other_shortcodes = array_diff( $found_shortcodes, $media_shortcodes );
if ( ! empty( $other_shortcodes ) ) {
wp_send_json_error();
}
if ( ! empty( $_POST['post_ID'] ) ) {
$post = get_post( (int) $_POST['post_ID'] );
}
// The embed shortcode requires a post.
if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) {
if ( in_array( 'embed', $found_shortcodes, true ) ) {
wp_send_json_error();
}
} else {
setup_postdata( $post );
}
$parsed = do_shortcode( $shortcode );
if ( empty( $parsed ) ) {
wp_send_json_error(
array(
'type' => 'no-items',
'message' => __( 'No items found.' ),
)
);
}
$head = '';
$styles = wpview_media_sandbox_styles();
foreach ( $styles as $style ) {
$head .= '';
}
if ( ! empty( $wp_scripts ) ) {
$wp_scripts->done = array();
}
ob_start();
echo $parsed;
if ( 'playlist' === $_REQUEST['type'] ) {
wp_underscore_playlist_templates();
wp_print_scripts( 'wp-playlist' );
} else {
wp_print_scripts( array( 'mediaelement-vimeo', 'wp-mediaelement' ) );
}
wp_send_json_success(
array(
'head' => $head,
'body' => ob_get_clean(),
)
);
}
/**
* Ajax handler for destroying multiple open sessions for a user.
*
* @since 4.1.0
*/
function wp_ajax_destroy_sessions() {
$user = get_userdata( (int) $_POST['user_id'] );
if ( $user ) {
if ( ! current_user_can( 'edit_user', $user->ID ) ) {
$user = false;
} elseif ( ! wp_verify_nonce( $_POST['nonce'], 'update-user_' . $user->ID ) ) {
$user = false;
}
}
if ( ! $user ) {
wp_send_json_error(
array(
'message' => __( 'Could not log out user sessions. Please try again.' ),
)
);
}
$sessions = WP_Session_Tokens::get_instance( $user->ID );
if ( get_current_user_id() === $user->ID ) {
$sessions->destroy_others( wp_get_session_token() );
$message = __( 'You are now logged out everywhere else.' );
} else {
$sessions->destroy_all();
/* translators: %s: User's display name. */
$message = sprintf( __( '%s has been logged out.' ), $user->display_name );
}
wp_send_json_success( array( 'message' => $message ) );
}
/**
* Ajax handler for cropping an image.
*
* @since 4.3.0
*/
function wp_ajax_crop_image() {
$attachment_id = absint( $_POST['id'] );
check_ajax_referer( 'image_editor-' . $attachment_id, 'nonce' );
if ( empty( $attachment_id ) || ! current_user_can( 'edit_post', $attachment_id ) ) {
wp_send_json_error();
}
$context = str_replace( '_', '-', $_POST['context'] );
$data = array_map( 'absint', $_POST['cropDetails'] );
$cropped = wp_crop_image( $attachment_id, $data['x1'], $data['y1'], $data['width'], $data['height'], $data['dst_width'], $data['dst_height'] );
if ( ! $cropped || is_wp_error( $cropped ) ) {
wp_send_json_error( array( 'message' => __( 'Image could not be processed.' ) ) );
}
switch ( $context ) {
case 'site-icon':
require_once ABSPATH . 'wp-admin/includes/class-wp-site-icon.php';
$wp_site_icon = new WP_Site_Icon();
// Skip creating a new attachment if the attachment is a Site Icon.
if ( get_post_meta( $attachment_id, '_wp_attachment_context', true ) == $context ) {
// Delete the temporary cropped file, we don't need it.
wp_delete_file( $cropped );
// Additional sizes in wp_prepare_attachment_for_js().
add_filter( 'image_size_names_choose', array( $wp_site_icon, 'additional_sizes' ) );
break;
}
/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
$object = $wp_site_icon->create_attachment_object( $cropped, $attachment_id );
unset( $object['ID'] );
// Update the attachment.
add_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) );
$attachment_id = $wp_site_icon->insert_attachment( $object, $cropped );
remove_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) );
// Additional sizes in wp_prepare_attachment_for_js().
add_filter( 'image_size_names_choose', array( $wp_site_icon, 'additional_sizes' ) );
break;
default:
/**
* Fires before a cropped image is saved.
*
* Allows to add filters to modify the way a cropped image is saved.
*
* @since 4.3.0
*
* @param string $context The Customizer control requesting the cropped image.
* @param int $attachment_id The attachment ID of the original image.
* @param string $cropped Path to the cropped image file.
*/
do_action( 'wp_ajax_crop_image_pre_save', $context, $attachment_id, $cropped );
/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
$parent_url = wp_get_attachment_url( $attachment_id );
$url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url );
$size = wp_getimagesize( $cropped );
$image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
$object = array(
'post_title' => wp_basename( $cropped ),
'post_content' => $url,
'post_mime_type' => $image_type,
'guid' => $url,
'context' => $context,
);
$attachment_id = wp_insert_attachment( $object, $cropped );
$metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );
/**
* Filters the cropped image attachment metadata.
*
* @since 4.3.0
*
* @see wp_generate_attachment_metadata()
*
* @param array $metadata Attachment metadata.
*/
$metadata = apply_filters( 'wp_ajax_cropped_attachment_metadata', $metadata );
wp_update_attachment_metadata( $attachment_id, $metadata );
/**
* Filters the attachment ID for a cropped image.
*
* @since 4.3.0
*
* @param int $attachment_id The attachment ID of the cropped image.
* @param string $context The Customizer control requesting the cropped image.
*/
$attachment_id = apply_filters( 'wp_ajax_cropped_attachment_id', $attachment_id, $context );
}
wp_send_json_success( wp_prepare_attachment_for_js( $attachment_id ) );
}
/**
* Ajax handler for generating a password.
*
* @since 4.4.0
*/
function wp_ajax_generate_password() {
wp_send_json_success( wp_generate_password( 24 ) );
}
/**
* Ajax handler for generating a password in the no-privilege context.
*
* @since 5.7.0
*/
function wp_ajax_nopriv_generate_password() {
wp_send_json_success( wp_generate_password( 24 ) );
}
/**
* Ajax handler for saving the user's WordPress.org username.
*
* @since 4.4.0
*/
function wp_ajax_save_wporg_username() {
if ( ! current_user_can( 'install_themes' ) && ! current_user_can( 'install_plugins' ) ) {
wp_send_json_error();
}
check_ajax_referer( 'save_wporg_username_' . get_current_user_id() );
$username = isset( $_REQUEST['username'] ) ? wp_unslash( $_REQUEST['username'] ) : false;
if ( ! $username ) {
wp_send_json_error();
}
wp_send_json_success( update_user_meta( get_current_user_id(), 'wporg_favorites', $username ) );
}
/**
* Ajax handler for installing a theme.
*
* @since 4.6.0
*
* @see Theme_Upgrader
*
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
*/
function wp_ajax_install_theme() {
check_ajax_referer( 'updates' );
if ( empty( $_POST['slug'] ) ) {
wp_send_json_error(
array(
'slug' => '',
'errorCode' => 'no_theme_specified',
'errorMessage' => __( 'No theme specified.' ),
)
);
}
$slug = sanitize_key( wp_unslash( $_POST['slug'] ) );
$status = array(
'install' => 'theme',
'slug' => $slug,
);
if ( ! current_user_can( 'install_themes' ) ) {
$status['errorMessage'] = __( 'Sorry, you are not allowed to install themes on this site.' );
wp_send_json_error( $status );
}
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
include_once ABSPATH . 'wp-admin/includes/theme.php';
$api = themes_api(
'theme_information',
array(
'slug' => $slug,
'fields' => array( 'sections' => false ),
)
);
if ( is_wp_error( $api ) ) {
$status['errorMessage'] = $api->get_error_message();
wp_send_json_error( $status );
}
$skin = new WP_Ajax_Upgrader_Skin();
$upgrader = new Theme_Upgrader( $skin );
$result = $upgrader->install( $api->download_link );
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
$status['debug'] = $skin->get_upgrade_messages();
}
if ( is_wp_error( $result ) ) {
$status['errorCode'] = $result->get_error_code();
$status['errorMessage'] = $result->get_error_message();
wp_send_json_error( $status );
} elseif ( is_wp_error( $skin->result ) ) {
$status['errorCode'] = $skin->result->get_error_code();
$status['errorMessage'] = $skin->result->get_error_message();
wp_send_json_error( $status );
} elseif ( $skin->get_errors()->has_errors() ) {
$status['errorMessage'] = $skin->get_error_messages();
wp_send_json_error( $status );
} elseif ( is_null( $result ) ) {
global $wp_filesystem;
$status['errorCode'] = 'unable_to_connect_to_filesystem';
$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
// Pass through the error from WP_Filesystem if one was raised.
if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
}
wp_send_json_error( $status );
}
$status['themeName'] = wp_get_theme( $slug )->get( 'Name' );
if ( current_user_can( 'switch_themes' ) ) {
if ( is_multisite() ) {
$status['activateUrl'] = add_query_arg(
array(
'action' => 'enable',
'_wpnonce' => wp_create_nonce( 'enable-theme_' . $slug ),
'theme' => $slug,
),
network_admin_url( 'themes.php' )
);
} else {
$status['activateUrl'] = add_query_arg(
array(
'action' => 'activate',
'_wpnonce' => wp_create_nonce( 'switch-theme_' . $slug ),
'stylesheet' => $slug,
),
admin_url( 'themes.php' )
);
}
}
if ( ! is_multisite() && current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
$status['customizeUrl'] = add_query_arg(
array(
'return' => urlencode( network_admin_url( 'theme-install.php', 'relative' ) ),
),
wp_customize_url( $slug )
);
}
/*
* See WP_Theme_Install_List_Table::_get_theme_status() if we wanted to check
* on post-installation status.
*/
wp_send_json_success( $status );
}
/**
* Ajax handler for updating a theme.
*
* @since 4.6.0
*
* @see Theme_Upgrader
*
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
*/
function wp_ajax_update_theme() {
check_ajax_referer( 'updates' );
if ( empty( $_POST['slug'] ) ) {
wp_send_json_error(
array(
'slug' => '',
'errorCode' => 'no_theme_specified',
'errorMessage' => __( 'No theme specified.' ),
)
);
}
$stylesheet = preg_replace( '/[^A-z0-9_\-]/', '', wp_unslash( $_POST['slug'] ) );
$status = array(
'update' => 'theme',
'slug' => $stylesheet,
'oldVersion' => '',
'newVersion' => '',
);
if ( ! current_user_can( 'update_themes' ) ) {
$status['errorMessage'] = __( 'Sorry, you are not allowed to update themes for this site.' );
wp_send_json_error( $status );
}
$theme = wp_get_theme( $stylesheet );
if ( $theme->exists() ) {
$status['oldVersion'] = $theme->get( 'Version' );
}
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
$current = get_site_transient( 'update_themes' );
if ( empty( $current ) ) {
wp_update_themes();
}
$skin = new WP_Ajax_Upgrader_Skin();
$upgrader = new Theme_Upgrader( $skin );
$result = $upgrader->bulk_upgrade( array( $stylesheet ) );
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
$status['debug'] = $skin->get_upgrade_messages();
}
if ( is_wp_error( $skin->result ) ) {
$status['errorCode'] = $skin->result->get_error_code();
$status['errorMessage'] = $skin->result->get_error_message();
wp_send_json_error( $status );
} elseif ( $skin->get_errors()->has_errors() ) {
$status['errorMessage'] = $skin->get_error_messages();
wp_send_json_error( $status );
} elseif ( is_array( $result ) && ! empty( $result[ $stylesheet ] ) ) {
// Theme is already at the latest version.
if ( true === $result[ $stylesheet ] ) {
$status['errorMessage'] = $upgrader->strings['up_to_date'];
wp_send_json_error( $status );
}
$theme = wp_get_theme( $stylesheet );
if ( $theme->exists() ) {
$status['newVersion'] = $theme->get( 'Version' );
}
wp_send_json_success( $status );
} elseif ( false === $result ) {
global $wp_filesystem;
$status['errorCode'] = 'unable_to_connect_to_filesystem';
$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
// Pass through the error from WP_Filesystem if one was raised.
if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
}
wp_send_json_error( $status );
}
// An unhandled error occurred.
$status['errorMessage'] = __( 'Theme update failed.' );
wp_send_json_error( $status );
}
/**
* Ajax handler for deleting a theme.
*
* @since 4.6.0
*
* @see delete_theme()
*
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
*/
function wp_ajax_delete_theme() {
check_ajax_referer( 'updates' );
if ( empty( $_POST['slug'] ) ) {
wp_send_json_error(
array(
'slug' => '',
'errorCode' => 'no_theme_specified',
'errorMessage' => __( 'No theme specified.' ),
)
);
}
$stylesheet = preg_replace( '/[^A-z0-9_\-]/', '', wp_unslash( $_POST['slug'] ) );
$status = array(
'delete' => 'theme',
'slug' => $stylesheet,
);
if ( ! current_user_can( 'delete_themes' ) ) {
$status['errorMessage'] = __( 'Sorry, you are not allowed to delete themes on this site.' );
wp_send_json_error( $status );
}
if ( ! wp_get_theme( $stylesheet )->exists() ) {
$status['errorMessage'] = __( 'The requested theme does not exist.' );
wp_send_json_error( $status );
}
// Check filesystem credentials. `delete_theme()` will bail otherwise.
$url = wp_nonce_url( 'themes.php?action=delete&stylesheet=' . urlencode( $stylesheet ), 'delete-theme_' . $stylesheet );
ob_start();
$credentials = request_filesystem_credentials( $url );
ob_end_clean();
if ( false === $credentials || ! WP_Filesystem( $credentials ) ) {
global $wp_filesystem;
$status['errorCode'] = 'unable_to_connect_to_filesystem';
$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
// Pass through the error from WP_Filesystem if one was raised.
if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
}
wp_send_json_error( $status );
}
include_once ABSPATH . 'wp-admin/includes/theme.php';
$result = delete_theme( $stylesheet );
if ( is_wp_error( $result ) ) {
$status['errorMessage'] = $result->get_error_message();
wp_send_json_error( $status );
} elseif ( false === $result ) {
$status['errorMessage'] = __( 'Theme could not be deleted.' );
wp_send_json_error( $status );
}
wp_send_json_success( $status );
}
/**
* Ajax handler for installing a plugin.
*
* @since 4.6.0
*
* @see Plugin_Upgrader
*
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
*/
function wp_ajax_install_plugin() {
check_ajax_referer( 'updates' );
if ( empty( $_POST['slug'] ) ) {
wp_send_json_error(
array(
'slug' => '',
'errorCode' => 'no_plugin_specified',
'errorMessage' => __( 'No plugin specified.' ),
)
);
}
$status = array(
'install' => 'plugin',
'slug' => sanitize_key( wp_unslash( $_POST['slug'] ) ),
);
if ( ! current_user_can( 'install_plugins' ) ) {
$status['errorMessage'] = __( 'Sorry, you are not allowed to install plugins on this site.' );
wp_send_json_error( $status );
}
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
$api = plugins_api(
'plugin_information',
array(
'slug' => sanitize_key( wp_unslash( $_POST['slug'] ) ),
'fields' => array(
'sections' => false,
),
)
);
if ( is_wp_error( $api ) ) {
$status['errorMessage'] = $api->get_error_message();
wp_send_json_error( $status );
}
$status['pluginName'] = $api->name;
$skin = new WP_Ajax_Upgrader_Skin();
$upgrader = new Plugin_Upgrader( $skin );
$result = $upgrader->install( $api->download_link );
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
$status['debug'] = $skin->get_upgrade_messages();
}
if ( is_wp_error( $result ) ) {
$status['errorCode'] = $result->get_error_code();
$status['errorMessage'] = $result->get_error_message();
wp_send_json_error( $status );
} elseif ( is_wp_error( $skin->result ) ) {
$status['errorCode'] = $skin->result->get_error_code();
$status['errorMessage'] = $skin->result->get_error_message();
wp_send_json_error( $status );
} elseif ( $skin->get_errors()->has_errors() ) {
$status['errorMessage'] = $skin->get_error_messages();
wp_send_json_error( $status );
} elseif ( is_null( $result ) ) {
global $wp_filesystem;
$status['errorCode'] = 'unable_to_connect_to_filesystem';
$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
// Pass through the error from WP_Filesystem if one was raised.
if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
}
wp_send_json_error( $status );
}
$install_status = install_plugin_install_status( $api );
$pagenow = isset( $_POST['pagenow'] ) ? sanitize_key( $_POST['pagenow'] ) : '';
// If installation request is coming from import page, do not return network activation link.
$plugins_url = ( 'import' === $pagenow ) ? admin_url( 'plugins.php' ) : network_admin_url( 'plugins.php' );
if ( current_user_can( 'activate_plugin', $install_status['file'] ) && is_plugin_inactive( $install_status['file'] ) ) {
$status['activateUrl'] = add_query_arg(
array(
'_wpnonce' => wp_create_nonce( 'activate-plugin_' . $install_status['file'] ),
'action' => 'activate',
'plugin' => $install_status['file'],
),
$plugins_url
);
}
if ( is_multisite() && current_user_can( 'manage_network_plugins' ) && 'import' !== $pagenow ) {
$status['activateUrl'] = add_query_arg( array( 'networkwide' => 1 ), $status['activateUrl'] );
}
wp_send_json_success( $status );
}
/**
* Ajax handler for updating a plugin.
*
* @since 4.2.0
*
* @see Plugin_Upgrader
*
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
*/
function wp_ajax_update_plugin() {
check_ajax_referer( 'updates' );
if ( empty( $_POST['plugin'] ) || empty( $_POST['slug'] ) ) {
wp_send_json_error(
array(
'slug' => '',
'errorCode' => 'no_plugin_specified',
'errorMessage' => __( 'No plugin specified.' ),
)
);
}
$plugin = plugin_basename( sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) );
$status = array(
'update' => 'plugin',
'slug' => sanitize_key( wp_unslash( $_POST['slug'] ) ),
'oldVersion' => '',
'newVersion' => '',
);
if ( ! current_user_can( 'update_plugins' ) || 0 !== validate_file( $plugin ) ) {
$status['errorMessage'] = __( 'Sorry, you are not allowed to update plugins for this site.' );
wp_send_json_error( $status );
}
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
$status['plugin'] = $plugin;
$status['pluginName'] = $plugin_data['Name'];
if ( $plugin_data['Version'] ) {
/* translators: %s: Plugin version. */
$status['oldVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
}
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
wp_update_plugins();
$skin = new WP_Ajax_Upgrader_Skin();
$upgrader = new Plugin_Upgrader( $skin );
$result = $upgrader->bulk_upgrade( array( $plugin ) );
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
$status['debug'] = $skin->get_upgrade_messages();
}
if ( is_wp_error( $skin->result ) ) {
$status['errorCode'] = $skin->result->get_error_code();
$status['errorMessage'] = $skin->result->get_error_message();
wp_send_json_error( $status );
} elseif ( $skin->get_errors()->has_errors() ) {
$status['errorMessage'] = $skin->get_error_messages();
wp_send_json_error( $status );
} elseif ( is_array( $result ) && ! empty( $result[ $plugin ] ) ) {
/*
* Plugin is already at the latest version.
*
* This may also be the return value if the `update_plugins` site transient is empty,
* e.g. when you update two plugins in quick succession before the transient repopulates.
*
* Preferably something can be done to ensure `update_plugins` isn't empty.
* For now, surface some sort of error here.
*/
if ( true === $result[ $plugin ] ) {
$status['errorMessage'] = $upgrader->strings['up_to_date'];
wp_send_json_error( $status );
}
$plugin_data = get_plugins( '/' . $result[ $plugin ]['destination_name'] );
$plugin_data = reset( $plugin_data );
if ( $plugin_data['Version'] ) {
/* translators: %s: Plugin version. */
$status['newVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
}
wp_send_json_success( $status );
} elseif ( false === $result ) {
global $wp_filesystem;
$status['errorCode'] = 'unable_to_connect_to_filesystem';
$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
// Pass through the error from WP_Filesystem if one was raised.
if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
}
wp_send_json_error( $status );
}
// An unhandled error occurred.
$status['errorMessage'] = __( 'Plugin update failed.' );
wp_send_json_error( $status );
}
/**
* Ajax handler for deleting a plugin.
*
* @since 4.6.0
*
* @see delete_plugins()
*
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
*/
function wp_ajax_delete_plugin() {
check_ajax_referer( 'updates' );
if ( empty( $_POST['slug'] ) || empty( $_POST['plugin'] ) ) {
wp_send_json_error(
array(
'slug' => '',
'errorCode' => 'no_plugin_specified',
'errorMessage' => __( 'No plugin specified.' ),
)
);
}
$plugin = plugin_basename( sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) );
$status = array(
'delete' => 'plugin',
'slug' => sanitize_key( wp_unslash( $_POST['slug'] ) ),
);
if ( ! current_user_can( 'delete_plugins' ) || 0 !== validate_file( $plugin ) ) {
$status['errorMessage'] = __( 'Sorry, you are not allowed to delete plugins for this site.' );
wp_send_json_error( $status );
}
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
$status['plugin'] = $plugin;
$status['pluginName'] = $plugin_data['Name'];
if ( is_plugin_active( $plugin ) ) {
$status['errorMessage'] = __( 'You cannot delete a plugin while it is active on the main site.' );
wp_send_json_error( $status );
}
// Check filesystem credentials. `delete_plugins()` will bail otherwise.
$url = wp_nonce_url( 'plugins.php?action=delete-selected&verify-delete=1&checked[]=' . $plugin, 'bulk-plugins' );
ob_start();
$credentials = request_filesystem_credentials( $url );
ob_end_clean();
if ( false === $credentials || ! WP_Filesystem( $credentials ) ) {
global $wp_filesystem;
$status['errorCode'] = 'unable_to_connect_to_filesystem';
$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
// Pass through the error from WP_Filesystem if one was raised.
if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
}
wp_send_json_error( $status );
}
$result = delete_plugins( array( $plugin ) );
if ( is_wp_error( $result ) ) {
$status['errorMessage'] = $result->get_error_message();
wp_send_json_error( $status );
} elseif ( false === $result ) {
$status['errorMessage'] = __( 'Plugin could not be deleted.' );
wp_send_json_error( $status );
}
wp_send_json_success( $status );
}
/**
* Ajax handler for searching plugins.
*
* @since 4.6.0
*
* @global string $s Search term.
*/
function wp_ajax_search_plugins() {
check_ajax_referer( 'updates' );
// Ensure after_plugin_row_{$plugin_file} gets hooked.
wp_plugin_update_rows();
$pagenow = isset( $_POST['pagenow'] ) ? sanitize_key( $_POST['pagenow'] ) : '';
if ( 'plugins-network' === $pagenow || 'plugins' === $pagenow ) {
set_current_screen( $pagenow );
}
/** @var WP_Plugins_List_Table $wp_list_table */
$wp_list_table = _get_list_table(
'WP_Plugins_List_Table',
array(
'screen' => get_current_screen(),
)
);
$status = array();
if ( ! $wp_list_table->ajax_user_can() ) {
$status['errorMessage'] = __( 'Sorry, you are not allowed to manage plugins for this site.' );
wp_send_json_error( $status );
}
// Set the correct requester, so pagination works.
$_SERVER['REQUEST_URI'] = add_query_arg(
array_diff_key(
$_POST,
array(
'_ajax_nonce' => null,
'action' => null,
)
),
network_admin_url( 'plugins.php', 'relative' )
);
$GLOBALS['s'] = wp_unslash( $_POST['s'] );
$wp_list_table->prepare_items();
ob_start();
$wp_list_table->display();
$status['count'] = count( $wp_list_table->items );
$status['items'] = ob_get_clean();
wp_send_json_success( $status );
}
/**
* Ajax handler for searching plugins to install.
*
* @since 4.6.0
*/
function wp_ajax_search_install_plugins() {
check_ajax_referer( 'updates' );
$pagenow = isset( $_POST['pagenow'] ) ? sanitize_key( $_POST['pagenow'] ) : '';
if ( 'plugin-install-network' === $pagenow || 'plugin-install' === $pagenow ) {
set_current_screen( $pagenow );
}
/** @var WP_Plugin_Install_List_Table $wp_list_table */
$wp_list_table = _get_list_table(
'WP_Plugin_Install_List_Table',
array(
'screen' => get_current_screen(),
)
);
$status = array();
if ( ! $wp_list_table->ajax_user_can() ) {
$status['errorMessage'] = __( 'Sorry, you are not allowed to manage plugins for this site.' );
wp_send_json_error( $status );
}
// Set the correct requester, so pagination works.
$_SERVER['REQUEST_URI'] = add_query_arg(
array_diff_key(
$_POST,
array(
'_ajax_nonce' => null,
'action' => null,
)
),
network_admin_url( 'plugin-install.php', 'relative' )
);
$wp_list_table->prepare_items();
ob_start();
$wp_list_table->display();
$status['count'] = (int) $wp_list_table->get_pagination_arg( 'total_items' );
$status['items'] = ob_get_clean();
wp_send_json_success( $status );
}
/**
* Ajax handler for editing a theme or plugin file.
*
* @since 4.9.0
*
* @see wp_edit_theme_plugin_file()
*/
function wp_ajax_edit_theme_plugin_file() {
$r = wp_edit_theme_plugin_file( wp_unslash( $_POST ) ); // Validation of args is done in wp_edit_theme_plugin_file().
if ( is_wp_error( $r ) ) {
wp_send_json_error(
array_merge(
array(
'code' => $r->get_error_code(),
'message' => $r->get_error_message(),
),
(array) $r->get_error_data()
)
);
} else {
wp_send_json_success(
array(
'message' => __( 'File edited successfully.' ),
)
);
}
}
/**
* Ajax handler for exporting a user's personal data.
*
* @since 4.9.6
*/
function wp_ajax_wp_privacy_export_personal_data() {
if ( empty( $_POST['id'] ) ) {
wp_send_json_error( __( 'Missing request ID.' ) );
}
$request_id = (int) $_POST['id'];
if ( $request_id < 1 ) {
wp_send_json_error( __( 'Invalid request ID.' ) );
}
if ( ! current_user_can( 'export_others_personal_data' ) ) {
wp_send_json_error( __( 'Sorry, you are not allowed to perform this action.' ) );
}
check_ajax_referer( 'wp-privacy-export-personal-data-' . $request_id, 'security' );
// Get the request.
$request = wp_get_user_request( $request_id );
if ( ! $request || 'export_personal_data' !== $request->action_name ) {
wp_send_json_error( __( 'Invalid request type.' ) );
}
$email_address = $request->email;
if ( ! is_email( $email_address ) ) {
wp_send_json_error( __( 'A valid email address must be given.' ) );
}
if ( ! isset( $_POST['exporter'] ) ) {
wp_send_json_error( __( 'Missing exporter index.' ) );
}
$exporter_index = (int) $_POST['exporter'];
if ( ! isset( $_POST['page'] ) ) {
wp_send_json_error( __( 'Missing page index.' ) );
}
$page = (int) $_POST['page'];
$send_as_email = isset( $_POST['sendAsEmail'] ) ? ( 'true' === $_POST['sendAsEmail'] ) : false;
/**
* Filters the array of exporter callbacks.
*
* @since 4.9.6
*
* @param array $args {
* An array of callable exporters of personal data. Default empty array.
*
* @type array ...$0 {
* Array of personal data exporters.
*
* @type callable $callback Callable exporter function that accepts an
* email address and a page and returns an array
* of name => value pairs of personal data.
* @type string $exporter_friendly_name Translated user facing friendly name for the
* exporter.
* }
* }
*/
$exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() );
if ( ! is_array( $exporters ) ) {
wp_send_json_error( __( 'An exporter has improperly used the registration filter.' ) );
}
// Do we have any registered exporters?
if ( 0 < count( $exporters ) ) {
if ( $exporter_index < 1 ) {
wp_send_json_error( __( 'Exporter index cannot be negative.' ) );
}
if ( $exporter_index > count( $exporters ) ) {
wp_send_json_error( __( 'Exporter index is out of range.' ) );
}
if ( $page < 1 ) {
wp_send_json_error( __( 'Page index cannot be less than one.' ) );
}
$exporter_keys = array_keys( $exporters );
$exporter_key = $exporter_keys[ $exporter_index - 1 ];
$exporter = $exporters[ $exporter_key ];
if ( ! is_array( $exporter ) ) {
wp_send_json_error(
/* translators: %s: Exporter array index. */
sprintf( __( 'Expected an array describing the exporter at index %s.' ), $exporter_key )
);
}
if ( ! array_key_exists( 'exporter_friendly_name', $exporter ) ) {
wp_send_json_error(
/* translators: %s: Exporter array index. */
sprintf( __( 'Exporter array at index %s does not include a friendly name.' ), $exporter_key )
);
}
$exporter_friendly_name = $exporter['exporter_friendly_name'];
if ( ! array_key_exists( 'callback', $exporter ) ) {
wp_send_json_error(
/* translators: %s: Exporter friendly name. */
sprintf( __( 'Exporter does not include a callback: %s.' ), esc_html( $exporter_friendly_name ) )
);
}
if ( ! is_callable( $exporter['callback'] ) ) {
wp_send_json_error(
/* translators: %s: Exporter friendly name. */
sprintf( __( 'Exporter callback is not a valid callback: %s.' ), esc_html( $exporter_friendly_name ) )
);
}
$callback = $exporter['callback'];
$response = call_user_func( $callback, $email_address, $page );
if ( is_wp_error( $response ) ) {
wp_send_json_error( $response );
}
if ( ! is_array( $response ) ) {
wp_send_json_error(
/* translators: %s: Exporter friendly name. */
sprintf( __( 'Expected response as an array from exporter: %s.' ), esc_html( $exporter_friendly_name ) )
);
}
if ( ! array_key_exists( 'data', $response ) ) {
wp_send_json_error(
/* translators: %s: Exporter friendly name. */
sprintf( __( 'Expected data in response array from exporter: %s.' ), esc_html( $exporter_friendly_name ) )
);
}
if ( ! is_array( $response['data'] ) ) {
wp_send_json_error(
/* translators: %s: Exporter friendly name. */
sprintf( __( 'Expected data array in response array from exporter: %s.' ), esc_html( $exporter_friendly_name ) )
);
}
if ( ! array_key_exists( 'done', $response ) ) {
wp_send_json_error(
/* translators: %s: Exporter friendly name. */
sprintf( __( 'Expected done (boolean) in response array from exporter: %s.' ), esc_html( $exporter_friendly_name ) )
);
}
} else {
// No exporters, so we're done.
$exporter_key = '';
$response = array(
'data' => array(),
'done' => true,
);
}
/**
* Filters a page of personal data exporter data. Used to build the export report.
*
* Allows the export response to be consumed by destinations in addition to Ajax.
*
* @since 4.9.6
*
* @param array $response The personal data for the given exporter and page.
* @param int $exporter_index The index of the exporter that provided this data.
* @param string $email_address The email address associated with this personal data.
* @param int $page The page for this response.
* @param int $request_id The privacy request post ID associated with this request.
* @param bool $send_as_email Whether the final results of the export should be emailed to the user.
* @param string $exporter_key The key (slug) of the exporter that provided this data.
*/
$response = apply_filters( 'wp_privacy_personal_data_export_page', $response, $exporter_index, $email_address, $page, $request_id, $send_as_email, $exporter_key );
if ( is_wp_error( $response ) ) {
wp_send_json_error( $response );
}
wp_send_json_success( $response );
}
/**
* Ajax handler for erasing personal data.
*
* @since 4.9.6
*/
function wp_ajax_wp_privacy_erase_personal_data() {
if ( empty( $_POST['id'] ) ) {
wp_send_json_error( __( 'Missing request ID.' ) );
}
$request_id = (int) $_POST['id'];
if ( $request_id < 1 ) {
wp_send_json_error( __( 'Invalid request ID.' ) );
}
// Both capabilities are required to avoid confusion, see `_wp_personal_data_removal_page()`.
if ( ! current_user_can( 'erase_others_personal_data' ) || ! current_user_can( 'delete_users' ) ) {
wp_send_json_error( __( 'Sorry, you are not allowed to perform this action.' ) );
}
check_ajax_referer( 'wp-privacy-erase-personal-data-' . $request_id, 'security' );
// Get the request.
$request = wp_get_user_request( $request_id );
if ( ! $request || 'remove_personal_data' !== $request->action_name ) {
wp_send_json_error( __( 'Invalid request type.' ) );
}
$email_address = $request->email;
if ( ! is_email( $email_address ) ) {
wp_send_json_error( __( 'Invalid email address in request.' ) );
}
if ( ! isset( $_POST['eraser'] ) ) {
wp_send_json_error( __( 'Missing eraser index.' ) );
}
$eraser_index = (int) $_POST['eraser'];
if ( ! isset( $_POST['page'] ) ) {
wp_send_json_error( __( 'Missing page index.' ) );
}
$page = (int) $_POST['page'];
/**
* Filters the array of personal data eraser callbacks.
*
* @since 4.9.6
*
* @param array $args {
* An array of callable erasers of personal data. Default empty array.
*
* @type array ...$0 {
* Array of personal data exporters.
*
* @type callable $callback Callable eraser that accepts an email address and
* a page and returns an array with boolean values for
* whether items were removed or retained and any messages
* from the eraser, as well as if additional pages are
* available.
* @type string $exporter_friendly_name Translated user facing friendly name for the eraser.
* }
* }
*/
$erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() );
// Do we have any registered erasers?
if ( 0 < count( $erasers ) ) {
if ( $eraser_index < 1 ) {
wp_send_json_error( __( 'Eraser index cannot be less than one.' ) );
}
if ( $eraser_index > count( $erasers ) ) {
wp_send_json_error( __( 'Eraser index is out of range.' ) );
}
if ( $page < 1 ) {
wp_send_json_error( __( 'Page index cannot be less than one.' ) );
}
$eraser_keys = array_keys( $erasers );
$eraser_key = $eraser_keys[ $eraser_index - 1 ];
$eraser = $erasers[ $eraser_key ];
if ( ! is_array( $eraser ) ) {
/* translators: %d: Eraser array index. */
wp_send_json_error( sprintf( __( 'Expected an array describing the eraser at index %d.' ), $eraser_index ) );
}
if ( ! array_key_exists( 'eraser_friendly_name', $eraser ) ) {
/* translators: %d: Eraser array index. */
wp_send_json_error( sprintf( __( 'Eraser array at index %d does not include a friendly name.' ), $eraser_index ) );
}
$eraser_friendly_name = $eraser['eraser_friendly_name'];
if ( ! array_key_exists( 'callback', $eraser ) ) {
wp_send_json_error(
sprintf(
/* translators: %s: Eraser friendly name. */
__( 'Eraser does not include a callback: %s.' ),
esc_html( $eraser_friendly_name )
)
);
}
if ( ! is_callable( $eraser['callback'] ) ) {
wp_send_json_error(
sprintf(
/* translators: %s: Eraser friendly name. */
__( 'Eraser callback is not valid: %s.' ),
esc_html( $eraser_friendly_name )
)
);
}
$callback = $eraser['callback'];
$response = call_user_func( $callback, $email_address, $page );
if ( is_wp_error( $response ) ) {
wp_send_json_error( $response );
}
if ( ! is_array( $response ) ) {
wp_send_json_error(
sprintf(
/* translators: 1: Eraser friendly name, 2: Eraser array index. */
__( 'Did not receive array from %1$s eraser (index %2$d).' ),
esc_html( $eraser_friendly_name ),
$eraser_index
)
);
}
if ( ! array_key_exists( 'items_removed', $response ) ) {
wp_send_json_error(
sprintf(
/* translators: 1: Eraser friendly name, 2: Eraser array index. */
__( 'Expected items_removed key in response array from %1$s eraser (index %2$d).' ),
esc_html( $eraser_friendly_name ),
$eraser_index
)
);
}
if ( ! array_key_exists( 'items_retained', $response ) ) {
wp_send_json_error(
sprintf(
/* translators: 1: Eraser friendly name, 2: Eraser array index. */
__( 'Expected items_retained key in response array from %1$s eraser (index %2$d).' ),
esc_html( $eraser_friendly_name ),
$eraser_index
)
);
}
if ( ! array_key_exists( 'messages', $response ) ) {
wp_send_json_error(
sprintf(
/* translators: 1: Eraser friendly name, 2: Eraser array index. */
__( 'Expected messages key in response array from %1$s eraser (index %2$d).' ),
esc_html( $eraser_friendly_name ),
$eraser_index
)
);
}
if ( ! is_array( $response['messages'] ) ) {
wp_send_json_error(
sprintf(
/* translators: 1: Eraser friendly name, 2: Eraser array index. */
__( 'Expected messages key to reference an array in response array from %1$s eraser (index %2$d).' ),
esc_html( $eraser_friendly_name ),
$eraser_index
)
);
}
if ( ! array_key_exists( 'done', $response ) ) {
wp_send_json_error(
sprintf(
/* translators: 1: Eraser friendly name, 2: Eraser array index. */
__( 'Expected done flag in response array from %1$s eraser (index %2$d).' ),
esc_html( $eraser_friendly_name ),
$eraser_index
)
);
}
} else {
// No erasers, so we're done.
$eraser_key = '';
$response = array(
'items_removed' => false,
'items_retained' => false,
'messages' => array(),
'done' => true,
);
}
/**
* Filters a page of personal data eraser data.
*
* Allows the erasure response to be consumed by destinations in addition to Ajax.
*
* @since 4.9.6
*
* @param array $response The personal data for the given exporter and page.
* @param int $eraser_index The index of the eraser that provided this data.
* @param string $email_address The email address associated with this personal data.
* @param int $page The page for this response.
* @param int $request_id The privacy request post ID associated with this request.
* @param string $eraser_key The key (slug) of the eraser that provided this data.
*/
$response = apply_filters( 'wp_privacy_personal_data_erasure_page', $response, $eraser_index, $email_address, $page, $request_id, $eraser_key );
if ( is_wp_error( $response ) ) {
wp_send_json_error( $response );
}
wp_send_json_success( $response );
}
/**
* Ajax handler for site health checks on server communication.
*
* @since 5.2.0
* @deprecated 5.6.0 Use WP_REST_Site_Health_Controller::test_dotorg_communication()
* @see WP_REST_Site_Health_Controller::test_dotorg_communication()
*/
function wp_ajax_health_check_dotorg_communication() {
_doing_it_wrong(
'wp_ajax_health_check_dotorg_communication',
sprintf(
// translators: 1: The Site Health action that is no longer used by core. 2: The new function that replaces it.
__( 'The Site Health check for %1$s has been replaced with %2$s.' ),
'wp_ajax_health_check_dotorg_communication',
'WP_REST_Site_Health_Controller::test_dotorg_communication'
),
'5.6.0'
);
check_ajax_referer( 'health-check-site-status' );
if ( ! current_user_can( 'view_site_health_checks' ) ) {
wp_send_json_error();
}
if ( ! class_exists( 'WP_Site_Health' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
}
$site_health = WP_Site_Health::get_instance();
wp_send_json_success( $site_health->get_test_dotorg_communication() );
}
/**
* Ajax handler for site health checks on background updates.
*
* @since 5.2.0
* @deprecated 5.6.0 Use WP_REST_Site_Health_Controller::test_background_updates()
* @see WP_REST_Site_Health_Controller::test_background_updates()
*/
function wp_ajax_health_check_background_updates() {
_doing_it_wrong(
'wp_ajax_health_check_background_updates',
sprintf(
// translators: 1: The Site Health action that is no longer used by core. 2: The new function that replaces it.
__( 'The Site Health check for %1$s has been replaced with %2$s.' ),
'wp_ajax_health_check_background_updates',
'WP_REST_Site_Health_Controller::test_background_updates'
),
'5.6.0'
);
check_ajax_referer( 'health-check-site-status' );
if ( ! current_user_can( 'view_site_health_checks' ) ) {
wp_send_json_error();
}
if ( ! class_exists( 'WP_Site_Health' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
}
$site_health = WP_Site_Health::get_instance();
wp_send_json_success( $site_health->get_test_background_updates() );
}
/**
* Ajax handler for site health checks on loopback requests.
*
* @since 5.2.0
* @deprecated 5.6.0 Use WP_REST_Site_Health_Controller::test_loopback_requests()
* @see WP_REST_Site_Health_Controller::test_loopback_requests()
*/
function wp_ajax_health_check_loopback_requests() {
_doing_it_wrong(
'wp_ajax_health_check_loopback_requests',
sprintf(
// translators: 1: The Site Health action that is no longer used by core. 2: The new function that replaces it.
__( 'The Site Health check for %1$s has been replaced with %2$s.' ),
'wp_ajax_health_check_loopback_requests',
'WP_REST_Site_Health_Controller::test_loopback_requests'
),
'5.6.0'
);
check_ajax_referer( 'health-check-site-status' );
if ( ! current_user_can( 'view_site_health_checks' ) ) {
wp_send_json_error();
}
if ( ! class_exists( 'WP_Site_Health' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
}
$site_health = WP_Site_Health::get_instance();
wp_send_json_success( $site_health->get_test_loopback_requests() );
}
/**
* Ajax handler for site health check to update the result status.
*
* @since 5.2.0
*/
function wp_ajax_health_check_site_status_result() {
check_ajax_referer( 'health-check-site-status-result' );
if ( ! current_user_can( 'view_site_health_checks' ) ) {
wp_send_json_error();
}
set_transient( 'health-check-site-status-result', wp_json_encode( $_POST['counts'] ) );
wp_send_json_success();
}
/**
* Ajax handler for site health check to get directories and database sizes.
*
* @since 5.2.0
* @deprecated 5.6.0 Use WP_REST_Site_Health_Controller::get_directory_sizes()
* @see WP_REST_Site_Health_Controller::get_directory_sizes()
*/
function wp_ajax_health_check_get_sizes() {
_doing_it_wrong(
'wp_ajax_health_check_get_sizes',
sprintf(
// translators: 1: The Site Health action that is no longer used by core. 2: The new function that replaces it.
__( 'The Site Health check for %1$s has been replaced with %2$s.' ),
'wp_ajax_health_check_get_sizes',
'WP_REST_Site_Health_Controller::get_directory_sizes'
),
'5.6.0'
);
check_ajax_referer( 'health-check-site-status-result' );
if ( ! current_user_can( 'view_site_health_checks' ) || is_multisite() ) {
wp_send_json_error();
}
if ( ! class_exists( 'WP_Debug_Data' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-debug-data.php';
}
$sizes_data = WP_Debug_Data::get_sizes();
$all_sizes = array( 'raw' => 0 );
foreach ( $sizes_data as $name => $value ) {
$name = sanitize_text_field( $name );
$data = array();
if ( isset( $value['size'] ) ) {
if ( is_string( $value['size'] ) ) {
$data['size'] = sanitize_text_field( $value['size'] );
} else {
$data['size'] = (int) $value['size'];
}
}
if ( isset( $value['debug'] ) ) {
if ( is_string( $value['debug'] ) ) {
$data['debug'] = sanitize_text_field( $value['debug'] );
} else {
$data['debug'] = (int) $value['debug'];
}
}
if ( ! empty( $value['raw'] ) ) {
$data['raw'] = (int) $value['raw'];
}
$all_sizes[ $name ] = $data;
}
if ( isset( $all_sizes['total_size']['debug'] ) && 'not available' === $all_sizes['total_size']['debug'] ) {
wp_send_json_error( $all_sizes );
}
wp_send_json_success( $all_sizes );
}
/**
* Ajax handler to renew the REST API nonce.
*
* @since 5.3.0
*/
function wp_ajax_rest_nonce() {
exit( wp_create_nonce( 'wp_rest' ) );
}
/**
* Ajax handler to enable or disable plugin and theme auto-updates.
*
* @since 5.5.0
*/
function wp_ajax_toggle_auto_updates() {
check_ajax_referer( 'updates' );
if ( empty( $_POST['type'] ) || empty( $_POST['asset'] ) || empty( $_POST['state'] ) ) {
wp_send_json_error( array( 'error' => __( 'Invalid data. No selected item.' ) ) );
}
$asset = sanitize_text_field( urldecode( $_POST['asset'] ) );
if ( 'enable' !== $_POST['state'] && 'disable' !== $_POST['state'] ) {
wp_send_json_error( array( 'error' => __( 'Invalid data. Unknown state.' ) ) );
}
$state = $_POST['state'];
if ( 'plugin' !== $_POST['type'] && 'theme' !== $_POST['type'] ) {
wp_send_json_error( array( 'error' => __( 'Invalid data. Unknown type.' ) ) );
}
$type = $_POST['type'];
switch ( $type ) {
case 'plugin':
if ( ! current_user_can( 'update_plugins' ) ) {
$error_message = __( 'Sorry, you are not allowed to modify plugins.' );
wp_send_json_error( array( 'error' => $error_message ) );
}
$option = 'auto_update_plugins';
/** This filter is documented in wp-admin/includes/class-wp-plugins-list-table.php */
$all_items = apply_filters( 'all_plugins', get_plugins() );
break;
case 'theme':
if ( ! current_user_can( 'update_themes' ) ) {
$error_message = __( 'Sorry, you are not allowed to modify themes.' );
wp_send_json_error( array( 'error' => $error_message ) );
}
$option = 'auto_update_themes';
$all_items = wp_get_themes();
break;
default:
wp_send_json_error( array( 'error' => __( 'Invalid data. Unknown type.' ) ) );
}
if ( ! array_key_exists( $asset, $all_items ) ) {
$error_message = __( 'Invalid data. The item does not exist.' );
wp_send_json_error( array( 'error' => $error_message ) );
}
$auto_updates = (array) get_site_option( $option, array() );
if ( 'disable' === $state ) {
$auto_updates = array_diff( $auto_updates, array( $asset ) );
} else {
$auto_updates[] = $asset;
$auto_updates = array_unique( $auto_updates );
}
// Remove items that have been deleted since the site option was last updated.
$auto_updates = array_intersect( $auto_updates, array_keys( $all_items ) );
update_site_option( $option, $auto_updates );
wp_send_json_success();
}
/**
* Ajax handler sends a password reset link.
*
* @since 5.7.0
*/
function wp_ajax_send_password_reset() {
// Validate the nonce for this action.
$user_id = isset( $_POST['user_id'] ) ? (int) $_POST['user_id'] : 0;
check_ajax_referer( 'reset-password-for-' . $user_id, 'nonce' );
// Verify user capabilities.
if ( ! current_user_can( 'edit_user', $user_id ) ) {
wp_send_json_error( __( 'Cannot send password reset, permission denied.' ) );
}
// Send the password reset link.
$user = get_userdata( $user_id );
$results = retrieve_password( $user->user_login );
if ( true === $results ) {
wp_send_json_success(
/* translators: %s: User's display name. */
sprintf( __( 'A password reset link was emailed to %s.' ), $user->display_name )
);
} else {
wp_send_json_error( $results->get_error_message() );
}
}
PK [w* * bookmark.phpnu [ ' . __( 'You need a higher level of permission.' ) . '' .
'' . __( 'Sorry, you are not allowed to edit the links for this site.' ) . '
', 403 ); } $_POST['link_url'] = esc_html( $_POST['link_url'] ); $_POST['link_url'] = esc_url( $_POST['link_url'] ); $_POST['link_name'] = esc_html( $_POST['link_name'] ); $_POST['link_image'] = esc_html( $_POST['link_image'] ); $_POST['link_rss'] = esc_url( $_POST['link_rss'] ); if ( ! isset( $_POST['link_visible'] ) || 'N' !== $_POST['link_visible'] ) { $_POST['link_visible'] = 'Y'; } if ( ! empty( $link_id ) ) { $_POST['link_id'] = $link_id; return wp_update_link( $_POST ); } else { return wp_insert_link( $_POST ); } } /** * Retrieves the default link for editing. * * @since 2.0.0 * * @return stdClass Default link object. */ function get_default_link_to_edit() { $link = new stdClass; if ( isset( $_GET['linkurl'] ) ) { $link->link_url = esc_url( wp_unslash( $_GET['linkurl'] ) ); } else { $link->link_url = ''; } if ( isset( $_GET['name'] ) ) { $link->link_name = esc_attr( wp_unslash( $_GET['name'] ) ); } else { $link->link_name = ''; } $link->link_visible = 'Y'; return $link; } /** * Deletes a specified link from the database. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $link_id ID of the link to delete * @return true Always true. */ function wp_delete_link( $link_id ) { global $wpdb; /** * Fires before a link is deleted. * * @since 2.0.0 * * @param int $link_id ID of the link to delete. */ do_action( 'delete_link', $link_id ); wp_delete_object_term_relationships( $link_id, 'link_category' ); $wpdb->delete( $wpdb->links, array( 'link_id' => $link_id ) ); /** * Fires after a link has been deleted. * * @since 2.2.0 * * @param int $link_id ID of the deleted link. */ do_action( 'deleted_link', $link_id ); clean_bookmark_cache( $link_id ); return true; } /** * Retrieves the link category IDs associated with the link specified. * * @since 2.1.0 * * @param int $link_id Link ID to look up. * @return int[] The IDs of the requested link's categories. */ function wp_get_link_cats( $link_id = 0 ) { $cats = wp_get_object_terms( $link_id, 'link_category', array( 'fields' => 'ids' ) ); return array_unique( $cats ); } /** * Retrieves link data based on its ID. * * @since 2.0.0 * * @param int|stdClass $link Link ID or object to retrieve. * @return object Link object for editing. */ function get_link_to_edit( $link ) { return get_bookmark( $link, OBJECT, 'edit' ); } /** * Inserts a link into the database, or updates an existing link. * * Runs all the necessary sanitizing, provides default values if arguments are missing, * and finally saves the link. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param array $linkdata { * Elements that make up the link to insert. * * @type int $link_id Optional. The ID of the existing link if updating. * @type string $link_url The URL the link points to. * @type string $link_name The title of the link. * @type string $link_image Optional. A URL of an image. * @type string $link_target Optional. The target element for the anchor tag. * @type string $link_description Optional. A short description of the link. * @type string $link_visible Optional. 'Y' means visible, anything else means not. * @type int $link_owner Optional. A user ID. * @type int $link_rating Optional. A rating for the link. * @type string $link_updated Optional. When the link was last updated. * @type string $link_rel Optional. A relationship of the link to you. * @type string $link_notes Optional. An extended description of or notes on the link. * @type string $link_rss Optional. A URL of an associated RSS feed. * @type int $link_category Optional. The term ID of the link category. * If empty, uses default link category. * } * @param bool $wp_error Optional. Whether to return a WP_Error object on failure. Default false. * @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success. */ function wp_insert_link( $linkdata, $wp_error = false ) { global $wpdb; $defaults = array( 'link_id' => 0, 'link_name' => '', 'link_url' => '', 'link_rating' => 0, ); $parsed_args = wp_parse_args( $linkdata, $defaults ); $parsed_args = wp_unslash( sanitize_bookmark( $parsed_args, 'db' ) ); $link_id = $parsed_args['link_id']; $link_name = $parsed_args['link_name']; $link_url = $parsed_args['link_url']; $update = false; if ( ! empty( $link_id ) ) { $update = true; } if ( '' === trim( $link_name ) ) { if ( '' !== trim( $link_url ) ) { $link_name = $link_url; } else { return 0; } } if ( '' === trim( $link_url ) ) { return 0; } $link_rating = ( ! empty( $parsed_args['link_rating'] ) ) ? $parsed_args['link_rating'] : 0; $link_image = ( ! empty( $parsed_args['link_image'] ) ) ? $parsed_args['link_image'] : ''; $link_target = ( ! empty( $parsed_args['link_target'] ) ) ? $parsed_args['link_target'] : ''; $link_visible = ( ! empty( $parsed_args['link_visible'] ) ) ? $parsed_args['link_visible'] : 'Y'; $link_owner = ( ! empty( $parsed_args['link_owner'] ) ) ? $parsed_args['link_owner'] : get_current_user_id(); $link_notes = ( ! empty( $parsed_args['link_notes'] ) ) ? $parsed_args['link_notes'] : ''; $link_description = ( ! empty( $parsed_args['link_description'] ) ) ? $parsed_args['link_description'] : ''; $link_rss = ( ! empty( $parsed_args['link_rss'] ) ) ? $parsed_args['link_rss'] : ''; $link_rel = ( ! empty( $parsed_args['link_rel'] ) ) ? $parsed_args['link_rel'] : ''; $link_category = ( ! empty( $parsed_args['link_category'] ) ) ? $parsed_args['link_category'] : array(); // Make sure we set a valid category. if ( ! is_array( $link_category ) || 0 === count( $link_category ) ) { $link_category = array( get_option( 'default_link_category' ) ); } if ( $update ) { if ( false === $wpdb->update( $wpdb->links, compact( 'link_url', 'link_name', 'link_image', 'link_target', 'link_description', 'link_visible', 'link_owner', 'link_rating', 'link_rel', 'link_notes', 'link_rss' ), compact( 'link_id' ) ) ) { if ( $wp_error ) { return new WP_Error( 'db_update_error', __( 'Could not update link in the database.' ), $wpdb->last_error ); } else { return 0; } } } else { if ( false === $wpdb->insert( $wpdb->links, compact( 'link_url', 'link_name', 'link_image', 'link_target', 'link_description', 'link_visible', 'link_owner', 'link_rating', 'link_rel', 'link_notes', 'link_rss' ) ) ) { if ( $wp_error ) { return new WP_Error( 'db_insert_error', __( 'Could not insert link into the database.' ), $wpdb->last_error ); } else { return 0; } } $link_id = (int) $wpdb->insert_id; } wp_set_link_cats( $link_id, $link_category ); if ( $update ) { /** * Fires after a link was updated in the database. * * @since 2.0.0 * * @param int $link_id ID of the link that was updated. */ do_action( 'edit_link', $link_id ); } else { /** * Fires after a link was added to the database. * * @since 2.0.0 * * @param int $link_id ID of the link that was added. */ do_action( 'add_link', $link_id ); } clean_bookmark_cache( $link_id ); return $link_id; } /** * Update link with the specified link categories. * * @since 2.1.0 * * @param int $link_id ID of the link to update. * @param int[] $link_categories Array of link category IDs to add the link to. */ function wp_set_link_cats( $link_id = 0, $link_categories = array() ) { // If $link_categories isn't already an array, make it one: if ( ! is_array( $link_categories ) || 0 === count( $link_categories ) ) { $link_categories = array( get_option( 'default_link_category' ) ); } $link_categories = array_map( 'intval', $link_categories ); $link_categories = array_unique( $link_categories ); wp_set_object_terms( $link_id, $link_categories, 'link_category' ); clean_bookmark_cache( $link_id ); } /** * Updates a link in the database. * * @since 2.0.0 * * @param array $linkdata Link data to update. See wp_insert_link() for accepted arguments. * @return int|WP_Error Value 0 or WP_Error on failure. The updated link ID on success. */ function wp_update_link( $linkdata ) { $link_id = (int) $linkdata['link_id']; $link = get_bookmark( $link_id, ARRAY_A ); // Escape data pulled from DB. $link = wp_slash( $link ); // Passed link category list overwrites existing category list if not empty. if ( isset( $linkdata['link_category'] ) && is_array( $linkdata['link_category'] ) && count( $linkdata['link_category'] ) > 0 ) { $link_cats = $linkdata['link_category']; } else { $link_cats = $link['link_category']; } // Merge old and new fields with new fields overwriting old ones. $linkdata = array_merge( $link, $linkdata ); $linkdata['link_category'] = $link_cats; return wp_insert_link( $linkdata ); } /** * Outputs the 'disabled' message for the WordPress Link Manager. * * @since 3.5.0 * @access private * * @global string $pagenow */ function wp_link_manager_disabled_message() { global $pagenow; if ( ! in_array( $pagenow, array( 'link-manager.php', 'link-add.php', 'link.php' ), true ) ) { return; } add_filter( 'pre_option_link_manager_enabled', '__return_true', 100 ); $really_can_manage_links = current_user_can( 'manage_links' ); remove_filter( 'pre_option_link_manager_enabled', '__return_true', 100 ); if ( $really_can_manage_links && current_user_can( 'install_plugins' ) ) { $link = network_admin_url( 'plugin-install.php?tab=search&s=Link+Manager' ); /* translators: %s: URL to install the Link Manager plugin. */ wp_die( sprintf( __( 'If you are looking to use the link manager, please install the Link Manager plugin.' ), $link ) ); } wp_die( __( 'Sorry, you are not allowed to edit the links for this site.' ) ); } PK [ʼn ! class-automatic-upgrader-skin.phpnu [ options['context'] = $context; } /* * TODO: Fix up request_filesystem_credentials(), or split it, to allow us to request a no-output version. * This will output a credentials form in event of failure. We don't want that, so just hide with a buffer. */ ob_start(); $result = parent::request_filesystem_credentials( $error, $context, $allow_relaxed_file_ownership ); ob_end_clean(); return $result; } /** * Retrieves the upgrade messages. * * @since 3.7.0 * * @return array Messages during an upgrade. */ public function get_upgrade_messages() { return $this->messages; } /** * Stores a message about the upgrade. * * @since 3.7.0 * * @param string|array|WP_Error $data Message data. * @param mixed ...$args Optional text replacements. */ public function feedback( $data, ...$args ) { if ( is_wp_error( $data ) ) { $string = $data->get_error_message(); } elseif ( is_array( $data ) ) { return; } else { $string = $data; } if ( ! empty( $this->upgrader->strings[ $string ] ) ) { $string = $this->upgrader->strings[ $string ]; } if ( strpos( $string, '%' ) !== false ) { if ( ! empty( $args ) ) { $string = vsprintf( $string, $args ); } } $string = trim( $string ); // Only allow basic HTML in the messages, as it'll be used in emails/logs rather than direct browser output. $string = wp_kses( $string, array( 'a' => array( 'href' => true, ), 'br' => true, 'em' => true, 'strong' => true, ) ); if ( empty( $string ) ) { return; } $this->messages[] = $string; } /** * Creates a new output buffer. * * @since 3.7.0 */ public function header() { ob_start(); } /** * Retrieves the buffered content, deletes the buffer, and processes the output. * * @since 3.7.0 */ public function footer() { $output = ob_get_clean(); if ( ! empty( $output ) ) { $this->feedback( $output ); } } } PK []o # class-bulk-plugin-upgrader-skin.phpnu [ upgrader->strings['skin_before_update_header'] = __( 'Updating Plugin %1$s (%2$d/%3$d)' ); } /** * @param string $title */ public function before( $title = '' ) { parent::before( $this->plugin_info['Title'] ); } /** * @param string $title */ public function after( $title = '' ) { parent::after( $this->plugin_info['Title'] ); $this->decrement_update_count( 'plugin' ); } /** */ public function bulk_footer() { parent::bulk_footer(); $update_actions = array( 'plugins_page' => sprintf( '%s', self_admin_url( 'plugins.php' ), __( 'Go to Plugins page' ) ), 'updates_page' => sprintf( '%s', self_admin_url( 'update-core.php' ), __( 'Go to WordPress Updates page' ) ), ); if ( ! current_user_can( 'activate_plugins' ) ) { unset( $update_actions['plugins_page'] ); } /** * Filters the list of action links available following bulk plugin updates. * * @since 3.0.0 * * @param string[] $update_actions Array of plugin action links. * @param array $plugin_info Array of information for the last-updated plugin. */ $update_actions = apply_filters( 'update_bulk_plugins_complete_actions', $update_actions, $this->plugin_info ); if ( ! empty( $update_actions ) ) { $this->feedback( implode( ' | ', (array) $update_actions ) ); } } } PK [Y63 3 " class-bulk-theme-upgrader-skin.phpnu [ upgrader->strings['skin_before_update_header'] = __( 'Updating Theme %1$s (%2$d/%3$d)' ); } /** * @param string $title */ public function before( $title = '' ) { parent::before( $this->theme_info->display( 'Name' ) ); } /** * @param string $title */ public function after( $title = '' ) { parent::after( $this->theme_info->display( 'Name' ) ); $this->decrement_update_count( 'theme' ); } /** */ public function bulk_footer() { parent::bulk_footer(); $update_actions = array( 'themes_page' => sprintf( '%s', self_admin_url( 'themes.php' ), __( 'Go to Themes page' ) ), 'updates_page' => sprintf( '%s', self_admin_url( 'update-core.php' ), __( 'Go to WordPress Updates page' ) ), ); if ( ! current_user_can( 'switch_themes' ) && ! current_user_can( 'edit_theme_options' ) ) { unset( $update_actions['themes_page'] ); } /** * Filters the list of action links available following bulk theme updates. * * @since 3.0.0 * * @param string[] $update_actions Array of theme action links. * @param WP_Theme $theme_info Theme object for the last-updated theme. */ $update_actions = apply_filters( 'update_bulk_theme_complete_actions', $update_actions, $this->theme_info ); if ( ! empty( $update_actions ) ) { $this->feedback( implode( ' | ', (array) $update_actions ) ); } } } PK [Pؽ class-bulk-upgrader-skin.phpnu [ '', 'nonce' => '', ); $args = wp_parse_args( $args, $defaults ); parent::__construct( $args ); } /** */ 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.' ); } /** * @param string $string * @param mixed ...$args Optional text replacements. */ public function feedback( $string, ...$args ) { if ( isset( $this->upgrader->strings[ $string ] ) ) { $string = $this->upgrader->strings[ $string ]; } if ( strpos( $string, '%' ) !== false ) { if ( $args ) { $args = array_map( 'strip_tags', $args ); $args = array_map( 'esc_html', $args ); $string = vsprintf( $string, $args ); } } if ( empty( $string ) ) { return; } if ( $this->in_loop ) { echo "$string$string
\n"; } } /** */ public function header() { // Nothing, This will be displayed within a iframe. } /** */ public function footer() { // Nothing, This will be displayed within a iframe. } /** * @param string|WP_Error $error */ public function error( $error ) { if ( is_string( $error ) && isset( $this->upgrader->strings[ $error ] ) ) { $this->error = $this->upgrader->strings[ $error ]; } if ( is_wp_error( $error ) ) { $messages = array(); foreach ( $error->get_error_messages() as $emessage ) { if ( $error->get_error_data() && is_string( $error->get_error_data() ) ) { $messages[] = $emessage . ' ' . esc_html( strip_tags( $error->get_error_data() ) ); } else { $messages[] = $emessage; } } $this->error = implode( ', ', $messages ); } echo ''; } /** */ public function bulk_header() { $this->feedback( 'skin_upgrade_start' ); } /** */ public function bulk_footer() { $this->feedback( 'skin_upgrade_end' ); } /** * @param string $title */ public function before( $title = '' ) { $this->in_loop = true; printf( '' . sprintf( $this->upgrader->strings['skin_update_failed_error'], $title, '' . $this->error . '' ) . '
' . sprintf( $this->upgrader->strings['skin_update_failed'], $title ) . '
' . sprintf( $this->upgrader->strings['skin_update_successful'], $title ) . ' ' . '
' . __( 'You can customize the look of your site without touching any of your theme’s code by using a custom background. Your background can be an image or a color.' ) . '
' . '' . __( 'To use a background image, simply upload it or choose an image that has already been uploaded to your Media Library by clicking the “Choose Image” button. You can display a single instance of your image, or tile it to fill the screen. You can have your background fixed in place, so your site content moves on top of it, or you can have it scroll with your site.' ) . '
' . '' . __( 'You can also choose a background color by clicking the Select Color button and either typing in a legitimate HTML hex value, e.g. “#ff0000” for red, or by choosing a color using the color picker.' ) . '
' . '' . __( 'Don’t forget to click on the Save Changes button when you are finished.' ) . '
', ) ); get_current_screen()->set_help_sidebar( '' . __( 'For more information:' ) . '
' . '' . __( 'Documentation on Custom Background' ) . '
' . '' . __( 'Support' ) . '
' ); wp_enqueue_media(); wp_enqueue_script( 'custom-background' ); wp_enqueue_style( 'wp-color-picker' ); } /** * Execute custom background modification. * * @since 3.0.0 */ public function take_action() { if ( empty( $_POST ) ) { return; } if ( isset( $_POST['reset-background'] ) ) { check_admin_referer( 'custom-background-reset', '_wpnonce-custom-background-reset' ); remove_theme_mod( 'background_image' ); remove_theme_mod( 'background_image_thumb' ); $this->updated = true; return; } if ( isset( $_POST['remove-background'] ) ) { // @todo Uploaded files are not removed here. check_admin_referer( 'custom-background-remove', '_wpnonce-custom-background-remove' ); set_theme_mod( 'background_image', '' ); set_theme_mod( 'background_image_thumb', '' ); $this->updated = true; wp_safe_redirect( $_POST['_wp_http_referer'] ); return; } if ( isset( $_POST['background-preset'] ) ) { check_admin_referer( 'custom-background' ); if ( in_array( $_POST['background-preset'], array( 'default', 'fill', 'fit', 'repeat', 'custom' ), true ) ) { $preset = $_POST['background-preset']; } else { $preset = 'default'; } set_theme_mod( 'background_preset', $preset ); } if ( isset( $_POST['background-position'] ) ) { check_admin_referer( 'custom-background' ); $position = explode( ' ', $_POST['background-position'] ); if ( in_array( $position[0], array( 'left', 'center', 'right' ), true ) ) { $position_x = $position[0]; } else { $position_x = 'left'; } if ( in_array( $position[1], array( 'top', 'center', 'bottom' ), true ) ) { $position_y = $position[1]; } else { $position_y = 'top'; } set_theme_mod( 'background_position_x', $position_x ); set_theme_mod( 'background_position_y', $position_y ); } if ( isset( $_POST['background-size'] ) ) { check_admin_referer( 'custom-background' ); if ( in_array( $_POST['background-size'], array( 'auto', 'contain', 'cover' ), true ) ) { $size = $_POST['background-size']; } else { $size = 'auto'; } set_theme_mod( 'background_size', $size ); } if ( isset( $_POST['background-repeat'] ) ) { check_admin_referer( 'custom-background' ); $repeat = $_POST['background-repeat']; if ( 'no-repeat' !== $repeat ) { $repeat = 'repeat'; } set_theme_mod( 'background_repeat', $repeat ); } if ( isset( $_POST['background-attachment'] ) ) { check_admin_referer( 'custom-background' ); $attachment = $_POST['background-attachment']; if ( 'fixed' !== $attachment ) { $attachment = 'scroll'; } set_theme_mod( 'background_attachment', $attachment ); } if ( isset( $_POST['background-color'] ) ) { check_admin_referer( 'custom-background' ); $color = preg_replace( '/[^0-9a-fA-F]/', '', $_POST['background-color'] ); if ( strlen( $color ) == 6 || strlen( $color ) == 3 ) { set_theme_mod( 'background_color', $color ); } else { set_theme_mod( 'background_color', '' ); } } $this->updated = true; } /** * Display the custom background page. * * @since 3.0.0 */ public function admin_page() { ?>Visit your site to see how it looks.' ), home_url( '/' ) ); ?>
|
admin_image_div_callback ) {
call_user_func( $this->admin_image_div_callback );
} else {
$background_styles = '';
$bgcolor = get_background_color();
if ( $bgcolor ) {
$background_styles .= 'background-color: #' . $bgcolor . ';';
}
$background_image_thumb = get_background_image();
if ( $background_image_thumb ) {
$background_image_thumb = esc_url( set_url_scheme( get_theme_mod( 'background_image_thumb', str_replace( '%', '%%', $background_image_thumb ) ) ) );
$background_position_x = get_theme_mod( 'background_position_x', get_theme_support( 'custom-background', 'default-position-x' ) );
$background_position_y = get_theme_mod( 'background_position_y', get_theme_support( 'custom-background', 'default-position-y' ) );
$background_size = get_theme_mod( 'background_size', get_theme_support( 'custom-background', 'default-size' ) );
$background_repeat = get_theme_mod( 'background_repeat', get_theme_support( 'custom-background', 'default-repeat' ) );
$background_attachment = get_theme_mod( 'background_attachment', get_theme_support( 'custom-background', 'default-attachment' ) );
// Background-image URL must be single quote, see below.
$background_styles .= " background-image: url('$background_image_thumb');"
. " background-size: $background_size;"
. " background-position: $background_position_x $background_position_y;"
. " background-repeat: $background_repeat;"
. " background-attachment: $background_attachment;";
}
?>
|
|
' . __( 'This screen is used to customize the header section of your theme.' ) . '
' . '' . __( 'You can choose from the theme’s default header images, or use one of your own. You can also customize how your Site Title and Tagline are displayed.' ) . '
', ) ); get_current_screen()->add_help_tab( array( 'id' => 'set-header-image', 'title' => __( 'Header Image' ), 'content' => '
' . __( 'You can set a custom image header for your site. Simply upload the image and crop it, and the new header will go live immediately. Alternatively, you can use an image that has already been uploaded to your Media Library by clicking the “Choose Image” button.' ) . '
' . '' . __( 'Some themes come with additional header images bundled. If you see multiple images displayed, select the one you’d like and click the “Save Changes” button.' ) . '
' . '' . __( 'If your theme has more than one default header image, or you have uploaded more than one custom header image, you have the option of having WordPress display a randomly different image on each page of your site. Click the “Random” radio button next to the Uploaded Images or Default Images section to enable this feature.' ) . '
' . '' . __( 'If you don’t want a header image to be displayed on your site at all, click the “Remove Header Image” button at the bottom of the Header Image section of this page. If you want to re-enable the header image later, you just have to select one of the other image options and click “Save Changes”.' ) . '
', ) ); get_current_screen()->add_help_tab( array( 'id' => 'set-header-text', 'title' => __( 'Header Text' ), 'content' => '' . sprintf( /* translators: %s: URL to General Settings screen. */ __( 'For most themes, the header text is your Site Title and Tagline, as defined in the General Settings section.' ), admin_url( 'options-general.php' ) ) . '
' . '' . __( 'In the Header Text section of this page, you can choose whether to display this text or hide it. You can also choose a color for the text by clicking the Select Color button and either typing in a legitimate HTML hex value, e.g. “#ff0000” for red, or by choosing a color using the color picker.' ) . '
' . '' . __( 'Don’t forget to click “Save Changes” when you’re done!' ) . '
', ) ); get_current_screen()->set_help_sidebar( '' . __( 'For more information:' ) . '
' . '' . __( 'Documentation on Custom Header' ) . '
' . '' . __( 'Support' ) . '
' ); } /** * Get the current step. * * @since 2.6.0 * * @return int Current step */ public function step() { if ( ! isset( $_GET['step'] ) ) { return 1; } $step = (int) $_GET['step']; if ( $step < 1 || 3 < $step || ( 2 == $step && ! wp_verify_nonce( $_REQUEST['_wpnonce-custom-header-upload'], 'custom-header-upload' ) ) || ( 3 == $step && ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'custom-header-crop-image' ) ) ) { return 1; } return $step; } /** * Set up the enqueue for the JavaScript files. * * @since 2.1.0 */ public function js_includes() { $step = $this->step(); if ( ( 1 == $step || 3 == $step ) ) { wp_enqueue_media(); wp_enqueue_script( 'custom-header' ); if ( current_theme_supports( 'custom-header', 'header-text' ) ) { wp_enqueue_script( 'wp-color-picker' ); } } elseif ( 2 == $step ) { wp_enqueue_script( 'imgareaselect' ); } } /** * Set up the enqueue for the CSS files * * @since 2.7.0 */ public function css_includes() { $step = $this->step(); if ( ( 1 == $step || 3 == $step ) && current_theme_supports( 'custom-header', 'header-text' ) ) { wp_enqueue_style( 'wp-color-picker' ); } elseif ( 2 == $step ) { wp_enqueue_style( 'imgareaselect' ); } } /** * Execute custom header modification. * * @since 2.6.0 */ public function take_action() { if ( ! current_user_can( 'edit_theme_options' ) ) { return; } if ( empty( $_POST ) ) { return; } $this->updated = true; if ( isset( $_POST['resetheader'] ) ) { check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' ); $this->reset_header_image(); return; } if ( isset( $_POST['removeheader'] ) ) { check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' ); $this->remove_header_image(); return; } if ( isset( $_POST['text-color'] ) && ! isset( $_POST['display-header-text'] ) ) { check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' ); set_theme_mod( 'header_textcolor', 'blank' ); } elseif ( isset( $_POST['text-color'] ) ) { check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' ); $_POST['text-color'] = str_replace( '#', '', $_POST['text-color'] ); $color = preg_replace( '/[^0-9a-fA-F]/', '', $_POST['text-color'] ); if ( strlen( $color ) == 6 || strlen( $color ) == 3 ) { set_theme_mod( 'header_textcolor', $color ); } elseif ( ! $color ) { set_theme_mod( 'header_textcolor', 'blank' ); } } if ( isset( $_POST['default-header'] ) ) { check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' ); $this->set_header_image( $_POST['default-header'] ); return; } } /** * Process the default headers * * @since 3.0.0 * * @global array $_wp_default_headers */ public function process_default_headers() { global $_wp_default_headers; if ( ! isset( $_wp_default_headers ) ) { return; } if ( ! empty( $this->default_headers ) ) { return; } $this->default_headers = $_wp_default_headers; $template_directory_uri = get_template_directory_uri(); $stylesheet_directory_uri = get_stylesheet_directory_uri(); foreach ( array_keys( $this->default_headers ) as $header ) { $this->default_headers[ $header ]['url'] = sprintf( $this->default_headers[ $header ]['url'], $template_directory_uri, $stylesheet_directory_uri ); $this->default_headers[ $header ]['thumbnail_url'] = sprintf( $this->default_headers[ $header ]['thumbnail_url'], $template_directory_uri, $stylesheet_directory_uri ); } } /** * Display UI for selecting one of several default headers. * * Show the random image option if this theme has multiple header images. * Random image option is on by default if no header has been set. * * @since 3.0.0 * * @param string $type The header type. One of 'default' (for the Uploaded Images control) * or 'uploaded' (for the Uploaded Images control). */ public function show_header_selector( $type = 'default' ) { if ( 'default' === $type ) { $headers = $this->default_headers; } else { $headers = get_uploaded_header_images(); $type = 'uploaded'; } if ( 1 < count( $headers ) ) { echo 'Visit your site to see how it looks.' ), home_url( '/' ) ); ?>
| admin_image_div_callback ) { call_user_func( $this->admin_image_div_callback ); } else { $custom_header = get_custom_header(); $header_image = get_header_image(); if ( $header_image ) { $header_image_style = 'background-image:url(' . esc_url( $header_image ) . ');'; } else { $header_image_style = ''; } if ( $custom_header->width ) { $header_image_style .= 'max-width:' . $custom_header->width . 'px;'; } if ( $custom_header->height ) { $header_image_style .= 'height:' . $custom_header->height . 'px;'; } ?> | |
|
|
' . __( 'The current theme does not support uploading a custom header image.' ) . '
', 403 ); } if ( empty( $_POST ) && isset( $_GET['file'] ) ) { $attachment_id = absint( $_GET['file'] ); $file = get_attached_file( $attachment_id, true ); $url = wp_get_attachment_image_src( $attachment_id, 'full' ); $url = $url[0]; } elseif ( isset( $_POST ) ) { $data = $this->step_2_manage_upload(); $attachment_id = $data['attachment_id']; $file = $data['file']; $url = $data['url']; } if ( file_exists( $file ) ) { list( $width, $height, $type, $attr ) = wp_getimagesize( $file ); } else { $data = wp_get_attachment_metadata( $attachment_id ); $height = isset( $data['height'] ) ? $data['height'] : 0; $width = isset( $data['width'] ) ? $data['width'] : 0; unset( $data ); } $max_width = 0; // For flex, limit size of image displayed to 1500px unless theme says otherwise. if ( current_theme_supports( 'custom-header', 'flex-width' ) ) { $max_width = 1500; } if ( current_theme_supports( 'custom-header', 'max-width' ) ) { $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) ); } $max_width = max( $max_width, get_theme_support( 'custom-header', 'width' ) ); // If flexible height isn't supported and the image is the exact right size. if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) && get_theme_support( 'custom-header', 'width' ) == $width && get_theme_support( 'custom-header', 'height' ) == $height ) { // Add the metadata. if ( file_exists( $file ) ) { wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) ); } $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) ); /** * Fires after the header image is set or an error is returned. * * @since 2.1.0 * * @param string $file Path to the file. * @param int $attachment_id Attachment ID. */ do_action( 'wp_create_file_in_uploads', $file, $attachment_id ); // For replication. return $this->finished(); } elseif ( $width > $max_width ) { $oitar = $width / $max_width; $image = wp_crop_image( $attachment_id, 0, 0, $width, $height, $max_width, $height / $oitar, false, str_replace( wp_basename( $file ), 'midsize-' . wp_basename( $file ), $file ) ); if ( ! $image || is_wp_error( $image ) ) { wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) ); } /** This filter is documented in wp-admin/includes/class-custom-image-header.php */ $image = apply_filters( 'wp_create_file_in_uploads', $image, $attachment_id ); // For replication. $url = str_replace( wp_basename( $url ), wp_basename( $image ), $url ); $width = $width / $oitar; $height = $height / $oitar; } else { $oitar = 1; } ?>' . __( 'The current theme does not support uploading a custom header image.' ) . '
', 403 ); } if ( ! empty( $_POST['skip-cropping'] ) && ! ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) ) { wp_die( '' . __( 'The current theme does not support a flexible sized header image.' ) . '
', 403 ); } if ( $_POST['oitar'] > 1 ) { $_POST['x1'] = $_POST['x1'] * $_POST['oitar']; $_POST['y1'] = $_POST['y1'] * $_POST['oitar']; $_POST['width'] = $_POST['width'] * $_POST['oitar']; $_POST['height'] = $_POST['height'] * $_POST['oitar']; } $attachment_id = absint( $_POST['attachment_id'] ); $original = get_attached_file( $attachment_id ); $dimensions = $this->get_header_dimensions( array( 'height' => $_POST['height'], 'width' => $_POST['width'], ) ); $height = $dimensions['dst_height']; $width = $dimensions['dst_width']; if ( empty( $_POST['skip-cropping'] ) ) { $cropped = wp_crop_image( $attachment_id, (int) $_POST['x1'], (int) $_POST['y1'], (int) $_POST['width'], (int) $_POST['height'], $width, $height ); } elseif ( ! empty( $_POST['create-new-attachment'] ) ) { $cropped = _copy_image_file( $attachment_id ); } else { $cropped = get_attached_file( $attachment_id ); } if ( ! $cropped || is_wp_error( $cropped ) ) { wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) ); } /** This filter is documented in wp-admin/includes/class-custom-image-header.php */ $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication. $object = $this->create_attachment_object( $cropped, $attachment_id ); if ( ! empty( $_POST['create-new-attachment'] ) ) { unset( $object['ID'] ); } // Update the attachment. $attachment_id = $this->insert_attachment( $object, $cropped ); $url = wp_get_attachment_url( $attachment_id ); $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) ); // Cleanup. $medium = str_replace( wp_basename( $original ), 'midsize-' . wp_basename( $original ), $original ); if ( file_exists( $medium ) ) { wp_delete_file( $medium ); } if ( empty( $_POST['create-new-attachment'] ) && empty( $_POST['skip-cropping'] ) ) { wp_delete_file( $original ); } return $this->finished(); } /** * Display last step of custom header image page. * * @since 2.1.0 */ public function finished() { $this->updated = true; $this->step_1(); } /** * Display the page based on the current step. * * @since 2.1.0 */ public function admin_page() { if ( ! current_user_can( 'edit_theme_options' ) ) { wp_die( __( 'Sorry, you are not allowed to customize headers.' ) ); } $step = $this->step(); if ( 2 == $step ) { $this->step_2(); } elseif ( 3 == $step ) { $this->step_3(); } else { $this->step_1(); } } /** * Unused since 3.5.0. * * @since 3.4.0 * * @param array $form_fields * @return array $form_fields */ public function attachment_fields_to_edit( $form_fields ) { return $form_fields; } /** * Unused since 3.5.0. * * @since 3.4.0 * * @param array $tabs * @return array $tabs */ public function filter_upload_tabs( $tabs ) { return $tabs; } /** * Choose a header image, selected from existing uploaded and default headers, * or provide an array of uploaded header data (either new, or from media library). * * @since 3.4.0 * * @param mixed $choice Which header image to select. Allows for values of 'random-default-image', * for randomly cycling among the default images; 'random-uploaded-image', for randomly cycling * among the uploaded images; the key of a default image registered for that theme; and * the key of an image uploaded for that theme (the attachment ID of the image). * Or an array of arguments: attachment_id, url, width, height. All are required. */ final public function set_header_image( $choice ) { if ( is_array( $choice ) || is_object( $choice ) ) { $choice = (array) $choice; if ( ! isset( $choice['attachment_id'] ) || ! isset( $choice['url'] ) ) { return; } $choice['url'] = esc_url_raw( $choice['url'] ); $header_image_data = (object) array( 'attachment_id' => $choice['attachment_id'], 'url' => $choice['url'], 'thumbnail_url' => $choice['url'], 'height' => $choice['height'], 'width' => $choice['width'], ); update_post_meta( $choice['attachment_id'], '_wp_attachment_is_custom_header', get_stylesheet() ); set_theme_mod( 'header_image', $choice['url'] ); set_theme_mod( 'header_image_data', $header_image_data ); return; } if ( in_array( $choice, array( 'remove-header', 'random-default-image', 'random-uploaded-image' ), true ) ) { set_theme_mod( 'header_image', $choice ); remove_theme_mod( 'header_image_data' ); return; } $uploaded = get_uploaded_header_images(); if ( $uploaded && isset( $uploaded[ $choice ] ) ) { $header_image_data = $uploaded[ $choice ]; } else { $this->process_default_headers(); if ( isset( $this->default_headers[ $choice ] ) ) { $header_image_data = $this->default_headers[ $choice ]; } else { return; } } set_theme_mod( 'header_image', esc_url_raw( $header_image_data['url'] ) ); set_theme_mod( 'header_image_data', $header_image_data ); } /** * Remove a header image. * * @since 3.4.0 */ final public function remove_header_image() { $this->set_header_image( 'remove-header' ); } /** * Reset a header image to the default image for the theme. * * This method does not do anything if the theme does not have a default header image. * * @since 3.4.0 */ final public function reset_header_image() { $this->process_default_headers(); $default = get_theme_support( 'custom-header', 'default-image' ); if ( ! $default ) { $this->remove_header_image(); return; } $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() ); $default_data = array(); foreach ( $this->default_headers as $header => $details ) { if ( $details['url'] == $default ) { $default_data = $details; break; } } set_theme_mod( 'header_image', $default ); set_theme_mod( 'header_image_data', (object) $default_data ); } /** * Calculate width and height based on what the currently selected theme supports. * * @since 3.9.0 * * @param array $dimensions * @return array dst_height and dst_width of header image. */ final public function get_header_dimensions( $dimensions ) { $max_width = 0; $width = absint( $dimensions['width'] ); $height = absint( $dimensions['height'] ); $theme_height = get_theme_support( 'custom-header', 'height' ); $theme_width = get_theme_support( 'custom-header', 'width' ); $has_flex_width = current_theme_supports( 'custom-header', 'flex-width' ); $has_flex_height = current_theme_supports( 'custom-header', 'flex-height' ); $has_max_width = current_theme_supports( 'custom-header', 'max-width' ); $dst = array( 'dst_height' => null, 'dst_width' => null, ); // For flex, limit size of image displayed to 1500px unless theme says otherwise. if ( $has_flex_width ) { $max_width = 1500; } if ( $has_max_width ) { $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) ); } $max_width = max( $max_width, $theme_width ); if ( $has_flex_height && ( ! $has_flex_width || $width > $max_width ) ) { $dst['dst_height'] = absint( $height * ( $max_width / $width ) ); } elseif ( $has_flex_height && $has_flex_width ) { $dst['dst_height'] = $height; } else { $dst['dst_height'] = $theme_height; } if ( $has_flex_width && ( ! $has_flex_height || $width > $max_width ) ) { $dst['dst_width'] = absint( $width * ( $max_width / $width ) ); } elseif ( $has_flex_width && $has_flex_height ) { $dst['dst_width'] = $width; } else { $dst['dst_width'] = $theme_width; } return $dst; } /** * Create an attachment 'object'. * * @since 3.9.0 * * @param string $cropped Cropped image URL. * @param int $parent_attachment_id Attachment ID of parent image. * @return array Attachment object. */ final public function create_attachment_object( $cropped, $parent_attachment_id ) { $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'; $object = array( 'ID' => $parent_attachment_id, 'post_title' => wp_basename( $cropped ), 'post_mime_type' => $image_type, 'guid' => $url, 'context' => 'custom-header', 'post_parent' => $parent_attachment_id, ); return $object; } /** * Insert an attachment and its metadata. * * @since 3.9.0 * * @param array $object Attachment object. * @param string $cropped File path to cropped image. * @return int Attachment ID. */ final public function insert_attachment( $object, $cropped ) { $parent_id = isset( $object['post_parent'] ) ? $object['post_parent'] : null; unset( $object['post_parent'] ); $attachment_id = wp_insert_attachment( $object, $cropped ); $metadata = wp_generate_attachment_metadata( $attachment_id, $cropped ); // If this is a crop, save the original attachment ID as metadata. if ( $parent_id ) { $metadata['attachment_parent'] = $parent_id; } /** * Filters the header image attachment metadata. * * @since 3.9.0 * * @see wp_generate_attachment_metadata() * * @param array $metadata Attachment metadata. */ $metadata = apply_filters( 'wp_header_image_attachment_metadata', $metadata ); wp_update_attachment_metadata( $attachment_id, $metadata ); return $attachment_id; } /** * Gets attachment uploaded by Media Manager, crops it, then saves it as a * new object. Returns JSON-encoded object details. * * @since 3.9.0 */ public function ajax_header_crop() { check_ajax_referer( 'image_editor-' . $_POST['id'], 'nonce' ); if ( ! current_user_can( 'edit_theme_options' ) ) { wp_send_json_error(); } if ( ! current_theme_supports( 'custom-header', 'uploads' ) ) { wp_send_json_error(); } $crop_details = $_POST['cropDetails']; $dimensions = $this->get_header_dimensions( array( 'height' => $crop_details['height'], 'width' => $crop_details['width'], ) ); $attachment_id = absint( $_POST['id'] ); $cropped = wp_crop_image( $attachment_id, (int) $crop_details['x1'], (int) $crop_details['y1'], (int) $crop_details['width'], (int) $crop_details['height'], (int) $dimensions['dst_width'], (int) $dimensions['dst_height'] ); if ( ! $cropped || is_wp_error( $cropped ) ) { wp_send_json_error( array( 'message' => __( 'Image could not be processed. Please go back and try again.' ) ) ); } /** This filter is documented in wp-admin/includes/class-custom-image-header.php */ $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication. $object = $this->create_attachment_object( $cropped, $attachment_id ); $previous = $this->get_previous_crop( $object ); if ( $previous ) { $object['ID'] = $previous; } else { unset( $object['ID'] ); } $new_attachment_id = $this->insert_attachment( $object, $cropped ); $object['attachment_id'] = $new_attachment_id; $object['url'] = wp_get_attachment_url( $new_attachment_id ); $object['width'] = $dimensions['dst_width']; $object['height'] = $dimensions['dst_height']; wp_send_json_success( $object ); } /** * Given an attachment ID for a header image, updates its "last used" * timestamp to now. * * Triggered when the user tries adds a new header image from the * Media Manager, even if s/he doesn't save that change. * * @since 3.9.0 */ public function ajax_header_add() { check_ajax_referer( 'header-add', 'nonce' ); if ( ! current_user_can( 'edit_theme_options' ) ) { wp_send_json_error(); } $attachment_id = absint( $_POST['attachment_id'] ); if ( $attachment_id < 1 ) { wp_send_json_error(); } $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet(); update_post_meta( $attachment_id, $key, time() ); update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() ); wp_send_json_success(); } /** * Given an attachment ID for a header image, unsets it as a user-uploaded * header image for the current theme. * * Triggered when the user clicks the overlay "X" button next to each image * choice in the Customizer's Header tool. * * @since 3.9.0 */ public function ajax_header_remove() { check_ajax_referer( 'header-remove', 'nonce' ); if ( ! current_user_can( 'edit_theme_options' ) ) { wp_send_json_error(); } $attachment_id = absint( $_POST['attachment_id'] ); if ( $attachment_id < 1 ) { wp_send_json_error(); } $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet(); delete_post_meta( $attachment_id, $key ); delete_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() ); wp_send_json_success(); } /** * Updates the last-used postmeta on a header image attachment after saving a new header image via the Customizer. * * @since 3.9.0 * * @param WP_Customize_Manager $wp_customize Customize manager. */ public function customize_set_last_used( $wp_customize ) { $header_image_data_setting = $wp_customize->get_setting( 'header_image_data' ); if ( ! $header_image_data_setting ) { return; } $data = $header_image_data_setting->post_value(); if ( ! isset( $data['attachment_id'] ) ) { return; } $attachment_id = $data['attachment_id']; $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet(); update_post_meta( $attachment_id, $key, time() ); } /** * Gets the details of default header images if defined. * * @since 3.9.0 * * @return array Default header images. */ public function get_default_header_images() { $this->process_default_headers(); // Get the default image if there is one. $default = get_theme_support( 'custom-header', 'default-image' ); if ( ! $default ) { // If not, easy peasy. return $this->default_headers; } $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() ); $already_has_default = false; foreach ( $this->default_headers as $k => $h ) { if ( $h['url'] === $default ) { $already_has_default = true; break; } } if ( $already_has_default ) { return $this->default_headers; } // If the one true image isn't included in the default set, prepend it. $header_images = array(); $header_images['default'] = array( 'url' => $default, 'thumbnail_url' => $default, 'description' => 'Default', ); // The rest of the set comes after. return array_merge( $header_images, $this->default_headers ); } /** * Gets the previously uploaded header images. * * @since 3.9.0 * * @return array Uploaded header images. */ public function get_uploaded_header_images() { $header_images = get_uploaded_header_images(); $timestamp_key = '_wp_attachment_custom_header_last_used_' . get_stylesheet(); $alt_text_key = '_wp_attachment_image_alt'; foreach ( $header_images as &$header_image ) { $header_meta = get_post_meta( $header_image['attachment_id'] ); $header_image['timestamp'] = isset( $header_meta[ $timestamp_key ] ) ? $header_meta[ $timestamp_key ] : ''; $header_image['alt_text'] = isset( $header_meta[ $alt_text_key ] ) ? $header_meta[ $alt_text_key ] : ''; } return $header_images; } /** * Get the ID of a previous crop from the same base image. * * @since 4.9.0 * * @param array $object A crop attachment object. * @return int|false An attachment ID if one exists. False if none. */ public function get_previous_crop( $object ) { $header_images = $this->get_uploaded_header_images(); // Bail early if there are no header images. if ( empty( $header_images ) ) { return false; } $previous = false; foreach ( $header_images as $image ) { if ( $image['attachment_parent'] === $object['post_parent'] ) { $previous = $image['attachment_id']; break; } } return $previous; } } PK [qX)yT T class-file-upload-upgrader.phpnu [ false, 'test_type' => false, ); $file = wp_handle_upload( $_FILES[ $form ], $overrides ); if ( isset( $file['error'] ) ) { wp_die( $file['error'] ); } if ( 'pluginzip' === $form || 'themezip' === $form ) { $archive_is_valid = false; /** This filter is documented in wp-admin/includes/file.php */ if ( class_exists( 'ZipArchive', false ) && apply_filters( 'unzip_file_use_ziparchive', true ) ) { $archive = new ZipArchive(); $archive_is_valid = $archive->open( $file['file'], ZIPARCHIVE::CHECKCONS ); if ( true === $archive_is_valid ) { $archive->close(); } } else { require_once ABSPATH . 'wp-admin/includes/class-pclzip.php'; $archive = new PclZip( $file['file'] ); $archive_is_valid = is_array( $archive->properties() ); } if ( true !== $archive_is_valid ) { wp_delete_file( $file['file'] ); wp_die( __( 'Incompatible Archive.' ) ); } } $this->filename = $_FILES[ $form ]['name']; $this->package = $file['file']; // Construct the object array. $object = array( 'post_title' => $this->filename, 'post_content' => $file['url'], 'post_mime_type' => $file['type'], 'guid' => $file['url'], 'context' => 'upgrader', 'post_status' => 'private', ); // Save the data. $this->id = wp_insert_attachment( $object, $file['file'] ); // Schedule a cleanup for 2 hours from now in case of failed installation. wp_schedule_single_event( time() + 2 * HOUR_IN_SECONDS, 'upgrader_scheduled_cleanup', array( $this->id ) ); } elseif ( is_numeric( $_GET[ $urlholder ] ) ) { // Numeric Package = previously uploaded file, see above. $this->id = (int) $_GET[ $urlholder ]; $attachment = get_post( $this->id ); if ( empty( $attachment ) ) { wp_die( __( 'Please select a file' ) ); } $this->filename = $attachment->post_title; $this->package = get_attached_file( $attachment->ID ); } else { // Else, It's set to something, Back compat for plugins using the old (pre-3.3) File_Uploader handler. $uploads = wp_upload_dir(); if ( ! ( $uploads && false === $uploads['error'] ) ) { wp_die( $uploads['error'] ); } $this->filename = sanitize_file_name( $_GET[ $urlholder ] ); $this->package = $uploads['basedir'] . '/' . $this->filename; if ( 0 !== strpos( realpath( $this->package ), realpath( $uploads['basedir'] ) ) ) { wp_die( __( 'Please select a file' ) ); } } } /** * Delete the attachment/uploaded file. * * @since 3.2.2 * * @return bool Whether the cleanup was successful. */ public function cleanup() { if ( $this->id ) { wp_delete_attachment( $this->id ); } elseif ( file_exists( $this->package ) ) { return @unlink( $this->package ); } return true; } } PK []=S2 2 class-ftp-pure.phpnu [ // // function _settimeout($sock) { if(!@stream_set_timeout($sock, $this->_timeout)) { $this->PushError('_settimeout','socket set send timeout'); $this->_quit(); return FALSE; } return TRUE; } function _connect($host, $port) { $this->SendMSG("Creating socket"); $sock = @fsockopen($host, $port, $errno, $errstr, $this->_timeout); if (!$sock) { $this->PushError('_connect','socket connect failed', $errstr." (".$errno.")"); return FALSE; } $this->_connected=true; return $sock; } function _readmsg($fnction="_readmsg"){ if(!$this->_connected) { $this->PushError($fnction, 'Connect first'); return FALSE; } $result=true; $this->_message=""; $this->_code=0; $go=true; do { $tmp=@fgets($this->_ftp_control_sock, 512); if($tmp===false) { $go=$result=false; $this->PushError($fnction,'Read failed'); } else { $this->_message.=$tmp; if(preg_match("/^([0-9]{3})(-(.*[".CRLF."]{1,2})+\\1)? [^".CRLF."]+[".CRLF."]{1,2}$/", $this->_message, $regs)) $go=false; } } while($go); if($this->LocalEcho) echo "GET < ".rtrim($this->_message, CRLF).CRLF; $this->_code=(int)$regs[1]; return $result; } function _exec($cmd, $fnction="_exec") { if(!$this->_ready) { $this->PushError($fnction,'Connect first'); return FALSE; } if($this->LocalEcho) echo "PUT > ",$cmd,CRLF; $status=@fputs($this->_ftp_control_sock, $cmd.CRLF); if($status===false) { $this->PushError($fnction,'socket write failed'); return FALSE; } $this->_lastaction=time(); if(!$this->_readmsg($fnction)) return FALSE; return TRUE; } function _data_prepare($mode=FTP_ASCII) { if(!$this->_settype($mode)) return FALSE; if($this->_passive) { if(!$this->_exec("PASV", "pasv")) { $this->_data_close(); return FALSE; } if(!$this->_checkCode()) { $this->_data_close(); return FALSE; } $ip_port = explode(",", preg_replace("/^.+ \\(?([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+)\\)?.*$/s", "\\1", $this->_message)); $this->_datahost=$ip_port[0].".".$ip_port[1].".".$ip_port[2].".".$ip_port[3]; $this->_dataport=(((int)$ip_port[4])<<8) + ((int)$ip_port[5]); $this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport); $this->_ftp_data_sock=@fsockopen($this->_datahost, $this->_dataport, $errno, $errstr, $this->_timeout); if(!$this->_ftp_data_sock) { $this->PushError("_data_prepare","fsockopen fails", $errstr." (".$errno.")"); $this->_data_close(); return FALSE; } else $this->_ftp_data_sock; } else { $this->SendMSG("Only passive connections available!"); return FALSE; } return TRUE; } function _data_read($mode=FTP_ASCII, $fp=NULL) { if(is_resource($fp)) $out=0; else $out=""; if(!$this->_passive) { $this->SendMSG("Only passive connections available!"); return FALSE; } while (!feof($this->_ftp_data_sock)) { $block=fread($this->_ftp_data_sock, $this->_ftp_buff_size); if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_local], $block); if(is_resource($fp)) $out+=fwrite($fp, $block, strlen($block)); else $out.=$block; } return $out; } function _data_write($mode=FTP_ASCII, $fp=NULL) { if(is_resource($fp)) $out=0; else $out=""; if(!$this->_passive) { $this->SendMSG("Only passive connections available!"); return FALSE; } if(is_resource($fp)) { while(!feof($fp)) { $block=fread($fp, $this->_ftp_buff_size); if(!$this->_data_write_block($mode, $block)) return false; } } elseif(!$this->_data_write_block($mode, $fp)) return false; return TRUE; } function _data_write_block($mode, $block) { if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_remote], $block); do { if(($t=@fwrite($this->_ftp_data_sock, $block))===FALSE) { $this->PushError("_data_write","Can't write to socket"); return FALSE; } $block=substr($block, $t); } while(!empty($block)); return true; } function _data_close() { @fclose($this->_ftp_data_sock); $this->SendMSG("Disconnected data from remote host"); return TRUE; } function _quit($force=FALSE) { if($this->_connected or $force) { @fclose($this->_ftp_control_sock); $this->_connected=false; $this->SendMSG("Socket closed"); } } } ?> PK [,=! ! class-ftp-sockets.phpnu [ // // function _settimeout($sock) { if(!@socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array("sec"=>$this->_timeout, "usec"=>0))) { $this->PushError('_connect','socket set receive timeout',socket_strerror(socket_last_error($sock))); @socket_close($sock); return FALSE; } if(!@socket_set_option($sock, SOL_SOCKET , SO_SNDTIMEO, array("sec"=>$this->_timeout, "usec"=>0))) { $this->PushError('_connect','socket set send timeout',socket_strerror(socket_last_error($sock))); @socket_close($sock); return FALSE; } return true; } function _connect($host, $port) { $this->SendMSG("Creating socket"); if(!($sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP))) { $this->PushError('_connect','socket create failed',socket_strerror(socket_last_error($sock))); return FALSE; } if(!$this->_settimeout($sock)) return FALSE; $this->SendMSG("Connecting to \"".$host.":".$port."\""); if (!($res = @socket_connect($sock, $host, $port))) { $this->PushError('_connect','socket connect failed',socket_strerror(socket_last_error($sock))); @socket_close($sock); return FALSE; } $this->_connected=true; return $sock; } function _readmsg($fnction="_readmsg"){ if(!$this->_connected) { $this->PushError($fnction,'Connect first'); return FALSE; } $result=true; $this->_message=""; $this->_code=0; $go=true; do { $tmp=@socket_read($this->_ftp_control_sock, 4096, PHP_BINARY_READ); if($tmp===false) { $go=$result=false; $this->PushError($fnction,'Read failed', socket_strerror(socket_last_error($this->_ftp_control_sock))); } else { $this->_message.=$tmp; $go = !preg_match("/^([0-9]{3})(-.+\\1)? [^".CRLF."]+".CRLF."$/Us", $this->_message, $regs); } } while($go); if($this->LocalEcho) echo "GET < ".rtrim($this->_message, CRLF).CRLF; $this->_code=(int)$regs[1]; return $result; } function _exec($cmd, $fnction="_exec") { if(!$this->_ready) { $this->PushError($fnction,'Connect first'); return FALSE; } if($this->LocalEcho) echo "PUT > ",$cmd,CRLF; $status=@socket_write($this->_ftp_control_sock, $cmd.CRLF); if($status===false) { $this->PushError($fnction,'socket write failed', socket_strerror(socket_last_error($this->stream))); return FALSE; } $this->_lastaction=time(); if(!$this->_readmsg($fnction)) return FALSE; return TRUE; } function _data_prepare($mode=FTP_ASCII) { if(!$this->_settype($mode)) return FALSE; $this->SendMSG("Creating data socket"); $this->_ftp_data_sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($this->_ftp_data_sock < 0) { $this->PushError('_data_prepare','socket create failed',socket_strerror(socket_last_error($this->_ftp_data_sock))); return FALSE; } if(!$this->_settimeout($this->_ftp_data_sock)) { $this->_data_close(); return FALSE; } if($this->_passive) { if(!$this->_exec("PASV", "pasv")) { $this->_data_close(); return FALSE; } if(!$this->_checkCode()) { $this->_data_close(); return FALSE; } $ip_port = explode(",", preg_replace("/^.+ \\(?([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+)\\)?.*$/s", "\\1", $this->_message)); $this->_datahost=$ip_port[0].".".$ip_port[1].".".$ip_port[2].".".$ip_port[3]; $this->_dataport=(((int)$ip_port[4])<<8) + ((int)$ip_port[5]); $this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport); if(!@socket_connect($this->_ftp_data_sock, $this->_datahost, $this->_dataport)) { $this->PushError("_data_prepare","socket_connect", socket_strerror(socket_last_error($this->_ftp_data_sock))); $this->_data_close(); return FALSE; } else $this->_ftp_temp_sock=$this->_ftp_data_sock; } else { if(!@socket_getsockname($this->_ftp_control_sock, $addr, $port)) { $this->PushError("_data_prepare","can't get control socket information", socket_strerror(socket_last_error($this->_ftp_control_sock))); $this->_data_close(); return FALSE; } if(!@socket_bind($this->_ftp_data_sock,$addr)){ $this->PushError("_data_prepare","can't bind data socket", socket_strerror(socket_last_error($this->_ftp_data_sock))); $this->_data_close(); return FALSE; } if(!@socket_listen($this->_ftp_data_sock)) { $this->PushError("_data_prepare","can't listen data socket", socket_strerror(socket_last_error($this->_ftp_data_sock))); $this->_data_close(); return FALSE; } if(!@socket_getsockname($this->_ftp_data_sock, $this->_datahost, $this->_dataport)) { $this->PushError("_data_prepare","can't get data socket information", socket_strerror(socket_last_error($this->_ftp_data_sock))); $this->_data_close(); return FALSE; } if(!$this->_exec('PORT '.str_replace('.',',',$this->_datahost.'.'.($this->_dataport>>8).'.'.($this->_dataport&0x00FF)), "_port")) { $this->_data_close(); return FALSE; } if(!$this->_checkCode()) { $this->_data_close(); return FALSE; } } return TRUE; } function _data_read($mode=FTP_ASCII, $fp=NULL) { $NewLine=$this->_eol_code[$this->OS_local]; if(is_resource($fp)) $out=0; else $out=""; if(!$this->_passive) { $this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport); $this->_ftp_temp_sock=socket_accept($this->_ftp_data_sock); if($this->_ftp_temp_sock===FALSE) { $this->PushError("_data_read","socket_accept", socket_strerror(socket_last_error($this->_ftp_temp_sock))); $this->_data_close(); return FALSE; } } while(($block=@socket_read($this->_ftp_temp_sock, $this->_ftp_buff_size, PHP_BINARY_READ))!==false) { if($block==="") break; if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_local], $block); if(is_resource($fp)) $out+=fwrite($fp, $block, strlen($block)); else $out.=$block; } return $out; } function _data_write($mode=FTP_ASCII, $fp=NULL) { $NewLine=$this->_eol_code[$this->OS_local]; if(is_resource($fp)) $out=0; else $out=""; if(!$this->_passive) { $this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport); $this->_ftp_temp_sock=socket_accept($this->_ftp_data_sock); if($this->_ftp_temp_sock===FALSE) { $this->PushError("_data_write","socket_accept", socket_strerror(socket_last_error($this->_ftp_temp_sock))); $this->_data_close(); return false; } } if(is_resource($fp)) { while(!feof($fp)) { $block=fread($fp, $this->_ftp_buff_size); if(!$this->_data_write_block($mode, $block)) return false; } } elseif(!$this->_data_write_block($mode, $fp)) return false; return true; } function _data_write_block($mode, $block) { if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_remote], $block); do { if(($t=@socket_write($this->_ftp_temp_sock, $block))===FALSE) { $this->PushError("_data_write","socket_write", socket_strerror(socket_last_error($this->_ftp_temp_sock))); $this->_data_close(); return FALSE; } $block=substr($block, $t); } while(!empty($block)); return true; } function _data_close() { @socket_close($this->_ftp_temp_sock); @socket_close($this->_ftp_data_sock); $this->SendMSG("Disconnected data from remote host"); return TRUE; } function _quit() { if($this->_connected) { @socket_close($this->_ftp_control_sock); $this->_connected=false; $this->SendMSG("Socket closed"); } } } ?> PK [fCj Cj class-ftp.phpnu [ LocalEcho=$le; $this->Verbose=$verb; $this->_lastaction=NULL; $this->_error_array=array(); $this->_eol_code=array(FTP_OS_Unix=>"\n", FTP_OS_Mac=>"\r", FTP_OS_Windows=>"\r\n"); $this->AuthorizedTransferMode=array(FTP_AUTOASCII, FTP_ASCII, FTP_BINARY); $this->OS_FullName=array(FTP_OS_Unix => 'UNIX', FTP_OS_Windows => 'WINDOWS', FTP_OS_Mac => 'MACOS'); $this->AutoAsciiExt=array("ASP","BAT","C","CPP","CSS","CSV","JS","H","HTM","HTML","SHTML","INI","LOG","PHP3","PHTML","PL","PERL","SH","SQL","TXT"); $this->_port_available=($port_mode==TRUE); $this->SendMSG("Staring FTP client class".($this->_port_available?"":" without PORT mode support")); $this->_connected=FALSE; $this->_ready=FALSE; $this->_can_restore=FALSE; $this->_code=0; $this->_message=""; $this->_ftp_buff_size=4096; $this->_curtype=NULL; $this->SetUmask(0022); $this->SetType(FTP_AUTOASCII); $this->SetTimeout(30); $this->Passive(!$this->_port_available); $this->_login="anonymous"; $this->_password="anon@ftp.com"; $this->_features=array(); $this->OS_local=FTP_OS_Unix; $this->OS_remote=FTP_OS_Unix; $this->features=array(); if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') $this->OS_local=FTP_OS_Windows; elseif(strtoupper(substr(PHP_OS, 0, 3)) === 'MAC') $this->OS_local=FTP_OS_Mac; } function ftp_base($port_mode=FALSE) { $this->__construct($port_mode); } // // // function parselisting($line) { $is_windows = ($this->OS_remote == FTP_OS_Windows); if ($is_windows && preg_match("/([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|.po',
'.mo'
)
);
}
return $source;
}
/**
* Get the name of an item being updated.
*
* @since 3.7.0
*
* @param object $update The data for an update.
* @return string The name of the item being updated.
*/
public function get_name_for_update( $update ) {
switch ( $update->type ) {
case 'core':
return 'WordPress'; // Not translated.
case 'theme':
$theme = wp_get_theme( $update->slug );
if ( $theme->exists() ) {
return $theme->Get( 'Name' );
}
break;
case 'plugin':
$plugin_data = get_plugins( '/' . $update->slug );
$plugin_data = reset( $plugin_data );
if ( $plugin_data ) {
return $plugin_data['Name'];
}
break;
}
return '';
}
/**
* Clears existing translations where this item is going to be installed into.
*
* @since 5.1.0
*
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
*
* @param string $remote_destination The location on the remote filesystem to be cleared.
* @return bool|WP_Error True upon success, WP_Error on failure.
*/
public function clear_destination( $remote_destination ) {
global $wp_filesystem;
$language_update = $this->skin->language_update;
$language_directory = WP_LANG_DIR . '/'; // Local path for use with glob().
if ( 'core' === $language_update->type ) {
$files = array(
$remote_destination . $language_update->language . '.po',
$remote_destination . $language_update->language . '.mo',
$remote_destination . 'admin-' . $language_update->language . '.po',
$remote_destination . 'admin-' . $language_update->language . '.mo',
$remote_destination . 'admin-network-' . $language_update->language . '.po',
$remote_destination . 'admin-network-' . $language_update->language . '.mo',
$remote_destination . 'continents-cities-' . $language_update->language . '.po',
$remote_destination . 'continents-cities-' . $language_update->language . '.mo',
);
$json_translation_files = glob( $language_directory . $language_update->language . '-*.json' );
if ( $json_translation_files ) {
foreach ( $json_translation_files as $json_translation_file ) {
$files[] = str_replace( $language_directory, $remote_destination, $json_translation_file );
}
}
} else {
$files = array(
$remote_destination . $language_update->slug . '-' . $language_update->language . '.po',
$remote_destination . $language_update->slug . '-' . $language_update->language . '.mo',
);
$language_directory = $language_directory . $language_update->type . 's/';
$json_translation_files = glob( $language_directory . $language_update->slug . '-' . $language_update->language . '-*.json' );
if ( $json_translation_files ) {
foreach ( $json_translation_files as $json_translation_file ) {
$files[] = str_replace( $language_directory, $remote_destination, $json_translation_file );
}
}
}
$files = array_filter( $files, array( $wp_filesystem, 'exists' ) );
// No files to delete.
if ( ! $files ) {
return true;
}
// Check all files are writable before attempting to clear the destination.
$unwritable_files = array();
// Check writability.
foreach ( $files as $file ) {
if ( ! $wp_filesystem->is_writable( $file ) ) {
// Attempt to alter permissions to allow writes and try again.
$wp_filesystem->chmod( $file, FS_CHMOD_FILE );
if ( ! $wp_filesystem->is_writable( $file ) ) {
$unwritable_files[] = $file;
}
}
}
if ( ! empty( $unwritable_files ) ) {
return new WP_Error( 'files_not_writable', $this->strings['files_not_writable'], implode( ', ', $unwritable_files ) );
}
foreach ( $files as $file ) {
if ( ! $wp_filesystem->delete( $file ) ) {
return new WP_Error( 'remove_old_failed', $this->strings['remove_old_failed'] );
}
}
return true;
}
}
PK [u! ! class-pclzip.phpnu [ zipname = $p_zipname;
$this->zip_fd = 0;
$this->magic_quotes_status = -1;
// ----- Return
return;
}
public function PclZip($p_zipname) {
self::__construct($p_zipname);
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function :
// create($p_filelist, $p_add_dir="", $p_remove_dir="")
// create($p_filelist, $p_option, $p_option_value, ...)
// Description :
// This method supports two different synopsis. The first one is historical.
// This method creates a Zip Archive. The Zip file is created in the
// filesystem. The files and directories indicated in $p_filelist
// are added in the archive. See the parameters description for the
// supported format of $p_filelist.
// When a directory is in the list, the directory and its content is added
// in the archive.
// In this synopsis, the function takes an optional variable list of
// options. See below the supported options.
// Parameters :
// $p_filelist : An array containing file or directory names, or
// a string containing one filename or one directory name, or
// a string containing a list of filenames and/or directory
// names separated by spaces.
// $p_add_dir : A path to add before the real path of the archived file,
// in order to have it memorized in the archive.
// $p_remove_dir : A path to remove from the real path of the file to archive,
// in order to have a shorter path memorized in the archive.
// When $p_add_dir and $p_remove_dir are set, $p_remove_dir
// is removed first, before $p_add_dir is added.
// Options :
// PCLZIP_OPT_ADD_PATH :
// PCLZIP_OPT_REMOVE_PATH :
// PCLZIP_OPT_REMOVE_ALL_PATH :
// PCLZIP_OPT_COMMENT :
// PCLZIP_CB_PRE_ADD :
// PCLZIP_CB_POST_ADD :
// Return Values :
// 0 on failure,
// The list of the added files, with a status of the add action.
// (see PclZip::listContent() for list entry format)
// --------------------------------------------------------------------------------
function create($p_filelist)
{
$v_result=1;
// ----- Reset the error handler
$this->privErrorReset();
// ----- Set default values
$v_options = array();
$v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
// ----- Look for variable options arguments
$v_size = func_num_args();
// ----- Look for arguments
if ($v_size > 1) {
// ----- Get the arguments
$v_arg_list = func_get_args();
// ----- Remove from the options list the first argument
array_shift($v_arg_list);
$v_size--;
// ----- Look for first arg
if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
// ----- Parse the options
$v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
array (PCLZIP_OPT_REMOVE_PATH => 'optional',
PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
PCLZIP_OPT_ADD_PATH => 'optional',
PCLZIP_CB_PRE_ADD => 'optional',
PCLZIP_CB_POST_ADD => 'optional',
PCLZIP_OPT_NO_COMPRESSION => 'optional',
PCLZIP_OPT_COMMENT => 'optional',
PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
PCLZIP_OPT_TEMP_FILE_ON => 'optional',
PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
//, PCLZIP_OPT_CRYPT => 'optional'
));
if ($v_result != 1) {
return 0;
}
}
// ----- Look for 2 args
// Here we need to support the first historic synopsis of the
// method.
else {
// ----- Get the first argument
$v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
// ----- Look for the optional second argument
if ($v_size == 2) {
$v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
}
else if ($v_size > 2) {
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
"Invalid number / type of arguments");
return 0;
}
}
}
// ----- Look for default option values
$this->privOptionDefaultThreshold($v_options);
// ----- Init
$v_string_list = array();
$v_att_list = array();
$v_filedescr_list = array();
$p_result_list = array();
// ----- Look if the $p_filelist is really an array
if (is_array($p_filelist)) {
// ----- Look if the first element is also an array
// This will mean that this is a file description entry
if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
$v_att_list = $p_filelist;
}
// ----- The list is a list of string names
else {
$v_string_list = $p_filelist;
}
}
// ----- Look if the $p_filelist is a string
else if (is_string($p_filelist)) {
// ----- Create a list from the string
$v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
}
// ----- Invalid variable type for $p_filelist
else {
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
return 0;
}
// ----- Reformat the string list
if (sizeof($v_string_list) != 0) {
foreach ($v_string_list as $v_string) {
if ($v_string != '') {
$v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
}
else {
}
}
}
// ----- For each file in the list check the attributes
$v_supported_attributes
= array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
,PCLZIP_ATT_FILE_MTIME => 'optional'
,PCLZIP_ATT_FILE_CONTENT => 'optional'
,PCLZIP_ATT_FILE_COMMENT => 'optional'
);
foreach ($v_att_list as $v_entry) {
$v_result = $this->privFileDescrParseAtt($v_entry,
$v_filedescr_list[],
$v_options,
$v_supported_attributes);
if ($v_result != 1) {
return 0;
}
}
// ----- Expand the filelist (expand directories)
$v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
if ($v_result != 1) {
return 0;
}
// ----- Call the create fct
$v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
if ($v_result != 1) {
return 0;
}
// ----- Return
return $p_result_list;
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function :
// add($p_filelist, $p_add_dir="", $p_remove_dir="")
// add($p_filelist, $p_option, $p_option_value, ...)
// Description :
// This method supports two synopsis. The first one is historical.
// This methods add the list of files in an existing archive.
// If a file with the same name already exists, it is added at the end of the
// archive, the first one is still present.
// If the archive does not exist, it is created.
// Parameters :
// $p_filelist : An array containing file or directory names, or
// a string containing one filename or one directory name, or
// a string containing a list of filenames and/or directory
// names separated by spaces.
// $p_add_dir : A path to add before the real path of the archived file,
// in order to have it memorized in the archive.
// $p_remove_dir : A path to remove from the real path of the file to archive,
// in order to have a shorter path memorized in the archive.
// When $p_add_dir and $p_remove_dir are set, $p_remove_dir
// is removed first, before $p_add_dir is added.
// Options :
// PCLZIP_OPT_ADD_PATH :
// PCLZIP_OPT_REMOVE_PATH :
// PCLZIP_OPT_REMOVE_ALL_PATH :
// PCLZIP_OPT_COMMENT :
// PCLZIP_OPT_ADD_COMMENT :
// PCLZIP_OPT_PREPEND_COMMENT :
// PCLZIP_CB_PRE_ADD :
// PCLZIP_CB_POST_ADD :
// Return Values :
// 0 on failure,
// The list of the added files, with a status of the add action.
// (see PclZip::listContent() for list entry format)
// --------------------------------------------------------------------------------
function add($p_filelist)
{
$v_result=1;
// ----- Reset the error handler
$this->privErrorReset();
// ----- Set default values
$v_options = array();
$v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
// ----- Look for variable options arguments
$v_size = func_num_args();
// ----- Look for arguments
if ($v_size > 1) {
// ----- Get the arguments
$v_arg_list = func_get_args();
// ----- Remove form the options list the first argument
array_shift($v_arg_list);
$v_size--;
// ----- Look for first arg
if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
// ----- Parse the options
$v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
array (PCLZIP_OPT_REMOVE_PATH => 'optional',
PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
PCLZIP_OPT_ADD_PATH => 'optional',
PCLZIP_CB_PRE_ADD => 'optional',
PCLZIP_CB_POST_ADD => 'optional',
PCLZIP_OPT_NO_COMPRESSION => 'optional',
PCLZIP_OPT_COMMENT => 'optional',
PCLZIP_OPT_ADD_COMMENT => 'optional',
PCLZIP_OPT_PREPEND_COMMENT => 'optional',
PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
PCLZIP_OPT_TEMP_FILE_ON => 'optional',
PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
//, PCLZIP_OPT_CRYPT => 'optional'
));
if ($v_result != 1) {
return 0;
}
}
// ----- Look for 2 args
// Here we need to support the first historic synopsis of the
// method.
else {
// ----- Get the first argument
$v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
// ----- Look for the optional second argument
if ($v_size == 2) {
$v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
}
else if ($v_size > 2) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
// ----- Return
return 0;
}
}
}
// ----- Look for default option values
$this->privOptionDefaultThreshold($v_options);
// ----- Init
$v_string_list = array();
$v_att_list = array();
$v_filedescr_list = array();
$p_result_list = array();
// ----- Look if the $p_filelist is really an array
if (is_array($p_filelist)) {
// ----- Look if the first element is also an array
// This will mean that this is a file description entry
if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
$v_att_list = $p_filelist;
}
// ----- The list is a list of string names
else {
$v_string_list = $p_filelist;
}
}
// ----- Look if the $p_filelist is a string
else if (is_string($p_filelist)) {
// ----- Create a list from the string
$v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
}
// ----- Invalid variable type for $p_filelist
else {
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist");
return 0;
}
// ----- Reformat the string list
if (sizeof($v_string_list) != 0) {
foreach ($v_string_list as $v_string) {
$v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
}
}
// ----- For each file in the list check the attributes
$v_supported_attributes
= array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
,PCLZIP_ATT_FILE_MTIME => 'optional'
,PCLZIP_ATT_FILE_CONTENT => 'optional'
,PCLZIP_ATT_FILE_COMMENT => 'optional'
);
foreach ($v_att_list as $v_entry) {
$v_result = $this->privFileDescrParseAtt($v_entry,
$v_filedescr_list[],
$v_options,
$v_supported_attributes);
if ($v_result != 1) {
return 0;
}
}
// ----- Expand the filelist (expand directories)
$v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
if ($v_result != 1) {
return 0;
}
// ----- Call the create fct
$v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
if ($v_result != 1) {
return 0;
}
// ----- Return
return $p_result_list;
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : listContent()
// Description :
// This public method, gives the list of the files and directories, with their
// properties.
// The properties of each entries in the list are (used also in other functions) :
// filename : Name of the file. For a create or add action it is the filename
// given by the user. For an extract function it is the filename
// of the extracted file.
// stored_filename : Name of the file / directory stored in the archive.
// size : Size of the stored file.
// compressed_size : Size of the file's data compressed in the archive
// (without the headers overhead)
// mtime : Last known modification date of the file (UNIX timestamp)
// comment : Comment associated with the file
// folder : true | false
// index : index of the file in the archive
// status : status of the action (depending of the action) :
// Values are :
// ok : OK !
// filtered : the file / dir is not extracted (filtered by user)
// already_a_directory : the file can not be extracted because a
// directory with the same name already exists
// write_protected : the file can not be extracted because a file
// with the same name already exists and is
// write protected
// newer_exist : the file was not extracted because a newer file exists
// path_creation_fail : the file is not extracted because the folder
// does not exist and can not be created
// write_error : the file was not extracted because there was a
// error while writing the file
// read_error : the file was not extracted because there was a error
// while reading the file
// invalid_header : the file was not extracted because of an archive
// format error (bad file header)
// Note that each time a method can continue operating when there
// is an action error on a file, the error is only logged in the file status.
// Return Values :
// 0 on an unrecoverable failure,
// The list of the files in the archive.
// --------------------------------------------------------------------------------
function listContent()
{
$v_result=1;
// ----- Reset the error handler
$this->privErrorReset();
// ----- Check archive
if (!$this->privCheckFormat()) {
return(0);
}
// ----- Call the extracting fct
$p_list = array();
if (($v_result = $this->privList($p_list)) != 1)
{
unset($p_list);
return(0);
}
// ----- Return
return $p_list;
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function :
// extract($p_path="./", $p_remove_path="")
// extract([$p_option, $p_option_value, ...])
// Description :
// This method supports two synopsis. The first one is historical.
// This method extract all the files / directories from the archive to the
// folder indicated in $p_path.
// If you want to ignore the 'root' part of path of the memorized files
// you can indicate this in the optional $p_remove_path parameter.
// By default, if a newer file with the same name already exists, the
// file is not extracted.
//
// If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH options
// are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
// at the end of the path value of PCLZIP_OPT_PATH.
// Parameters :
// $p_path : Path where the files and directories are to be extracted
// $p_remove_path : First part ('root' part) of the memorized path
// (if any similar) to remove while extracting.
// Options :
// PCLZIP_OPT_PATH :
// PCLZIP_OPT_ADD_PATH :
// PCLZIP_OPT_REMOVE_PATH :
// PCLZIP_OPT_REMOVE_ALL_PATH :
// PCLZIP_CB_PRE_EXTRACT :
// PCLZIP_CB_POST_EXTRACT :
// Return Values :
// 0 or a negative value on failure,
// The list of the extracted files, with a status of the action.
// (see PclZip::listContent() for list entry format)
// --------------------------------------------------------------------------------
function extract()
{
$v_result=1;
// ----- Reset the error handler
$this->privErrorReset();
// ----- Check archive
if (!$this->privCheckFormat()) {
return(0);
}
// ----- Set default values
$v_options = array();
// $v_path = "./";
$v_path = '';
$v_remove_path = "";
$v_remove_all_path = false;
// ----- Look for variable options arguments
$v_size = func_num_args();
// ----- Default values for option
$v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
// ----- Look for arguments
if ($v_size > 0) {
// ----- Get the arguments
$v_arg_list = func_get_args();
// ----- Look for first arg
if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
// ----- Parse the options
$v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
array (PCLZIP_OPT_PATH => 'optional',
PCLZIP_OPT_REMOVE_PATH => 'optional',
PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
PCLZIP_OPT_ADD_PATH => 'optional',
PCLZIP_CB_PRE_EXTRACT => 'optional',
PCLZIP_CB_POST_EXTRACT => 'optional',
PCLZIP_OPT_SET_CHMOD => 'optional',
PCLZIP_OPT_BY_NAME => 'optional',
PCLZIP_OPT_BY_EREG => 'optional',
PCLZIP_OPT_BY_PREG => 'optional',
PCLZIP_OPT_BY_INDEX => 'optional',
PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
PCLZIP_OPT_REPLACE_NEWER => 'optional'
,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
PCLZIP_OPT_TEMP_FILE_ON => 'optional',
PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
));
if ($v_result != 1) {
return 0;
}
// ----- Set the arguments
if (isset($v_options[PCLZIP_OPT_PATH])) {
$v_path = $v_options[PCLZIP_OPT_PATH];
}
if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
$v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
}
if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
$v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
}
if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
// ----- Check for '/' in last path char
if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
$v_path .= '/';
}
$v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
}
}
// ----- Look for 2 args
// Here we need to support the first historic synopsis of the
// method.
else {
// ----- Get the first argument
$v_path = $v_arg_list[0];
// ----- Look for the optional second argument
if ($v_size == 2) {
$v_remove_path = $v_arg_list[1];
}
else if ($v_size > 2) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
// ----- Return
return 0;
}
}
}
// ----- Look for default option values
$this->privOptionDefaultThreshold($v_options);
// ----- Trace
// ----- Call the extracting fct
$p_list = array();
$v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path,
$v_remove_all_path, $v_options);
if ($v_result < 1) {
unset($p_list);
return(0);
}
// ----- Return
return $p_list;
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function :
// extractByIndex($p_index, $p_path="./", $p_remove_path="")
// extractByIndex($p_index, [$p_option, $p_option_value, ...])
// Description :
// This method supports two synopsis. The first one is historical.
// This method is doing a partial extract of the archive.
// The extracted files or folders are identified by their index in the
// archive (from 0 to n).
// Note that if the index identify a folder, only the folder entry is
// extracted, not all the files included in the archive.
// Parameters :
// $p_index : A single index (integer) or a string of indexes of files to
// extract. The form of the string is "0,4-6,8-12" with only numbers
// and '-' for range or ',' to separate ranges. No spaces or ';'
// are allowed.
// $p_path : Path where the files and directories are to be extracted
// $p_remove_path : First part ('root' part) of the memorized path
// (if any similar) to remove while extracting.
// Options :
// PCLZIP_OPT_PATH :
// PCLZIP_OPT_ADD_PATH :
// PCLZIP_OPT_REMOVE_PATH :
// PCLZIP_OPT_REMOVE_ALL_PATH :
// PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
// not as files.
// The resulting content is in a new field 'content' in the file
// structure.
// This option must be used alone (any other options are ignored).
// PCLZIP_CB_PRE_EXTRACT :
// PCLZIP_CB_POST_EXTRACT :
// Return Values :
// 0 on failure,
// The list of the extracted files, with a status of the action.
// (see PclZip::listContent() for list entry format)
// --------------------------------------------------------------------------------
//function extractByIndex($p_index, options...)
function extractByIndex($p_index)
{
$v_result=1;
// ----- Reset the error handler
$this->privErrorReset();
// ----- Check archive
if (!$this->privCheckFormat()) {
return(0);
}
// ----- Set default values
$v_options = array();
// $v_path = "./";
$v_path = '';
$v_remove_path = "";
$v_remove_all_path = false;
// ----- Look for variable options arguments
$v_size = func_num_args();
// ----- Default values for option
$v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
// ----- Look for arguments
if ($v_size > 1) {
// ----- Get the arguments
$v_arg_list = func_get_args();
// ----- Remove form the options list the first argument
array_shift($v_arg_list);
$v_size--;
// ----- Look for first arg
if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
// ----- Parse the options
$v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
array (PCLZIP_OPT_PATH => 'optional',
PCLZIP_OPT_REMOVE_PATH => 'optional',
PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
PCLZIP_OPT_ADD_PATH => 'optional',
PCLZIP_CB_PRE_EXTRACT => 'optional',
PCLZIP_CB_POST_EXTRACT => 'optional',
PCLZIP_OPT_SET_CHMOD => 'optional',
PCLZIP_OPT_REPLACE_NEWER => 'optional'
,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
PCLZIP_OPT_TEMP_FILE_ON => 'optional',
PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
));
if ($v_result != 1) {
return 0;
}
// ----- Set the arguments
if (isset($v_options[PCLZIP_OPT_PATH])) {
$v_path = $v_options[PCLZIP_OPT_PATH];
}
if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
$v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
}
if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
$v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
}
if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
// ----- Check for '/' in last path char
if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
$v_path .= '/';
}
$v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
}
if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
$v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
}
else {
}
}
// ----- Look for 2 args
// Here we need to support the first historic synopsis of the
// method.
else {
// ----- Get the first argument
$v_path = $v_arg_list[0];
// ----- Look for the optional second argument
if ($v_size == 2) {
$v_remove_path = $v_arg_list[1];
}
else if ($v_size > 2) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
// ----- Return
return 0;
}
}
}
// ----- Trace
// ----- Trick
// Here I want to reuse extractByRule(), so I need to parse the $p_index
// with privParseOptions()
$v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index);
$v_options_trick = array();
$v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick,
array (PCLZIP_OPT_BY_INDEX => 'optional' ));
if ($v_result != 1) {
return 0;
}
$v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
// ----- Look for default option values
$this->privOptionDefaultThreshold($v_options);
// ----- Call the extracting fct
if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
return(0);
}
// ----- Return
return $p_list;
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function :
// delete([$p_option, $p_option_value, ...])
// Description :
// This method removes files from the archive.
// If no parameters are given, then all the archive is emptied.
// Parameters :
// None or optional arguments.
// Options :
// PCLZIP_OPT_BY_INDEX :
// PCLZIP_OPT_BY_NAME :
// PCLZIP_OPT_BY_EREG :
// PCLZIP_OPT_BY_PREG :
// Return Values :
// 0 on failure,
// The list of the files which are still present in the archive.
// (see PclZip::listContent() for list entry format)
// --------------------------------------------------------------------------------
function delete()
{
$v_result=1;
// ----- Reset the error handler
$this->privErrorReset();
// ----- Check archive
if (!$this->privCheckFormat()) {
return(0);
}
// ----- Set default values
$v_options = array();
// ----- Look for variable options arguments
$v_size = func_num_args();
// ----- Look for arguments
if ($v_size > 0) {
// ----- Get the arguments
$v_arg_list = func_get_args();
// ----- Parse the options
$v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
array (PCLZIP_OPT_BY_NAME => 'optional',
PCLZIP_OPT_BY_EREG => 'optional',
PCLZIP_OPT_BY_PREG => 'optional',
PCLZIP_OPT_BY_INDEX => 'optional' ));
if ($v_result != 1) {
return 0;
}
}
// ----- Magic quotes trick
$this->privDisableMagicQuotes();
// ----- Call the delete fct
$v_list = array();
if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
$this->privSwapBackMagicQuotes();
unset($v_list);
return(0);
}
// ----- Magic quotes trick
$this->privSwapBackMagicQuotes();
// ----- Return
return $v_list;
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : deleteByIndex()
// Description :
// ***** Deprecated *****
// delete(PCLZIP_OPT_BY_INDEX, $p_index) should be preferred.
// --------------------------------------------------------------------------------
function deleteByIndex($p_index)
{
$p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
// ----- Return
return $p_list;
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : properties()
// Description :
// This method gives the properties of the archive.
// The properties are :
// nb : Number of files in the archive
// comment : Comment associated with the archive file
// status : not_exist, ok
// Parameters :
// None
// Return Values :
// 0 on failure,
// An array with the archive properties.
// --------------------------------------------------------------------------------
function properties()
{
// ----- Reset the error handler
$this->privErrorReset();
// ----- Magic quotes trick
$this->privDisableMagicQuotes();
// ----- Check archive
if (!$this->privCheckFormat()) {
$this->privSwapBackMagicQuotes();
return(0);
}
// ----- Default properties
$v_prop = array();
$v_prop['comment'] = '';
$v_prop['nb'] = 0;
$v_prop['status'] = 'not_exist';
// ----- Look if file exists
if (@is_file($this->zipname))
{
// ----- Open the zip file
if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
{
$this->privSwapBackMagicQuotes();
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
// ----- Return
return 0;
}
// ----- Read the central directory information
$v_central_dir = array();
if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
{
$this->privSwapBackMagicQuotes();
return 0;
}
// ----- Close the zip file
$this->privCloseFd();
// ----- Set the user attributes
$v_prop['comment'] = $v_central_dir['comment'];
$v_prop['nb'] = $v_central_dir['entries'];
$v_prop['status'] = 'ok';
}
// ----- Magic quotes trick
$this->privSwapBackMagicQuotes();
// ----- Return
return $v_prop;
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : duplicate()
// Description :
// This method creates an archive by copying the content of an other one. If
// the archive already exist, it is replaced by the new one without any warning.
// Parameters :
// $p_archive : The filename of a valid archive, or
// a valid PclZip object.
// Return Values :
// 1 on success.
// 0 or a negative value on error (error code).
// --------------------------------------------------------------------------------
function duplicate($p_archive)
{
$v_result = 1;
// ----- Reset the error handler
$this->privErrorReset();
// ----- Look if the $p_archive is a PclZip object
if (is_object($p_archive) && $p_archive instanceof pclzip)
{
// ----- Duplicate the archive
$v_result = $this->privDuplicate($p_archive->zipname);
}
// ----- Look if the $p_archive is a string (so a filename)
else if (is_string($p_archive))
{
// ----- Check that $p_archive is a valid zip file
// TBC : Should also check the archive format
if (!is_file($p_archive)) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'");
$v_result = PCLZIP_ERR_MISSING_FILE;
}
else {
// ----- Duplicate the archive
$v_result = $this->privDuplicate($p_archive);
}
}
// ----- Invalid variable
else
{
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
$v_result = PCLZIP_ERR_INVALID_PARAMETER;
}
// ----- Return
return $v_result;
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : merge()
// Description :
// This method merge the $p_archive_to_add archive at the end of the current
// one ($this).
// If the archive ($this) does not exist, the merge becomes a duplicate.
// If the $p_archive_to_add archive does not exist, the merge is a success.
// Parameters :
// $p_archive_to_add : It can be directly the filename of a valid zip archive,
// or a PclZip object archive.
// Return Values :
// 1 on success,
// 0 or negative values on error (see below).
// --------------------------------------------------------------------------------
function merge($p_archive_to_add)
{
$v_result = 1;
// ----- Reset the error handler
$this->privErrorReset();
// ----- Check archive
if (!$this->privCheckFormat()) {
return(0);
}
// ----- Look if the $p_archive_to_add is a PclZip object
if (is_object($p_archive_to_add) && $p_archive_to_add instanceof pclzip)
{
// ----- Merge the archive
$v_result = $this->privMerge($p_archive_to_add);
}
// ----- Look if the $p_archive_to_add is a string (so a filename)
else if (is_string($p_archive_to_add))
{
// ----- Create a temporary archive
$v_object_archive = new PclZip($p_archive_to_add);
// ----- Merge the archive
$v_result = $this->privMerge($v_object_archive);
}
// ----- Invalid variable
else
{
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
$v_result = PCLZIP_ERR_INVALID_PARAMETER;
}
// ----- Return
return $v_result;
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : errorCode()
// Description :
// Parameters :
// --------------------------------------------------------------------------------
function errorCode()
{
if (PCLZIP_ERROR_EXTERNAL == 1) {
return(PclErrorCode());
}
else {
return($this->error_code);
}
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : errorName()
// Description :
// Parameters :
// --------------------------------------------------------------------------------
function errorName($p_with_code=false)
{
$v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION'
,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE'
,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION'
);
if (isset($v_name[$this->error_code])) {
$v_value = $v_name[$this->error_code];
}
else {
$v_value = 'NoName';
}
if ($p_with_code) {
return($v_value.' ('.$this->error_code.')');
}
else {
return($v_value);
}
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : errorInfo()
// Description :
// Parameters :
// --------------------------------------------------------------------------------
function errorInfo($p_full=false)
{
if (PCLZIP_ERROR_EXTERNAL == 1) {
return(PclErrorString());
}
else {
if ($p_full) {
return($this->errorName(true)." : ".$this->error_string);
}
else {
return($this->error_string." [code ".$this->error_code."]");
}
}
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
// ***** *****
// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY *****
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : privCheckFormat()
// Description :
// This method check that the archive exists and is a valid zip archive.
// Several level of check exists. (futur)
// Parameters :
// $p_level : Level of check. Default 0.
// 0 : Check the first bytes (magic codes) (default value))
// 1 : 0 + Check the central directory (futur)
// 2 : 1 + Check each file header (futur)
// Return Values :
// true on success,
// false on error, the error code is set.
// --------------------------------------------------------------------------------
function privCheckFormat($p_level=0)
{
$v_result = true;
// ----- Reset the file system cache
clearstatcache();
// ----- Reset the error handler
$this->privErrorReset();
// ----- Look if the file exits
if (!is_file($this->zipname)) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'");
return(false);
}
// ----- Check that the file is readable
if (!is_readable($this->zipname)) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'");
return(false);
}
// ----- Check the magic code
// TBC
// ----- Check the central header
// TBC
// ----- Check each file header
// TBC
// ----- Return
return $v_result;
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : privParseOptions()
// Description :
// This internal methods reads the variable list of arguments ($p_options_list,
// $p_size) and generate an array with the options and values ($v_result_list).
// $v_requested_options contains the options that can be present and those that
// must be present.
// $v_requested_options is an array, with the option value as key, and 'optional',
// or 'mandatory' as value.
// Parameters :
// See above.
// Return Values :
// 1 on success.
// 0 on failure.
// --------------------------------------------------------------------------------
function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false)
{
$v_result=1;
// ----- Read the options
$i=0;
while ($i<$p_size) {
// ----- Check if the option is supported
if (!isset($v_requested_options[$p_options_list[$i]])) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method");
// ----- Return
return PclZip::errorCode();
}
// ----- Look for next option
switch ($p_options_list[$i]) {
// ----- Look for options that request a path value
case PCLZIP_OPT_PATH :
case PCLZIP_OPT_REMOVE_PATH :
case PCLZIP_OPT_ADD_PATH :
// ----- Check the number of parameters
if (($i+1) >= $p_size) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
// ----- Return
return PclZip::errorCode();
}
// ----- Get the value
$v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
$i++;
break;
case PCLZIP_OPT_TEMP_FILE_THRESHOLD :
// ----- Check the number of parameters
if (($i+1) >= $p_size) {
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
return PclZip::errorCode();
}
// ----- Check for incompatible options
if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
return PclZip::errorCode();
}
// ----- Check the value
$v_value = $p_options_list[$i+1];
if ((!is_integer($v_value)) || ($v_value<0)) {
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'");
return PclZip::errorCode();
}
// ----- Get the value (and convert it in bytes)
$v_result_list[$p_options_list[$i]] = $v_value*1048576;
$i++;
break;
case PCLZIP_OPT_TEMP_FILE_ON :
// ----- Check for incompatible options
if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
return PclZip::errorCode();
}
$v_result_list[$p_options_list[$i]] = true;
break;
case PCLZIP_OPT_TEMP_FILE_OFF :
// ----- Check for incompatible options
if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
return PclZip::errorCode();
}
// ----- Check for incompatible options
if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
return PclZip::errorCode();
}
$v_result_list[$p_options_list[$i]] = true;
break;
case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION :
// ----- Check the number of parameters
if (($i+1) >= $p_size) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
// ----- Return
return PclZip::errorCode();
}
// ----- Get the value
if ( is_string($p_options_list[$i+1])
&& ($p_options_list[$i+1] != '')) {
$v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
$i++;
}
else {
}
break;
// ----- Look for options that request an array of string for value
case PCLZIP_OPT_BY_NAME :
// ----- Check the number of parameters
if (($i+1) >= $p_size) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
// ----- Return
return PclZip::errorCode();
}
// ----- Get the value
if (is_string($p_options_list[$i+1])) {
$v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1];
}
else if (is_array($p_options_list[$i+1])) {
$v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
}
else {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
// ----- Return
return PclZip::errorCode();
}
$i++;
break;
// ----- Look for options that request an EREG or PREG expression
case PCLZIP_OPT_BY_EREG :
// ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
// to PCLZIP_OPT_BY_PREG
$p_options_list[$i] = PCLZIP_OPT_BY_PREG;
case PCLZIP_OPT_BY_PREG :
//case PCLZIP_OPT_CRYPT :
// ----- Check the number of parameters
if (($i+1) >= $p_size) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
// ----- Return
return PclZip::errorCode();
}
// ----- Get the value
if (is_string($p_options_list[$i+1])) {
$v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
}
else {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
// ----- Return
return PclZip::errorCode();
}
$i++;
break;
// ----- Look for options that takes a string
case PCLZIP_OPT_COMMENT :
case PCLZIP_OPT_ADD_COMMENT :
case PCLZIP_OPT_PREPEND_COMMENT :
// ----- Check the number of parameters
if (($i+1) >= $p_size) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
"Missing parameter value for option '"
.PclZipUtilOptionText($p_options_list[$i])
."'");
// ----- Return
return PclZip::errorCode();
}
// ----- Get the value
if (is_string($p_options_list[$i+1])) {
$v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
}
else {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
"Wrong parameter value for option '"
.PclZipUtilOptionText($p_options_list[$i])
."'");
// ----- Return
return PclZip::errorCode();
}
$i++;
break;
// ----- Look for options that request an array of index
case PCLZIP_OPT_BY_INDEX :
// ----- Check the number of parameters
if (($i+1) >= $p_size) {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
// ----- Return
return PclZip::errorCode();
}
// ----- Get the value
$v_work_list = array();
if (is_string($p_options_list[$i+1])) {
// ----- Remove spaces
$p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', '');
// ----- Parse items
$v_work_list = explode(",", $p_options_list[$i+1]);
}
else if (is_integer($p_options_list[$i+1])) {
$v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1];
}
else if (is_array($p_options_list[$i+1])) {
$v_work_list = $p_options_list[$i+1];
}
else {
// ----- Error log
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'");
// ----- Return
return PclZip::errorCode();
}
// ----- Reduce the index list
// each index item in the list must be a couple with a start and
// an end value : [0,3], [5-5], [8-10], ...
// ----- Check the format of each item
$v_sort_flag=false;
$v_sort_value=0;
for ($j=0; $j| ' . esc_html( __( 'Current' ) ) . ' | '; $table .= '' . esc_html( __( 'Uploaded' ) ) . ' | ||
|---|---|---|---|
| ' . $label . ' | ' . wp_strip_all_tags( $old_value ) . ' | '; $table .= ( $diff_field || $diff_version ) ? '' : ' | '; $table .= wp_strip_all_tags( $new_value ) . ' |
' . esc_html( __( 'The plugin cannot be updated due to the following:' ) ) . '
'; $blocked_message .= '' . $warning . '
'; $overwrite = $this->is_downgrading ? 'downgrade-plugin' : 'update-plugin'; $install_actions['overwrite_plugin'] = sprintf( '%s', wp_nonce_url( add_query_arg( 'overwrite', $overwrite, $this->url ), 'plugin-upload' ), __( 'Replace current with uploaded' ) ); } else { echo $blocked_message; } $cancel_url = add_query_arg( 'action', 'upload-plugin-cancel-overwrite', $this->url ); $install_actions['plugins_page'] = sprintf( '%s', wp_nonce_url( $cancel_url, 'plugin-upload-cancel-overwrite' ), __( 'Cancel and go back' ) ); /** * Filters the list of action links available following a single plugin installation failure * when overwriting is allowed. * * @since 5.5.0 * * @param string[] $install_actions Array of plugin action links. * @param object $api Object containing WordPress.org API plugin data. * @param array $new_plugin_data Array with uploaded plugin data. */ $install_actions = apply_filters( 'install_plugin_overwrite_actions', $install_actions, $this->api, $new_plugin_data ); if ( ! empty( $install_actions ) ) { printf( '', __( 'The uploaded file has expired. Please go back and upload it again.' ) ); echo '' . implode( ' ', (array) $install_actions ) . '
'; } return true; } } PK [2Bc class-plugin-upgrader-skin.phpnu [ '', 'plugin' => '', 'nonce' => '', 'title' => __( 'Update Plugin' ), ); $args = wp_parse_args( $args, $defaults ); $this->plugin = $args['plugin']; $this->plugin_active = is_plugin_active( $this->plugin ); $this->plugin_network_active = is_plugin_active_for_network( $this->plugin ); parent::__construct( $args ); } /** * Action to perform following a single plugin update. * * @since 2.8.0 */ public function after() { $this->plugin = $this->upgrader->plugin_info(); if ( ! empty( $this->plugin ) && ! is_wp_error( $this->result ) && $this->plugin_active ) { // Currently used only when JS is off for a single plugin update? printf( '', esc_attr__( 'Update progress' ), wp_nonce_url( 'update.php?action=activate-plugin&networkwide=' . $this->plugin_network_active . '&plugin=' . urlencode( $this->plugin ), 'activate-plugin_' . $this->plugin ) ); } $this->decrement_update_count( 'plugin' ); $update_actions = array( 'activate_plugin' => sprintf( '%s', wp_nonce_url( 'plugins.php?action=activate&plugin=' . urlencode( $this->plugin ), 'activate-plugin_' . $this->plugin ), __( 'Activate Plugin' ) ), 'plugins_page' => sprintf( '%s', self_admin_url( 'plugins.php' ), __( 'Go to Plugins page' ) ), ); if ( $this->plugin_active || ! $this->result || is_wp_error( $this->result ) || ! current_user_can( 'activate_plugin', $this->plugin ) ) { unset( $update_actions['activate_plugin'] ); } /** * Filters the list of action links available following a single plugin update. * * @since 2.7.0 * * @param string[] $update_actions Array of plugin action links. * @param string $plugin Path to the plugin file relative to the plugins directory. */ $update_actions = apply_filters( 'update_plugin_complete_actions', $update_actions, $this->plugin ); if ( ! empty( $update_actions ) ) { $this->feedback( implode( ' | ', (array) $update_actions ) ); } } } PK [lNS S class-plugin-upgrader.phpnu [ strings['up_to_date'] = __( 'The plugin is at the latest version.' ); $this->strings['no_package'] = __( 'Update package not available.' ); /* translators: %s: Package URL. */ $this->strings['downloading_package'] = sprintf( __( 'Downloading update from %s…' ), '%s' ); $this->strings['unpack_package'] = __( 'Unpacking the update…' ); $this->strings['remove_old'] = __( 'Removing the old version of the plugin…' ); $this->strings['remove_old_failed'] = __( 'Could not remove the old plugin.' ); $this->strings['process_failed'] = __( 'Plugin update failed.' ); $this->strings['process_success'] = __( 'Plugin updated successfully.' ); $this->strings['process_bulk_success'] = __( 'Plugins updated successfully.' ); } /** * Initialize the installation strings. * * @since 2.8.0 */ public function install_strings() { $this->strings['no_package'] = __( 'Installation package not available.' ); /* translators: %s: Package URL. */ $this->strings['downloading_package'] = sprintf( __( 'Downloading installation package from %s…' ), '%s' ); $this->strings['unpack_package'] = __( 'Unpacking the package…' ); $this->strings['installing_package'] = __( 'Installing the plugin…' ); $this->strings['remove_old'] = __( 'Removing the current plugin…' ); $this->strings['remove_old_failed'] = __( 'Could not remove the current plugin.' ); $this->strings['no_files'] = __( 'The plugin contains no files.' ); $this->strings['process_failed'] = __( 'Plugin installation failed.' ); $this->strings['process_success'] = __( 'Plugin installed successfully.' ); /* translators: 1: Plugin name, 2: Plugin version. */ $this->strings['process_success_specific'] = __( 'Successfully installed the plugin %1$s %2$s.' ); if ( ! empty( $this->skin->overwrite ) ) { if ( 'update-plugin' === $this->skin->overwrite ) { $this->strings['installing_package'] = __( 'Updating the plugin…' ); $this->strings['process_failed'] = __( 'Plugin update failed.' ); $this->strings['process_success'] = __( 'Plugin updated successfully.' ); } if ( 'downgrade-plugin' === $this->skin->overwrite ) { $this->strings['installing_package'] = __( 'Downgrading the plugin…' ); $this->strings['process_failed'] = __( 'Plugin downgrade failed.' ); $this->strings['process_success'] = __( 'Plugin downgraded successfully.' ); } } } /** * Install a plugin package. * * @since 2.8.0 * @since 3.7.0 The `$args` parameter was added, making clearing the plugin update cache optional. * * @param string $package The full local path or URI of the package. * @param array $args { * Optional. Other arguments for installing a plugin package. Default empty array. * * @type bool $clear_update_cache Whether to clear the plugin updates cache if successful. * Default true. * } * @return bool|WP_Error True if the installation was successful, false or a WP_Error otherwise. */ public function install( $package, $args = array() ) { $defaults = array( 'clear_update_cache' => true, 'overwrite_package' => false, // Do not overwrite files. ); $parsed_args = wp_parse_args( $args, $defaults ); $this->init(); $this->install_strings(); add_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); if ( $parsed_args['clear_update_cache'] ) { // Clear cache so wp_update_plugins() knows about the new plugin. add_action( 'upgrader_process_complete', 'wp_clean_plugins_cache', 9, 0 ); } $this->run( array( 'package' => $package, 'destination' => WP_PLUGIN_DIR, 'clear_destination' => $parsed_args['overwrite_package'], 'clear_working' => true, 'hook_extra' => array( 'type' => 'plugin', 'action' => 'install', ), ) ); remove_action( 'upgrader_process_complete', 'wp_clean_plugins_cache', 9 ); remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); if ( ! $this->result || is_wp_error( $this->result ) ) { return $this->result; } // Force refresh of plugin update information. wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); if ( $parsed_args['overwrite_package'] ) { /** * Fires when the upgrader has successfully overwritten a currently installed * plugin or theme with an uploaded zip package. * * @since 5.5.0 * * @param string $package The package file. * @param array $data The new plugin or theme data. * @param string $package_type The package type ('plugin' or 'theme'). */ do_action( 'upgrader_overwrote_package', $package, $this->new_plugin_data, 'plugin' ); } return true; } /** * Upgrade a plugin. * * @since 2.8.0 * @since 3.7.0 The `$args` parameter was added, making clearing the plugin update cache optional. * * @param string $plugin Path to the plugin file relative to the plugins directory. * @param array $args { * Optional. Other arguments for upgrading a plugin package. Default empty array. * * @type bool $clear_update_cache Whether to clear the plugin updates cache if successful. * Default true. * } * @return bool|WP_Error True if the upgrade was successful, false or a WP_Error object otherwise. */ public function upgrade( $plugin, $args = array() ) { $defaults = array( 'clear_update_cache' => true, ); $parsed_args = wp_parse_args( $args, $defaults ); $this->init(); $this->upgrade_strings(); $current = get_site_transient( 'update_plugins' ); if ( ! isset( $current->response[ $plugin ] ) ) { $this->skin->before(); $this->skin->set_result( false ); $this->skin->error( 'up_to_date' ); $this->skin->after(); return false; } // Get the URL to the zip file. $r = $current->response[ $plugin ]; add_filter( 'upgrader_pre_install', array( $this, 'deactivate_plugin_before_upgrade' ), 10, 2 ); add_filter( 'upgrader_pre_install', array( $this, 'active_before' ), 10, 2 ); add_filter( 'upgrader_clear_destination', array( $this, 'delete_old_plugin' ), 10, 4 ); add_filter( 'upgrader_post_install', array( $this, 'active_after' ), 10, 2 ); // There's a Trac ticket to move up the directory for zips which are made a bit differently, useful for non-.org plugins. // 'source_selection' => array( $this, 'source_selection' ), if ( $parsed_args['clear_update_cache'] ) { // Clear cache so wp_update_plugins() knows about the new plugin. add_action( 'upgrader_process_complete', 'wp_clean_plugins_cache', 9, 0 ); } $this->run( array( 'package' => $r->package, 'destination' => WP_PLUGIN_DIR, 'clear_destination' => true, 'clear_working' => true, 'hook_extra' => array( 'plugin' => $plugin, 'type' => 'plugin', 'action' => 'update', ), ) ); // Cleanup our hooks, in case something else does a upgrade on this connection. remove_action( 'upgrader_process_complete', 'wp_clean_plugins_cache', 9 ); remove_filter( 'upgrader_pre_install', array( $this, 'deactivate_plugin_before_upgrade' ) ); remove_filter( 'upgrader_pre_install', array( $this, 'active_before' ) ); remove_filter( 'upgrader_clear_destination', array( $this, 'delete_old_plugin' ) ); remove_filter( 'upgrader_post_install', array( $this, 'active_after' ) ); if ( ! $this->result || is_wp_error( $this->result ) ) { return $this->result; } // Force refresh of plugin update information. wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); // Ensure any future auto-update failures trigger a failure email by removing // the last failure notification from the list when plugins update successfully. $past_failure_emails = get_option( 'auto_plugin_theme_update_emails', array() ); if ( isset( $past_failure_emails[ $plugin ] ) ) { unset( $past_failure_emails[ $plugin ] ); update_option( 'auto_plugin_theme_update_emails', $past_failure_emails ); } return true; } /** * Bulk upgrade several plugins at once. * * @since 2.8.0 * @since 3.7.0 The `$args` parameter was added, making clearing the plugin update cache optional. * * @param string[] $plugins Array of paths to plugin files relative to the plugins directory. * @param array $args { * Optional. Other arguments for upgrading several plugins at once. * * @type bool $clear_update_cache Whether to clear the plugin updates cache if successful. Default true. * } * @return array|false An array of results indexed by plugin file, or false if unable to connect to the filesystem. */ public function bulk_upgrade( $plugins, $args = array() ) { $defaults = array( 'clear_update_cache' => true, ); $parsed_args = wp_parse_args( $args, $defaults ); $this->init(); $this->bulk = true; $this->upgrade_strings(); $current = get_site_transient( 'update_plugins' ); add_filter( 'upgrader_clear_destination', array( $this, 'delete_old_plugin' ), 10, 4 ); $this->skin->header(); // Connect to the filesystem first. $res = $this->fs_connect( array( WP_CONTENT_DIR, WP_PLUGIN_DIR ) ); if ( ! $res ) { $this->skin->footer(); return false; } $this->skin->bulk_header(); /* * Only start maintenance mode if: * - running Multisite and there are one or more plugins specified, OR * - a plugin with an update available is currently active. * @todo For multisite, maintenance mode should only kick in for individual sites if at all possible. */ $maintenance = ( is_multisite() && ! empty( $plugins ) ); foreach ( $plugins as $plugin ) { $maintenance = $maintenance || ( is_plugin_active( $plugin ) && isset( $current->response[ $plugin ] ) ); } if ( $maintenance ) { $this->maintenance_mode( true ); } $results = array(); $this->update_count = count( $plugins ); $this->update_current = 0; foreach ( $plugins as $plugin ) { $this->update_current++; $this->skin->plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true ); if ( ! isset( $current->response[ $plugin ] ) ) { $this->skin->set_result( 'up_to_date' ); $this->skin->before(); $this->skin->feedback( 'up_to_date' ); $this->skin->after(); $results[ $plugin ] = true; continue; } // Get the URL to the zip file. $r = $current->response[ $plugin ]; $this->skin->plugin_active = is_plugin_active( $plugin ); $result = $this->run( array( 'package' => $r->package, 'destination' => WP_PLUGIN_DIR, 'clear_destination' => true, 'clear_working' => true, 'is_multi' => true, 'hook_extra' => array( 'plugin' => $plugin, ), ) ); $results[ $plugin ] = $this->result; // Prevent credentials auth screen from displaying multiple times. if ( false === $result ) { break; } } // End foreach $plugins. $this->maintenance_mode( false ); // Force refresh of plugin update information. wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); /** This action is documented in wp-admin/includes/class-wp-upgrader.php */ do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'plugin', 'bulk' => true, 'plugins' => $plugins, ) ); $this->skin->bulk_footer(); $this->skin->footer(); // Cleanup our hooks, in case something else does a upgrade on this connection. remove_filter( 'upgrader_clear_destination', array( $this, 'delete_old_plugin' ) ); // Ensure any future auto-update failures trigger a failure email by removing // the last failure notification from the list when plugins update successfully. $past_failure_emails = get_option( 'auto_plugin_theme_update_emails', array() ); foreach ( $results as $plugin => $result ) { // Maintain last failure notification when plugins failed to update manually. if ( ! $result || is_wp_error( $result ) || ! isset( $past_failure_emails[ $plugin ] ) ) { continue; } unset( $past_failure_emails[ $plugin ] ); } update_option( 'auto_plugin_theme_update_emails', $past_failure_emails ); return $results; } /** * Checks that the source package contains a valid plugin. * * Hooked to the {@see 'upgrader_source_selection'} filter by Plugin_Upgrader::install(). * * @since 3.3.0 * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * @global string $wp_version The WordPress version string. * * @param string $source The path to the downloaded package source. * @return string|WP_Error The source as passed, or a WP_Error object on failure. */ public function check_package( $source ) { global $wp_filesystem, $wp_version; $this->new_plugin_data = array(); if ( is_wp_error( $source ) ) { return $source; } $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit( WP_CONTENT_DIR ), $source ); if ( ! is_dir( $working_directory ) ) { // Sanity check, if the above fails, let's not prevent installation. return $source; } // Check that the folder contains at least 1 valid plugin. $files = glob( $working_directory . '*.php' ); if ( $files ) { foreach ( $files as $file ) { $info = get_plugin_data( $file, false, false ); if ( ! empty( $info['Name'] ) ) { $this->new_plugin_data = $info; break; } } } if ( empty( $this->new_plugin_data ) ) { return new WP_Error( 'incompatible_archive_no_plugins', $this->strings['incompatible_archive'], __( 'No valid plugins were found.' ) ); } $requires_php = isset( $info['RequiresPHP'] ) ? $info['RequiresPHP'] : null; $requires_wp = isset( $info['RequiresWP'] ) ? $info['RequiresWP'] : null; if ( ! is_php_version_compatible( $requires_php ) ) { $error = sprintf( /* translators: 1: Current PHP version, 2: Version required by the uploaded plugin. */ __( 'The PHP version on your server is %1$s, however the uploaded plugin requires %2$s.' ), phpversion(), $requires_php ); return new WP_Error( 'incompatible_php_required_version', $this->strings['incompatible_archive'], $error ); } if ( ! is_wp_version_compatible( $requires_wp ) ) { $error = sprintf( /* translators: 1: Current WordPress version, 2: Version required by the uploaded plugin. */ __( 'Your WordPress version is %1$s, however the uploaded plugin requires %2$s.' ), $wp_version, $requires_wp ); return new WP_Error( 'incompatible_wp_required_version', $this->strings['incompatible_archive'], $error ); } return $source; } /** * Retrieve the path to the file that contains the plugin info. * * This isn't used internally in the class, but is called by the skins. * * @since 2.8.0 * * @return string|false The full path to the main plugin file, or false. */ public function plugin_info() { if ( ! is_array( $this->result ) ) { return false; } if ( empty( $this->result['destination_name'] ) ) { return false; } // Ensure to pass with leading slash. $plugin = get_plugins( '/' . $this->result['destination_name'] ); if ( empty( $plugin ) ) { return false; } // Assume the requested plugin is the first in the list. $pluginfiles = array_keys( $plugin ); return $this->result['destination_name'] . '/' . $pluginfiles[0]; } /** * Deactivates a plugin before it is upgraded. * * Hooked to the {@see 'upgrader_pre_install'} filter by Plugin_Upgrader::upgrade(). * * @since 2.8.0 * @since 4.1.0 Added a return value. * * @param bool|WP_Error $return Upgrade offer return. * @param array $plugin Plugin package arguments. * @return bool|WP_Error The passed in $return param or WP_Error. */ public function deactivate_plugin_before_upgrade( $return, $plugin ) { if ( is_wp_error( $return ) ) { // Bypass. return $return; } // When in cron (background updates) don't deactivate the plugin, as we require a browser to reactivate it. if ( wp_doing_cron() ) { return $return; } $plugin = isset( $plugin['plugin'] ) ? $plugin['plugin'] : ''; if ( empty( $plugin ) ) { return new WP_Error( 'bad_request', $this->strings['bad_request'] ); } if ( is_plugin_active( $plugin ) ) { // Deactivate the plugin silently, Prevent deactivation hooks from running. deactivate_plugins( $plugin, true ); } return $return; } /** * Turns on maintenance mode before attempting to background update an active plugin. * * Hooked to the {@see 'upgrader_pre_install'} filter by Plugin_Upgrader::upgrade(). * * @since 5.4.0 * * @param bool|WP_Error $return Upgrade offer return. * @param array $plugin Plugin package arguments. * @return bool|WP_Error The passed in $return param or WP_Error. */ public function active_before( $return, $plugin ) { if ( is_wp_error( $return ) ) { return $return; } // Only enable maintenance mode when in cron (background update). if ( ! wp_doing_cron() ) { return $return; } $plugin = isset( $plugin['plugin'] ) ? $plugin['plugin'] : ''; // Only run if plugin is active. if ( ! is_plugin_active( $plugin ) ) { return $return; } // Change to maintenance mode. Bulk edit handles this separately. if ( ! $this->bulk ) { $this->maintenance_mode( true ); } return $return; } /** * Turns off maintenance mode after upgrading an active plugin. * * Hooked to the {@see 'upgrader_post_install'} filter by Plugin_Upgrader::upgrade(). * * @since 5.4.0 * * @param bool|WP_Error $return Upgrade offer return. * @param array $plugin Plugin package arguments. * @return bool|WP_Error The passed in $return param or WP_Error. */ public function active_after( $return, $plugin ) { if ( is_wp_error( $return ) ) { return $return; } // Only disable maintenance mode when in cron (background update). if ( ! wp_doing_cron() ) { return $return; } $plugin = isset( $plugin['plugin'] ) ? $plugin['plugin'] : ''; // Only run if plugin is active if ( ! is_plugin_active( $plugin ) ) { return $return; } // Time to remove maintenance mode. Bulk edit handles this separately. if ( ! $this->bulk ) { $this->maintenance_mode( false ); } return $return; } /** * Deletes the old plugin during an upgrade. * * Hooked to the {@see 'upgrader_clear_destination'} filter by * Plugin_Upgrader::upgrade() and Plugin_Upgrader::bulk_upgrade(). * * @since 2.8.0 * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * * @param bool|WP_Error $removed Whether the destination was cleared. * True on success, WP_Error on failure. * @param string $local_destination The local package destination. * @param string $remote_destination The remote package destination. * @param array $plugin Extra arguments passed to hooked filters. * @return bool|WP_Error */ public function delete_old_plugin( $removed, $local_destination, $remote_destination, $plugin ) { global $wp_filesystem; if ( is_wp_error( $removed ) ) { return $removed; // Pass errors through. } $plugin = isset( $plugin['plugin'] ) ? $plugin['plugin'] : ''; if ( empty( $plugin ) ) { return new WP_Error( 'bad_request', $this->strings['bad_request'] ); } $plugins_dir = $wp_filesystem->wp_plugins_dir(); $this_plugin_dir = trailingslashit( dirname( $plugins_dir . $plugin ) ); if ( ! $wp_filesystem->exists( $this_plugin_dir ) ) { // If it's already vanished. return $removed; } // If plugin is in its own directory, recursively delete the directory. // Base check on if plugin includes directory separator AND that it's not the root plugin folder. if ( strpos( $plugin, '/' ) && $this_plugin_dir !== $plugins_dir ) { $deleted = $wp_filesystem->delete( $this_plugin_dir, true ); } else { $deleted = $wp_filesystem->delete( $plugins_dir . $plugin ); } if ( ! $deleted ) { return new WP_Error( 'remove_old_failed', $this->strings['remove_old_failed'] ); } return true; } } PK [ji|ǧ0 0 class-theme-installer-skin.phpnu [ 'web', 'url' => '', 'theme' => '', 'nonce' => '', 'title' => '', 'overwrite' => '', ); $args = wp_parse_args( $args, $defaults ); $this->type = $args['type']; $this->url = $args['url']; $this->api = isset( $args['api'] ) ? $args['api'] : array(); $this->overwrite = $args['overwrite']; parent::__construct( $args ); } /** * Action to perform before installing a theme. * * @since 2.8.0 */ public function before() { if ( ! empty( $this->api ) ) { $this->upgrader->strings['process_success'] = sprintf( $this->upgrader->strings['process_success_specific'], $this->api->name, $this->api->version ); } } /** * Hides the `process_failed` error when updating a theme by uploading a zip file. * * @since 5.5.0 * * @param WP_Error $wp_error WP_Error object. * @return bool */ public function hide_process_failed( $wp_error ) { if ( 'upload' === $this->type && '' === $this->overwrite && $wp_error->get_error_code() === 'folder_exists' ) { return true; } return false; } /** * Action to perform following a single theme install. * * @since 2.8.0 */ public function after() { if ( $this->do_overwrite() ) { return; } if ( empty( $this->upgrader->result['destination_name'] ) ) { return; } $theme_info = $this->upgrader->theme_info(); if ( empty( $theme_info ) ) { return; } $name = $theme_info->display( 'Name' ); $stylesheet = $this->upgrader->result['destination_name']; $template = $theme_info->get_template(); $activate_link = add_query_arg( array( 'action' => 'activate', 'template' => urlencode( $template ), 'stylesheet' => urlencode( $stylesheet ), ), admin_url( 'themes.php' ) ); $activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $stylesheet ); $install_actions = array(); if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { $customize_url = add_query_arg( array( 'theme' => urlencode( $stylesheet ), 'return' => urlencode( admin_url( 'web' === $this->type ? 'theme-install.php' : 'themes.php' ) ), ), admin_url( 'customize.php' ) ); $install_actions['preview'] = sprintf( '' . '%s', esc_url( $customize_url ), __( 'Live Preview' ), /* translators: %s: Theme name. */ sprintf( __( 'Live Preview “%s”' ), $name ) ); } $install_actions['activate'] = sprintf( '' . '%s', esc_url( $activate_link ), __( 'Activate' ), /* translators: %s: Theme name. */ sprintf( _x( 'Activate “%s”', 'theme' ), $name ) ); if ( is_network_admin() && current_user_can( 'manage_network_themes' ) ) { $install_actions['network_enable'] = sprintf( '%s', esc_url( wp_nonce_url( 'themes.php?action=enable&theme=' . urlencode( $stylesheet ), 'enable-theme_' . $stylesheet ) ), __( 'Network Enable' ) ); } if ( 'web' === $this->type ) { $install_actions['themes_page'] = sprintf( '%s', self_admin_url( 'theme-install.php' ), __( 'Go to Theme Installer' ) ); } elseif ( current_user_can( 'switch_themes' ) || current_user_can( 'edit_theme_options' ) ) { $install_actions['themes_page'] = sprintf( '%s', self_admin_url( 'themes.php' ), __( 'Go to Themes page' ) ); } if ( ! $this->result || is_wp_error( $this->result ) || is_network_admin() || ! current_user_can( 'switch_themes' ) ) { unset( $install_actions['activate'], $install_actions['preview'] ); } elseif ( get_option( 'template' ) === $stylesheet ) { unset( $install_actions['activate'] ); } /** * Filters the list of action links available following a single theme installation. * * @since 2.8.0 * * @param string[] $install_actions Array of theme action links. * @param object $api Object containing WordPress.org API theme data. * @param string $stylesheet Theme directory name. * @param WP_Theme $theme_info Theme object. */ $install_actions = apply_filters( 'install_theme_complete_actions', $install_actions, $this->api, $stylesheet, $theme_info ); if ( ! empty( $install_actions ) ) { $this->feedback( implode( ' | ', (array) $install_actions ) ); } } /** * Check if the theme can be overwritten and output the HTML for overwriting a theme on upload. * * @since 5.5.0 * * @return bool Whether the theme can be overwritten and HTML was outputted. */ private function do_overwrite() { if ( 'upload' !== $this->type || ! is_wp_error( $this->result ) || 'folder_exists' !== $this->result->get_error_code() ) { return false; } $folder = $this->result->get_error_data( 'folder_exists' ); $folder = rtrim( $folder, '/' ); $current_theme_data = false; $all_themes = wp_get_themes( array( 'errors' => null ) ); foreach ( $all_themes as $theme ) { $stylesheet_dir = wp_normalize_path( $theme->get_stylesheet_directory() ); if ( rtrim( $stylesheet_dir, '/' ) !== $folder ) { continue; } $current_theme_data = $theme; } $new_theme_data = $this->upgrader->new_theme_data; if ( ! $current_theme_data || ! $new_theme_data ) { return false; } echo '| ' . esc_html( __( 'Current' ) ) . ' | ' . esc_html( __( 'Uploaded' ) ) . ' | ||
|---|---|---|---|
| ' . $label . ' | ' . wp_strip_all_tags( $old_value ) . ' | '; $table .= ( $diff_field || $diff_version || $invalid_parent ) ? '' : ' | '; $table .= wp_strip_all_tags( $new_value ) . ' |
' . esc_html( __( 'The theme cannot be updated due to the following:' ) ) . '
'; $blocked_message .= '' . $warning . '
'; $overwrite = $this->is_downgrading ? 'downgrade-theme' : 'update-theme'; $install_actions['overwrite_theme'] = sprintf( '%s', wp_nonce_url( add_query_arg( 'overwrite', $overwrite, $this->url ), 'theme-upload' ), __( 'Replace current with uploaded' ) ); } else { echo $blocked_message; } $cancel_url = add_query_arg( 'action', 'upload-theme-cancel-overwrite', $this->url ); $install_actions['themes_page'] = sprintf( '%s', wp_nonce_url( $cancel_url, 'theme-upload-cancel-overwrite' ), __( 'Cancel and go back' ) ); /** * Filters the list of action links available following a single theme installation failure * when overwriting is allowed. * * @since 5.5.0 * * @param string[] $install_actions Array of theme action links. * @param object $api Object containing WordPress.org API theme data. * @param array $new_theme_data Array with uploaded theme data. */ $install_actions = apply_filters( 'install_theme_overwrite_actions', $install_actions, $this->api, $new_theme_data ); if ( ! empty( $install_actions ) ) { printf( '', __( 'The uploaded file has expired. Please go back and upload it again.' ) ); echo '' . implode( ' ', (array) $install_actions ) . '
'; } return true; } } PK [ class-theme-upgrader-skin.phpnu [ '', 'theme' => '', 'nonce' => '', 'title' => __( 'Update Theme' ), ); $args = wp_parse_args( $args, $defaults ); $this->theme = $args['theme']; parent::__construct( $args ); } /** * Action to perform following a single theme update. * * @since 2.8.0 */ public function after() { $this->decrement_update_count( 'theme' ); $update_actions = array(); $theme_info = $this->upgrader->theme_info(); if ( $theme_info ) { $name = $theme_info->display( 'Name' ); $stylesheet = $this->upgrader->result['destination_name']; $template = $theme_info->get_template(); $activate_link = add_query_arg( array( 'action' => 'activate', 'template' => urlencode( $template ), 'stylesheet' => urlencode( $stylesheet ), ), admin_url( 'themes.php' ) ); $activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $stylesheet ); $customize_url = add_query_arg( array( 'theme' => urlencode( $stylesheet ), 'return' => urlencode( admin_url( 'themes.php' ) ), ), admin_url( 'customize.php' ) ); if ( get_stylesheet() === $stylesheet ) { if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { $update_actions['preview'] = sprintf( '' . '%s', esc_url( $customize_url ), __( 'Customize' ), /* translators: %s: Theme name. */ sprintf( __( 'Customize “%s”' ), $name ) ); } } elseif ( current_user_can( 'switch_themes' ) ) { if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { $update_actions['preview'] = sprintf( '' . '%s', esc_url( $customize_url ), __( 'Live Preview' ), /* translators: %s: Theme name. */ sprintf( __( 'Live Preview “%s”' ), $name ) ); } $update_actions['activate'] = sprintf( '' . '%s', esc_url( $activate_link ), __( 'Activate' ), /* translators: %s: Theme name. */ sprintf( _x( 'Activate “%s”', 'theme' ), $name ) ); } if ( ! $this->result || is_wp_error( $this->result ) || is_network_admin() ) { unset( $update_actions['preview'], $update_actions['activate'] ); } } $update_actions['themes_page'] = sprintf( '%s', self_admin_url( 'themes.php' ), __( 'Go to Themes page' ) ); /** * Filters the list of action links available following a single theme update. * * @since 2.8.0 * * @param string[] $update_actions Array of theme action links. * @param string $theme Theme directory name. */ $update_actions = apply_filters( 'update_theme_complete_actions', $update_actions, $this->theme ); if ( ! empty( $update_actions ) ) { $this->feedback( implode( ' | ', (array) $update_actions ) ); } } } PK [ll_ _ class-theme-upgrader.phpnu [ strings['up_to_date'] = __( 'The theme is at the latest version.' ); $this->strings['no_package'] = __( 'Update package not available.' ); /* translators: %s: Package URL. */ $this->strings['downloading_package'] = sprintf( __( 'Downloading update from %s…' ), '%s' ); $this->strings['unpack_package'] = __( 'Unpacking the update…' ); $this->strings['remove_old'] = __( 'Removing the old version of the theme…' ); $this->strings['remove_old_failed'] = __( 'Could not remove the old theme.' ); $this->strings['process_failed'] = __( 'Theme update failed.' ); $this->strings['process_success'] = __( 'Theme updated successfully.' ); } /** * Initialize the installation strings. * * @since 2.8.0 */ public function install_strings() { $this->strings['no_package'] = __( 'Installation package not available.' ); /* translators: %s: Package URL. */ $this->strings['downloading_package'] = sprintf( __( 'Downloading installation package from %s…' ), '%s' ); $this->strings['unpack_package'] = __( 'Unpacking the package…' ); $this->strings['installing_package'] = __( 'Installing the theme…' ); $this->strings['remove_old'] = __( 'Removing the old version of the theme…' ); $this->strings['remove_old_failed'] = __( 'Could not remove the old theme.' ); $this->strings['no_files'] = __( 'The theme contains no files.' ); $this->strings['process_failed'] = __( 'Theme installation failed.' ); $this->strings['process_success'] = __( 'Theme installed successfully.' ); /* translators: 1: Theme name, 2: Theme version. */ $this->strings['process_success_specific'] = __( 'Successfully installed the theme %1$s %2$s.' ); $this->strings['parent_theme_search'] = __( 'This theme requires a parent theme. Checking if it is installed…' ); /* translators: 1: Theme name, 2: Theme version. */ $this->strings['parent_theme_prepare_install'] = __( 'Preparing to install %1$s %2$s…' ); /* translators: 1: Theme name, 2: Theme version. */ $this->strings['parent_theme_currently_installed'] = __( 'The parent theme, %1$s %2$s, is currently installed.' ); /* translators: 1: Theme name, 2: Theme version. */ $this->strings['parent_theme_install_success'] = __( 'Successfully installed the parent theme, %1$s %2$s.' ); /* translators: %s: Theme name. */ $this->strings['parent_theme_not_found'] = sprintf( __( 'The parent theme could not be found. You will need to install the parent theme, %s, before you can use this child theme.' ), '%s' ); /* translators: %s: Theme error. */ $this->strings['current_theme_has_errors'] = __( 'The current theme has the following error: "%s".' ); if ( ! empty( $this->skin->overwrite ) ) { if ( 'update-theme' === $this->skin->overwrite ) { $this->strings['installing_package'] = __( 'Updating the theme…' ); $this->strings['process_failed'] = __( 'Theme update failed.' ); $this->strings['process_success'] = __( 'Theme updated successfully.' ); } if ( 'downgrade-theme' === $this->skin->overwrite ) { $this->strings['installing_package'] = __( 'Downgrading the theme…' ); $this->strings['process_failed'] = __( 'Theme downgrade failed.' ); $this->strings['process_success'] = __( 'Theme downgraded successfully.' ); } } } /** * Check if a child theme is being installed and we need to install its parent. * * Hooked to the {@see 'upgrader_post_install'} filter by Theme_Upgrader::install(). * * @since 3.4.0 * * @param bool $install_result * @param array $hook_extra * @param array $child_result * @return bool */ public function check_parent_theme_filter( $install_result, $hook_extra, $child_result ) { // Check to see if we need to install a parent theme. $theme_info = $this->theme_info(); if ( ! $theme_info->parent() ) { return $install_result; } $this->skin->feedback( 'parent_theme_search' ); if ( ! $theme_info->parent()->errors() ) { $this->skin->feedback( 'parent_theme_currently_installed', $theme_info->parent()->display( 'Name' ), $theme_info->parent()->display( 'Version' ) ); // We already have the theme, fall through. return $install_result; } // We don't have the parent theme, let's install it. $api = themes_api( 'theme_information', array( 'slug' => $theme_info->get( 'Template' ), 'fields' => array( 'sections' => false, 'tags' => false, ), ) ); // Save on a bit of bandwidth. if ( ! $api || is_wp_error( $api ) ) { $this->skin->feedback( 'parent_theme_not_found', $theme_info->get( 'Template' ) ); // Don't show activate or preview actions after installation. add_filter( 'install_theme_complete_actions', array( $this, 'hide_activate_preview_actions' ) ); return $install_result; } // Backup required data we're going to override: $child_api = $this->skin->api; $child_success_message = $this->strings['process_success']; // Override them. $this->skin->api = $api; $this->strings['process_success_specific'] = $this->strings['parent_theme_install_success']; $this->skin->feedback( 'parent_theme_prepare_install', $api->name, $api->version ); add_filter( 'install_theme_complete_actions', '__return_false', 999 ); // Don't show any actions after installing the theme. // Install the parent theme. $parent_result = $this->run( array( 'package' => $api->download_link, 'destination' => get_theme_root(), 'clear_destination' => false, // Do not overwrite files. 'clear_working' => true, ) ); if ( is_wp_error( $parent_result ) ) { add_filter( 'install_theme_complete_actions', array( $this, 'hide_activate_preview_actions' ) ); } // Start cleaning up after the parent's installation. remove_filter( 'install_theme_complete_actions', '__return_false', 999 ); // Reset child's result and data. $this->result = $child_result; $this->skin->api = $child_api; $this->strings['process_success'] = $child_success_message; return $install_result; } /** * Don't display the activate and preview actions to the user. * * Hooked to the {@see 'install_theme_complete_actions'} filter by * Theme_Upgrader::check_parent_theme_filter() when installing * a child theme and installing the parent theme fails. * * @since 3.4.0 * * @param array $actions Preview actions. * @return array */ public function hide_activate_preview_actions( $actions ) { unset( $actions['activate'], $actions['preview'] ); return $actions; } /** * Install a theme package. * * @since 2.8.0 * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional. * * @param string $package The full local path or URI of the package. * @param array $args { * Optional. Other arguments for installing a theme package. Default empty array. * * @type bool $clear_update_cache Whether to clear the updates cache if successful. * Default true. * } * * @return bool|WP_Error True if the installation was successful, false or a WP_Error object otherwise. */ public function install( $package, $args = array() ) { $defaults = array( 'clear_update_cache' => true, 'overwrite_package' => false, // Do not overwrite files. ); $parsed_args = wp_parse_args( $args, $defaults ); $this->init(); $this->install_strings(); add_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); add_filter( 'upgrader_post_install', array( $this, 'check_parent_theme_filter' ), 10, 3 ); if ( $parsed_args['clear_update_cache'] ) { // Clear cache so wp_update_themes() knows about the new theme. add_action( 'upgrader_process_complete', 'wp_clean_themes_cache', 9, 0 ); } $this->run( array( 'package' => $package, 'destination' => get_theme_root(), 'clear_destination' => $parsed_args['overwrite_package'], 'clear_working' => true, 'hook_extra' => array( 'type' => 'theme', 'action' => 'install', ), ) ); remove_action( 'upgrader_process_complete', 'wp_clean_themes_cache', 9 ); remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); remove_filter( 'upgrader_post_install', array( $this, 'check_parent_theme_filter' ) ); if ( ! $this->result || is_wp_error( $this->result ) ) { return $this->result; } // Refresh the Theme Update information. wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); if ( $parsed_args['overwrite_package'] ) { /** This action is documented in wp-admin/includes/class-plugin-upgrader.php */ do_action( 'upgrader_overwrote_package', $package, $this->new_theme_data, 'theme' ); } return true; } /** * Upgrade a theme. * * @since 2.8.0 * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional. * * @param string $theme The theme slug. * @param array $args { * Optional. Other arguments for upgrading a theme. Default empty array. * * @type bool $clear_update_cache Whether to clear the update cache if successful. * Default true. * } * @return bool|WP_Error True if the upgrade was successful, false or a WP_Error object otherwise. */ public function upgrade( $theme, $args = array() ) { $defaults = array( 'clear_update_cache' => true, ); $parsed_args = wp_parse_args( $args, $defaults ); $this->init(); $this->upgrade_strings(); // Is an update available? $current = get_site_transient( 'update_themes' ); if ( ! isset( $current->response[ $theme ] ) ) { $this->skin->before(); $this->skin->set_result( false ); $this->skin->error( 'up_to_date' ); $this->skin->after(); return false; } $r = $current->response[ $theme ]; add_filter( 'upgrader_pre_install', array( $this, 'current_before' ), 10, 2 ); add_filter( 'upgrader_post_install', array( $this, 'current_after' ), 10, 2 ); add_filter( 'upgrader_clear_destination', array( $this, 'delete_old_theme' ), 10, 4 ); if ( $parsed_args['clear_update_cache'] ) { // Clear cache so wp_update_themes() knows about the new theme. add_action( 'upgrader_process_complete', 'wp_clean_themes_cache', 9, 0 ); } $this->run( array( 'package' => $r['package'], 'destination' => get_theme_root( $theme ), 'clear_destination' => true, 'clear_working' => true, 'hook_extra' => array( 'theme' => $theme, 'type' => 'theme', 'action' => 'update', ), ) ); remove_action( 'upgrader_process_complete', 'wp_clean_themes_cache', 9 ); remove_filter( 'upgrader_pre_install', array( $this, 'current_before' ) ); remove_filter( 'upgrader_post_install', array( $this, 'current_after' ) ); remove_filter( 'upgrader_clear_destination', array( $this, 'delete_old_theme' ) ); if ( ! $this->result || is_wp_error( $this->result ) ) { return $this->result; } wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); // Ensure any future auto-update failures trigger a failure email by removing // the last failure notification from the list when themes update successfully. $past_failure_emails = get_option( 'auto_plugin_theme_update_emails', array() ); if ( isset( $past_failure_emails[ $theme ] ) ) { unset( $past_failure_emails[ $theme ] ); update_option( 'auto_plugin_theme_update_emails', $past_failure_emails ); } return true; } /** * Upgrade several themes at once. * * @since 3.0.0 * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional. * * @param string[] $themes Array of the theme slugs. * @param array $args { * Optional. Other arguments for upgrading several themes at once. Default empty array. * * @type bool $clear_update_cache Whether to clear the update cache if successful. * Default true. * } * @return array[]|false An array of results, or false if unable to connect to the filesystem. */ public function bulk_upgrade( $themes, $args = array() ) { $defaults = array( 'clear_update_cache' => true, ); $parsed_args = wp_parse_args( $args, $defaults ); $this->init(); $this->bulk = true; $this->upgrade_strings(); $current = get_site_transient( 'update_themes' ); add_filter( 'upgrader_pre_install', array( $this, 'current_before' ), 10, 2 ); add_filter( 'upgrader_post_install', array( $this, 'current_after' ), 10, 2 ); add_filter( 'upgrader_clear_destination', array( $this, 'delete_old_theme' ), 10, 4 ); $this->skin->header(); // Connect to the filesystem first. $res = $this->fs_connect( array( WP_CONTENT_DIR ) ); if ( ! $res ) { $this->skin->footer(); return false; } $this->skin->bulk_header(); /* * Only start maintenance mode if: * - running Multisite and there are one or more themes specified, OR * - a theme with an update available is currently in use. * @todo For multisite, maintenance mode should only kick in for individual sites if at all possible. */ $maintenance = ( is_multisite() && ! empty( $themes ) ); foreach ( $themes as $theme ) { $maintenance = $maintenance || get_stylesheet() === $theme || get_template() === $theme; } if ( $maintenance ) { $this->maintenance_mode( true ); } $results = array(); $this->update_count = count( $themes ); $this->update_current = 0; foreach ( $themes as $theme ) { $this->update_current++; $this->skin->theme_info = $this->theme_info( $theme ); if ( ! isset( $current->response[ $theme ] ) ) { $this->skin->set_result( true ); $this->skin->before(); $this->skin->feedback( 'up_to_date' ); $this->skin->after(); $results[ $theme ] = true; continue; } // Get the URL to the zip file. $r = $current->response[ $theme ]; $result = $this->run( array( 'package' => $r['package'], 'destination' => get_theme_root( $theme ), 'clear_destination' => true, 'clear_working' => true, 'is_multi' => true, 'hook_extra' => array( 'theme' => $theme, ), ) ); $results[ $theme ] = $this->result; // Prevent credentials auth screen from displaying multiple times. if ( false === $result ) { break; } } // End foreach $themes. $this->maintenance_mode( false ); // Refresh the Theme Update information. wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); /** This action is documented in wp-admin/includes/class-wp-upgrader.php */ do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'theme', 'bulk' => true, 'themes' => $themes, ) ); $this->skin->bulk_footer(); $this->skin->footer(); // Cleanup our hooks, in case something else does a upgrade on this connection. remove_filter( 'upgrader_pre_install', array( $this, 'current_before' ) ); remove_filter( 'upgrader_post_install', array( $this, 'current_after' ) ); remove_filter( 'upgrader_clear_destination', array( $this, 'delete_old_theme' ) ); // Ensure any future auto-update failures trigger a failure email by removing // the last failure notification from the list when themes update successfully. $past_failure_emails = get_option( 'auto_plugin_theme_update_emails', array() ); foreach ( $results as $theme => $result ) { // Maintain last failure notification when themes failed to update manually. if ( ! $result || is_wp_error( $result ) || ! isset( $past_failure_emails[ $theme ] ) ) { continue; } unset( $past_failure_emails[ $theme ] ); } update_option( 'auto_plugin_theme_update_emails', $past_failure_emails ); return $results; } /** * Checks that the package source contains a valid theme. * * Hooked to the {@see 'upgrader_source_selection'} filter by Theme_Upgrader::install(). * * @since 3.3.0 * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * @global string $wp_version The WordPress version string. * * @param string $source The path to the downloaded package source. * @return string|WP_Error The source as passed, or a WP_Error object on failure. */ public function check_package( $source ) { global $wp_filesystem, $wp_version; $this->new_theme_data = array(); if ( is_wp_error( $source ) ) { return $source; } // Check that the folder contains a valid theme. $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit( WP_CONTENT_DIR ), $source ); if ( ! is_dir( $working_directory ) ) { // Sanity check, if the above fails, let's not prevent installation. return $source; } // A proper archive should have a style.css file in the single subdirectory. if ( ! file_exists( $working_directory . 'style.css' ) ) { return new WP_Error( 'incompatible_archive_theme_no_style', $this->strings['incompatible_archive'], sprintf( /* translators: %s: style.css */ __( 'The theme is missing the %s stylesheet.' ), 'style.css'
)
);
}
// All these headers are needed on Theme_Installer_Skin::do_overwrite().
$info = get_file_data(
$working_directory . 'style.css',
array(
'Name' => 'Theme Name',
'Version' => 'Version',
'Author' => 'Author',
'Template' => 'Template',
'RequiresWP' => 'Requires at least',
'RequiresPHP' => 'Requires PHP',
)
);
if ( empty( $info['Name'] ) ) {
return new WP_Error(
'incompatible_archive_theme_no_name',
$this->strings['incompatible_archive'],
sprintf(
/* translators: %s: style.css */
__( 'The %s stylesheet doesn’t contain a valid theme header.' ),
'style.css'
)
);
}
// If it's not a child theme, it must have at least an index.php to be legit.
if ( empty( $info['Template'] ) && ! file_exists( $working_directory . 'index.php' ) ) {
return new WP_Error(
'incompatible_archive_theme_no_index',
$this->strings['incompatible_archive'],
sprintf(
/* translators: %s: index.php */
__( 'The theme is missing the %s file.' ),
'index.php'
)
);
}
$requires_php = isset( $info['RequiresPHP'] ) ? $info['RequiresPHP'] : null;
$requires_wp = isset( $info['RequiresWP'] ) ? $info['RequiresWP'] : null;
if ( ! is_php_version_compatible( $requires_php ) ) {
$error = sprintf(
/* translators: 1: Current PHP version, 2: Version required by the uploaded theme. */
__( 'The PHP version on your server is %1$s, however the uploaded theme requires %2$s.' ),
phpversion(),
$requires_php
);
return new WP_Error( 'incompatible_php_required_version', $this->strings['incompatible_archive'], $error );
}
if ( ! is_wp_version_compatible( $requires_wp ) ) {
$error = sprintf(
/* translators: 1: Current WordPress version, 2: Version required by the uploaded theme. */
__( 'Your WordPress version is %1$s, however the uploaded theme requires %2$s.' ),
$wp_version,
$requires_wp
);
return new WP_Error( 'incompatible_wp_required_version', $this->strings['incompatible_archive'], $error );
}
$this->new_theme_data = $info;
return $source;
}
/**
* Turn on maintenance mode before attempting to upgrade the current theme.
*
* Hooked to the {@see 'upgrader_pre_install'} filter by Theme_Upgrader::upgrade() and
* Theme_Upgrader::bulk_upgrade().
*
* @since 2.8.0
*
* @param bool|WP_Error $return Upgrade offer return.
* @param array $theme Theme arguments.
* @return bool|WP_Error The passed in $return param or WP_Error.
*/
public function current_before( $return, $theme ) {
if ( is_wp_error( $return ) ) {
return $return;
}
$theme = isset( $theme['theme'] ) ? $theme['theme'] : '';
// Only run if current theme
if ( get_stylesheet() !== $theme ) {
return $return;
}
// Change to maintenance mode. Bulk edit handles this separately.
if ( ! $this->bulk ) {
$this->maintenance_mode( true );
}
return $return;
}
/**
* Turn off maintenance mode after upgrading the current theme.
*
* Hooked to the {@see 'upgrader_post_install'} filter by Theme_Upgrader::upgrade()
* and Theme_Upgrader::bulk_upgrade().
*
* @since 2.8.0
*
* @param bool|WP_Error $return Upgrade offer return.
* @param array $theme Theme arguments.
* @return bool|WP_Error The passed in $return param or WP_Error.
*/
public function current_after( $return, $theme ) {
if ( is_wp_error( $return ) ) {
return $return;
}
$theme = isset( $theme['theme'] ) ? $theme['theme'] : '';
// Only run if current theme.
if ( get_stylesheet() !== $theme ) {
return $return;
}
// Ensure stylesheet name hasn't changed after the upgrade:
if ( get_stylesheet() === $theme && $theme !== $this->result['destination_name'] ) {
wp_clean_themes_cache();
$stylesheet = $this->result['destination_name'];
switch_theme( $stylesheet );
}
// Time to remove maintenance mode. Bulk edit handles this separately.
if ( ! $this->bulk ) {
$this->maintenance_mode( false );
}
return $return;
}
/**
* Delete the old theme during an upgrade.
*
* Hooked to the {@see 'upgrader_clear_destination'} filter by Theme_Upgrader::upgrade()
* and Theme_Upgrader::bulk_upgrade().
*
* @since 2.8.0
*
* @global WP_Filesystem_Base $wp_filesystem Subclass
*
* @param bool $removed
* @param string $local_destination
* @param string $remote_destination
* @param array $theme
* @return bool
*/
public function delete_old_theme( $removed, $local_destination, $remote_destination, $theme ) {
global $wp_filesystem;
if ( is_wp_error( $removed ) ) {
return $removed; // Pass errors through.
}
if ( ! isset( $theme['theme'] ) ) {
return $removed;
}
$theme = $theme['theme'];
$themes_dir = trailingslashit( $wp_filesystem->wp_themes_dir( $theme ) );
if ( $wp_filesystem->exists( $themes_dir . $theme ) ) {
if ( ! $wp_filesystem->delete( $themes_dir . $theme, true ) ) {
return false;
}
}
return true;
}
/**
* Get the WP_Theme object for a theme.
*
* @since 2.8.0
* @since 3.0.0 The `$theme` argument was added.
*
* @param string $theme The directory name of the theme. This is optional, and if not supplied,
* the directory name from the last result will be used.
* @return WP_Theme|false The theme's info object, or false `$theme` is not supplied
* and the last result isn't set.
*/
public function theme_info( $theme = null ) {
if ( empty( $theme ) ) {
if ( ! empty( $this->result['destination_name'] ) ) {
$theme = $this->result['destination_name'];
} else {
return false;
}
}
$theme = wp_get_theme( $theme );
$theme->cache_delete();
return $theme;
}
}
PK [\% % # class-walker-category-checklist.phpnu [ 'parent',
'id' => 'term_id',
); // TODO: Decouple this.
/**
* Starts the list before the elements are added.
*
* @see Walker:start_lvl()
*
* @since 2.5.1
*
* @param string $output Used to append additional content (passed by reference).
* @param int $depth Depth of category. Used for tab indentation.
* @param array $args An array of arguments. @see wp_terms_checklist()
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "$indent' . str_replace( ABSPATH, '', WP_CONTENT_DIR ) . ''
),
'fields' => array(),
);
$info['wp-active-theme'] = array(
'label' => __( 'Active Theme' ),
'fields' => array(),
);
$info['wp-parent-theme'] = array(
'label' => __( 'Parent Theme' ),
'fields' => array(),
);
$info['wp-themes-inactive'] = array(
'label' => __( 'Inactive Themes' ),
'show_count' => true,
'fields' => array(),
);
$info['wp-mu-plugins'] = array(
'label' => __( 'Must Use Plugins' ),
'show_count' => true,
'fields' => array(),
);
$info['wp-plugins-active'] = array(
'label' => __( 'Active Plugins' ),
'show_count' => true,
'fields' => array(),
);
$info['wp-plugins-inactive'] = array(
'label' => __( 'Inactive Plugins' ),
'show_count' => true,
'fields' => array(),
);
$info['wp-media'] = array(
'label' => __( 'Media Handling' ),
'fields' => array(),
);
$info['wp-server'] = array(
'label' => __( 'Server' ),
'description' => __( 'The options shown below relate to your server setup. If changes are required, you may need your web host’s assistance.' ),
'fields' => array(),
);
$info['wp-database'] = array(
'label' => __( 'Database' ),
'fields' => array(),
);
// Check if WP_DEBUG_LOG is set.
$wp_debug_log_value = __( 'Disabled' );
if ( is_string( WP_DEBUG_LOG ) ) {
$wp_debug_log_value = WP_DEBUG_LOG;
} elseif ( WP_DEBUG_LOG ) {
$wp_debug_log_value = __( 'Enabled' );
}
// Check CONCATENATE_SCRIPTS.
if ( defined( 'CONCATENATE_SCRIPTS' ) ) {
$concatenate_scripts = CONCATENATE_SCRIPTS ? __( 'Enabled' ) : __( 'Disabled' );
$concatenate_scripts_debug = CONCATENATE_SCRIPTS ? 'true' : 'false';
} else {
$concatenate_scripts = __( 'Undefined' );
$concatenate_scripts_debug = 'undefined';
}
// Check COMPRESS_SCRIPTS.
if ( defined( 'COMPRESS_SCRIPTS' ) ) {
$compress_scripts = COMPRESS_SCRIPTS ? __( 'Enabled' ) : __( 'Disabled' );
$compress_scripts_debug = COMPRESS_SCRIPTS ? 'true' : 'false';
} else {
$compress_scripts = __( 'Undefined' );
$compress_scripts_debug = 'undefined';
}
// Check COMPRESS_CSS.
if ( defined( 'COMPRESS_CSS' ) ) {
$compress_css = COMPRESS_CSS ? __( 'Enabled' ) : __( 'Disabled' );
$compress_css_debug = COMPRESS_CSS ? 'true' : 'false';
} else {
$compress_css = __( 'Undefined' );
$compress_css_debug = 'undefined';
}
// Check WP_LOCAL_DEV.
if ( defined( 'WP_LOCAL_DEV' ) ) {
$wp_local_dev = WP_LOCAL_DEV ? __( 'Enabled' ) : __( 'Disabled' );
$wp_local_dev_debug = WP_LOCAL_DEV ? 'true' : 'false';
} else {
$wp_local_dev = __( 'Undefined' );
$wp_local_dev_debug = 'undefined';
}
$info['wp-constants'] = array(
'label' => __( 'WordPress Constants' ),
'description' => __( 'These settings alter where and how parts of WordPress are loaded.' ),
'fields' => array(
'ABSPATH' => array(
'label' => 'ABSPATH',
'value' => ABSPATH,
'private' => true,
),
'WP_HOME' => array(
'label' => 'WP_HOME',
'value' => ( defined( 'WP_HOME' ) ? WP_HOME : __( 'Undefined' ) ),
'debug' => ( defined( 'WP_HOME' ) ? WP_HOME : 'undefined' ),
),
'WP_SITEURL' => array(
'label' => 'WP_SITEURL',
'value' => ( defined( 'WP_SITEURL' ) ? WP_SITEURL : __( 'Undefined' ) ),
'debug' => ( defined( 'WP_SITEURL' ) ? WP_SITEURL : 'undefined' ),
),
'WP_CONTENT_DIR' => array(
'label' => 'WP_CONTENT_DIR',
'value' => WP_CONTENT_DIR,
),
'WP_PLUGIN_DIR' => array(
'label' => 'WP_PLUGIN_DIR',
'value' => WP_PLUGIN_DIR,
),
'WP_MEMORY_LIMIT' => array(
'label' => 'WP_MEMORY_LIMIT',
'value' => WP_MEMORY_LIMIT,
),
'WP_MAX_MEMORY_LIMIT' => array(
'label' => 'WP_MAX_MEMORY_LIMIT',
'value' => WP_MAX_MEMORY_LIMIT,
),
'WP_DEBUG' => array(
'label' => 'WP_DEBUG',
'value' => WP_DEBUG ? __( 'Enabled' ) : __( 'Disabled' ),
'debug' => WP_DEBUG,
),
'WP_DEBUG_DISPLAY' => array(
'label' => 'WP_DEBUG_DISPLAY',
'value' => WP_DEBUG_DISPLAY ? __( 'Enabled' ) : __( 'Disabled' ),
'debug' => WP_DEBUG_DISPLAY,
),
'WP_DEBUG_LOG' => array(
'label' => 'WP_DEBUG_LOG',
'value' => $wp_debug_log_value,
'debug' => WP_DEBUG_LOG,
),
'SCRIPT_DEBUG' => array(
'label' => 'SCRIPT_DEBUG',
'value' => SCRIPT_DEBUG ? __( 'Enabled' ) : __( 'Disabled' ),
'debug' => SCRIPT_DEBUG,
),
'WP_CACHE' => array(
'label' => 'WP_CACHE',
'value' => WP_CACHE ? __( 'Enabled' ) : __( 'Disabled' ),
'debug' => WP_CACHE,
),
'CONCATENATE_SCRIPTS' => array(
'label' => 'CONCATENATE_SCRIPTS',
'value' => $concatenate_scripts,
'debug' => $concatenate_scripts_debug,
),
'COMPRESS_SCRIPTS' => array(
'label' => 'COMPRESS_SCRIPTS',
'value' => $compress_scripts,
'debug' => $compress_scripts_debug,
),
'COMPRESS_CSS' => array(
'label' => 'COMPRESS_CSS',
'value' => $compress_css,
'debug' => $compress_css_debug,
),
'WP_LOCAL_DEV' => array(
'label' => 'WP_LOCAL_DEV',
'value' => $wp_local_dev,
'debug' => $wp_local_dev_debug,
),
'DB_CHARSET' => array(
'label' => 'DB_CHARSET',
'value' => ( defined( 'DB_CHARSET' ) ? DB_CHARSET : __( 'Undefined' ) ),
'debug' => ( defined( 'DB_CHARSET' ) ? DB_CHARSET : 'undefined' ),
),
'DB_COLLATE' => array(
'label' => 'DB_COLLATE',
'value' => ( defined( 'DB_COLLATE' ) ? DB_COLLATE : __( 'Undefined' ) ),
'debug' => ( defined( 'DB_COLLATE' ) ? DB_COLLATE : 'undefined' ),
),
),
);
$is_writable_abspath = wp_is_writable( ABSPATH );
$is_writable_wp_content_dir = wp_is_writable( WP_CONTENT_DIR );
$is_writable_upload_dir = wp_is_writable( $upload_dir['basedir'] );
$is_writable_wp_plugin_dir = wp_is_writable( WP_PLUGIN_DIR );
$is_writable_template_directory = wp_is_writable( get_theme_root( get_template() ) );
$info['wp-filesystem'] = array(
'label' => __( 'Filesystem Permissions' ),
'description' => __( 'Shows whether WordPress is able to write to the directories it needs access to.' ),
'fields' => array(
'wordpress' => array(
'label' => __( 'The main WordPress directory' ),
'value' => ( $is_writable_abspath ? __( 'Writable' ) : __( 'Not writable' ) ),
'debug' => ( $is_writable_abspath ? 'writable' : 'not writable' ),
),
'wp-content' => array(
'label' => __( 'The wp-content directory' ),
'value' => ( $is_writable_wp_content_dir ? __( 'Writable' ) : __( 'Not writable' ) ),
'debug' => ( $is_writable_wp_content_dir ? 'writable' : 'not writable' ),
),
'uploads' => array(
'label' => __( 'The uploads directory' ),
'value' => ( $is_writable_upload_dir ? __( 'Writable' ) : __( 'Not writable' ) ),
'debug' => ( $is_writable_upload_dir ? 'writable' : 'not writable' ),
),
'plugins' => array(
'label' => __( 'The plugins directory' ),
'value' => ( $is_writable_wp_plugin_dir ? __( 'Writable' ) : __( 'Not writable' ) ),
'debug' => ( $is_writable_wp_plugin_dir ? 'writable' : 'not writable' ),
),
'themes' => array(
'label' => __( 'The themes directory' ),
'value' => ( $is_writable_template_directory ? __( 'Writable' ) : __( 'Not writable' ) ),
'debug' => ( $is_writable_template_directory ? 'writable' : 'not writable' ),
),
),
);
// Conditionally add debug information for multisite setups.
if ( is_multisite() ) {
$network_query = new WP_Network_Query();
$network_ids = $network_query->query(
array(
'fields' => 'ids',
'number' => 100,
'no_found_rows' => false,
)
);
$site_count = 0;
foreach ( $network_ids as $network_id ) {
$site_count += get_blog_count( $network_id );
}
$info['wp-core']['fields']['user_count'] = array(
'label' => __( 'User count' ),
'value' => get_user_count(),
);
$info['wp-core']['fields']['site_count'] = array(
'label' => __( 'Site count' ),
'value' => $site_count,
);
$info['wp-core']['fields']['network_count'] = array(
'label' => __( 'Network count' ),
'value' => $network_query->found_networks,
);
} else {
$user_count = count_users();
$info['wp-core']['fields']['user_count'] = array(
'label' => __( 'User count' ),
'value' => $user_count['total_users'],
);
}
// WordPress features requiring processing.
$wp_dotorg = wp_remote_get( 'https://wordpress.org', array( 'timeout' => 10 ) );
if ( ! is_wp_error( $wp_dotorg ) ) {
$info['wp-core']['fields']['dotorg_communication'] = array(
'label' => __( 'Communication with WordPress.org' ),
'value' => __( 'WordPress.org is reachable' ),
'debug' => 'true',
);
} else {
$info['wp-core']['fields']['dotorg_communication'] = array(
'label' => __( 'Communication with WordPress.org' ),
'value' => sprintf(
/* translators: 1: The IP address WordPress.org resolves to. 2: The error returned by the lookup. */
__( 'Unable to reach WordPress.org at %1$s: %2$s' ),
gethostbyname( 'wordpress.org' ),
$wp_dotorg->get_error_message()
),
'debug' => $wp_dotorg->get_error_message(),
);
}
// Remove accordion for Directories and Sizes if in Multisite.
if ( ! $is_multisite ) {
$loading = __( 'Loading…' );
$info['wp-paths-sizes']['fields'] = array(
'wordpress_path' => array(
'label' => __( 'WordPress directory location' ),
'value' => untrailingslashit( ABSPATH ),
),
'wordpress_size' => array(
'label' => __( 'WordPress directory size' ),
'value' => $loading,
'debug' => 'loading...',
),
'uploads_path' => array(
'label' => __( 'Uploads directory location' ),
'value' => $upload_dir['basedir'],
),
'uploads_size' => array(
'label' => __( 'Uploads directory size' ),
'value' => $loading,
'debug' => 'loading...',
),
'themes_path' => array(
'label' => __( 'Themes directory location' ),
'value' => get_theme_root(),
),
'themes_size' => array(
'label' => __( 'Themes directory size' ),
'value' => $loading,
'debug' => 'loading...',
),
'plugins_path' => array(
'label' => __( 'Plugins directory location' ),
'value' => WP_PLUGIN_DIR,
),
'plugins_size' => array(
'label' => __( 'Plugins directory size' ),
'value' => $loading,
'debug' => 'loading...',
),
'database_size' => array(
'label' => __( 'Database size' ),
'value' => $loading,
'debug' => 'loading...',
),
'total_size' => array(
'label' => __( 'Total installation size' ),
'value' => $loading,
'debug' => 'loading...',
),
);
}
// Get a list of all drop-in replacements.
$dropins = get_dropins();
// Get dropins descriptions.
$dropin_descriptions = _get_dropins();
// Spare few function calls.
$not_available = __( 'Not available' );
foreach ( $dropins as $dropin_key => $dropin ) {
$info['wp-dropins']['fields'][ sanitize_text_field( $dropin_key ) ] = array(
'label' => $dropin_key,
'value' => $dropin_descriptions[ $dropin_key ][0],
'debug' => 'true',
);
}
// Populate the media fields.
$info['wp-media']['fields']['image_editor'] = array(
'label' => __( 'Active editor' ),
'value' => _wp_image_editor_choose(),
);
// Get ImageMagic information, if available.
if ( class_exists( 'Imagick' ) ) {
// Save the Imagick instance for later use.
$imagick = new Imagick();
$imagick_version = $imagick->getVersion();
} else {
$imagick_version = __( 'Not available' );
}
$info['wp-media']['fields']['imagick_module_version'] = array(
'label' => __( 'ImageMagick version number' ),
'value' => ( is_array( $imagick_version ) ? $imagick_version['versionNumber'] : $imagick_version ),
);
$info['wp-media']['fields']['imagemagick_version'] = array(
'label' => __( 'ImageMagick version string' ),
'value' => ( is_array( $imagick_version ) ? $imagick_version['versionString'] : $imagick_version ),
);
if ( ! function_exists( 'ini_get' ) ) {
$info['wp-media']['fields']['ini_get'] = array(
'label' => __( 'File upload settings' ),
'value' => sprintf(
/* translators: %s: ini_get() */
__( 'Unable to determine some settings, as the %s function has been disabled.' ),
'ini_get()'
),
'debug' => 'ini_get() is disabled',
);
} else {
// Get the PHP ini directive values.
$post_max_size = ini_get( 'post_max_size' );
$upload_max_filesize = ini_get( 'upload_max_filesize' );
$max_file_uploads = ini_get( 'max_file_uploads' );
$effective = min( wp_convert_hr_to_bytes( $post_max_size ), wp_convert_hr_to_bytes( $upload_max_filesize ) );
// Add info in Media section.
$info['wp-media']['fields']['file_uploads'] = array(
'label' => __( 'File uploads' ),
'value' => empty( ini_get( 'file_uploads' ) ) ? __( 'Disabled' ) : __( 'Enabled' ),
'debug' => 'File uploads is turned off',
);
$info['wp-media']['fields']['post_max_size'] = array(
'label' => __( 'Max size of post data allowed' ),
'value' => $post_max_size,
);
$info['wp-media']['fields']['upload_max_filesize'] = array(
'label' => __( 'Max size of an uploaded file' ),
'value' => $upload_max_filesize,
);
$info['wp-media']['fields']['max_effective_size'] = array(
'label' => __( 'Max effective file size' ),
'value' => size_format( $effective ),
);
$info['wp-media']['fields']['max_file_uploads'] = array(
'label' => __( 'Max number of files allowed' ),
'value' => number_format( $max_file_uploads ),
);
}
// If Imagick is used as our editor, provide some more information about its limitations.
if ( 'WP_Image_Editor_Imagick' === _wp_image_editor_choose() && isset( $imagick ) && $imagick instanceof Imagick ) {
$limits = array(
'area' => ( defined( 'imagick::RESOURCETYPE_AREA' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_AREA ) ) : $not_available ),
'disk' => ( defined( 'imagick::RESOURCETYPE_DISK' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_DISK ) : $not_available ),
'file' => ( defined( 'imagick::RESOURCETYPE_FILE' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_FILE ) : $not_available ),
'map' => ( defined( 'imagick::RESOURCETYPE_MAP' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MAP ) ) : $not_available ),
'memory' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : $not_available ),
'thread' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : $not_available ),
);
$limits_debug = array(
'imagick::RESOURCETYPE_AREA' => ( defined( 'imagick::RESOURCETYPE_AREA' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_AREA ) ) : 'not available' ),
'imagick::RESOURCETYPE_DISK' => ( defined( 'imagick::RESOURCETYPE_DISK' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_DISK ) : 'not available' ),
'imagick::RESOURCETYPE_FILE' => ( defined( 'imagick::RESOURCETYPE_FILE' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_FILE ) : 'not available' ),
'imagick::RESOURCETYPE_MAP' => ( defined( 'imagick::RESOURCETYPE_MAP' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MAP ) ) : 'not available' ),
'imagick::RESOURCETYPE_MEMORY' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : 'not available' ),
'imagick::RESOURCETYPE_THREAD' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : 'not available' ),
);
$info['wp-media']['fields']['imagick_limits'] = array(
'label' => __( 'Imagick Resource Limits' ),
'value' => $limits,
'debug' => $limits_debug,
);
}
// Get GD information, if available.
if ( function_exists( 'gd_info' ) ) {
$gd = gd_info();
} else {
$gd = false;
}
$info['wp-media']['fields']['gd_version'] = array(
'label' => __( 'GD version' ),
'value' => ( is_array( $gd ) ? $gd['GD Version'] : $not_available ),
'debug' => ( is_array( $gd ) ? $gd['GD Version'] : 'not available' ),
);
// Get Ghostscript information, if available.
if ( function_exists( 'exec' ) ) {
$gs = exec( 'gs --version' );
if ( empty( $gs ) ) {
$gs = $not_available;
$gs_debug = 'not available';
} else {
$gs_debug = $gs;
}
} else {
$gs = __( 'Unable to determine if Ghostscript is installed' );
$gs_debug = 'unknown';
}
$info['wp-media']['fields']['ghostscript_version'] = array(
'label' => __( 'Ghostscript version' ),
'value' => $gs,
'debug' => $gs_debug,
);
// Populate the server debug fields.
if ( function_exists( 'php_uname' ) ) {
$server_architecture = sprintf( '%s %s %s', php_uname( 's' ), php_uname( 'r' ), php_uname( 'm' ) );
} else {
$server_architecture = 'unknown';
}
if ( function_exists( 'phpversion' ) ) {
$php_version_debug = phpversion();
// Whether PHP supports 64-bit.
$php64bit = ( PHP_INT_SIZE * 8 === 64 );
$php_version = sprintf(
'%s %s',
$php_version_debug,
( $php64bit ? __( '(Supports 64bit values)' ) : __( '(Does not support 64bit values)' ) )
);
if ( $php64bit ) {
$php_version_debug .= ' 64bit';
}
} else {
$php_version = __( 'Unable to determine PHP version' );
$php_version_debug = 'unknown';
}
if ( function_exists( 'php_sapi_name' ) ) {
$php_sapi = php_sapi_name();
} else {
$php_sapi = 'unknown';
}
$info['wp-server']['fields']['server_architecture'] = array(
'label' => __( 'Server architecture' ),
'value' => ( 'unknown' !== $server_architecture ? $server_architecture : __( 'Unable to determine server architecture' ) ),
'debug' => $server_architecture,
);
$info['wp-server']['fields']['httpd_software'] = array(
'label' => __( 'Web server' ),
'value' => ( isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : __( 'Unable to determine what web server software is used' ) ),
'debug' => ( isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : 'unknown' ),
);
$info['wp-server']['fields']['php_version'] = array(
'label' => __( 'PHP version' ),
'value' => $php_version,
'debug' => $php_version_debug,
);
$info['wp-server']['fields']['php_sapi'] = array(
'label' => __( 'PHP SAPI' ),
'value' => ( 'unknown' !== $php_sapi ? $php_sapi : __( 'Unable to determine PHP SAPI' ) ),
'debug' => $php_sapi,
);
// Some servers disable `ini_set()` and `ini_get()`, we check this before trying to get configuration values.
if ( ! function_exists( 'ini_get' ) ) {
$info['wp-server']['fields']['ini_get'] = array(
'label' => __( 'Server settings' ),
'value' => sprintf(
/* translators: %s: ini_get() */
__( 'Unable to determine some settings, as the %s function has been disabled.' ),
'ini_get()'
),
'debug' => 'ini_get() is disabled',
);
} else {
$info['wp-server']['fields']['max_input_variables'] = array(
'label' => __( 'PHP max input variables' ),
'value' => ini_get( 'max_input_vars' ),
);
$info['wp-server']['fields']['time_limit'] = array(
'label' => __( 'PHP time limit' ),
'value' => ini_get( 'max_execution_time' ),
);
if ( WP_Site_Health::get_instance()->php_memory_limit !== ini_get( 'memory_limit' ) ) {
$info['wp-server']['fields']['memory_limit'] = array(
'label' => __( 'PHP memory limit' ),
'value' => WP_Site_Health::get_instance()->php_memory_limit,
);
$info['wp-server']['fields']['admin_memory_limit'] = array(
'label' => __( 'PHP memory limit (only for admin screens)' ),
'value' => ini_get( 'memory_limit' ),
);
} else {
$info['wp-server']['fields']['memory_limit'] = array(
'label' => __( 'PHP memory limit' ),
'value' => ini_get( 'memory_limit' ),
);
}
$info['wp-server']['fields']['max_input_time'] = array(
'label' => __( 'Max input time' ),
'value' => ini_get( 'max_input_time' ),
);
$info['wp-server']['fields']['upload_max_filesize'] = array(
'label' => __( 'Upload max filesize' ),
'value' => ini_get( 'upload_max_filesize' ),
);
$info['wp-server']['fields']['php_post_max_size'] = array(
'label' => __( 'PHP post max size' ),
'value' => ini_get( 'post_max_size' ),
);
}
if ( function_exists( 'curl_version' ) ) {
$curl = curl_version();
$info['wp-server']['fields']['curl_version'] = array(
'label' => __( 'cURL version' ),
'value' => sprintf( '%s %s', $curl['version'], $curl['ssl_version'] ),
);
} else {
$info['wp-server']['fields']['curl_version'] = array(
'label' => __( 'cURL version' ),
'value' => $not_available,
'debug' => 'not available',
);
}
// SUHOSIN.
$suhosin_loaded = ( extension_loaded( 'suhosin' ) || ( defined( 'SUHOSIN_PATCH' ) && constant( 'SUHOSIN_PATCH' ) ) );
$info['wp-server']['fields']['suhosin'] = array(
'label' => __( 'Is SUHOSIN installed?' ),
'value' => ( $suhosin_loaded ? __( 'Yes' ) : __( 'No' ) ),
'debug' => $suhosin_loaded,
);
// Imagick.
$imagick_loaded = extension_loaded( 'imagick' );
$info['wp-server']['fields']['imagick_availability'] = array(
'label' => __( 'Is the Imagick library available?' ),
'value' => ( $imagick_loaded ? __( 'Yes' ) : __( 'No' ) ),
'debug' => $imagick_loaded,
);
// Pretty permalinks.
$pretty_permalinks_supported = got_url_rewrite();
$info['wp-server']['fields']['pretty_permalinks'] = array(
'label' => __( 'Are pretty permalinks supported?' ),
'value' => ( $pretty_permalinks_supported ? __( 'Yes' ) : __( 'No' ) ),
'debug' => $pretty_permalinks_supported,
);
// Check if a .htaccess file exists.
if ( is_file( ABSPATH . '.htaccess' ) ) {
// If the file exists, grab the content of it.
$htaccess_content = file_get_contents( ABSPATH . '.htaccess' );
// Filter away the core WordPress rules.
$filtered_htaccess_content = trim( preg_replace( '/\# BEGIN WordPress[\s\S]+?# END WordPress/si', '', $htaccess_content ) );
$filtered_htaccess_content = ! empty( $filtered_htaccess_content );
if ( $filtered_htaccess_content ) {
/* translators: %s: .htaccess */
$htaccess_rules_string = sprintf( __( 'Custom rules have been added to your %s file.' ), '.htaccess' );
} else {
/* translators: %s: .htaccess */
$htaccess_rules_string = sprintf( __( 'Your %s file contains only core WordPress features.' ), '.htaccess' );
}
$info['wp-server']['fields']['htaccess_extra_rules'] = array(
'label' => __( '.htaccess rules' ),
'value' => $htaccess_rules_string,
'debug' => $filtered_htaccess_content,
);
}
// Populate the database debug fields.
if ( is_resource( $wpdb->dbh ) ) {
// Old mysql extension.
$extension = 'mysql';
} elseif ( is_object( $wpdb->dbh ) ) {
// mysqli or PDO.
$extension = get_class( $wpdb->dbh );
} else {
// Unknown sql extension.
$extension = null;
}
$server = $wpdb->get_var( 'SELECT VERSION()' );
if ( isset( $wpdb->use_mysqli ) && $wpdb->use_mysqli ) {
$client_version = $wpdb->dbh->client_info;
} else {
// phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_client_info,PHPCompatibility.Extensions.RemovedExtensions.mysql_DeprecatedRemoved
if ( preg_match( '|[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}|', mysql_get_client_info(), $matches ) ) {
$client_version = $matches[0];
} else {
$client_version = null;
}
}
$info['wp-database']['fields']['extension'] = array(
'label' => __( 'Extension' ),
'value' => $extension,
);
$info['wp-database']['fields']['server_version'] = array(
'label' => __( 'Server version' ),
'value' => $server,
);
$info['wp-database']['fields']['client_version'] = array(
'label' => __( 'Client version' ),
'value' => $client_version,
);
$info['wp-database']['fields']['database_user'] = array(
'label' => __( 'Database username' ),
'value' => $wpdb->dbuser,
'private' => true,
);
$info['wp-database']['fields']['database_host'] = array(
'label' => __( 'Database host' ),
'value' => $wpdb->dbhost,
'private' => true,
);
$info['wp-database']['fields']['database_name'] = array(
'label' => __( 'Database name' ),
'value' => $wpdb->dbname,
'private' => true,
);
$info['wp-database']['fields']['database_prefix'] = array(
'label' => __( 'Table prefix' ),
'value' => $wpdb->prefix,
'private' => true,
);
$info['wp-database']['fields']['database_charset'] = array(
'label' => __( 'Database charset' ),
'value' => $wpdb->charset,
'private' => true,
);
$info['wp-database']['fields']['database_collate'] = array(
'label' => __( 'Database collation' ),
'value' => $wpdb->collate,
'private' => true,
);
// List must use plugins if there are any.
$mu_plugins = get_mu_plugins();
foreach ( $mu_plugins as $plugin_path => $plugin ) {
$plugin_version = $plugin['Version'];
$plugin_author = $plugin['Author'];
$plugin_version_string = __( 'No version or author information is available.' );
$plugin_version_string_debug = 'author: (undefined), version: (undefined)';
if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) {
/* translators: 1: Plugin version number. 2: Plugin author name. */
$plugin_version_string = sprintf( __( 'Version %1$s by %2$s' ), $plugin_version, $plugin_author );
$plugin_version_string_debug = sprintf( 'version: %s, author: %s', $plugin_version, $plugin_author );
} else {
if ( ! empty( $plugin_author ) ) {
/* translators: %s: Plugin author name. */
$plugin_version_string = sprintf( __( 'By %s' ), $plugin_author );
$plugin_version_string_debug = sprintf( 'author: %s, version: (undefined)', $plugin_author );
}
if ( ! empty( $plugin_version ) ) {
/* translators: %s: Plugin version number. */
$plugin_version_string = sprintf( __( 'Version %s' ), $plugin_version );
$plugin_version_string_debug = sprintf( 'author: (undefined), version: %s', $plugin_version );
}
}
$info['wp-mu-plugins']['fields'][ sanitize_text_field( $plugin['Name'] ) ] = array(
'label' => $plugin['Name'],
'value' => $plugin_version_string,
'debug' => $plugin_version_string_debug,
);
}
// List all available plugins.
$plugins = get_plugins();
$plugin_updates = get_plugin_updates();
$transient = get_site_transient( 'update_plugins' );
$auto_updates = array();
$auto_updates_enabled = wp_is_auto_update_enabled_for_type( 'plugin' );
if ( $auto_updates_enabled ) {
$auto_updates = (array) get_site_option( 'auto_update_plugins', array() );
}
foreach ( $plugins as $plugin_path => $plugin ) {
$plugin_part = ( is_plugin_active( $plugin_path ) ) ? 'wp-plugins-active' : 'wp-plugins-inactive';
$plugin_version = $plugin['Version'];
$plugin_author = $plugin['Author'];
$plugin_version_string = __( 'No version or author information is available.' );
$plugin_version_string_debug = 'author: (undefined), version: (undefined)';
if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) {
/* translators: 1: Plugin version number. 2: Plugin author name. */
$plugin_version_string = sprintf( __( 'Version %1$s by %2$s' ), $plugin_version, $plugin_author );
$plugin_version_string_debug = sprintf( 'version: %s, author: %s', $plugin_version, $plugin_author );
} else {
if ( ! empty( $plugin_author ) ) {
/* translators: %s: Plugin author name. */
$plugin_version_string = sprintf( __( 'By %s' ), $plugin_author );
$plugin_version_string_debug = sprintf( 'author: %s, version: (undefined)', $plugin_author );
}
if ( ! empty( $plugin_version ) ) {
/* translators: %s: Plugin version number. */
$plugin_version_string = sprintf( __( 'Version %s' ), $plugin_version );
$plugin_version_string_debug = sprintf( 'author: (undefined), version: %s', $plugin_version );
}
}
if ( array_key_exists( $plugin_path, $plugin_updates ) ) {
/* translators: %s: Latest plugin version number. */
$plugin_version_string .= ' ' . sprintf( __( '(Latest version: %s)' ), $plugin_updates[ $plugin_path ]->update->new_version );
$plugin_version_string_debug .= sprintf( ' (latest version: %s)', $plugin_updates[ $plugin_path ]->update->new_version );
}
if ( $auto_updates_enabled ) {
if ( isset( $transient->response[ $plugin_path ] ) ) {
$item = $transient->response[ $plugin_path ];
} elseif ( isset( $transient->no_update[ $plugin_path ] ) ) {
$item = $transient->no_update[ $plugin_path ];
} else {
$item = array(
'id' => $plugin_path,
'slug' => '',
'plugin' => $plugin_path,
'new_version' => '',
'url' => '',
'package' => '',
'icons' => array(),
'banners' => array(),
'banners_rtl' => array(),
'tested' => '',
'requires_php' => '',
'compatibility' => new stdClass(),
);
$item = wp_parse_args( $plugin, $item );
}
$auto_update_forced = wp_is_auto_update_forced_for_item( 'plugin', null, (object) $item );
if ( ! is_null( $auto_update_forced ) ) {
$enabled = $auto_update_forced;
} else {
$enabled = in_array( $plugin_path, $auto_updates, true );
}
if ( $enabled ) {
$auto_updates_string = __( 'Auto-updates enabled' );
} else {
$auto_updates_string = __( 'Auto-updates disabled' );
}
/**
* Filters the text string of the auto-updates setting for each plugin in the Site Health debug data.
*
* @since 5.5.0
*
* @param string $auto_updates_string The string output for the auto-updates column.
* @param string $plugin_path The path to the plugin file.
* @param array $plugin An array of plugin data.
* @param bool $enabled Whether auto-updates are enabled for this item.
*/
$auto_updates_string = apply_filters( 'plugin_auto_update_debug_string', $auto_updates_string, $plugin_path, $plugin, $enabled );
$plugin_version_string .= ' | ' . $auto_updates_string;
$plugin_version_string_debug .= ', ' . $auto_updates_string;
}
$info[ $plugin_part ]['fields'][ sanitize_text_field( $plugin['Name'] ) ] = array(
'label' => $plugin['Name'],
'value' => $plugin_version_string,
'debug' => $plugin_version_string_debug,
);
}
// Populate the section for the currently active theme.
global $_wp_theme_features;
$theme_features = array();
if ( ! empty( $_wp_theme_features ) ) {
foreach ( $_wp_theme_features as $feature => $options ) {
$theme_features[] = $feature;
}
}
$active_theme = wp_get_theme();
$theme_updates = get_theme_updates();
$transient = get_site_transient( 'update_themes' );
$active_theme_version = $active_theme->version;
$active_theme_version_debug = $active_theme_version;
$auto_updates = array();
$auto_updates_enabled = wp_is_auto_update_enabled_for_type( 'theme' );
if ( $auto_updates_enabled ) {
$auto_updates = (array) get_site_option( 'auto_update_themes', array() );
}
if ( array_key_exists( $active_theme->stylesheet, $theme_updates ) ) {
$theme_update_new_version = $theme_updates[ $active_theme->stylesheet ]->update['new_version'];
/* translators: %s: Latest theme version number. */
$active_theme_version .= ' ' . sprintf( __( '(Latest version: %s)' ), $theme_update_new_version );
$active_theme_version_debug .= sprintf( ' (latest version: %s)', $theme_update_new_version );
}
$active_theme_author_uri = $active_theme->display( 'AuthorURI' );
if ( $active_theme->parent_theme ) {
$active_theme_parent_theme = sprintf(
/* translators: 1: Theme name. 2: Theme slug. */
__( '%1$s (%2$s)' ),
$active_theme->parent_theme,
$active_theme->template
);
$active_theme_parent_theme_debug = sprintf(
'%s (%s)',
$active_theme->parent_theme,
$active_theme->template
);
} else {
$active_theme_parent_theme = __( 'None' );
$active_theme_parent_theme_debug = 'none';
}
$info['wp-active-theme']['fields'] = array(
'name' => array(
'label' => __( 'Name' ),
'value' => sprintf(
/* translators: 1: Theme name. 2: Theme slug. */
__( '%1$s (%2$s)' ),
$active_theme->name,
$active_theme->stylesheet
),
),
'version' => array(
'label' => __( 'Version' ),
'value' => $active_theme_version,
'debug' => $active_theme_version_debug,
),
'author' => array(
'label' => __( 'Author' ),
'value' => wp_kses( $active_theme->author, array() ),
),
'author_website' => array(
'label' => __( 'Author website' ),
'value' => ( $active_theme_author_uri ? $active_theme_author_uri : __( 'Undefined' ) ),
'debug' => ( $active_theme_author_uri ? $active_theme_author_uri : '(undefined)' ),
),
'parent_theme' => array(
'label' => __( 'Parent theme' ),
'value' => $active_theme_parent_theme,
'debug' => $active_theme_parent_theme_debug,
),
'theme_features' => array(
'label' => __( 'Theme features' ),
'value' => implode( ', ', $theme_features ),
),
'theme_path' => array(
'label' => __( 'Theme directory location' ),
'value' => get_stylesheet_directory(),
),
);
if ( $auto_updates_enabled ) {
if ( isset( $transient->response[ $active_theme->stylesheet ] ) ) {
$item = $transient->response[ $active_theme->stylesheet ];
} elseif ( isset( $transient->no_update[ $active_theme->stylesheet ] ) ) {
$item = $transient->no_update[ $active_theme->stylesheet ];
} else {
$item = array(
'theme' => $active_theme->stylesheet,
'new_version' => $active_theme->version,
'url' => '',
'package' => '',
'requires' => '',
'requires_php' => '',
);
}
$auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, (object) $item );
if ( ! is_null( $auto_update_forced ) ) {
$enabled = $auto_update_forced;
} else {
$enabled = in_array( $active_theme->stylesheet, $auto_updates, true );
}
if ( $enabled ) {
$auto_updates_string = __( 'Enabled' );
} else {
$auto_updates_string = __( 'Disabled' );
}
/** This filter is documented in wp-admin/includes/class-wp-debug-data.php */
$auto_updates_string = apply_filters( 'theme_auto_update_debug_string', $auto_updates_string, $active_theme, $enabled );
$info['wp-active-theme']['fields']['auto_update'] = array(
'label' => __( 'Auto-updates' ),
'value' => $auto_updates_string,
'debug' => $auto_updates_string,
);
}
$parent_theme = $active_theme->parent();
if ( $parent_theme ) {
$parent_theme_version = $parent_theme->version;
$parent_theme_version_debug = $parent_theme_version;
if ( array_key_exists( $parent_theme->stylesheet, $theme_updates ) ) {
$parent_theme_update_new_version = $theme_updates[ $parent_theme->stylesheet ]->update['new_version'];
/* translators: %s: Latest theme version number. */
$parent_theme_version .= ' ' . sprintf( __( '(Latest version: %s)' ), $parent_theme_update_new_version );
$parent_theme_version_debug .= sprintf( ' (latest version: %s)', $parent_theme_update_new_version );
}
$parent_theme_author_uri = $parent_theme->display( 'AuthorURI' );
$info['wp-parent-theme']['fields'] = array(
'name' => array(
'label' => __( 'Name' ),
'value' => sprintf(
/* translators: 1: Theme name. 2: Theme slug. */
__( '%1$s (%2$s)' ),
$parent_theme->name,
$parent_theme->stylesheet
),
),
'version' => array(
'label' => __( 'Version' ),
'value' => $parent_theme_version,
'debug' => $parent_theme_version_debug,
),
'author' => array(
'label' => __( 'Author' ),
'value' => wp_kses( $parent_theme->author, array() ),
),
'author_website' => array(
'label' => __( 'Author website' ),
'value' => ( $parent_theme_author_uri ? $parent_theme_author_uri : __( 'Undefined' ) ),
'debug' => ( $parent_theme_author_uri ? $parent_theme_author_uri : '(undefined)' ),
),
'theme_path' => array(
'label' => __( 'Theme directory location' ),
'value' => get_template_directory(),
),
);
if ( $auto_updates_enabled ) {
if ( isset( $transient->response[ $parent_theme->stylesheet ] ) ) {
$item = $transient->response[ $parent_theme->stylesheet ];
} elseif ( isset( $transient->no_update[ $parent_theme->stylesheet ] ) ) {
$item = $transient->no_update[ $parent_theme->stylesheet ];
} else {
$item = array(
'theme' => $parent_theme->stylesheet,
'new_version' => $parent_theme->version,
'url' => '',
'package' => '',
'requires' => '',
'requires_php' => '',
);
}
$auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, (object) $item );
if ( ! is_null( $auto_update_forced ) ) {
$enabled = $auto_update_forced;
} else {
$enabled = in_array( $parent_theme->stylesheet, $auto_updates, true );
}
if ( $enabled ) {
$parent_theme_auto_update_string = __( 'Enabled' );
} else {
$parent_theme_auto_update_string = __( 'Disabled' );
}
/** This filter is documented in wp-admin/includes/class-wp-debug-data.php */
$parent_theme_auto_update_string = apply_filters( 'theme_auto_update_debug_string', $auto_updates_string, $parent_theme, $enabled );
$info['wp-parent-theme']['fields']['auto_update'] = array(
'label' => __( 'Auto-update' ),
'value' => $parent_theme_auto_update_string,
'debug' => $parent_theme_auto_update_string,
);
}
}
// Populate a list of all themes available in the install.
$all_themes = wp_get_themes();
foreach ( $all_themes as $theme_slug => $theme ) {
// Exclude the currently active theme from the list of all themes.
if ( $active_theme->stylesheet === $theme_slug ) {
continue;
}
// Exclude the currently active parent theme from the list of all themes.
if ( ! empty( $parent_theme ) && $parent_theme->stylesheet === $theme_slug ) {
continue;
}
$theme_version = $theme->version;
$theme_author = $theme->author;
// Sanitize.
$theme_author = wp_kses( $theme_author, array() );
$theme_version_string = __( 'No version or author information is available.' );
$theme_version_string_debug = 'undefined';
if ( ! empty( $theme_version ) && ! empty( $theme_author ) ) {
/* translators: 1: Theme version number. 2: Theme author name. */
$theme_version_string = sprintf( __( 'Version %1$s by %2$s' ), $theme_version, $theme_author );
$theme_version_string_debug = sprintf( 'version: %s, author: %s', $theme_version, $theme_author );
} else {
if ( ! empty( $theme_author ) ) {
/* translators: %s: Theme author name. */
$theme_version_string = sprintf( __( 'By %s' ), $theme_author );
$theme_version_string_debug = sprintf( 'author: %s, version: (undefined)', $theme_author );
}
if ( ! empty( $theme_version ) ) {
/* translators: %s: Theme version number. */
$theme_version_string = sprintf( __( 'Version %s' ), $theme_version );
$theme_version_string_debug = sprintf( 'author: (undefined), version: %s', $theme_version );
}
}
if ( array_key_exists( $theme_slug, $theme_updates ) ) {
/* translators: %s: Latest theme version number. */
$theme_version_string .= ' ' . sprintf( __( '(Latest version: %s)' ), $theme_updates[ $theme_slug ]->update['new_version'] );
$theme_version_string_debug .= sprintf( ' (latest version: %s)', $theme_updates[ $theme_slug ]->update['new_version'] );
}
if ( $auto_updates_enabled ) {
if ( isset( $transient->response[ $theme_slug ] ) ) {
$item = $transient->response[ $theme_slug ];
} elseif ( isset( $transient->no_update[ $theme_slug ] ) ) {
$item = $transient->no_update[ $theme_slug ];
} else {
$item = array(
'theme' => $theme_slug,
'new_version' => $theme->version,
'url' => '',
'package' => '',
'requires' => '',
'requires_php' => '',
);
}
$auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, (object) $item );
if ( ! is_null( $auto_update_forced ) ) {
$enabled = $auto_update_forced;
} else {
$enabled = in_array( $theme_slug, $auto_updates, true );
}
if ( $enabled ) {
$auto_updates_string = __( 'Auto-updates enabled' );
} else {
$auto_updates_string = __( 'Auto-updates disabled' );
}
/**
* Filters the text string of the auto-updates setting for each theme in the Site Health debug data.
*
* @since 5.5.0
*
* @param string $auto_updates_string The string output for the auto-updates column.
* @param WP_Theme $theme An object of theme data.
* @param bool $enabled Whether auto-updates are enabled for this item.
*/
$auto_updates_string = apply_filters( 'theme_auto_update_debug_string', $auto_updates_string, $theme, $enabled );
$theme_version_string .= ' | ' . $auto_updates_string;
$theme_version_string_debug .= ', ' . $auto_updates_string;
}
$info['wp-themes-inactive']['fields'][ sanitize_text_field( $theme->name ) ] = array(
'label' => sprintf(
/* translators: 1: Theme name. 2: Theme slug. */
__( '%1$s (%2$s)' ),
$theme->name,
$theme_slug
),
'value' => $theme_version_string,
'debug' => $theme_version_string_debug,
);
}
// Add more filesystem checks.
if ( defined( 'WPMU_PLUGIN_DIR' ) && is_dir( WPMU_PLUGIN_DIR ) ) {
$is_writable_wpmu_plugin_dir = wp_is_writable( WPMU_PLUGIN_DIR );
$info['wp-filesystem']['fields']['mu-plugins'] = array(
'label' => __( 'The must use plugins directory' ),
'value' => ( $is_writable_wpmu_plugin_dir ? __( 'Writable' ) : __( 'Not writable' ) ),
'debug' => ( $is_writable_wpmu_plugin_dir ? 'writable' : 'not writable' ),
);
}
/**
* Add or modify the debug information.
*
* Plugin or themes may wish to introduce their own debug information without creating additional admin pages
* they can utilize this filter to introduce their own sections or add more data to existing sections.
*
* Array keys for sections added by core are all prefixed with `wp-`, plugins and themes should use their own slug as
* a prefix, both for consistency as well as avoiding key collisions. Note that the array keys are used as labels
* for the copied data.
*
* All strings are expected to be plain text except $description that can contain inline HTML tags (see below).
*
* @since 5.2.0
*
* @param array $args {
* The debug information to be added to the core information page.
*
* This is an associative multi-dimensional array, up to three levels deep. The topmost array holds the sections.
* Each section has a `$fields` associative array (see below), and each `$value` in `$fields` can be
* another associative array of name/value pairs when there is more structured data to display.
*
* @type string $label The title for this section of the debug output.
* @type string $description Optional. A description for your information section which may contain basic HTML
* markup, inline tags only as it is outputted in a paragraph.
* @type boolean $show_count Optional. If set to `true` the amount of fields will be included in the title for
* this section.
* @type boolean $private Optional. If set to `true` the section and all associated fields will be excluded
* from the copied data.
* @type array $fields {
* An associative array containing the data to be displayed.
*
* @type string $label The label for this piece of information.
* @type string $value The output that is displayed for this field. Text should be translated. Can be
* an associative array that is displayed as name/value pairs.
* @type string $debug Optional. The output that is used for this field when the user copies the data.
* It should be more concise and not translated. If not set, the content of `$value` is used.
* Note that the array keys are used as labels for the copied data.
* @type boolean $private Optional. If set to `true` the field will not be included in the copied data
* allowing you to show, for example, API keys here.
* }
* }
*/
$info = apply_filters( 'debug_information', $info );
return $info;
}
/**
* Format the information gathered for debugging, in a manner suitable for copying to a forum or support ticket.
*
* @since 5.2.0
*
* @param array $info_array Information gathered from the `WP_Debug_Data::debug_data` function.
* @param string $type The data type to return, either 'info' or 'debug'.
* @return string The formatted data.
*/
public static function format( $info_array, $type ) {
$return = "`\n";
foreach ( $info_array as $section => $details ) {
// Skip this section if there are no fields, or the section has been declared as private.
if ( empty( $details['fields'] ) || ( isset( $details['private'] ) && $details['private'] ) ) {
continue;
}
$section_label = 'debug' === $type ? $section : $details['label'];
$return .= sprintf(
"### %s%s ###\n\n",
$section_label,
( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' )
);
foreach ( $details['fields'] as $field_name => $field ) {
if ( isset( $field['private'] ) && true === $field['private'] ) {
continue;
}
if ( 'debug' === $type && isset( $field['debug'] ) ) {
$debug_data = $field['debug'];
} else {
$debug_data = $field['value'];
}
// Can be array, one level deep only.
if ( is_array( $debug_data ) ) {
$value = '';
foreach ( $debug_data as $sub_field_name => $sub_field_value ) {
$value .= sprintf( "\n\t%s: %s", $sub_field_name, $sub_field_value );
}
} elseif ( is_bool( $debug_data ) ) {
$value = $debug_data ? 'true' : 'false';
} elseif ( empty( $debug_data ) && '0' !== $debug_data ) {
$value = 'undefined';
} else {
$value = $debug_data;
}
if ( 'debug' === $type ) {
$label = $field_name;
} else {
$label = $field['label'];
}
$return .= sprintf( "%s: %s\n", $label, $value );
}
$return .= "\n";
}
$return .= '`';
return $return;
}
/**
* Fetch the total size of all the database tables for the active database user.
*
* @since 5.2.0
*
* @return int The size of the database, in bytes.
*/
public static function get_database_size() {
global $wpdb;
$size = 0;
$rows = $wpdb->get_results( 'SHOW TABLE STATUS', ARRAY_A );
if ( $wpdb->num_rows > 0 ) {
foreach ( $rows as $row ) {
$size += $row['Data_length'] + $row['Index_length'];
}
}
return (int) $size;
}
/**
* Fetch the sizes of the WordPress directories: `wordpress` (ABSPATH), `plugins`, `themes`, and `uploads`.
* Intended to supplement the array returned by `WP_Debug_Data::debug_data()`.
*
* @since 5.2.0
*
* @return array The sizes of the directories, also the database size and total installation size.
*/
public static function get_sizes() {
$size_db = self::get_database_size();
$upload_dir = wp_get_upload_dir();
/*
* We will be using the PHP max execution time to prevent the size calculations
* from causing a timeout. The default value is 30 seconds, and some
* hosts do not allow you to read configuration values.
*/
if ( function_exists( 'ini_get' ) ) {
$max_execution_time = ini_get( 'max_execution_time' );
}
// The max_execution_time defaults to 0 when PHP runs from cli.
// We still want to limit it below.
if ( empty( $max_execution_time ) ) {
$max_execution_time = 30;
}
if ( $max_execution_time > 20 ) {
// If the max_execution_time is set to lower than 20 seconds, reduce it a bit to prevent
// edge-case timeouts that may happen after the size loop has finished running.
$max_execution_time -= 2;
}
// Go through the various installation directories and calculate their sizes.
// No trailing slashes.
$paths = array(
'wordpress_size' => untrailingslashit( ABSPATH ),
'themes_size' => get_theme_root(),
'plugins_size' => WP_PLUGIN_DIR,
'uploads_size' => $upload_dir['basedir'],
);
$exclude = $paths;
unset( $exclude['wordpress_size'] );
$exclude = array_values( $exclude );
$size_total = 0;
$all_sizes = array();
// Loop over all the directories we want to gather the sizes for.
foreach ( $paths as $name => $path ) {
$dir_size = null; // Default to timeout.
$results = array(
'path' => $path,
'raw' => 0,
);
if ( microtime( true ) - WP_START_TIMESTAMP < $max_execution_time ) {
if ( 'wordpress_size' === $name ) {
$dir_size = recurse_dirsize( $path, $exclude, $max_execution_time );
} else {
$dir_size = recurse_dirsize( $path, null, $max_execution_time );
}
}
if ( false === $dir_size ) {
// Error reading.
$results['size'] = __( 'The size cannot be calculated. The directory is not accessible. Usually caused by invalid permissions.' );
$results['debug'] = 'not accessible';
// Stop total size calculation.
$size_total = null;
} elseif ( null === $dir_size ) {
// Timeout.
$results['size'] = __( 'The directory size calculation has timed out. Usually caused by a very large number of sub-directories and files.' );
$results['debug'] = 'timeout while calculating size';
// Stop total size calculation.
$size_total = null;
} else {
if ( null !== $size_total ) {
$size_total += $dir_size;
}
$results['raw'] = $dir_size;
$results['size'] = size_format( $dir_size, 2 );
$results['debug'] = $results['size'] . " ({$dir_size} bytes)";
}
$all_sizes[ $name ] = $results;
}
if ( $size_db > 0 ) {
$database_size = size_format( $size_db, 2 );
$all_sizes['database_size'] = array(
'raw' => $size_db,
'size' => $database_size,
'debug' => $database_size . " ({$size_db} bytes)",
);
} else {
$all_sizes['database_size'] = array(
'size' => __( 'Not available' ),
'debug' => 'not available',
);
}
if ( null !== $size_total && $size_db > 0 ) {
$total_size = $size_total + $size_db;
$total_size_mb = size_format( $total_size, 2 );
$all_sizes['total_size'] = array(
'raw' => $total_size,
'size' => $total_size_mb,
'debug' => $total_size_mb . " ({$total_size} bytes)",
);
} else {
$all_sizes['total_size'] = array(
'size' => __( 'Total size is not available. Some errors were encountered when determining the size of your installation.' ),
'debug' => 'not available',
);
}
return $all_sizes;
}
}
PK [r9aZ Z class-wp-filesystem-base.phpnu [ find_folder( ABSPATH );
// Perhaps the FTP folder is rooted at the WordPress install.
// Check for wp-includes folder in root. Could have some false positives, but rare.
if ( ! $folder && $this->is_dir( '/' . WPINC ) ) {
$folder = '/';
}
return $folder;
}
/**
* Returns the path on the remote filesystem of WP_CONTENT_DIR.
*
* @since 2.7.0
*
* @return string The location of the remote path.
*/
public function wp_content_dir() {
return $this->find_folder( WP_CONTENT_DIR );
}
/**
* Returns the path on the remote filesystem of WP_PLUGIN_DIR.
*
* @since 2.7.0
*
* @return string The location of the remote path.
*/
public function wp_plugins_dir() {
return $this->find_folder( WP_PLUGIN_DIR );
}
/**
* Returns the path on the remote filesystem of the Themes Directory.
*
* @since 2.7.0
*
* @param string|false $theme Optional. The theme stylesheet or template for the directory.
* Default false.
* @return string The location of the remote path.
*/
public function wp_themes_dir( $theme = false ) {
$theme_root = get_theme_root( $theme );
// Account for relative theme roots.
if ( '/themes' === $theme_root || ! is_dir( $theme_root ) ) {
$theme_root = WP_CONTENT_DIR . $theme_root;
}
return $this->find_folder( $theme_root );
}
/**
* Returns the path on the remote filesystem of WP_LANG_DIR.
*
* @since 3.2.0
*
* @return string The location of the remote path.
*/
public function wp_lang_dir() {
return $this->find_folder( WP_LANG_DIR );
}
/**
* Locates a folder on the remote filesystem.
*
* @since 2.5.0
* @deprecated 2.7.0 use WP_Filesystem_Base::abspath() or WP_Filesystem_Base::wp_*_dir() instead.
* @see WP_Filesystem_Base::abspath()
* @see WP_Filesystem_Base::wp_content_dir()
* @see WP_Filesystem_Base::wp_plugins_dir()
* @see WP_Filesystem_Base::wp_themes_dir()
* @see WP_Filesystem_Base::wp_lang_dir()
*
* @param string $base The folder to start searching from.
* @param bool $echo True to display debug information.
* Default false.
* @return string The location of the remote path.
*/
public function find_base_dir( $base = '.', $echo = false ) {
_deprecated_function( __FUNCTION__, '2.7.0', 'WP_Filesystem_Base::abspath() or WP_Filesystem_Base::wp_*_dir()' );
$this->verbose = $echo;
return $this->abspath();
}
/**
* Locates a folder on the remote filesystem.
*
* @since 2.5.0
* @deprecated 2.7.0 use WP_Filesystem_Base::abspath() or WP_Filesystem_Base::wp_*_dir() methods instead.
* @see WP_Filesystem_Base::abspath()
* @see WP_Filesystem_Base::wp_content_dir()
* @see WP_Filesystem_Base::wp_plugins_dir()
* @see WP_Filesystem_Base::wp_themes_dir()
* @see WP_Filesystem_Base::wp_lang_dir()
*
* @param string $base The folder to start searching from.
* @param bool $echo True to display debug information.
* @return string The location of the remote path.
*/
public function get_base_dir( $base = '.', $echo = false ) {
_deprecated_function( __FUNCTION__, '2.7.0', 'WP_Filesystem_Base::abspath() or WP_Filesystem_Base::wp_*_dir()' );
$this->verbose = $echo;
return $this->abspath();
}
/**
* Locates a folder on the remote filesystem.
*
* Assumes that on Windows systems, Stripping off the Drive
* letter is OK Sanitizes \\ to / in Windows filepaths.
*
* @since 2.7.0
*
* @param string $folder the folder to locate.
* @return string|false The location of the remote path, false on failure.
*/
public function find_folder( $folder ) {
if ( isset( $this->cache[ $folder ] ) ) {
return $this->cache[ $folder ];
}
if ( stripos( $this->method, 'ftp' ) !== false ) {
$constant_overrides = array(
'FTP_BASE' => ABSPATH,
'FTP_CONTENT_DIR' => WP_CONTENT_DIR,
'FTP_PLUGIN_DIR' => WP_PLUGIN_DIR,
'FTP_LANG_DIR' => WP_LANG_DIR,
);
// Direct matches ( folder = CONSTANT/ ).
foreach ( $constant_overrides as $constant => $dir ) {
if ( ! defined( $constant ) ) {
continue;
}
if ( $folder === $dir ) {
return trailingslashit( constant( $constant ) );
}
}
// Prefix matches ( folder = CONSTANT/subdir ),
foreach ( $constant_overrides as $constant => $dir ) {
if ( ! defined( $constant ) ) {
continue;
}
if ( 0 === stripos( $folder, $dir ) ) { // $folder starts with $dir.
$potential_folder = preg_replace( '#^' . preg_quote( $dir, '#' ) . '/#i', trailingslashit( constant( $constant ) ), $folder );
$potential_folder = trailingslashit( $potential_folder );
if ( $this->is_dir( $potential_folder ) ) {
$this->cache[ $folder ] = $potential_folder;
return $potential_folder;
}
}
}
} elseif ( 'direct' === $this->method ) {
$folder = str_replace( '\\', '/', $folder ); // Windows path sanitisation.
return trailingslashit( $folder );
}
$folder = preg_replace( '|^([a-z]{1}):|i', '', $folder ); // Strip out Windows drive letter if it's there.
$folder = str_replace( '\\', '/', $folder ); // Windows path sanitisation.
if ( isset( $this->cache[ $folder ] ) ) {
return $this->cache[ $folder ];
}
if ( $this->exists( $folder ) ) { // Folder exists at that absolute path.
$folder = trailingslashit( $folder );
$this->cache[ $folder ] = $folder;
return $folder;
}
$return = $this->search_for_folder( $folder );
if ( $return ) {
$this->cache[ $folder ] = $return;
}
return $return;
}
/**
* Locates a folder on the remote filesystem.
*
* Expects Windows sanitized path.
*
* @since 2.7.0
*
* @param string $folder The folder to locate.
* @param string $base The folder to start searching from.
* @param bool $loop If the function has recursed. Internal use only.
* @return string|false The location of the remote path, false to cease looping.
*/
public function search_for_folder( $folder, $base = '.', $loop = false ) {
if ( empty( $base ) || '.' === $base ) {
$base = trailingslashit( $this->cwd() );
}
$folder = untrailingslashit( $folder );
if ( $this->verbose ) {
/* translators: 1: Folder to locate, 2: Folder to start searching from. */
printf( "\n" . __( 'Looking for %1$s in %2$s' ) . "