File manager - Edit - /home/rbwebsco/sidrafran2.rb-webs.com/includes.zip
Back
PK $��\1�9�� � class-custom-image-header.phpnu �[��� <?php /** * The custom header image script. * * @package WordPress * @subpackage Administration */ /** * The custom header image class. * * @since 2.1.0 */ #[AllowDynamicProperties] class Custom_Image_Header { /** * Callback for administration header. * * @since 2.1.0 * @var callable */ public $admin_header_callback; /** * Callback for header div. * * @since 3.0.0 * @var callable */ public $admin_image_div_callback; /** * Holds default headers. * * @since 3.0.0 * @var array */ public $default_headers = array(); /** * Used to trigger a success message when settings updated and set to true. * * @since 3.0.0 * @var bool */ private $updated; /** * Constructor - Registers administration header callback. * * @since 2.1.0 * * @param callable $admin_header_callback Administration header callback. * @param callable $admin_image_div_callback Optional. Custom image div output callback. * Default empty string. */ public function __construct( $admin_header_callback, $admin_image_div_callback = '' ) { $this->admin_header_callback = $admin_header_callback; $this->admin_image_div_callback = $admin_image_div_callback; add_action( 'admin_menu', array( $this, 'init' ) ); add_action( 'customize_save_after', array( $this, 'customize_set_last_used' ) ); add_action( 'wp_ajax_custom-header-crop', array( $this, 'ajax_header_crop' ) ); add_action( 'wp_ajax_custom-header-add', array( $this, 'ajax_header_add' ) ); add_action( 'wp_ajax_custom-header-remove', array( $this, 'ajax_header_remove' ) ); } /** * Sets up the hooks for the Custom Header admin page. * * @since 2.1.0 */ public function init() { $page = add_theme_page( _x( 'Header', 'custom image header' ), _x( 'Header', 'custom image header' ), 'edit_theme_options', 'custom-header', array( $this, 'admin_page' ) ); if ( ! $page ) { return; } add_action( "admin_print_scripts-{$page}", array( $this, 'js_includes' ) ); add_action( "admin_print_styles-{$page}", array( $this, 'css_includes' ) ); add_action( "admin_head-{$page}", array( $this, 'help' ) ); add_action( "admin_head-{$page}", array( $this, 'take_action' ), 50 ); add_action( "admin_head-{$page}", array( $this, 'js' ), 50 ); if ( $this->admin_header_callback ) { add_action( "admin_head-{$page}", $this->admin_header_callback, 51 ); } } /** * Adds contextual help. * * @since 3.0.0 */ public function help() { get_current_screen()->add_help_tab( array( 'id' => 'overview', 'title' => __( 'Overview' ), 'content' => '<p>' . __( 'This screen is used to customize the header section of your theme.' ) . '</p>' . '<p>' . __( '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.' ) . '<p>', ) ); get_current_screen()->add_help_tab( array( 'id' => 'set-header-image', 'title' => __( 'Header Image' ), 'content' => '<p>' . __( '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.' ) . '</p>' . '<p>' . __( 'Some themes come with additional header images bundled. If you see multiple images displayed, select the one you would like and click the “Save Changes” button.' ) . '</p>' . '<p>' . __( '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.' ) . '</p>' . '<p>' . __( 'If you do not 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”.' ) . '</p>', ) ); get_current_screen()->add_help_tab( array( 'id' => 'set-header-text', 'title' => __( 'Header Text' ), 'content' => '<p>' . sprintf( /* translators: %s: URL to General Settings screen. */ __( 'For most themes, the header text is your Site Title and Tagline, as defined in the <a href="%s">General Settings</a> section.' ), admin_url( 'options-general.php' ) ) . '</p>' . '<p>' . __( '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.' ) . '</p>' . '<p>' . __( 'Do not forget to click “Save Changes” when you are done!' ) . '</p>', ) ); get_current_screen()->set_help_sidebar( '<p><strong>' . __( 'For more information:' ) . '</strong></p>' . '<p>' . __( '<a href="https://codex.wordpress.org/Appearance_Header_Screen">Documentation on Custom Header</a>' ) . '</p>' . '<p>' . __( '<a href="https://wordpress.org/support/forums/">Support forums</a>' ) . '</p>' ); } /** * Gets 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; } /** * Sets 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' ); } } /** * Sets 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' ); } } /** * Executes 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; } } /** * Processes the default headers. * * @since 3.0.0 * * @global array $_wp_default_headers Default headers registered for themes. */ 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 ); } } /** * Displays UI for selecting one of several default headers. * * Shows 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 '<div class="random-header">'; echo '<label><input name="default-header" type="radio" value="random-' . $type . '-image"' . checked( is_random_header_image( $type ), true, false ) . ' />'; _e( '<strong>Random:</strong> Show a different image on each page.' ); echo '</label>'; echo '</div>'; } echo '<div class="available-headers">'; foreach ( $headers as $header_key => $header ) { $header_thumbnail = $header['thumbnail_url']; $header_url = $header['url']; $header_alt_text = empty( $header['alt_text'] ) ? '' : $header['alt_text']; echo '<div class="default-header">'; echo '<label><input name="default-header" type="radio" value="' . esc_attr( $header_key ) . '" ' . checked( $header_url, get_theme_mod( 'header_image' ), false ) . ' />'; $width = ''; if ( ! empty( $header['attachment_id'] ) ) { $width = ' width="230"'; } echo '<img src="' . esc_url( set_url_scheme( $header_thumbnail ) ) . '" alt="' . esc_attr( $header_alt_text ) . '"' . $width . ' /></label>'; echo '</div>'; } echo '<div class="clear"></div></div>'; } /** * Executes JavaScript depending on step. * * @since 2.1.0 */ public function js() { $step = $this->step(); if ( ( 1 === $step || 3 === $step ) && current_theme_supports( 'custom-header', 'header-text' ) ) { $this->js_1(); } elseif ( 2 === $step ) { $this->js_2(); } } /** * Displays JavaScript based on Step 1 and 3. * * @since 2.6.0 */ public function js_1() { $default_color = ''; if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) { $default_color = get_theme_support( 'custom-header', 'default-text-color' ); if ( $default_color && ! str_contains( $default_color, '#' ) ) { $default_color = '#' . $default_color; } } ?> <script> (function($){ var default_color = '<?php echo esc_js( $default_color ); ?>', header_text_fields; function pickColor(color) { $('#name').css('color', color); $('#desc').css('color', color); $('#text-color').val(color); } function toggle_text() { var checked = $('#display-header-text').prop('checked'), text_color; header_text_fields.toggle( checked ); if ( ! checked ) return; text_color = $('#text-color'); if ( '' === text_color.val().replace('#', '') ) { text_color.val( default_color ); pickColor( default_color ); } else { pickColor( text_color.val() ); } } $( function() { var text_color = $('#text-color'); header_text_fields = $('.displaying-header-text'); text_color.wpColorPicker({ change: function( event, ui ) { pickColor( text_color.wpColorPicker('color') ); }, clear: function() { pickColor( '' ); } }); $('#display-header-text').click( toggle_text ); <?php if ( ! display_header_text() ) : ?> toggle_text(); <?php endif; ?> } ); })(jQuery); </script> <?php } /** * Displays JavaScript based on Step 2. * * @since 2.6.0 */ public function js_2() { ?> <script> function onEndCrop( coords ) { jQuery( '#x1' ).val(coords.x); jQuery( '#y1' ).val(coords.y); jQuery( '#width' ).val(coords.w); jQuery( '#height' ).val(coords.h); } jQuery( function() { var xinit = <?php echo absint( get_theme_support( 'custom-header', 'width' ) ); ?>; var yinit = <?php echo absint( get_theme_support( 'custom-header', 'height' ) ); ?>; var ratio = xinit / yinit; var ximg = jQuery('img#upload').width(); var yimg = jQuery('img#upload').height(); if ( yimg < yinit || ximg < xinit ) { if ( ximg / yimg > ratio ) { yinit = yimg; xinit = yinit * ratio; } else { xinit = ximg; yinit = xinit / ratio; } } jQuery('img#upload').imgAreaSelect({ handles: true, keys: true, show: true, x1: 0, y1: 0, x2: xinit, y2: yinit, <?php if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) { ?> aspectRatio: xinit + ':' + yinit, <?php } if ( ! current_theme_supports( 'custom-header', 'flex-height' ) ) { ?> maxHeight: <?php echo get_theme_support( 'custom-header', 'height' ); ?>, <?php } if ( ! current_theme_supports( 'custom-header', 'flex-width' ) ) { ?> maxWidth: <?php echo get_theme_support( 'custom-header', 'width' ); ?>, <?php } ?> onInit: function () { jQuery('#width').val(xinit); jQuery('#height').val(yinit); }, onSelectChange: function(img, c) { jQuery('#x1').val(c.x1); jQuery('#y1').val(c.y1); jQuery('#width').val(c.width); jQuery('#height').val(c.height); } }); } ); </script> <?php } /** * Displays first step of custom header image page. * * @since 2.1.0 */ public function step_1() { $this->process_default_headers(); ?> <div class="wrap"> <h1><?php _e( 'Custom Header' ); ?></h1> <?php if ( current_user_can( 'customize' ) ) { $message = sprintf( /* translators: %s: URL to header image configuration in Customizer. */ __( 'You can now manage and live-preview Custom Header in the <a href="%s">Customizer</a>.' ), admin_url( 'customize.php?autofocus[control]=header_image' ) ); wp_admin_notice( $message, array( 'type' => 'info', 'additional_classes' => array( 'hide-if-no-customize' ), ) ); } if ( ! empty( $this->updated ) ) { $updated_message = sprintf( /* translators: %s: Home URL. */ __( 'Header updated. <a href="%s">Visit your site</a> to see how it looks.' ), esc_url( home_url( '/' ) ) ); wp_admin_notice( $updated_message, array( 'id' => 'message', 'additional_classes' => array( 'updated' ), ) ); } ?> <h2><?php _e( 'Header Image' ); ?></h2> <table class="form-table" role="presentation"> <tbody> <?php if ( get_custom_header() || display_header_text() ) : ?> <tr> <th scope="row"><?php echo esc_html_x( 'Preview', 'noun' ); ?></th> <td> <?php if ( $this->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;'; } ?> <div id="headimg" style="<?php echo $header_image_style; ?>"> <?php if ( display_header_text() ) { $style = ' style="color:#' . get_header_textcolor() . ';"'; } else { $style = ' style="display:none;"'; } ?> <h1><a id="name" class="displaying-header-text" <?php echo $style; ?> onclick="return false;" href="<?php bloginfo( 'url' ); ?>" tabindex="-1"><?php bloginfo( 'name' ); ?></a></h1> <div id="desc" class="displaying-header-text" <?php echo $style; ?>><?php bloginfo( 'description' ); ?></div> </div> <?php } ?> </td> </tr> <?php endif; ?> <?php if ( current_user_can( 'upload_files' ) && current_theme_supports( 'custom-header', 'uploads' ) ) : ?> <tr> <th scope="row"><?php _e( 'Select Image' ); ?></th> <td> <p><?php _e( 'You can select an image to be shown at the top of your site by uploading from your computer or choosing from your media library. After selecting an image you will be able to crop it.' ); ?><br /> <?php if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) { printf( /* translators: 1: Image width in pixels, 2: Image height in pixels. */ __( 'Images of exactly <strong>%1$d × %2$d pixels</strong> will be used as-is.' ) . '<br />', get_theme_support( 'custom-header', 'width' ), get_theme_support( 'custom-header', 'height' ) ); } elseif ( current_theme_supports( 'custom-header', 'flex-height' ) ) { if ( ! current_theme_supports( 'custom-header', 'flex-width' ) ) { printf( /* translators: %s: Size in pixels. */ __( 'Images should be at least %s wide.' ) . ' ', sprintf( /* translators: %d: Custom header width. */ '<strong>' . __( '%d pixels' ) . '</strong>', get_theme_support( 'custom-header', 'width' ) ) ); } } elseif ( current_theme_supports( 'custom-header', 'flex-width' ) ) { if ( ! current_theme_supports( 'custom-header', 'flex-height' ) ) { printf( /* translators: %s: Size in pixels. */ __( 'Images should be at least %s tall.' ) . ' ', sprintf( /* translators: %d: Custom header height. */ '<strong>' . __( '%d pixels' ) . '</strong>', get_theme_support( 'custom-header', 'height' ) ) ); } } if ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) { if ( current_theme_supports( 'custom-header', 'width' ) ) { printf( /* translators: %s: Size in pixels. */ __( 'Suggested width is %s.' ) . ' ', sprintf( /* translators: %d: Custom header width. */ '<strong>' . __( '%d pixels' ) . '</strong>', get_theme_support( 'custom-header', 'width' ) ) ); } if ( current_theme_supports( 'custom-header', 'height' ) ) { printf( /* translators: %s: Size in pixels. */ __( 'Suggested height is %s.' ) . ' ', sprintf( /* translators: %d: Custom header height. */ '<strong>' . __( '%d pixels' ) . '</strong>', get_theme_support( 'custom-header', 'height' ) ) ); } } ?> </p> <form enctype="multipart/form-data" id="upload-form" class="wp-upload-form" method="post" action="<?php echo esc_url( add_query_arg( 'step', 2 ) ); ?>"> <p> <label for="upload"><?php _e( 'Choose an image from your computer:' ); ?></label><br /> <input type="file" id="upload" name="import" /> <input type="hidden" name="action" value="save" /> <?php wp_nonce_field( 'custom-header-upload', '_wpnonce-custom-header-upload' ); ?> <?php submit_button( _x( 'Upload', 'verb' ), '', 'submit', false ); ?> </p> <?php $modal_update_href = add_query_arg( array( 'page' => 'custom-header', 'step' => 2, '_wpnonce-custom-header-upload' => wp_create_nonce( 'custom-header-upload' ), ), admin_url( 'themes.php' ) ); ?> <p> <label for="choose-from-library-link"><?php _e( 'Or choose an image from your media library:' ); ?></label><br /> <button id="choose-from-library-link" class="button" data-update-link="<?php echo esc_url( $modal_update_href ); ?>" data-choose="<?php esc_attr_e( 'Choose a Custom Header' ); ?>" data-update="<?php esc_attr_e( 'Set as header' ); ?>"><?php _e( 'Choose Image' ); ?></button> </p> </form> </td> </tr> <?php endif; ?> </tbody> </table> <form method="post" action="<?php echo esc_url( add_query_arg( 'step', 1 ) ); ?>"> <?php submit_button( null, 'screen-reader-text', 'save-header-options', false ); ?> <table class="form-table" role="presentation"> <tbody> <?php if ( get_uploaded_header_images() ) : ?> <tr> <th scope="row"><?php _e( 'Uploaded Images' ); ?></th> <td> <p><?php _e( 'You can choose one of your previously uploaded headers, or show a random one.' ); ?></p> <?php $this->show_header_selector( 'uploaded' ); ?> </td> </tr> <?php endif; if ( ! empty( $this->default_headers ) ) : ?> <tr> <th scope="row"><?php _e( 'Default Images' ); ?></th> <td> <?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?> <p><?php _e( 'If you do not want to upload your own image, you can use one of these cool headers, or show a random one.' ); ?></p> <?php else : ?> <p><?php _e( 'You can use one of these cool headers or show a random one on each page.' ); ?></p> <?php endif; ?> <?php $this->show_header_selector( 'default' ); ?> </td> </tr> <?php endif; if ( get_header_image() ) : ?> <tr> <th scope="row"><?php _e( 'Remove Image' ); ?></th> <td> <p><?php _e( 'This will remove the header image. You will not be able to restore any customizations.' ); ?></p> <?php submit_button( __( 'Remove Header Image' ), '', 'removeheader', false ); ?> </td> </tr> <?php endif; $default_image = sprintf( get_theme_support( 'custom-header', 'default-image' ), get_template_directory_uri(), get_stylesheet_directory_uri() ); if ( $default_image && get_header_image() !== $default_image ) : ?> <tr> <th scope="row"><?php _e( 'Reset Image' ); ?></th> <td> <p><?php _e( 'This will restore the original header image. You will not be able to restore any customizations.' ); ?></p> <?php submit_button( __( 'Restore Original Header Image' ), '', 'resetheader', false ); ?> </td> </tr> <?php endif; ?> </tbody> </table> <?php if ( current_theme_supports( 'custom-header', 'header-text' ) ) : ?> <h2><?php _e( 'Header Text' ); ?></h2> <table class="form-table" role="presentation"> <tbody> <tr> <th scope="row"><?php _e( 'Header Text' ); ?></th> <td> <p> <label><input type="checkbox" name="display-header-text" id="display-header-text"<?php checked( display_header_text() ); ?> /> <?php _e( 'Show header text with your image.' ); ?></label> </p> </td> </tr> <tr class="displaying-header-text"> <th scope="row"><?php _e( 'Text Color' ); ?></th> <td> <p> <?php $default_color = ''; if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) { $default_color = get_theme_support( 'custom-header', 'default-text-color' ); if ( $default_color && ! str_contains( $default_color, '#' ) ) { $default_color = '#' . $default_color; } } $default_color_attr = $default_color ? ' data-default-color="' . esc_attr( $default_color ) . '"' : ''; $header_textcolor = display_header_text() ? get_header_textcolor() : get_theme_support( 'custom-header', 'default-text-color' ); if ( $header_textcolor && ! str_contains( $header_textcolor, '#' ) ) { $header_textcolor = '#' . $header_textcolor; } echo '<input type="text" name="text-color" id="text-color" value="' . esc_attr( $header_textcolor ) . '"' . $default_color_attr . ' />'; if ( $default_color ) { /* translators: %s: Default text color. */ echo ' <span class="description hide-if-js">' . sprintf( _x( 'Default: %s', 'color' ), esc_html( $default_color ) ) . '</span>'; } ?> </p> </td> </tr> </tbody> </table> <?php endif; /** * Fires just before the submit button in the custom header options form. * * @since 3.1.0 */ do_action( 'custom_header_options' ); wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?> <?php submit_button( null, 'primary', 'save-header-options' ); ?> </form> </div> <?php } /** * Displays second step of custom header image page. * * @since 2.1.0 */ public function step_2() { check_admin_referer( 'custom-header-upload', '_wpnonce-custom-header-upload' ); if ( ! current_theme_supports( 'custom-header', 'uploads' ) ) { wp_die( '<h1>' . __( 'An error occurred while processing your header image.' ) . '</h1>' . '<p>' . __( 'The active theme does not support uploading a custom header image. Please ensure your theme supports custom headers and try again.' ) . '</p>', 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'] ) ? (int) $data['height'] : 0; $width = isset( $data['width'] ) ? (int) $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' ) && (int) get_theme_support( 'custom-header', 'width' ) === $width && (int) 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' ) ); /** * Filters the attachment file path after the custom header or background image is set. * * Used for file replication. * * @since 2.1.0 * * @param string $file Path to the file. * @param int $attachment_id Attachment ID. */ $file = apply_filters( '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; } ?> <div class="wrap"> <h1><?php _e( 'Crop Header Image' ); ?></h1> <form method="post" action="<?php echo esc_url( add_query_arg( 'step', 3 ) ); ?>"> <p class="hide-if-no-js"><?php _e( 'Choose the part of the image you want to use as your header.' ); ?></p> <p class="hide-if-js"><strong><?php _e( 'You need JavaScript to choose a part of the image.' ); ?></strong></p> <div id="crop_image" style="position: relative"> <img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo esc_attr( $width ); ?>" height="<?php echo esc_attr( $height ); ?>" alt="" /> </div> <input type="hidden" name="x1" id="x1" value="0" /> <input type="hidden" name="y1" id="y1" value="0" /> <input type="hidden" name="width" id="width" value="<?php echo esc_attr( $width ); ?>" /> <input type="hidden" name="height" id="height" value="<?php echo esc_attr( $height ); ?>" /> <input type="hidden" name="attachment_id" id="attachment_id" value="<?php echo esc_attr( $attachment_id ); ?>" /> <input type="hidden" name="oitar" id="oitar" value="<?php echo esc_attr( $oitar ); ?>" /> <?php if ( empty( $_POST ) && isset( $_GET['file'] ) ) { ?> <input type="hidden" name="create-new-attachment" value="true" /> <?php } ?> <?php wp_nonce_field( 'custom-header-crop-image' ); ?> <p class="submit"> <?php submit_button( __( 'Crop and Publish' ), 'primary', 'submit', false ); ?> <?php if ( 1 === $oitar && ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) ) { submit_button( __( 'Skip Cropping, Publish Image as Is' ), '', 'skip-cropping', false ); } ?> </p> </form> </div> <?php } /** * Uploads the file to be cropped in the second step. * * @since 3.4.0 */ public function step_2_manage_upload() { $overrides = array( 'test_form' => false ); $uploaded_file = $_FILES['import']; $wp_filetype = wp_check_filetype_and_ext( $uploaded_file['tmp_name'], $uploaded_file['name'] ); if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) { wp_die( __( 'The uploaded file is not a valid image. Please try again.' ) ); } $file = wp_handle_upload( $uploaded_file, $overrides ); if ( isset( $file['error'] ) ) { wp_die( $file['error'], __( 'Image Upload Error' ) ); } $url = $file['url']; $type = $file['type']; $file = $file['file']; $filename = wp_basename( $file ); // Construct the attachment array. $attachment = array( 'post_title' => $filename, 'post_content' => $url, 'post_mime_type' => $type, 'guid' => $url, 'context' => 'custom-header', ); // Save the data. $attachment_id = wp_insert_attachment( $attachment, $file ); return compact( 'attachment_id', 'file', 'filename', 'url', 'type' ); } /** * Displays third step of custom header image page. * * @since 2.1.0 * @since 4.4.0 Switched to using wp_get_attachment_url() instead of the guid * for retrieving the header image URL. */ public function step_3() { check_admin_referer( 'custom-header-crop-image' ); if ( ! current_theme_supports( 'custom-header', 'uploads' ) ) { wp_die( '<h1>' . __( 'An error occurred while processing your header image.' ) . '</h1>' . '<p>' . __( 'The active theme does not support uploading a custom header image. Please ensure your theme supports custom headers and try again.' ) . '</p>', 403 ); } if ( ! empty( $_POST['skip-cropping'] ) && ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) { wp_die( '<h1>' . __( 'An error occurred while processing your header image.' ) . '</h1>' . '<p>' . __( 'The active theme does not support a flexible sized header image.' ) . '</p>', 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. $attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, 'custom-header' ); if ( ! empty( $_POST['create-new-attachment'] ) ) { unset( $attachment['ID'] ); } // Update the attachment. $attachment_id = $this->insert_attachment( $attachment, $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(); } /** * Displays last step of custom header image page. * * @since 2.1.0 */ public function finished() { $this->updated = true; $this->step_1(); } /** * Displays 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; } /** * Chooses a header image, selected from existing uploaded and default headers, * or provides 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'] = sanitize_url( $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', sanitize_url( $header_image_data['url'] ) ); set_theme_mod( 'header_image_data', $header_image_data ); } /** * Removes a header image. * * @since 3.4.0 */ final public function remove_header_image() { $this->set_header_image( 'remove-header' ); } /** * Resets 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 ); } /** * Calculates 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; } /** * Creates an attachment 'object'. * * @since 3.9.0 * @deprecated 6.5.0 * * @param string $cropped Cropped image URL. * @param int $parent_attachment_id Attachment ID of parent image. * @return array An array with attachment object data. */ final public function create_attachment_object( $cropped, $parent_attachment_id ) { _deprecated_function( __METHOD__, '6.5.0', 'wp_copy_parent_attachment_properties()' ); $parent = get_post( $parent_attachment_id ); $parent_url = wp_get_attachment_url( $parent->ID ); $url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url ); $size = wp_getimagesize( $cropped ); $image_type = ( $size ) ? $size['mime'] : 'image/jpeg'; $attachment = array( 'ID' => $parent_attachment_id, 'post_title' => wp_basename( $cropped ), 'post_mime_type' => $image_type, 'guid' => $url, 'context' => 'custom-header', 'post_parent' => $parent_attachment_id, ); return $attachment; } /** * Inserts an attachment and its metadata. * * @since 3.9.0 * * @param array $attachment An array with attachment object data. * @param string $cropped File path to cropped image. * @return int Attachment ID. */ final public function insert_attachment( $attachment, $cropped ) { $parent_id = $attachment['post_parent'] ?? null; unset( $attachment['post_parent'] ); $attachment_id = wp_insert_attachment( $attachment, $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. $attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, 'custom-header' ); $previous = $this->get_previous_crop( $attachment ); if ( $previous ) { $attachment['ID'] = $previous; } else { unset( $attachment['ID'] ); } $new_attachment_id = $this->insert_attachment( $attachment, $cropped ); $attachment['attachment_id'] = $new_attachment_id; $attachment['url'] = wp_get_attachment_url( $new_attachment_id ); $attachment['width'] = $dimensions['dst_width']; $attachment['height'] = $dimensions['dst_height']; wp_send_json_success( $attachment ); } /** * 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 active 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 => $header ) { if ( $header['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'] = $header_meta[ $timestamp_key ] ?? ''; $header_image['alt_text'] = $header_meta[ $alt_text_key ] ?? ''; } return $header_images; } /** * Gets the ID of a previous crop from the same base image. * * @since 4.9.0 * * @param array $attachment An array with a cropped attachment object data. * @return int|false An attachment ID if one exists. False if none. */ public function get_previous_crop( $attachment ) { $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'] === $attachment['post_parent'] ) { $previous = $image['attachment_id']; break; } } return $previous; } } PK $��\����W= W= % class-wp-theme-install-list-table.phpnu �[��� <?php /** * List Table API: WP_Theme_Install_List_Table class * * @package WordPress * @subpackage Administration * @since 3.1.0 */ /** * Core class used to implement displaying themes to install in a list table. * * @since 3.1.0 * * @see WP_Themes_List_Table */ class WP_Theme_Install_List_Table extends WP_Themes_List_Table { public $features = array(); /** * @return bool Whether the user can install themes. */ public function ajax_user_can() { return current_user_can( 'install_themes' ); } /** * @global array $tabs * @global string $tab * @global int $paged * @global string $type * @global array $theme_field_defaults */ public function prepare_items() { require ABSPATH . 'wp-admin/includes/theme-install.php'; global $tabs, $tab, $paged, $type, $theme_field_defaults; $tab = ! empty( $_REQUEST['tab'] ) ? sanitize_text_field( $_REQUEST['tab'] ) : ''; $search_terms = array(); $search_string = ''; if ( ! empty( $_REQUEST['s'] ) ) { $search_string = strtolower( wp_unslash( $_REQUEST['s'] ) ); $search_terms = array_unique( array_filter( array_map( 'trim', explode( ',', $search_string ) ) ) ); } if ( ! empty( $_REQUEST['features'] ) ) { $this->features = $_REQUEST['features']; } $paged = $this->get_pagenum(); $per_page = 36; // These are the tabs which are shown on the page, $tabs = array(); $tabs['dashboard'] = __( 'Search' ); if ( 'search' === $tab ) { $tabs['search'] = __( 'Search Results' ); } $tabs['upload'] = _x( 'Upload', 'noun' ); $tabs['featured'] = _x( 'Featured', 'themes' ); //$tabs['popular'] = _x( 'Popular', 'themes' ); $tabs['new'] = _x( 'Latest', 'themes' ); $tabs['updated'] = _x( 'Recently Updated', 'themes' ); $nonmenu_tabs = array( 'theme-information' ); // Valid actions to perform which do not have a Menu item. /** This filter is documented in wp-admin/theme-install.php */ $tabs = apply_filters( 'install_themes_tabs', $tabs ); /** * Filters tabs not associated with a menu item on the Install Themes screen. * * @since 2.8.0 * * @param string[] $nonmenu_tabs The tabs that don't have a menu item on * the Install Themes screen. */ $nonmenu_tabs = apply_filters( 'install_themes_nonmenu_tabs', $nonmenu_tabs ); // If a non-valid menu tab has been selected, And it's not a non-menu action. if ( empty( $tab ) || ( ! isset( $tabs[ $tab ] ) && ! in_array( $tab, (array) $nonmenu_tabs, true ) ) ) { $tab = key( $tabs ); } $args = array( 'page' => $paged, 'per_page' => $per_page, 'fields' => $theme_field_defaults, ); switch ( $tab ) { case 'search': $type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term'; switch ( $type ) { case 'tag': $args['tag'] = array_map( 'sanitize_key', $search_terms ); break; case 'term': $args['search'] = $search_string; break; case 'author': $args['author'] = $search_string; break; } if ( ! empty( $this->features ) ) { $args['tag'] = $this->features; $_REQUEST['s'] = implode( ',', $this->features ); $_REQUEST['type'] = 'tag'; } add_action( 'install_themes_table_header', 'install_theme_search_form', 10, 0 ); break; case 'featured': // case 'popular': case 'new': case 'updated': $args['browse'] = $tab; break; default: $args = false; break; } /** * Filters API request arguments for each Install Themes screen tab. * * The dynamic portion of the hook name, `$tab`, refers to the theme install * tab. * * Possible hook names include: * * - `install_themes_table_api_args_dashboard` * - `install_themes_table_api_args_featured` * - `install_themes_table_api_args_new` * - `install_themes_table_api_args_search` * - `install_themes_table_api_args_updated` * - `install_themes_table_api_args_upload` * * @since 3.7.0 * * @param array|false $args Theme install API arguments. */ $args = apply_filters( "install_themes_table_api_args_{$tab}", $args ); if ( ! $args ) { return; } $api = themes_api( 'query_themes', $args ); if ( is_wp_error( $api ) ) { wp_die( '<p>' . $api->get_error_message() . '</p> <p><a href="#" onclick="document.location.reload(); return false;">' . __( 'Try Again' ) . '</a></p>' ); } $this->items = $api->themes; $this->set_pagination_args( array( 'total_items' => $api->info['results'], 'per_page' => $args['per_page'], 'infinite_scroll' => true, ) ); } /** */ public function no_items() { _e( 'No themes match your request.' ); } /** * @global array $tabs * @global string $tab * @return array<string, string> An array of links for the available views. */ protected function get_views() { global $tabs, $tab; $display_tabs = array(); foreach ( (array) $tabs as $action => $text ) { $display_tabs[ 'theme-install-' . $action ] = array( 'url' => self_admin_url( 'theme-install.php?tab=' . $action ), 'label' => $text, 'current' => $action === $tab, ); } return $this->get_views_links( $display_tabs ); } /** * Displays the theme install table. * * Overrides the parent display() method to provide a different container. * * @since 3.1.0 */ public function display() { wp_nonce_field( 'fetch-list-' . get_class( $this ), '_ajax_fetch_list_nonce' ); ?> <div class="tablenav top themes"> <div class="alignleft actions"> <?php /** * Fires in the Install Themes list table header. * * @since 2.8.0 */ do_action( 'install_themes_table_header' ); ?> </div> <?php $this->pagination( 'top' ); ?> <br class="clear" /> </div> <div id="availablethemes"> <?php $this->display_rows_or_placeholder(); ?> </div> <?php $this->tablenav( 'bottom' ); } /** * Generates the list table rows. * * @since 3.1.0 */ public function display_rows() { $themes = $this->items; foreach ( $themes as $theme ) { ?> <div class="available-theme installable-theme"> <?php $this->single_row( $theme ); ?> </div> <?php } // End foreach $theme_names. $this->theme_installer(); } /** * Prints a theme from the WordPress.org API. * * @since 3.1.0 * * @global array $themes_allowedtags * * @param stdClass $theme { * An object that contains theme data returned by the WordPress.org API. * * @type string $name Theme name, e.g. 'Twenty Twenty-One'. * @type string $slug Theme slug, e.g. 'twentytwentyone'. * @type string $version Theme version, e.g. '1.1'. * @type string $author Theme author username, e.g. 'melchoyce'. * @type string $preview_url Preview URL, e.g. 'https://2021.wordpress.net/'. * @type string $screenshot_url Screenshot URL, e.g. 'https://wordpress.org/themes/twentytwentyone/'. * @type float $rating Rating score. * @type int $num_ratings The number of ratings. * @type string $homepage Theme homepage, e.g. 'https://wordpress.org/themes/twentytwentyone/'. * @type string $description Theme description. * @type string $download_link Theme ZIP download URL. * } */ public function single_row( $theme ) { global $themes_allowedtags; if ( empty( $theme ) ) { return; } $name = wp_kses( $theme->name, $themes_allowedtags ); $author = wp_kses( $theme->author, $themes_allowedtags ); /* translators: %s: Theme name. */ $preview_title = sprintf( __( 'Preview “%s”' ), $name ); $preview_url = add_query_arg( array( 'tab' => 'theme-information', 'theme' => $theme->slug, ), self_admin_url( 'theme-install.php' ) ); $actions = array(); $install_url = add_query_arg( array( 'action' => 'install-theme', 'theme' => $theme->slug, ), self_admin_url( 'update.php' ) ); $update_url = add_query_arg( array( 'action' => 'upgrade-theme', 'theme' => $theme->slug, ), self_admin_url( 'update.php' ) ); $status = $this->_get_theme_status( $theme ); switch ( $status ) { case 'update_available': $actions[] = sprintf( '<a class="install-now" href="%s" aria-label="%s">%s</a>', esc_url( wp_nonce_url( $update_url, 'upgrade-theme_' . $theme->slug ) ), /* translators: %s: Theme version. */ esc_attr( sprintf( __( 'Update to version %s' ), $theme->version ) ), __( 'Update' ) ); break; case 'newer_installed': case 'latest_installed': $actions[] = sprintf( '<span class="install-now">%s</span>', _x( 'Installed', 'theme' ) ); break; case 'install': default: $actions[] = sprintf( '<a class="install-now" href="%s" aria-label="%s">%s</a>', esc_url( wp_nonce_url( $install_url, 'install-theme_' . $theme->slug ) ), /* translators: %s: Theme name. */ esc_attr( sprintf( _x( 'Install %s', 'theme' ), $name ) ), _x( 'Install Now', 'theme' ) ); break; } $actions[] = sprintf( '<a class="install-theme-preview" href="%s" aria-label="%s">%s</a>', esc_url( $preview_url ), esc_attr( $preview_title ), _x( 'Preview', 'verb' ) ); /** * Filters the install action links for a theme in the Install Themes list table. * * @since 3.4.0 * * @param string[] $actions An array of theme action links. Defaults are * links to Install Now, Preview, and Details. * @param stdClass $theme An object that contains theme data returned by the * WordPress.org API. */ $actions = apply_filters( 'theme_install_actions', $actions, $theme ); ?> <a class="screenshot install-theme-preview" href="<?php echo esc_url( $preview_url ); ?>" aria-label="<?php echo esc_attr( $preview_title ); ?>"> <img src="<?php echo esc_url( $theme->screenshot_url . '?ver=' . $theme->version ); ?>" width="150" alt="" /> </a> <h3><?php echo $name; ?></h3> <div class="theme-author"> <?php /* translators: %s: Theme author. */ printf( __( 'By %s' ), $author ); ?> </div> <div class="action-links"> <ul> <?php foreach ( $actions as $action ) : ?> <li><?php echo $action; ?></li> <?php endforeach; ?> <li class="hide-if-no-js"><a href="#" class="theme-detail"><?php _e( 'Details' ); ?></a></li> </ul> </div> <?php $this->install_theme_info( $theme ); } /** * Prints the wrapper for the theme installer. */ public function theme_installer() { ?> <div id="theme-installer" class="wp-full-overlay expanded"> <div class="wp-full-overlay-sidebar"> <div class="wp-full-overlay-header"> <a href="#" class="close-full-overlay button"><?php _e( 'Close' ); ?></a> <span class="theme-install"></span> </div> <div class="wp-full-overlay-sidebar-content"> <div class="install-theme-info"></div> </div> <div class="wp-full-overlay-footer"> <button type="button" class="collapse-sidebar button" aria-expanded="true" aria-label="<?php esc_attr_e( 'Collapse Sidebar' ); ?>"> <span class="collapse-sidebar-arrow"></span> <span class="collapse-sidebar-label"><?php _e( 'Collapse' ); ?></span> </button> </div> </div> <div class="wp-full-overlay-main"></div> </div> <?php } /** * Prints the wrapper for the theme installer with a provided theme's data. * Used to make the theme installer work for no-js. * * @param stdClass $theme A WordPress.org Theme API object. */ public function theme_installer_single( $theme ) { ?> <div id="theme-installer" class="wp-full-overlay single-theme"> <div class="wp-full-overlay-sidebar"> <?php $this->install_theme_info( $theme ); ?> </div> <div class="wp-full-overlay-main"> <iframe src="<?php echo esc_url( $theme->preview_url ); ?>"></iframe> </div> </div> <?php } /** * Prints the info for a theme (to be used in the theme installer modal). * * @global array $themes_allowedtags * * @param stdClass $theme A WordPress.org Theme API object. */ public function install_theme_info( $theme ) { global $themes_allowedtags; if ( empty( $theme ) ) { return; } $name = wp_kses( $theme->name, $themes_allowedtags ); $author = wp_kses( $theme->author, $themes_allowedtags ); $install_url = add_query_arg( array( 'action' => 'install-theme', 'theme' => $theme->slug, ), self_admin_url( 'update.php' ) ); $update_url = add_query_arg( array( 'action' => 'upgrade-theme', 'theme' => $theme->slug, ), self_admin_url( 'update.php' ) ); $status = $this->_get_theme_status( $theme ); ?> <div class="install-theme-info"> <?php switch ( $status ) { case 'update_available': printf( '<a class="theme-install button button-primary" href="%s" aria-label="%s">%s</a>', esc_url( wp_nonce_url( $update_url, 'upgrade-theme_' . $theme->slug ) ), /* translators: %s: Theme version. */ esc_attr( sprintf( __( 'Update to version %s' ), $theme->version ) ), __( 'Update' ) ); break; case 'newer_installed': case 'latest_installed': printf( '<span class="theme-install">%s</span>', _x( 'Installed', 'theme' ) ); break; case 'install': default: printf( '<a class="theme-install button button-primary" href="%s">%s</a>', esc_url( wp_nonce_url( $install_url, 'install-theme_' . $theme->slug ) ), __( 'Install' ) ); break; } ?> <h3 class="theme-name"><?php echo $name; ?></h3> <span class="theme-by"> <?php /* translators: %s: Theme author. */ printf( __( 'By %s' ), $author ); ?> </span> <?php if ( isset( $theme->screenshot_url ) ) : ?> <img class="theme-screenshot" src="<?php echo esc_url( $theme->screenshot_url . '?ver=' . $theme->version ); ?>" alt="" /> <?php endif; ?> <div class="theme-details"> <?php wp_star_rating( array( 'rating' => $theme->rating, 'type' => 'percent', 'number' => $theme->num_ratings, ) ); ?> <div class="theme-version"> <strong><?php _e( 'Version:' ); ?> </strong> <?php echo wp_kses( $theme->version, $themes_allowedtags ); ?> </div> <div class="theme-description"> <?php echo wp_kses( $theme->description, $themes_allowedtags ); ?> </div> </div> <input class="theme-preview-url" type="hidden" value="<?php echo esc_url( $theme->preview_url ); ?>" /> </div> <?php } /** * Send required variables to JavaScript land * * @since 3.4.0 * * @global string $tab Current tab within Themes->Install screen * @global string $type Type of search. * * @param array $extra_args Unused. */ public function _js_vars( $extra_args = array() ) { global $tab, $type; parent::_js_vars( compact( 'tab', 'type' ) ); } /** * Checks to see if the theme is already installed. * * @since 3.4.0 * * @param stdClass $theme A WordPress.org Theme API object. * @return string Theme status. */ private function _get_theme_status( $theme ) { $status = 'install'; $installed_theme = wp_get_theme( $theme->slug ); if ( $installed_theme->exists() ) { if ( version_compare( $installed_theme->get( 'Version' ), $theme->version, '=' ) ) { $status = 'latest_installed'; } elseif ( version_compare( $installed_theme->get( 'Version' ), $theme->version, '>' ) ) { $status = 'newer_installed'; } else { $status = 'update_available'; } } return $status; } } PK $��\&�YI�X �X class-wp-ms-sites-list-table.phpnu �[��� <?php /** * List Table API: WP_MS_Sites_List_Table class * * @package WordPress * @subpackage Administration * @since 3.1.0 */ /** * Core class used to implement displaying sites in a list table for the network admin. * * @since 3.1.0 * * @see WP_List_Table */ class WP_MS_Sites_List_Table extends WP_List_Table { /** * Site status list. * * @since 4.3.0 * @var array */ public $status_list; /** * Constructor. * * @since 3.1.0 * * @see WP_List_Table::__construct() for more information on default arguments. * * @param array $args An associative array of arguments. */ public function __construct( $args = array() ) { $this->status_list = array( 'archived' => array( 'site-archived', __( 'Archived' ) ), 'spam' => array( 'site-spammed', _x( 'Spam', 'site' ) ), 'deleted' => array( 'site-deleted', __( 'Flagged for Deletion' ) ), 'mature' => array( 'site-mature', __( 'Mature' ) ), ); parent::__construct( array( 'plural' => 'sites', 'screen' => $args['screen'] ?? null, ) ); } /** * Checks if the current user has permissions to manage sites. * * @since 3.1.0 * * @return bool Whether the user can manage sites. */ public function ajax_user_can() { return current_user_can( 'manage_sites' ); } /** * Prepares the list of sites for display. * * @since 3.1.0 * * @global string $mode List table view mode. * @global string $s Search string. * @global wpdb $wpdb WordPress database abstraction object. */ public function prepare_items() { global $mode, $s, $wpdb; if ( ! empty( $_REQUEST['mode'] ) ) { $mode = 'excerpt' === $_REQUEST['mode'] ? 'excerpt' : 'list'; set_user_setting( 'sites_list_mode', $mode ); } else { $mode = get_user_setting( 'sites_list_mode', 'list' ); } $per_page = $this->get_items_per_page( 'sites_network_per_page' ); $pagenum = $this->get_pagenum(); $s = isset( $_REQUEST['s'] ) ? wp_unslash( trim( $_REQUEST['s'] ) ) : ''; $wild = ''; if ( str_contains( $s, '*' ) ) { $wild = '*'; $s = trim( $s, '*' ); } /* * If the network is large and a search is not being performed, show only * the latest sites with no paging in order to avoid expensive count queries. */ if ( ! $s && wp_is_large_network() ) { if ( ! isset( $_REQUEST['orderby'] ) ) { $_GET['orderby'] = ''; $_REQUEST['orderby'] = ''; } if ( ! isset( $_REQUEST['order'] ) ) { $_GET['order'] = 'DESC'; $_REQUEST['order'] = 'DESC'; } } $args = array( 'number' => (int) $per_page, 'offset' => (int) ( ( $pagenum - 1 ) * $per_page ), 'network_id' => get_current_network_id(), ); if ( empty( $s ) ) { // Nothing to do. } elseif ( preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $s ) || preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.?$/', $s ) || preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.?$/', $s ) || preg_match( '/^[0-9]{1,3}\.$/', $s ) ) { // IPv4 address. $reg_blog_ids = $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM {$wpdb->registration_log} WHERE {$wpdb->registration_log}.IP LIKE %s", $wpdb->esc_like( $s ) . ( ! empty( $wild ) ? '%' : '' ) ) ); if ( $reg_blog_ids ) { $args['site__in'] = $reg_blog_ids; } } elseif ( is_numeric( $s ) && empty( $wild ) ) { $args['ID'] = $s; } else { $args['search'] = $s; if ( ! is_subdomain_install() ) { $args['search_columns'] = array( 'path' ); } } $order_by = $_REQUEST['orderby'] ?? ''; if ( 'registered' === $order_by ) { // 'registered' is a valid field name. } elseif ( 'lastupdated' === $order_by ) { $order_by = 'last_updated'; } elseif ( 'blogname' === $order_by ) { if ( is_subdomain_install() ) { $order_by = 'domain'; } else { $order_by = 'path'; } } elseif ( 'blog_id' === $order_by ) { $order_by = 'id'; } elseif ( ! $order_by ) { $order_by = false; } $args['orderby'] = $order_by; if ( $order_by ) { $args['order'] = ( isset( $_REQUEST['order'] ) && 'DESC' === strtoupper( $_REQUEST['order'] ) ) ? 'DESC' : 'ASC'; } if ( wp_is_large_network() ) { $args['no_found_rows'] = true; } else { $args['no_found_rows'] = false; } // Take into account the role the user has selected. $status = isset( $_REQUEST['status'] ) ? wp_unslash( trim( $_REQUEST['status'] ) ) : ''; if ( in_array( $status, array( 'public', 'archived', 'mature', 'spam', 'deleted' ), true ) ) { $args[ $status ] = 1; } /** * Filters the arguments for the site query in the sites list table. * * @since 4.6.0 * * @param array $args An array of get_sites() arguments. */ $args = apply_filters( 'ms_sites_list_table_query_args', $args ); $_sites = get_sites( $args ); if ( is_array( $_sites ) ) { update_site_cache( $_sites ); $this->items = array_slice( $_sites, 0, $per_page ); } $total_sites = get_sites( array_merge( $args, array( 'count' => true, 'offset' => 0, 'number' => 0, ) ) ); $this->set_pagination_args( array( 'total_items' => $total_sites, 'per_page' => $per_page, ) ); } /** * Displays a message when no sites are found. * * @since 3.1.0 */ public function no_items() { _e( 'No sites found.' ); } /** * Gets links to filter sites by status. * * @since 5.3.0 * * @return array */ protected function get_views() { $counts = wp_count_sites(); $statuses = array( /* translators: %s: Number of sites. */ 'all' => _nx_noop( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', 'sites' ), /* translators: %s: Number of sites. */ 'public' => _n_noop( 'Public <span class="count">(%s)</span>', 'Public <span class="count">(%s)</span>' ), /* translators: %s: Number of sites. */ 'archived' => _n_noop( 'Archived <span class="count">(%s)</span>', 'Archived <span class="count">(%s)</span>' ), /* translators: %s: Number of sites. */ 'mature' => _n_noop( 'Mature <span class="count">(%s)</span>', 'Mature <span class="count">(%s)</span>' ), /* translators: %s: Number of sites. */ 'spam' => _nx_noop( 'Spam <span class="count">(%s)</span>', 'Spam <span class="count">(%s)</span>', 'sites' ), /* translators: %s: Number of sites. */ 'deleted' => _n_noop( 'Flagged for Deletion <span class="count">(%s)</span>', 'Flagged for Deletion <span class="count">(%s)</span>' ), ); $view_links = array(); $requested_status = isset( $_REQUEST['status'] ) ? wp_unslash( trim( $_REQUEST['status'] ) ) : ''; $url = 'sites.php'; foreach ( $statuses as $status => $label_count ) { if ( (int) $counts[ $status ] > 0 ) { $label = sprintf( translate_nooped_plural( $label_count, $counts[ $status ] ), number_format_i18n( $counts[ $status ] ) ); $full_url = 'all' === $status ? $url : add_query_arg( 'status', $status, $url ); $view_links[ $status ] = array( 'url' => esc_url( $full_url ), 'label' => $label, 'current' => $requested_status === $status || ( '' === $requested_status && 'all' === $status ), ); } } return $this->get_views_links( $view_links ); } /** * Gets an associative array of bulk actions for this table. * * @since 3.1.0 * * @return array<string, string> An associative array of bulk actions. */ protected function get_bulk_actions() { $actions = array(); if ( current_user_can( 'delete_sites' ) ) { $actions['delete'] = __( 'Delete' ); } $actions['spam'] = _x( 'Mark as spam', 'site' ); $actions['notspam'] = _x( 'Not spam', 'site' ); return $actions; } /** * Displays the pagination. * * @since 3.1.0 * * @global string $mode List table view mode. * * @param string $which The location of the pagination nav markup: Either 'top' or 'bottom'. */ protected function pagination( $which ) { global $mode; parent::pagination( $which ); if ( 'top' === $which ) { $this->view_switcher( $mode ); } } /** * Displays extra controls between bulk actions and pagination. * * @since 5.3.0 * * @param string $which The location of the extra table nav markup: Either 'top' or 'bottom'. */ protected function extra_tablenav( $which ) { ?> <div class="alignleft actions"> <?php if ( 'top' === $which ) { ob_start(); /** * Fires before the Filter button on the MS sites list table. * * @since 5.3.0 * * @param string $which The location of the extra table nav markup: Either 'top' or 'bottom'. */ do_action( 'restrict_manage_sites', $which ); $output = ob_get_clean(); if ( ! empty( $output ) ) { echo $output; submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'site-query-submit' ) ); } } ?> </div> <?php /** * Fires immediately following the closing "actions" div in the tablenav for the * MS sites list table. * * @since 5.3.0 * * @param string $which The location of the extra table nav markup: Either 'top' or 'bottom'. */ do_action( 'manage_sites_extra_tablenav', $which ); } /** * Gets an array of column titles keyed by their column name. * * @since 3.1.0 * * @return string[] Array of column titles keyed by their column name. */ public function get_columns() { $sites_columns = array( 'cb' => '<input type="checkbox" />', 'blogname' => __( 'URL' ), 'lastupdated' => __( 'Last Updated' ), 'registered' => _x( 'Registered', 'site' ), 'users' => __( 'Users' ), ); if ( has_filter( 'wpmublogsaction' ) ) { $sites_columns['plugins'] = __( 'Actions' ); } /** * Filters the displayed site columns in Sites list table. * * @since MU (3.0.0) * * @param string[] $sites_columns An array of displayed site columns. Default 'cb', * 'blogname', 'lastupdated', 'registered', 'users'. */ return apply_filters( 'wpmu_blogs_columns', $sites_columns ); } /** * Gets an array of sortable columns. * * @since 3.1.0 * * @return array<string, mixed> An array of sortable columns. */ protected function get_sortable_columns() { if ( is_subdomain_install() ) { $blogname_abbr = __( 'Domain' ); $blogname_orderby_text = __( 'Table ordered by Site Domain Name.' ); } else { $blogname_abbr = __( 'Path' ); $blogname_orderby_text = __( 'Table ordered by Site Path.' ); } return array( 'blogname' => array( 'blogname', false, $blogname_abbr, $blogname_orderby_text ), 'lastupdated' => array( 'lastupdated', true, __( 'Last Updated' ), __( 'Table ordered by Last Updated.' ) ), 'registered' => array( 'blog_id', true, _x( 'Registered', 'site' ), __( 'Table ordered by Site Registered Date.' ), 'desc' ), ); } /** * Handles the checkbox column output. * * @since 4.3.0 * @since 5.9.0 Renamed `$blog` to `$item` to match parent class for PHP 8 named parameter support. * * @param array $item Current site. */ public function column_cb( $item ) { // Restores the more descriptive, specific name for use within this method. $blog = $item; if ( ! is_main_site( $blog['blog_id'] ) ) : $blogname = untrailingslashit( $blog['domain'] . $blog['path'] ); ?> <input type="checkbox" id="blog_<?php echo $blog['blog_id']; ?>" name="allblogs[]" value="<?php echo esc_attr( $blog['blog_id'] ); ?>" /> <label for="blog_<?php echo $blog['blog_id']; ?>"> <span class="screen-reader-text"> <?php /* translators: %s: Site URL. */ printf( __( 'Select %s' ), $blogname ); ?> </span> </label> <?php endif; } /** * Handles the ID column output. * * @since 4.4.0 * * @param array $blog Current site. */ public function column_id( $blog ) { echo $blog['blog_id']; } /** * Handles the site name column output. * * @since 4.3.0 * * @global string $mode List table view mode. * * @param array $blog Current site. */ public function column_blogname( $blog ) { global $mode; $blogname = untrailingslashit( $blog['domain'] . $blog['path'] ); ?> <strong> <?php printf( '<a href="%1$s" class="edit">%2$s</a>', esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ), $blogname ); $this->site_states( $blog ); ?> </strong> <?php if ( 'list' !== $mode ) { switch_to_blog( $blog['blog_id'] ); echo '<p>'; printf( /* translators: 1: Site title, 2: Site tagline. */ __( '%1$s – %2$s' ), get_option( 'blogname' ), '<em>' . get_option( 'blogdescription' ) . '</em>' ); echo '</p>'; restore_current_blog(); } } /** * Handles the lastupdated column output. * * @since 4.3.0 * * @global string $mode List table view mode. * * @param array $blog Current site. */ public function column_lastupdated( $blog ) { global $mode; if ( 'list' === $mode ) { $date = __( 'Y/m/d' ); } else { $date = __( 'Y/m/d g:i:s a' ); } if ( '0000-00-00 00:00:00' === $blog['last_updated'] ) { _e( 'Never' ); } else { echo mysql2date( $date, $blog['last_updated'] ); } } /** * Handles the registered column output. * * @since 4.3.0 * * @global string $mode List table view mode. * * @param array $blog Current site. */ public function column_registered( $blog ) { global $mode; if ( 'list' === $mode ) { $date = __( 'Y/m/d' ); } else { $date = __( 'Y/m/d g:i:s a' ); } if ( '0000-00-00 00:00:00' === $blog['registered'] ) { echo '—'; } else { echo mysql2date( $date, $blog['registered'] ); } } /** * Handles the users column output. * * @since 4.3.0 * * @param array $blog Current site. */ public function column_users( $blog ) { $user_count = wp_cache_get( $blog['blog_id'] . '_user_count', 'blog-details' ); if ( ! $user_count ) { $blog_users = new WP_User_Query( array( 'blog_id' => $blog['blog_id'], 'fields' => 'ID', 'number' => 1, 'count_total' => true, ) ); $user_count = $blog_users->get_total(); wp_cache_set( $blog['blog_id'] . '_user_count', $user_count, 'blog-details', 12 * HOUR_IN_SECONDS ); } printf( '<a href="%1$s">%2$s</a>', esc_url( network_admin_url( 'site-users.php?id=' . $blog['blog_id'] ) ), number_format_i18n( $user_count ) ); } /** * Handles the plugins column output. * * @since 4.3.0 * * @param array $blog Current site. */ public function column_plugins( $blog ) { if ( has_filter( 'wpmublogsaction' ) ) { /** * Fires inside the auxiliary 'Actions' column of the Sites list table. * * By default this column is hidden unless something is hooked to the action. * * @since MU (3.0.0) * * @param int $blog_id The site ID. */ do_action( 'wpmublogsaction', $blog['blog_id'] ); } } /** * Handles output for the default column. * * @since 4.3.0 * @since 5.9.0 Renamed `$blog` to `$item` to match parent class for PHP 8 named parameter support. * * @param array $item Current site. * @param string $column_name Current column name. */ public function column_default( $item, $column_name ) { // Restores the more descriptive, specific name for use within this method. $blog = $item; /** * Fires for each registered custom column in the Sites list table. * * @since 3.1.0 * * @param string $column_name The name of the column to display. * @param int $blog_id The site ID. */ do_action( 'manage_sites_custom_column', $column_name, $blog['blog_id'] ); } /** * Generates the list table rows. * * @since 3.1.0 */ public function display_rows() { foreach ( $this->items as $blog ) { $blog = $blog->to_array(); $class = ''; reset( $this->status_list ); foreach ( $this->status_list as $status => $col ) { if ( '1' === $blog[ $status ] ) { $class = " class='{$col[0]}'"; } } echo "<tr{$class}>"; $this->single_row_columns( $blog ); echo '</tr>'; } } /** * Determines whether to output comma-separated site states. * * @since 5.3.0 * * @param array<string, mixed> $site An array of site data. */ protected function site_states( $site ) { $site_states = array(); // $site is still an array, so get the object. $_site = WP_Site::get_instance( $site['blog_id'] ); if ( is_main_site( $_site->id ) ) { $site_states['main'] = __( 'Main' ); } reset( $this->status_list ); $site_status = isset( $_REQUEST['status'] ) ? wp_unslash( trim( $_REQUEST['status'] ) ) : ''; foreach ( $this->status_list as $status => $col ) { if ( '1' === $_site->{$status} && $site_status !== $status ) { $site_states[ $col[0] ] = $col[1]; } } /** * Filters the default site display states for items in the Sites list table. * * @since 5.3.0 * * @param string[] $site_states An array of site states. Default 'Main', * 'Archived', 'Mature', 'Spam', 'Flagged for Deletion'. * @param WP_Site $site The current site object. */ $site_states = apply_filters( 'display_site_states', $site_states, $_site ); if ( ! empty( $site_states ) ) { $state_count = count( $site_states ); $separator = wp_get_list_item_separator(); $i = 0; echo ' — '; foreach ( $site_states as $state ) { ++$i; $suffix = ( $i < $state_count ) ? $separator : ''; echo "<span class='post-state'>{$state}{$suffix}</span>"; } } } /** * Gets the name of the default primary column. * * @since 4.3.0 * * @return string Name of the default primary column, in this case, 'blogname'. */ protected function get_default_primary_column_name() { return 'blogname'; } /** * Generates and displays row action links. * * @since 4.3.0 * @since 5.9.0 Renamed `$blog` to `$item` to match parent class for PHP 8 named parameter support. * * @param array $item Site being acted upon. * @param string $column_name Current column name. * @param string $primary Primary column name. * @return string Row actions output for sites in Multisite, or an empty string * if the current column is not the primary column. */ protected function handle_row_actions( $item, $column_name, $primary ) { if ( $primary !== $column_name ) { return ''; } // Restores the more descriptive, specific name for use within this method. $blog = $item; $blogname = untrailingslashit( $blog['domain'] . $blog['path'] ); // Preordered. $actions = array( 'edit' => '', 'backend' => '', 'activate' => '', 'deactivate' => '', 'archive' => '', 'unarchive' => '', 'spam' => '', 'unspam' => '', 'delete' => '', 'visit' => '', ); $actions['edit'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ), __( 'Edit' ) ); $actions['backend'] = sprintf( '<a href="%1$s" class="edit">%2$s</a>', esc_url( get_admin_url( $blog['blog_id'] ) ), __( 'Dashboard' ) ); if ( ! is_main_site( $blog['blog_id'] ) ) { if ( '1' === $blog['deleted'] ) { $actions['activate'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&action2=activateblog&id=' . $blog['blog_id'] ), 'activateblog_' . $blog['blog_id'] ) ), _x( 'Remove Deletion Flag', 'site' ) ); } else { $actions['deactivate'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&action2=deactivateblog&id=' . $blog['blog_id'] ), 'deactivateblog_' . $blog['blog_id'] ) ), __( 'Flag for Deletion' ) ); } if ( '1' === $blog['archived'] ) { $actions['unarchive'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&action2=unarchiveblog&id=' . $blog['blog_id'] ), 'unarchiveblog_' . $blog['blog_id'] ) ), __( 'Unarchive' ) ); } else { $actions['archive'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&action2=archiveblog&id=' . $blog['blog_id'] ), 'archiveblog_' . $blog['blog_id'] ) ), _x( 'Archive', 'verb; site' ) ); } if ( '1' === $blog['spam'] ) { $actions['unspam'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&action2=unspamblog&id=' . $blog['blog_id'] ), 'unspamblog_' . $blog['blog_id'] ) ), _x( 'Not Spam', 'site' ) ); } else { $actions['spam'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&action2=spamblog&id=' . $blog['blog_id'] ), 'spamblog_' . $blog['blog_id'] ) ), _x( 'Spam', 'site' ) ); } if ( current_user_can( 'delete_site', $blog['blog_id'] ) ) { $actions['delete'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&action2=deleteblog&id=' . $blog['blog_id'] ), 'deleteblog_' . $blog['blog_id'] ) ), __( 'Delete Permanently' ) ); } } $actions['visit'] = sprintf( '<a href="%1$s" rel="bookmark">%2$s</a>', esc_url( get_home_url( $blog['blog_id'], '/' ) ), __( 'Visit' ) ); /** * Filters the action links displayed for each site in the Sites list table. * * The 'Edit', 'Dashboard', 'Delete Permanently', and 'Visit' links are displayed by * default for each site. The site's status determines whether to show the * 'Remove Deletion Flag' or 'Flag for Deletion' link, 'Unarchive' or 'Archive' links, and * 'Not Spam' or 'Spam' link for each site. * * @since 3.1.0 * * @param string[] $actions An array of action links to be displayed. * @param int $blog_id The site ID. * @param string $blogname Site path, formatted depending on whether it is a sub-domain * or subdirectory multisite installation. */ $actions = apply_filters( 'manage_sites_action_links', array_filter( $actions ), $blog['blog_id'], $blogname ); return $this->row_actions( $actions ); } } PK $��\�͕�8 8 % class-wp-site-health-auto-updates.phpnu �[��� <?php /** * Class for testing automatic updates in the WordPress code. * * @package WordPress * @subpackage Site_Health * @since 5.2.0 */ #[AllowDynamicProperties] class WP_Site_Health_Auto_Updates { /** * WP_Site_Health_Auto_Updates constructor. * * @since 5.2.0 */ public function __construct() { require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; } /** * Runs tests to determine if auto-updates can run. * * @since 5.2.0 * * @return array The test results. */ public function run_tests() { $tests = array( $this->test_constants( 'WP_AUTO_UPDATE_CORE', array( true, 'beta', 'rc', 'development', 'branch-development', 'minor' ) ), $this->test_wp_version_check_attached(), $this->test_filters_automatic_updater_disabled(), $this->test_wp_automatic_updates_disabled(), $this->test_if_failed_update(), $this->test_vcs_abspath(), $this->test_check_wp_filesystem_method(), $this->test_all_files_writable(), $this->test_accepts_dev_updates(), $this->test_accepts_minor_updates(), ); $tests = array_filter( $tests ); $tests = array_map( static function ( $test ) { $test = (object) $test; if ( empty( $test->severity ) ) { $test->severity = 'warning'; } return $test; }, $tests ); return $tests; } /** * Tests if auto-updates related constants are set correctly. * * @since 5.2.0 * @since 5.5.1 The `$value` parameter can accept an array. * * @param string $constant The name of the constant to check. * @param bool|string|array $value The value that the constant should be, if set, * or an array of acceptable values. * @return array|null The test results if there are any constants set incorrectly, * or null if the test passed. */ public function test_constants( $constant, $value ) { $acceptable_values = (array) $value; if ( defined( $constant ) && ! in_array( constant( $constant ), $acceptable_values, true ) ) { return array( 'description' => sprintf( /* translators: 1: Name of the constant used. 2: Value of the constant used. */ __( 'The %1$s constant is defined as %2$s' ), "<code>$constant</code>", '<code>' . esc_html( var_export( constant( $constant ), true ) ) . '</code>' ), 'severity' => 'fail', ); } return null; } /** * Checks if updates are intercepted by a filter. * * @since 5.2.0 * * @return array|null The test results if wp_version_check() is disabled, * or null if the test passed. */ public function test_wp_version_check_attached() { if ( ( ! is_multisite() || is_main_site() && is_network_admin() ) && ! has_filter( 'wp_version_check', 'wp_version_check' ) ) { return array( 'description' => sprintf( /* translators: %s: Name of the filter used. */ __( 'A plugin has prevented updates by disabling %s.' ), '<code>wp_version_check()</code>' ), 'severity' => 'fail', ); } return null; } /** * Checks if automatic updates are disabled by a filter. * * @since 5.2.0 * * @return array|null The test results if the {@see 'automatic_updater_disabled'} filter is set, * or null if the test passed. */ public function test_filters_automatic_updater_disabled() { /** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */ if ( apply_filters( 'automatic_updater_disabled', false ) ) { return array( 'description' => sprintf( /* translators: %s: Name of the filter used. */ __( 'The %s filter is enabled.' ), '<code>automatic_updater_disabled</code>' ), 'severity' => 'fail', ); } return null; } /** * Checks if automatic updates are disabled. * * @since 5.3.0 * * @return array|false The test results if auto-updates are disabled, false otherwise. */ public function test_wp_automatic_updates_disabled() { if ( ! class_exists( 'WP_Automatic_Updater' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-automatic-updater.php'; } $auto_updates = new WP_Automatic_Updater(); if ( ! $auto_updates->is_disabled() ) { return false; } return array( 'description' => __( 'All automatic updates are disabled.' ), 'severity' => 'fail', ); } /** * Checks if automatic updates have tried to run, but failed, previously. * * @since 5.2.0 * * @return array|false The test results if auto-updates previously failed, false otherwise. */ public function test_if_failed_update() { $failed = get_site_option( 'auto_core_update_failed' ); if ( ! $failed ) { return false; } if ( ! empty( $failed['critical'] ) ) { $description = __( 'A previous automatic background update ended with a critical failure, so updates are now disabled.' ); $description .= ' ' . __( 'You would have received an email because of this.' ); $description .= ' ' . __( "When you've been able to update using the \"Update now\" button on Dashboard > Updates, this error will be cleared for future update attempts." ); $description .= ' ' . sprintf( /* translators: %s: Code of error shown. */ __( 'The error code was %s.' ), '<code>' . $failed['error_code'] . '</code>' ); return array( 'description' => $description, 'severity' => 'warning', ); } $description = __( 'A previous automatic background update could not occur.' ); if ( empty( $failed['retry'] ) ) { $description .= ' ' . __( 'You would have received an email because of this.' ); } $description .= ' ' . __( 'Another attempt will be made with the next release.' ); $description .= ' ' . sprintf( /* translators: %s: Code of error shown. */ __( 'The error code was %s.' ), '<code>' . $failed['error_code'] . '</code>' ); return array( 'description' => $description, 'severity' => 'warning', ); } /** * Checks if WordPress is controlled by a VCS (Git, Subversion etc). * * @since 5.2.0 * * @return array The test results. */ public function test_vcs_abspath() { $context_dirs = array( ABSPATH ); $vcs_dirs = array( '.svn', '.git', '.hg', '.bzr' ); $check_dirs = array(); foreach ( $context_dirs as $context_dir ) { // Walk up from $context_dir to the root. do { $check_dirs[] = $context_dir; // Once we've hit '/' or 'C:\', we need to stop. dirname will keep returning the input here. if ( dirname( $context_dir ) === $context_dir ) { break; } // Continue one level at a time. } while ( $context_dir = dirname( $context_dir ) ); } $check_dirs = array_unique( $check_dirs ); $updater = new WP_Automatic_Updater(); $checkout = false; // Search all directories we've found for evidence of version control. foreach ( $vcs_dirs as $vcs_dir ) { foreach ( $check_dirs as $check_dir ) { if ( ! $updater->is_allowed_dir( $check_dir ) ) { continue; } $checkout = is_dir( rtrim( $check_dir, '\\/' ) . "/$vcs_dir" ); if ( $checkout ) { break 2; } } } /** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */ if ( $checkout && ! apply_filters( 'automatic_updates_is_vcs_checkout', true, ABSPATH ) ) { return array( 'description' => sprintf( /* translators: 1: Folder name. 2: Version control directory. 3: Filter name. */ __( 'The folder %1$s was detected as being under version control (%2$s), but the %3$s filter is allowing updates.' ), '<code>' . $check_dir . '</code>', "<code>$vcs_dir</code>", '<code>automatic_updates_is_vcs_checkout</code>' ), 'severity' => 'info', ); } if ( $checkout ) { return array( 'description' => sprintf( /* translators: 1: Folder name. 2: Version control directory. */ __( 'The folder %1$s was detected as being under version control (%2$s).' ), '<code>' . $check_dir . '</code>', "<code>$vcs_dir</code>" ), 'severity' => 'warning', ); } return array( 'description' => __( 'No version control systems were detected.' ), 'severity' => 'pass', ); } /** * Checks if we can access files without providing credentials. * * @since 5.2.0 * * @return array The test results. */ public function test_check_wp_filesystem_method() { // Make sure the `request_filesystem_credentials()` function is available during our REST API call. if ( ! function_exists( 'request_filesystem_credentials' ) ) { require_once ABSPATH . 'wp-admin/includes/file.php'; } $skin = new Automatic_Upgrader_Skin(); $success = $skin->request_filesystem_credentials( false, ABSPATH ); if ( ! $success ) { $description = __( 'Your installation of WordPress prompts for FTP credentials to perform updates.' ); $description .= ' ' . __( '(Your site is performing updates over FTP due to file ownership. Talk to your hosting company.)' ); return array( 'description' => $description, 'severity' => 'fail', ); } return array( 'description' => __( 'Your installation of WordPress does not require FTP credentials to perform updates.' ), 'severity' => 'pass', ); } /** * Checks if core files are writable by the web user/group. * * @since 5.2.0 * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * * @return array|false The test results if at least some of WordPress core files are writeable, * or if a list of the checksums could not be retrieved from WordPress.org. * False if the core files are not writeable. */ public function test_all_files_writable() { global $wp_filesystem; require ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z $skin = new Automatic_Upgrader_Skin(); $success = $skin->request_filesystem_credentials( false, ABSPATH ); if ( ! $success ) { return false; } WP_Filesystem(); if ( 'direct' !== $wp_filesystem->method ) { return false; } // Make sure the `get_core_checksums()` function is available during our REST API call. if ( ! function_exists( 'get_core_checksums' ) ) { require_once ABSPATH . 'wp-admin/includes/update.php'; } $checksums = get_core_checksums( $wp_version, 'en_US' ); $dev = ( str_contains( $wp_version, '-' ) ); // Get the last stable version's files and test against that. if ( ! $checksums && $dev ) { $checksums = get_core_checksums( (float) $wp_version - 0.1, 'en_US' ); } // There aren't always checksums for development releases, so just skip the test if we still can't find any. if ( ! $checksums && $dev ) { return false; } if ( ! $checksums ) { $description = sprintf( /* translators: %s: WordPress version. */ __( "Couldn't retrieve a list of the checksums for WordPress %s." ), $wp_version ); $description .= ' ' . __( 'This could mean that connections are failing to WordPress.org.' ); return array( 'description' => $description, 'severity' => 'warning', ); } $unwritable_files = array(); foreach ( array_keys( $checksums ) as $file ) { if ( str_starts_with( $file, 'wp-content' ) ) { continue; } if ( ! file_exists( ABSPATH . $file ) ) { continue; } if ( ! is_writable( ABSPATH . $file ) ) { $unwritable_files[] = $file; } } if ( $unwritable_files ) { if ( count( $unwritable_files ) > 20 ) { $unwritable_files = array_slice( $unwritable_files, 0, 20 ); $unwritable_files[] = '...'; } return array( 'description' => __( 'Some files are not writable by WordPress:' ) . ' <ul><li>' . implode( '</li><li>', $unwritable_files ) . '</li></ul>', 'severity' => 'fail', ); } else { return array( 'description' => __( 'All of your WordPress files are writable.' ), 'severity' => 'pass', ); } } /** * Checks if the install is using a development branch and can use nightly packages. * * @since 5.2.0 * * @return array|false|null The test results if development updates are blocked. * False if it isn't a development version. Null if the test passed. */ public function test_accepts_dev_updates() { require ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z // Only for dev versions. if ( ! str_contains( $wp_version, '-' ) ) { return false; } if ( defined( 'WP_AUTO_UPDATE_CORE' ) && ( 'minor' === WP_AUTO_UPDATE_CORE || false === WP_AUTO_UPDATE_CORE ) ) { return array( 'description' => sprintf( /* translators: %s: Name of the constant used. */ __( 'WordPress development updates are blocked by the %s constant.' ), '<code>WP_AUTO_UPDATE_CORE</code>' ), 'severity' => 'fail', ); } /** This filter is documented in wp-admin/includes/class-core-upgrader.php */ if ( ! apply_filters( 'allow_dev_auto_core_updates', $wp_version ) ) { return array( 'description' => sprintf( /* translators: %s: Name of the filter used. */ __( 'WordPress development updates are blocked by the %s filter.' ), '<code>allow_dev_auto_core_updates</code>' ), 'severity' => 'fail', ); } return null; } /** * Checks if the site supports automatic minor updates. * * @since 5.2.0 * * @return array|null The test results if minor updates are blocked, * or null if the test passed. */ public function test_accepts_minor_updates() { if ( defined( 'WP_AUTO_UPDATE_CORE' ) && false === WP_AUTO_UPDATE_CORE ) { return array( 'description' => sprintf( /* translators: %s: Name of the constant used. */ __( 'WordPress security and maintenance releases are blocked by %s.' ), "<code>define( 'WP_AUTO_UPDATE_CORE', false );</code>" ), 'severity' => 'fail', ); } /** This filter is documented in wp-admin/includes/class-core-upgrader.php */ if ( ! apply_filters( 'allow_minor_auto_core_updates', true ) ) { return array( 'description' => sprintf( /* translators: %s: Name of the filter used. */ __( 'WordPress security and maintenance releases are blocked by the %s filter.' ), '<code>allow_minor_auto_core_updates</code>' ), 'severity' => 'fail', ); } return null; } } PK $��\s��Wd� d� template.phpnu �[��� <?php /** * Template WordPress Administration API. * * A Big Mess. Also some neat functions that are nicely written. * * @package WordPress * @subpackage Administration */ /** Walker_Category_Checklist class */ require_once ABSPATH . 'wp-admin/includes/class-walker-category-checklist.php'; /** WP_Internal_Pointers class */ require_once ABSPATH . 'wp-admin/includes/class-wp-internal-pointers.php'; // // Category Checklists. // /** * Outputs an unordered list of checkbox input elements labeled with category names. * * @since 2.5.1 * * @see wp_terms_checklist() * * @param int $post_id Optional. Post to generate a categories checklist for. Default 0. * $selected_cats must not be an array. Default 0. * @param int $descendants_and_self Optional. ID of the category to output along with its descendants. * Default 0. * @param int[]|false $selected_cats Optional. Array of category IDs to mark as checked. Default false. * @param int[]|false $popular_cats Optional. Array of category IDs to receive the "popular-category" class. * Default false. * @param Walker $walker Optional. Walker object to use to build the output. * Default is a Walker_Category_Checklist instance. * @param bool $checked_ontop Optional. Whether to move checked items out of the hierarchy and to * the top of the list. Default true. */ function wp_category_checklist( $post_id = 0, $descendants_and_self = 0, $selected_cats = false, $popular_cats = false, $walker = null, $checked_ontop = true ) { wp_terms_checklist( $post_id, array( 'taxonomy' => 'category', 'descendants_and_self' => $descendants_and_self, 'selected_cats' => $selected_cats, 'popular_cats' => $popular_cats, 'walker' => $walker, 'checked_ontop' => $checked_ontop, ) ); } /** * Outputs an unordered list of checkbox input elements labelled with term names. * * Taxonomy-independent version of wp_category_checklist(). * * @since 3.0.0 * @since 4.4.0 Introduced the `$echo` argument. * * @param int $post_id Optional. Post ID. Default 0. * @param array|string $args { * Optional. Array or string of arguments for generating a terms checklist. Default empty array. * * @type int $descendants_and_self ID of the category to output along with its descendants. * Default 0. * @type int[] $selected_cats Array of category IDs to mark as checked. Default false. * @type int[] $popular_cats Array of category IDs to receive the "popular-category" class. * Default false. * @type Walker $walker Walker object to use to build the output. Default empty which * results in a Walker_Category_Checklist instance being used. * @type string $taxonomy Taxonomy to generate the checklist for. Default 'category'. * @type bool $checked_ontop Whether to move checked items out of the hierarchy and to * the top of the list. Default true. * @type bool $echo Whether to echo the generated markup. False to return the markup instead * of echoing it. Default true. * } * @return string HTML list of input elements. */ function wp_terms_checklist( $post_id = 0, $args = array() ) { $defaults = array( 'descendants_and_self' => 0, 'selected_cats' => false, 'popular_cats' => false, 'walker' => null, 'taxonomy' => 'category', 'checked_ontop' => true, 'echo' => true, ); /** * Filters the taxonomy terms checklist arguments. * * @since 3.4.0 * * @see wp_terms_checklist() * * @param array|string $args An array or string of arguments. * @param int $post_id The post ID. */ $params = apply_filters( 'wp_terms_checklist_args', $args, $post_id ); $parsed_args = wp_parse_args( $params, $defaults ); if ( empty( $parsed_args['walker'] ) || ! ( $parsed_args['walker'] instanceof Walker ) ) { $walker = new Walker_Category_Checklist(); } else { $walker = $parsed_args['walker']; } $taxonomy = $parsed_args['taxonomy']; $descendants_and_self = (int) $parsed_args['descendants_and_self']; $args = array( 'taxonomy' => $taxonomy ); $tax = get_taxonomy( $taxonomy ); $args['disabled'] = ! current_user_can( $tax->cap->assign_terms ); $args['list_only'] = ! empty( $parsed_args['list_only'] ); if ( is_array( $parsed_args['selected_cats'] ) ) { $args['selected_cats'] = array_map( 'intval', $parsed_args['selected_cats'] ); } elseif ( $post_id ) { $args['selected_cats'] = wp_get_object_terms( $post_id, $taxonomy, array_merge( $args, array( 'fields' => 'ids' ) ) ); } else { $args['selected_cats'] = array(); } if ( is_array( $parsed_args['popular_cats'] ) ) { $args['popular_cats'] = array_map( 'intval', $parsed_args['popular_cats'] ); } else { $args['popular_cats'] = get_terms( array( 'taxonomy' => $taxonomy, 'fields' => 'ids', 'orderby' => 'count', 'order' => 'DESC', 'number' => 10, 'hierarchical' => false, ) ); } if ( $descendants_and_self ) { $categories = (array) get_terms( array( 'taxonomy' => $taxonomy, 'child_of' => $descendants_and_self, 'hierarchical' => 0, 'hide_empty' => 0, ) ); $self = get_term( $descendants_and_self, $taxonomy ); array_unshift( $categories, $self ); } else { $categories = (array) get_terms( array( 'taxonomy' => $taxonomy, 'get' => 'all', ) ); } $output = ''; if ( $parsed_args['checked_ontop'] ) { /* * Post-process $categories rather than adding an exclude to the get_terms() query * to keep the query the same across all posts (for any query cache). */ $checked_categories = array(); $keys = array_keys( $categories ); foreach ( $keys as $k ) { if ( in_array( $categories[ $k ]->term_id, $args['selected_cats'], true ) ) { $checked_categories[] = $categories[ $k ]; unset( $categories[ $k ] ); } } // Put checked categories on top. $output .= $walker->walk( $checked_categories, 0, $args ); } // Then the rest of them. $output .= $walker->walk( $categories, 0, $args ); if ( $parsed_args['echo'] ) { echo $output; } return $output; } /** * Retrieves a list of the most popular terms from the specified taxonomy. * * If the `$display` argument is true then the elements for a list of checkbox * `<input>` elements labelled with the names of the selected terms is output. * If the `$post_ID` global is not empty then the terms associated with that * post will be marked as checked. * * @since 2.5.0 * * @param string $taxonomy Taxonomy to retrieve terms from. * @param int $default_term Optional. Not used. * @param int $number Optional. Number of terms to retrieve. Default 10. * @param bool $display Optional. Whether to display the list as well. Default true. * @return int[] Array of popular term IDs. */ function wp_popular_terms_checklist( $taxonomy, $default_term = 0, $number = 10, $display = true ) { $post = get_post(); if ( $post && $post->ID ) { $checked_terms = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'ids' ) ); } else { $checked_terms = array(); } $terms = get_terms( array( 'taxonomy' => $taxonomy, 'orderby' => 'count', 'order' => 'DESC', 'number' => $number, 'hierarchical' => false, ) ); $tax = get_taxonomy( $taxonomy ); $popular_ids = array(); foreach ( (array) $terms as $term ) { $popular_ids[] = $term->term_id; if ( ! $display ) { // Hack for Ajax use. continue; } $id = "popular-$taxonomy-$term->term_id"; $checked = in_array( $term->term_id, $checked_terms, true ) ? 'checked="checked"' : ''; ?> <li id="<?php echo $id; ?>" class="popular-category"> <label class="selectit"> <input id="in-<?php echo $id; ?>" type="checkbox" <?php echo $checked; ?> value="<?php echo (int) $term->term_id; ?>" <?php disabled( ! current_user_can( $tax->cap->assign_terms ) ); ?> /> <?php /** This filter is documented in wp-includes/category-template.php */ echo esc_html( apply_filters( 'the_category', $term->name, '', '' ) ); ?> </label> </li> <?php } return $popular_ids; } /** * Outputs a link category checklist element. * * @since 2.5.1 * * @param int $link_id Optional. The link ID. Default 0. */ function wp_link_category_checklist( $link_id = 0 ) { $default = 1; $checked_categories = array(); if ( $link_id ) { $checked_categories = wp_get_link_cats( $link_id ); // No selected categories, strange. if ( ! count( $checked_categories ) ) { $checked_categories[] = $default; } } else { $checked_categories[] = $default; } $categories = get_terms( array( 'taxonomy' => 'link_category', 'orderby' => 'name', 'hide_empty' => 0, ) ); if ( empty( $categories ) ) { return; } foreach ( $categories as $category ) { $cat_id = $category->term_id; /** This filter is documented in wp-includes/category-template.php */ $name = esc_html( apply_filters( 'the_category', $category->name, '', '' ) ); $checked = in_array( $cat_id, $checked_categories, true ) ? ' checked="checked"' : ''; echo '<li id="link-category-', $cat_id, '"><label for="in-link-category-', $cat_id, '" class="selectit"><input value="', $cat_id, '" type="checkbox" name="link_category[]" id="in-link-category-', $cat_id, '"', $checked, '/> ', $name, '</label></li>'; } } /** * Adds hidden fields with the data for use in the inline editor for posts and pages. * * @since 2.7.0 * * @param WP_Post $post Post object. */ function get_inline_data( $post ) { $post_type_object = get_post_type_object( $post->post_type ); if ( ! current_user_can( 'edit_post', $post->ID ) ) { return; } $title = esc_textarea( trim( $post->post_title ) ); echo ' <div class="hidden" id="inline_' . $post->ID . '"> <div class="post_title">' . $title . '</div>' . /** This filter is documented in wp-admin/edit-tag-form.php */ '<div class="post_name">' . apply_filters( 'editable_slug', $post->post_name, $post ) . '</div> <div class="post_author">' . $post->post_author . '</div> <div class="comment_status">' . esc_html( $post->comment_status ) . '</div> <div class="ping_status">' . esc_html( $post->ping_status ) . '</div> <div class="_status">' . esc_html( $post->post_status ) . '</div> <div class="jj">' . mysql2date( 'd', $post->post_date, false ) . '</div> <div class="mm">' . mysql2date( 'm', $post->post_date, false ) . '</div> <div class="aa">' . mysql2date( 'Y', $post->post_date, false ) . '</div> <div class="hh">' . mysql2date( 'H', $post->post_date, false ) . '</div> <div class="mn">' . mysql2date( 'i', $post->post_date, false ) . '</div> <div class="ss">' . mysql2date( 's', $post->post_date, false ) . '</div> <div class="post_password">' . esc_html( $post->post_password ) . '</div>'; if ( $post_type_object->hierarchical ) { echo '<div class="post_parent">' . $post->post_parent . '</div>'; } echo '<div class="page_template">' . ( $post->page_template ? esc_html( $post->page_template ) : 'default' ) . '</div>'; if ( post_type_supports( $post->post_type, 'page-attributes' ) ) { echo '<div class="menu_order">' . $post->menu_order . '</div>'; } $taxonomy_names = get_object_taxonomies( $post->post_type ); foreach ( $taxonomy_names as $taxonomy_name ) { $taxonomy = get_taxonomy( $taxonomy_name ); if ( ! $taxonomy->show_in_quick_edit ) { continue; } if ( $taxonomy->hierarchical ) { $terms = get_object_term_cache( $post->ID, $taxonomy_name ); if ( false === $terms ) { $terms = wp_get_object_terms( $post->ID, $taxonomy_name ); wp_cache_add( $post->ID, wp_list_pluck( $terms, 'term_id' ), $taxonomy_name . '_relationships' ); } $term_ids = empty( $terms ) ? array() : wp_list_pluck( $terms, 'term_id' ); echo '<div class="post_category" id="' . $taxonomy_name . '_' . $post->ID . '">' . implode( ',', $term_ids ) . '</div>'; } else { $terms_to_edit = get_terms_to_edit( $post->ID, $taxonomy_name ); if ( ! is_string( $terms_to_edit ) ) { $terms_to_edit = ''; } echo '<div class="tags_input" id="' . $taxonomy_name . '_' . $post->ID . '">' . esc_html( str_replace( ',', ', ', $terms_to_edit ) ) . '</div>'; } } if ( ! $post_type_object->hierarchical ) { echo '<div class="sticky">' . ( is_sticky( $post->ID ) ? 'sticky' : '' ) . '</div>'; } if ( post_type_supports( $post->post_type, 'post-formats' ) ) { echo '<div class="post_format">' . esc_html( get_post_format( $post->ID ) ) . '</div>'; } /** * Fires after outputting the fields for the inline editor for posts and pages. * * @since 4.9.8 * * @param WP_Post $post The current post object. * @param WP_Post_Type $post_type_object The current post's post type object. */ do_action( 'add_inline_data', $post, $post_type_object ); echo '</div>'; } /** * Outputs the in-line comment reply-to form in the Comments list table. * * @since 2.7.0 * * @global WP_List_Table $wp_list_table * * @param int $position Optional. The value of the 'position' input field. Default 1. * @param bool $checkbox Optional. The value of the 'checkbox' input field. Default false. * @param string $mode Optional. If set to 'single', will use WP_Post_Comments_List_Table, * otherwise WP_Comments_List_Table. Default 'single'. * @param bool $table_row Optional. Whether to use a table instead of a div element. Default true. */ function wp_comment_reply( $position = 1, $checkbox = false, $mode = 'single', $table_row = true ) { global $wp_list_table; /** * Filters the in-line comment reply-to form output in the Comments * list table. * * Returning a non-empty value here will short-circuit display * of the in-line comment-reply form in the Comments list table, * echoing the returned value instead. * * @since 2.7.0 * * @see wp_comment_reply() * * @param string $content The reply-to form content. * @param array $args An array of default args. */ $content = apply_filters( 'wp_comment_reply', '', array( 'position' => $position, 'checkbox' => $checkbox, 'mode' => $mode, ) ); if ( ! empty( $content ) ) { echo $content; return; } if ( ! $wp_list_table ) { if ( 'single' === $mode ) { $wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table' ); } else { $wp_list_table = _get_list_table( 'WP_Comments_List_Table' ); } } ?> <form method="get"> <?php if ( $table_row ) : ?> <table style="display:none;"><tbody id="com-reply"><tr id="replyrow" class="inline-edit-row" style="display:none;"><td colspan="<?php echo $wp_list_table->get_column_count(); ?>" class="colspanchange"> <?php else : ?> <div id="com-reply" style="display:none;"><div id="replyrow" style="display:none;"> <?php endif; ?> <fieldset class="comment-reply"> <legend> <span class="hidden" id="editlegend"><?php _e( 'Edit Comment' ); ?></span> <span class="hidden" id="replyhead"><?php _e( 'Reply to Comment' ); ?></span> <span class="hidden" id="addhead"><?php _e( 'Add Comment' ); ?></span> </legend> <div id="replycontainer"> <label for="replycontent" class="screen-reader-text"> <?php /* translators: Hidden accessibility text. */ _e( 'Comment' ); ?> </label> <?php $quicktags_settings = array( 'buttons' => 'strong,em,link,block,del,ins,img,ul,ol,li,code,close' ); wp_editor( '', 'replycontent', array( 'media_buttons' => false, 'tinymce' => false, 'quicktags' => $quicktags_settings, ) ); ?> </div> <div id="edithead" style="display:none;"> <div class="inside"> <label for="author-name"><?php _e( 'Name' ); ?></label> <input type="text" name="newcomment_author" size="50" value="" id="author-name" /> </div> <div class="inside"> <label for="author-email"><?php _e( 'Email' ); ?></label> <input type="text" name="newcomment_author_email" size="50" class="code" value="" id="author-email" /> </div> <div class="inside"> <label for="author-url"><?php _e( 'URL' ); ?></label> <input type="text" id="author-url" name="newcomment_author_url" class="code" size="103" value="" /> </div> </div> <div id="replysubmit" class="submit"> <p class="reply-submit-buttons"> <button type="button" class="save button button-primary"> <span id="addbtn" style="display: none;"><?php _e( 'Add Comment' ); ?></span> <span id="savebtn" style="display: none;"><?php _e( 'Update Comment' ); ?></span> <span id="replybtn" style="display: none;"><?php _e( 'Submit Reply' ); ?></span> </button> <button type="button" class="cancel button"><?php _e( 'Cancel' ); ?></button> <span class="waiting spinner"></span> </p> <?php wp_admin_notice( '<p class="error"></p>', array( 'type' => 'error', 'additional_classes' => array( 'notice-alt', 'inline', 'hidden' ), 'paragraph_wrap' => false, ) ); ?> </div> <input type="hidden" name="action" id="action" value="" /> <input type="hidden" name="comment_ID" id="comment_ID" value="" /> <input type="hidden" name="comment_post_ID" id="comment_post_ID" value="" /> <input type="hidden" name="status" id="status" value="" /> <input type="hidden" name="position" id="position" value="<?php echo $position; ?>" /> <input type="hidden" name="checkbox" id="checkbox" value="<?php echo $checkbox ? 1 : 0; ?>" /> <input type="hidden" name="mode" id="mode" value="<?php echo esc_attr( $mode ); ?>" /> <?php wp_nonce_field( 'replyto-comment', '_ajax_nonce-replyto-comment', false ); if ( current_user_can( 'unfiltered_html' ) ) { wp_nonce_field( 'unfiltered-html-comment', '_wp_unfiltered_html_comment', false ); } ?> </fieldset> <?php if ( $table_row ) : ?> </td></tr></tbody></table> <?php else : ?> </div></div> <?php endif; ?> </form> <?php } /** * Outputs 'undo move to Trash' text for comments. * * @since 2.9.0 */ function wp_comment_trashnotice() { ?> <div class="hidden" id="trash-undo-holder"> <div class="trash-undo-inside"> <?php /* translators: %s: Comment author, filled by Ajax. */ printf( __( 'Comment by %s moved to the Trash.' ), '<strong></strong>' ); ?> <span class="undo untrash"><a href="#"><?php _e( 'Undo' ); ?></a></span> </div> </div> <div class="hidden" id="spam-undo-holder"> <div class="spam-undo-inside"> <?php /* translators: %s: Comment author, filled by Ajax. */ printf( __( 'Comment by %s marked as spam.' ), '<strong></strong>' ); ?> <span class="undo unspam"><a href="#"><?php _e( 'Undo' ); ?></a></span> </div> </div> <?php } /** * Outputs a post's public meta data in the Custom Fields meta box. * * @since 1.2.0 * * @param array[] $meta An array of meta data arrays keyed on 'meta_key' and 'meta_value'. */ function list_meta( $meta ) { // Exit if no meta. if ( ! $meta ) { echo ' <table id="list-table" style="display: none;"> <thead> <tr> <th class="left">' . _x( 'Name', 'meta name' ) . '</th> <th>' . __( 'Value' ) . '</th> </tr> </thead> <tbody id="the-list" data-wp-lists="list:meta"> <tr><td></td></tr> </tbody> </table>'; // TBODY needed for list-manipulation JS. return; } $count = 0; ?> <table id="list-table"> <thead> <tr> <th class="left"><?php _ex( 'Name', 'meta name' ); ?></th> <th><?php _e( 'Value' ); ?></th> </tr> </thead> <tbody id='the-list' data-wp-lists='list:meta'> <?php foreach ( $meta as $entry ) { echo _list_meta_row( $entry, $count ); } ?> </tbody> </table> <?php } /** * Outputs a single row of public meta data in the Custom Fields meta box. * * @since 2.5.0 * * @param array $entry An array of meta data keyed on 'meta_key' and 'meta_value'. * @param int $count Reference to the row number. * @return string A single row of public meta data. */ function _list_meta_row( $entry, &$count ) { static $update_nonce = ''; if ( is_protected_meta( $entry['meta_key'], 'post' ) ) { return ''; } if ( ! $update_nonce ) { $update_nonce = wp_create_nonce( 'add-meta' ); } $r = ''; ++$count; if ( is_serialized( $entry['meta_value'] ) ) { if ( is_serialized_string( $entry['meta_value'] ) ) { // This is a serialized string, so we should display it. $entry['meta_value'] = maybe_unserialize( $entry['meta_value'] ); } else { // This is a serialized array/object so we should NOT display it. --$count; return ''; } } $entry['meta_key'] = esc_attr( $entry['meta_key'] ); $entry['meta_value'] = esc_textarea( $entry['meta_value'] ); // Using a <textarea />. $entry['meta_id'] = (int) $entry['meta_id']; $delete_nonce = wp_create_nonce( 'delete-meta_' . $entry['meta_id'] ); $r .= "\n\t<tr id='meta-{$entry['meta_id']}'>"; $r .= "\n\t\t<td class='left'><label class='screen-reader-text' for='meta-{$entry['meta_id']}-key'>" . /* translators: Hidden accessibility text. */ __( 'Key' ) . "</label><input name='meta[{$entry['meta_id']}][key]' id='meta-{$entry['meta_id']}-key' type='text' size='20' value='{$entry['meta_key']}' />"; $r .= "\n\t\t<div class='submit'>"; $r .= get_submit_button( __( 'Delete' ), 'deletemeta small', "deletemeta[{$entry['meta_id']}]", false, array( 'data-wp-lists' => "delete:the-list:meta-{$entry['meta_id']}::_ajax_nonce=$delete_nonce" ) ); $r .= "\n\t\t"; $r .= get_submit_button( __( 'Update' ), 'updatemeta small', "meta-{$entry['meta_id']}-submit", false, array( 'data-wp-lists' => "add:the-list:meta-{$entry['meta_id']}::_ajax_nonce-add-meta=$update_nonce" ) ); $r .= '</div>'; $r .= wp_nonce_field( 'change-meta', '_ajax_nonce', false, false ); $r .= '</td>'; $r .= "\n\t\t<td><label class='screen-reader-text' for='meta-{$entry['meta_id']}-value'>" . /* translators: Hidden accessibility text. */ __( 'Value' ) . "</label><textarea name='meta[{$entry['meta_id']}][value]' id='meta-{$entry['meta_id']}-value' rows='2' cols='30'>{$entry['meta_value']}</textarea></td>\n\t</tr>"; return $r; } /** * Prints the form in the Custom Fields meta box. * * @since 1.2.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param WP_Post $post Optional. The post being edited. */ function meta_form( $post = null ) { global $wpdb; $post = get_post( $post ); /** * Filters values for the meta key dropdown in the Custom Fields meta box. * * Returning a non-null value will effectively short-circuit and avoid a * potentially expensive query against postmeta. * * @since 4.4.0 * * @param array|null $keys Pre-defined meta keys to be used in place of a postmeta query. Default null. * @param WP_Post $post The current post object. */ $keys = apply_filters( 'postmeta_form_keys', null, $post ); if ( null === $keys ) { /** * Filters the number of custom fields to retrieve for the drop-down * in the Custom Fields meta box. * * @since 2.1.0 * * @param int $limit Number of custom fields to retrieve. Default 30. */ $limit = apply_filters( 'postmeta_form_limit', 30 ); $keys = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT meta_key FROM $wpdb->postmeta WHERE meta_key NOT BETWEEN '_' AND '_z' HAVING meta_key NOT LIKE %s ORDER BY meta_key LIMIT %d", $wpdb->esc_like( '_' ) . '%', $limit ) ); } if ( $keys ) { natcasesort( $keys ); } ?> <p><strong><?php _e( 'Add Custom Field:' ); ?></strong></p> <table id="newmeta"> <thead> <tr> <th class="left"><label for="metakeyselect"><?php _ex( 'Name', 'meta name' ); ?></label></th> <th><label for="metavalue"><?php _e( 'Value' ); ?></label></th> </tr> </thead> <tbody> <tr> <td id="newmetaleft" class="left"> <?php if ( $keys ) { ?> <select id="metakeyselect" name="metakeyselect"> <option value="#NONE#"><?php _e( '— Select —' ); ?></option> <?php foreach ( $keys as $key ) { if ( is_protected_meta( $key, 'post' ) || ! current_user_can( 'add_post_meta', $post->ID, $key ) ) { continue; } echo "\n<option value='" . esc_attr( $key ) . "'>" . esc_html( $key ) . '</option>'; } ?> </select> <input class="hidden" type="text" id="metakeyinput" name="metakeyinput" value="" aria-label="<?php _e( 'New custom field name' ); ?>" /> <button type="button" id="newmeta-button" class="button button-small hide-if-no-js" onclick="jQuery('#metakeyinput, #metakeyselect, #enternew, #cancelnew').toggleClass('hidden');jQuery('#metakeyinput, #metakeyselect').filter(':visible').trigger('focus');"> <span id="enternew"><?php _e( 'Enter new' ); ?></span> <span id="cancelnew" class="hidden"><?php _e( 'Cancel' ); ?></span></button> <?php } else { ?> <input type="text" id="metakeyinput" name="metakeyinput" value="" /> <?php } ?> </td> <td><textarea id="metavalue" name="metavalue" rows="2" cols="25"></textarea> <?php wp_nonce_field( 'add-meta', '_ajax_nonce-add-meta', false ); ?> </td> </tr> </tbody> </table> <div class="submit add-custom-field"> <?php submit_button( __( 'Add Custom Field' ), '', 'addmeta', false, array( 'id' => 'newmeta-submit', 'data-wp-lists' => 'add:the-list:newmeta', ) ); ?> </div> <?php } /** * Prints out HTML form date elements for editing post or comment publish date. * * @since 0.71 * @since 4.4.0 Converted to use get_comment() instead of the global `$comment`. * * @global WP_Locale $wp_locale WordPress date and time locale object. * * @param int|bool $edit Accepts 1|true for editing the date, 0|false for adding the date. * @param int|bool $for_post Accepts 1|true for applying the date to a post, 0|false for a comment. * @param int $tab_index The tabindex attribute to add. Default 0. * @param int|bool $multi Optional. Whether the additional fields and buttons should be added. * Default 0|false. */ function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) { global $wp_locale; $post = get_post(); if ( $for_post ) { $edit = ! ( in_array( $post->post_status, array( 'draft', 'pending' ), true ) && ( ! $post->post_date_gmt || '0000-00-00 00:00:00' === $post->post_date_gmt ) ); } $tab_index_attribute = ''; if ( (int) $tab_index > 0 ) { $tab_index_attribute = " tabindex=\"$tab_index\""; } $post_date = ( $for_post ) ? $post->post_date : get_comment()->comment_date; $jj = ( $edit ) ? mysql2date( 'd', $post_date, false ) : current_time( 'd' ); $mm = ( $edit ) ? mysql2date( 'm', $post_date, false ) : current_time( 'm' ); $aa = ( $edit ) ? mysql2date( 'Y', $post_date, false ) : current_time( 'Y' ); $hh = ( $edit ) ? mysql2date( 'H', $post_date, false ) : current_time( 'H' ); $mn = ( $edit ) ? mysql2date( 'i', $post_date, false ) : current_time( 'i' ); $ss = ( $edit ) ? mysql2date( 's', $post_date, false ) : current_time( 's' ); $cur_jj = current_time( 'd' ); $cur_mm = current_time( 'm' ); $cur_aa = current_time( 'Y' ); $cur_hh = current_time( 'H' ); $cur_mn = current_time( 'i' ); $month = '<label><span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Month' ) . '</span><select class="form-required" ' . ( $multi ? '' : 'id="mm" ' ) . 'name="mm"' . $tab_index_attribute . ">\n"; for ( $i = 1; $i < 13; $i = $i + 1 ) { $monthnum = zeroise( $i, 2 ); $monthtext = $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) ); $month .= "\t\t\t" . '<option value="' . $monthnum . '" data-text="' . $monthtext . '" ' . selected( $monthnum, $mm, false ) . '>'; /* translators: 1: Month number (01, 02, etc.), 2: Month abbreviation. */ $month .= sprintf( __( '%1$s-%2$s' ), $monthnum, $monthtext ) . "</option>\n"; } $month .= '</select></label>'; $day = '<label><span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Day' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="jj" ' ) . 'name="jj" value="' . $jj . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" class="form-required" inputmode="numeric" /></label>'; $year = '<label><span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Year' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="aa" ' ) . 'name="aa" value="' . $aa . '" size="4" maxlength="4"' . $tab_index_attribute . ' autocomplete="off" class="form-required" inputmode="numeric" /></label>'; $hour = '<label><span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Hour' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="hh" ' ) . 'name="hh" value="' . $hh . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" class="form-required" inputmode="numeric" /></label>'; $minute = '<label><span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Minute' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="mn" ' ) . 'name="mn" value="' . $mn . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" class="form-required" inputmode="numeric" /></label>'; echo '<div class="timestamp-wrap">'; /* translators: 1: Month, 2: Day, 3: Year, 4: Hour, 5: Minute. */ printf( __( '%1$s %2$s, %3$s at %4$s:%5$s' ), $month, $day, $year, $hour, $minute ); echo '</div><input type="hidden" id="ss" name="ss" value="' . $ss . '" />'; if ( $multi ) { return; } echo "\n\n"; $map = array( 'mm' => array( $mm, $cur_mm ), 'jj' => array( $jj, $cur_jj ), 'aa' => array( $aa, $cur_aa ), 'hh' => array( $hh, $cur_hh ), 'mn' => array( $mn, $cur_mn ), ); foreach ( $map as $timeunit => $value ) { list( $unit, $curr ) = $value; echo '<input type="hidden" id="hidden_' . $timeunit . '" name="hidden_' . $timeunit . '" value="' . $unit . '" />' . "\n"; $cur_timeunit = 'cur_' . $timeunit; echo '<input type="hidden" id="' . $cur_timeunit . '" name="' . $cur_timeunit . '" value="' . $curr . '" />' . "\n"; } ?> <p> <a href="#edit_timestamp" class="save-timestamp hide-if-no-js button"><?php _e( 'OK' ); ?></a> <a href="#edit_timestamp" class="cancel-timestamp hide-if-no-js button-cancel"><?php _e( 'Cancel' ); ?></a> </p> <?php } /** * Prints out option HTML elements for the page templates drop-down. * * @since 1.5.0 * @since 4.7.0 Added the `$post_type` parameter. * * @param string $default_template Optional. The template file name. Default empty. * @param string $post_type Optional. Post type to get templates for. Default 'page'. */ function page_template_dropdown( $default_template = '', $post_type = 'page' ) { $templates = get_page_templates( null, $post_type ); ksort( $templates ); foreach ( array_keys( $templates ) as $template ) { $selected = selected( $default_template, $templates[ $template ], false ); echo "\n\t<option value='" . esc_attr( $templates[ $template ] ) . "' $selected>" . esc_html( $template ) . '</option>'; } } /** * Prints out option HTML elements for the page parents drop-down. * * @since 1.5.0 * @since 4.4.0 `$post` argument was added. * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $default_page Optional. The default page ID to be pre-selected. Default 0. * @param int $parent_page Optional. The parent page ID. Default 0. * @param int $level Optional. Page depth level. Default 0. * @param int|WP_Post $post Post ID or WP_Post object. * @return void|false Void on success, false if the page has no children. */ function parent_dropdown( $default_page = 0, $parent_page = 0, $level = 0, $post = null ) { global $wpdb; $post = get_post( $post ); $items = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_parent, post_title FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'page' ORDER BY menu_order", $parent_page ) ); if ( $items ) { foreach ( $items as $item ) { // A page cannot be its own parent. if ( $post && $post->ID && (int) $item->ID === $post->ID ) { continue; } $pad = str_repeat( ' ', $level * 3 ); $selected = selected( $default_page, $item->ID, false ); echo "\n\t<option class='level-$level' value='$item->ID' $selected>$pad " . esc_html( $item->post_title ) . '</option>'; parent_dropdown( $default_page, $item->ID, $level + 1 ); } } else { return false; } } /** * Prints out option HTML elements for role selectors. * * @since 2.1.0 * @since 7.0.0 Added $editable_roles parameter. * * @param string $selected Slug for the role that should be already selected. * @param array $editable_roles Array of roles to include in the dropdown. Defaults to all * roles the current user is allowed to edit. */ function wp_dropdown_roles( $selected = '', $editable_roles = null ) { $r = ''; if ( null === $editable_roles ) { $editable_roles = array_reverse( get_editable_roles() ); } foreach ( $editable_roles as $role => $details ) { $name = translate_user_role( $details['name'] ); // Preselect specified role. if ( $selected === $role ) { $r .= "\n\t<option selected='selected' value='" . esc_attr( $role ) . "'>$name</option>"; } else { $r .= "\n\t<option value='" . esc_attr( $role ) . "'>$name</option>"; } } echo $r; } /** * Outputs the form used by the importers to accept the data to be imported. * * @since 2.0.0 * * @param string $action The action attribute for the form. */ function wp_import_upload_form( $action ) { /** * Filters the maximum allowed upload size for import files. * * @since 2.3.0 * * @see wp_max_upload_size() * * @param int $max_upload_size Allowed upload size. Default 1 MB. */ $bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() ); $size = size_format( $bytes ); $upload_dir = wp_upload_dir(); if ( ! empty( $upload_dir['error'] ) ) : $upload_directory_error = '<p>' . __( 'Before you can upload your import file, you will need to fix the following error:' ) . '</p>'; $upload_directory_error .= '<p><strong>' . $upload_dir['error'] . '</strong></p>'; wp_admin_notice( $upload_directory_error, array( 'additional_classes' => array( 'error' ), 'paragraph_wrap' => false, ) ); else : ?> <form enctype="multipart/form-data" id="import-upload-form" method="post" class="wp-upload-form" action="<?php echo esc_url( wp_nonce_url( $action, 'import-upload' ) ); ?>"> <p> <?php printf( '<label for="upload">%s</label> (%s)', __( 'Choose a file from your computer:' ), /* translators: %s: Maximum allowed file size. */ sprintf( __( 'Maximum size: %s' ), $size ) ); ?> <input type="file" id="upload" name="import" size="25" /> <input type="hidden" name="action" value="save" /> <input type="hidden" name="max_file_size" value="<?php echo $bytes; ?>" /> </p> <?php submit_button( __( 'Upload file and import' ), 'primary' ); ?> </form> <?php endif; } /** * Adds a meta box to one or more screens. * * @since 2.5.0 * @since 4.4.0 The `$screen` parameter now accepts an array of screen IDs. * * @global array $wp_meta_boxes Global meta box state. * * @param string $id Meta box ID (used in the 'id' attribute for the meta box). * @param string $title Title of the meta box. * @param callable $callback Function that fills the box with the desired content. * The function should echo its output. * @param string|array|WP_Screen $screen Optional. The screen or screens on which to show the box * (such as a post type, 'link', or 'comment'). Accepts a single * screen ID, WP_Screen object, or array of screen IDs. Default * is the current screen. If you have used add_menu_page() or * add_submenu_page() to create a new screen (and hence screen_id), * make sure your menu slug conforms to the limits of sanitize_key() * otherwise the 'screen' menu may not correctly render on your page. * @param string $context Optional. The context within the screen where the box * should display. Available contexts vary from screen to * screen. Post edit screen contexts include 'normal', 'side', * and 'advanced'. Comments screen contexts include 'normal' * and 'side'. Menus meta boxes (accordion sections) all use * the 'side' context. Global default is 'advanced'. * @param string $priority Optional. The priority within the context where the box should show. * Accepts 'high', 'core', 'default', or 'low'. Default 'default'. * @param array $callback_args Optional. Data that should be set as the $args property * of the box array (which is the second parameter passed * to your callback). Default null. */ function add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null ) { global $wp_meta_boxes; if ( empty( $screen ) ) { $screen = get_current_screen(); } elseif ( is_string( $screen ) ) { $screen = convert_to_screen( $screen ); } elseif ( is_array( $screen ) ) { foreach ( $screen as $single_screen ) { add_meta_box( $id, $title, $callback, $single_screen, $context, $priority, $callback_args ); } } if ( ! isset( $screen->id ) ) { return; } $page = $screen->id; if ( ! isset( $wp_meta_boxes ) ) { $wp_meta_boxes = array(); } if ( ! isset( $wp_meta_boxes[ $page ] ) ) { $wp_meta_boxes[ $page ] = array(); } if ( ! isset( $wp_meta_boxes[ $page ][ $context ] ) ) { $wp_meta_boxes[ $page ][ $context ] = array(); } foreach ( array_keys( $wp_meta_boxes[ $page ] ) as $a_context ) { foreach ( array( 'high', 'core', 'default', 'low' ) as $a_priority ) { if ( ! isset( $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ] ) ) { continue; } // If a core box was previously removed, don't add. if ( ( 'core' === $priority || 'sorted' === $priority ) && false === $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ] ) { return; } // If a core box was previously added by a plugin, don't add. if ( 'core' === $priority ) { /* * If the box was added with default priority, give it core priority * to maintain sort order. */ if ( 'default' === $a_priority ) { $wp_meta_boxes[ $page ][ $a_context ]['core'][ $id ] = $wp_meta_boxes[ $page ][ $a_context ]['default'][ $id ]; unset( $wp_meta_boxes[ $page ][ $a_context ]['default'][ $id ] ); } return; } // If no priority given and ID already present, use existing priority. if ( empty( $priority ) ) { $priority = $a_priority; /* * Else, if we're adding to the sorted priority, we don't know the title * or callback. Grab them from the previously added context/priority. */ } elseif ( 'sorted' === $priority ) { $title = $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ]['title']; $callback = $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ]['callback']; $callback_args = $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ]['args']; } // An ID can be in only one priority and one context. if ( $priority !== $a_priority || $context !== $a_context ) { unset( $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ] ); } } } if ( empty( $priority ) ) { $priority = 'low'; } if ( ! isset( $wp_meta_boxes[ $page ][ $context ][ $priority ] ) ) { $wp_meta_boxes[ $page ][ $context ][ $priority ] = array(); } $wp_meta_boxes[ $page ][ $context ][ $priority ][ $id ] = array( 'id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $callback_args, ); } /** * Renders a "fake" meta box with an information message, * shown on the block editor, when an incompatible meta box is found. * * @since 5.0.0 * * @param mixed $data_object The data object being rendered on this screen. * @param array $box { * Custom formats meta box arguments. * * @type string $id Meta box 'id' attribute. * @type string $title Meta box title. * @type callable $old_callback The original callback for this meta box. * @type array $args Extra meta box arguments. * } */ function do_block_editor_incompatible_meta_box( $data_object, $box ) { $plugin = _get_plugin_from_callback( $box['old_callback'] ); $plugins = get_plugins(); echo '<p>'; if ( $plugin ) { /* translators: %s: The name of the plugin that generated this meta box. */ printf( __( 'This meta box, from the %s plugin, is not compatible with the block editor.' ), "<strong>{$plugin['Name']}</strong>" ); } else { _e( 'This meta box is not compatible with the block editor.' ); } echo '</p>'; if ( empty( $plugins['classic-editor/classic-editor.php'] ) ) { if ( current_user_can( 'install_plugins' ) ) { $install_url = wp_nonce_url( self_admin_url( 'plugin-install.php?tab=favorites&user=wordpressdotorg&save=0' ), 'save_wporg_username_' . get_current_user_id() ); echo '<p>'; /* translators: %s: A link to install the Classic Editor plugin. */ printf( __( 'Please install the <a href="%s">Classic Editor plugin</a> to use this meta box.' ), esc_url( $install_url ) ); echo '</p>'; } } elseif ( is_plugin_inactive( 'classic-editor/classic-editor.php' ) ) { if ( current_user_can( 'activate_plugins' ) ) { $activate_url = wp_nonce_url( self_admin_url( 'plugins.php?action=activate&plugin=classic-editor/classic-editor.php' ), 'activate-plugin_classic-editor/classic-editor.php' ); echo '<p>'; /* translators: %s: A link to activate the Classic Editor plugin. */ printf( __( 'Please activate the <a href="%s">Classic Editor plugin</a> to use this meta box.' ), esc_url( $activate_url ) ); echo '</p>'; } } elseif ( $data_object instanceof WP_Post ) { $edit_url = add_query_arg( array( 'classic-editor' => '', 'classic-editor__forget' => '', ), get_edit_post_link( $data_object ) ); echo '<p>'; /* translators: %s: A link to use the Classic Editor plugin. */ printf( __( 'Please open the <a href="%s">classic editor</a> to use this meta box.' ), esc_url( $edit_url ) ); echo '</p>'; } } /** * Internal helper function to find the plugin from a meta box callback. * * @since 5.0.0 * * @access private * * @param callable $callback The callback function to check. * @return array|null The plugin that the callback belongs to, or null if it doesn't belong to a plugin. */ function _get_plugin_from_callback( $callback ) { try { if ( is_array( $callback ) ) { $reflection = new ReflectionMethod( $callback[0], $callback[1] ); } elseif ( is_string( $callback ) && str_contains( $callback, '::' ) ) { $reflection = new ReflectionMethod( $callback ); } else { $reflection = new ReflectionFunction( $callback ); } } catch ( ReflectionException $exception ) { // We could not properly reflect on the callable, so we abort here. return null; } // Don't show an error if it's an internal PHP function. if ( ! $reflection->isInternal() ) { // Only show errors if the meta box was registered by a plugin. $filename = wp_normalize_path( $reflection->getFileName() ); $plugin_dir = wp_normalize_path( WP_PLUGIN_DIR ); if ( str_starts_with( $filename, $plugin_dir ) ) { $filename = str_replace( $plugin_dir, '', $filename ); $filename = preg_replace( '|^/([^/]*/).*$|', '\\1', $filename ); $plugins = get_plugins(); foreach ( $plugins as $name => $plugin ) { if ( str_starts_with( $name, $filename ) ) { return $plugin; } } } } return null; } /** * Meta-Box template function. * * @since 2.5.0 * * @global array $wp_meta_boxes Global meta box state. * * @param string|WP_Screen $screen The screen identifier. If you have used add_menu_page() or * add_submenu_page() to create a new screen (and hence screen_id) * make sure your menu slug conforms to the limits of sanitize_key() * otherwise the 'screen' menu may not correctly render on your page. * @param string $context The screen context for which to display meta boxes. * @param mixed $data_object Gets passed to the meta box callback function as the first parameter. * Often this is the object that's the focus of the current screen, * for example a `WP_Post` or `WP_Comment` object. * @return int Number of meta_boxes. */ function do_meta_boxes( $screen, $context, $data_object ) { global $wp_meta_boxes; static $already_sorted = false; if ( empty( $screen ) ) { $screen = get_current_screen(); } elseif ( is_string( $screen ) ) { $screen = convert_to_screen( $screen ); } $page = $screen->id; $hidden = get_hidden_meta_boxes( $screen ); printf( '<div id="%s-sortables" class="meta-box-sortables">', esc_attr( $context ) ); /* * Grab the ones the user has manually sorted. * Pull them out of their previous context/priority and into the one the user chose. */ $sorted = get_user_option( "meta-box-order_$page" ); if ( ! $already_sorted && $sorted ) { foreach ( $sorted as $box_context => $ids ) { foreach ( explode( ',', $ids ) as $id ) { if ( $id && 'dashboard_browser_nag' !== $id ) { add_meta_box( $id, null, null, $screen, $box_context, 'sorted' ); } } } } $already_sorted = true; $i = 0; if ( isset( $wp_meta_boxes[ $page ][ $context ] ) ) { foreach ( array( 'high', 'sorted', 'core', 'default', 'low' ) as $priority ) { if ( isset( $wp_meta_boxes[ $page ][ $context ][ $priority ] ) ) { foreach ( (array) $wp_meta_boxes[ $page ][ $context ][ $priority ] as $box ) { if ( false === $box || ! $box['title'] ) { continue; } $block_compatible = true; if ( is_array( $box['args'] ) ) { // If a meta box is just here for back compat, don't show it in the block editor. if ( $screen->is_block_editor() && isset( $box['args']['__back_compat_meta_box'] ) && $box['args']['__back_compat_meta_box'] ) { continue; } if ( isset( $box['args']['__block_editor_compatible_meta_box'] ) ) { $block_compatible = (bool) $box['args']['__block_editor_compatible_meta_box']; unset( $box['args']['__block_editor_compatible_meta_box'] ); } // If the meta box is declared as incompatible with the block editor, override the callback function. if ( ! $block_compatible && $screen->is_block_editor() ) { $box['old_callback'] = $box['callback']; $box['callback'] = 'do_block_editor_incompatible_meta_box'; } if ( isset( $box['args']['__back_compat_meta_box'] ) ) { $block_compatible = $block_compatible || (bool) $box['args']['__back_compat_meta_box']; unset( $box['args']['__back_compat_meta_box'] ); } } ++$i; // get_hidden_meta_boxes() doesn't apply in the block editor. $hidden_class = ( ! $screen->is_block_editor() && in_array( $box['id'], $hidden, true ) ) ? ' hide-if-js' : ''; echo '<div id="' . $box['id'] . '" class="postbox ' . postbox_classes( $box['id'], $page ) . $hidden_class . '" ' . '>' . "\n"; echo '<div class="postbox-header">'; echo '<h2 class="hndle">'; if ( 'dashboard_php_nag' === $box['id'] ) { echo '<span aria-hidden="true" class="dashicons dashicons-warning"></span>'; echo '<span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Warning:' ) . ' </span>'; } echo $box['title']; echo "</h2>\n"; if ( 'dashboard_browser_nag' !== $box['id'] ) { $widget_title = $box['title']; if ( is_array( $box['args'] ) && isset( $box['args']['__widget_basename'] ) ) { $widget_title = $box['args']['__widget_basename']; // Do not pass this parameter to the user callback function. unset( $box['args']['__widget_basename'] ); } echo '<div class="handle-actions hide-if-no-js">'; echo '<button type="button" class="handle-order-higher" aria-disabled="false" aria-describedby="' . $box['id'] . '-handle-order-higher-description">'; echo '<span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Move up' ) . '</span>'; echo '<span class="order-higher-indicator" aria-hidden="true"></span>'; echo '</button>'; echo '<span class="hidden" id="' . $box['id'] . '-handle-order-higher-description">' . sprintf( /* translators: %s: Meta box title. */ __( 'Move %s box up' ), $widget_title ) . '</span>'; echo '<button type="button" class="handle-order-lower" aria-disabled="false" aria-describedby="' . $box['id'] . '-handle-order-lower-description">'; echo '<span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Move down' ) . '</span>'; echo '<span class="order-lower-indicator" aria-hidden="true"></span>'; echo '</button>'; echo '<span class="hidden" id="' . $box['id'] . '-handle-order-lower-description">' . sprintf( /* translators: %s: Meta box title. */ __( 'Move %s box down' ), $widget_title ) . '</span>'; echo '<button type="button" class="handlediv" aria-expanded="true">'; echo '<span class="screen-reader-text">' . sprintf( /* translators: %s: Hidden accessibility text. Meta box title. */ __( 'Toggle panel: %s' ), $widget_title ) . '</span>'; echo '<span class="toggle-indicator" aria-hidden="true"></span>'; echo '</button>'; echo '</div>'; } echo '</div>'; echo '<div class="inside">' . "\n"; if ( WP_DEBUG && ! $block_compatible && 'edit' === $screen->parent_base && ! $screen->is_block_editor() && ! isset( $_GET['meta-box-loader'] ) ) { $plugin = _get_plugin_from_callback( $box['callback'] ); if ( $plugin ) { $meta_box_not_compatible_message = sprintf( /* translators: %s: The name of the plugin that generated this meta box. */ __( 'This meta box, from the %s plugin, is not compatible with the block editor.' ), "<strong>{$plugin['Name']}</strong>" ); wp_admin_notice( $meta_box_not_compatible_message, array( 'additional_classes' => array( 'error', 'inline' ), ) ); } } call_user_func( $box['callback'], $data_object, $box ); echo "</div>\n"; echo "</div>\n"; } } } } echo '</div>'; return $i; } /** * Removes a meta box from one or more screens. * * @since 2.6.0 * @since 4.4.0 The `$screen` parameter now accepts an array of screen IDs. * * @global array $wp_meta_boxes Global meta box state. * * @param string $id Meta box ID (used in the 'id' attribute for the meta box). * @param string|array|WP_Screen $screen The screen or screens on which the meta box is shown (such as a * post type, 'link', or 'comment'). Accepts a single screen ID, * WP_Screen object, or array of screen IDs. * @param string $context The context within the screen where the box is set to display. * Contexts vary from screen to screen. Post edit screen contexts * include 'normal', 'side', and 'advanced'. Comments screen contexts * include 'normal' and 'side'. Menus meta boxes (accordion sections) * all use the 'side' context. */ function remove_meta_box( $id, $screen, $context ) { global $wp_meta_boxes; if ( empty( $screen ) ) { $screen = get_current_screen(); } elseif ( is_string( $screen ) ) { $screen = convert_to_screen( $screen ); } elseif ( is_array( $screen ) ) { foreach ( $screen as $single_screen ) { remove_meta_box( $id, $single_screen, $context ); } } if ( ! isset( $screen->id ) ) { return; } $page = $screen->id; if ( ! isset( $wp_meta_boxes ) ) { $wp_meta_boxes = array(); } if ( ! isset( $wp_meta_boxes[ $page ] ) ) { $wp_meta_boxes[ $page ] = array(); } if ( ! isset( $wp_meta_boxes[ $page ][ $context ] ) ) { $wp_meta_boxes[ $page ][ $context ] = array(); } foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) { $wp_meta_boxes[ $page ][ $context ][ $priority ][ $id ] = false; } } /** * Meta Box Accordion Template Function. * * Largely made up of abstracted code from do_meta_boxes(), this * function serves to build meta boxes as list items for display as * a collapsible accordion. * * @since 3.6.0 * * @uses global $wp_meta_boxes Used to retrieve registered meta boxes. * * @param string|object $screen The screen identifier. * @param string $context The screen context for which to display accordion sections. * @param mixed $data_object Gets passed to the section callback function as the first parameter. * @return int Number of meta boxes as accordion sections. */ function do_accordion_sections( $screen, $context, $data_object ) { global $wp_meta_boxes; wp_enqueue_script( 'accordion' ); if ( empty( $screen ) ) { $screen = get_current_screen(); } elseif ( is_string( $screen ) ) { $screen = convert_to_screen( $screen ); } $page = $screen->id; $hidden = get_hidden_meta_boxes( $screen ); ?> <div id="side-sortables" class="accordion-container"> <ul class="outer-border"> <?php $i = 0; $first_open = false; if ( isset( $wp_meta_boxes[ $page ][ $context ] ) ) { foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) { if ( isset( $wp_meta_boxes[ $page ][ $context ][ $priority ] ) ) { foreach ( $wp_meta_boxes[ $page ][ $context ][ $priority ] as $box ) { if ( false === $box || ! $box['title'] ) { continue; } ++$i; $hidden_class = in_array( $box['id'], $hidden, true ) ? 'hide-if-js' : ''; $open_class = ''; $aria_expanded = 'false'; if ( ! $first_open && empty( $hidden_class ) ) { $first_open = true; $open_class = 'open'; $aria_expanded = 'true'; } ?> <li class="control-section accordion-section <?php echo $hidden_class; ?> <?php echo $open_class; ?> <?php echo esc_attr( $box['id'] ); ?>" id="<?php echo esc_attr( $box['id'] ); ?>"> <h3 class="accordion-section-title hndle"> <button type="button" class="accordion-trigger" aria-expanded="<?php echo $aria_expanded; ?>" aria-controls="<?php echo esc_attr( $box['id'] ); ?>-content"> <span class="accordion-title"> <?php echo esc_html( $box['title'] ); ?> <span class="dashicons dashicons-arrow-down" aria-hidden="true"></span> </span> </button> </h3> <div class="accordion-section-content <?php postbox_classes( $box['id'], $page ); ?>" id="<?php echo esc_attr( $box['id'] ); ?>-content"> <div class="inside"> <?php call_user_func( $box['callback'], $data_object, $box ); ?> </div><!-- .inside --> </div><!-- .accordion-section-content --> </li><!-- .accordion-section --> <?php } } } } ?> </ul><!-- .outer-border --> </div><!-- .accordion-container --> <?php return $i; } /** * Adds a new section to a settings page. * * Part of the Settings API. Use this to define new settings sections for an admin page. * Show settings sections in your admin page callback function with do_settings_sections(). * Add settings fields to your section with add_settings_field(). * * The $callback argument should be the name of a function that echoes out any * content you want to show at the top of the settings section before the actual * fields. It can output nothing if you want. * * @since 2.7.0 * @since 6.1.0 Added an `$args` parameter for the section's HTML wrapper and class name. * * @global array $wp_settings_sections Storage array of all settings sections added to admin pages. * * @param string $id Slug-name to identify the section. Used in the 'id' attribute of tags. * @param string $title Formatted title of the section. Shown as the heading for the section. * @param callable $callback Function that displays any content at the top of the section (between heading and fields). * @param string $page The slug-name of the settings page on which to show the section. Built-in pages include * 'general', 'reading', 'writing', 'discussion', 'media', etc. Create your own using * add_options_page(); * @param array $args { * Arguments used to create the settings section. * * @type string $before_section HTML content to prepend to the section's HTML output. * Receives the section's class name as `%s`. Default empty. * @type string $after_section HTML content to append to the section's HTML output. Default empty. * @type string $section_class The class name to use for the section. Default empty. * } */ function add_settings_section( $id, $title, $callback, $page, $args = array() ) { global $wp_settings_sections; $defaults = array( 'id' => $id, 'title' => $title, 'callback' => $callback, 'before_section' => '', 'after_section' => '', 'section_class' => '', ); $section = wp_parse_args( $args, $defaults ); if ( 'misc' === $page ) { _deprecated_argument( __FUNCTION__, '3.0.0', sprintf( /* translators: %s: misc */ __( 'The "%s" options group has been removed. Use another settings group.' ), 'misc' ) ); $page = 'general'; } if ( 'privacy' === $page ) { _deprecated_argument( __FUNCTION__, '3.5.0', sprintf( /* translators: %s: privacy */ __( 'The "%s" options group has been removed. Use another settings group.' ), 'privacy' ) ); $page = 'reading'; } $wp_settings_sections[ $page ][ $id ] = $section; } /** * Adds a new field to a section of a settings page. * * Part of the Settings API. Use this to define a settings field that will show * as part of a settings section inside a settings page. The fields are shown using * do_settings_fields() in do_settings_sections(). * * The $callback argument should be the name of a function that echoes out the * HTML input tags for this setting field. Use get_option() to retrieve existing * values to show. * * @since 2.7.0 * @since 4.2.0 The `$class` argument was added. * * @global array $wp_settings_fields Storage array of settings fields and info about their pages/sections. * * @param string $id Slug-name to identify the field. Used in the 'id' attribute of tags. * @param string $title Formatted title of the field. Shown as the label for the field * during output. * @param callable $callback Function that fills the field with the desired form inputs. The * function should echo its output. * @param string $page The slug-name of the settings page on which to show the section * (general, reading, writing, ...). * @param string $section Optional. The slug-name of the section of the settings page * in which to show the box. Default 'default'. * @param array $args { * Optional. Extra arguments that get passed to the callback function. * * @type string $label_for When supplied, the setting title will be wrapped * in a `<label>` element, its `for` attribute populated * with this value. * @type string $class CSS Class to be added to the `<tr>` element when the * field is output. * } */ function add_settings_field( $id, $title, $callback, $page, $section = 'default', $args = array() ) { global $wp_settings_fields; if ( 'misc' === $page ) { _deprecated_argument( __FUNCTION__, '3.0.0', sprintf( /* translators: %s: misc */ __( 'The "%s" options group has been removed. Use another settings group.' ), 'misc' ) ); $page = 'general'; } if ( 'privacy' === $page ) { _deprecated_argument( __FUNCTION__, '3.5.0', sprintf( /* translators: %s: privacy */ __( 'The "%s" options group has been removed. Use another settings group.' ), 'privacy' ) ); $page = 'reading'; } $wp_settings_fields[ $page ][ $section ][ $id ] = array( 'id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $args, ); } /** * Prints out all settings sections added to a particular settings page. * * Part of the Settings API. Use this in a settings page callback function * to output all the sections and fields that were added to that $page with * add_settings_section() and add_settings_field() * * @since 2.7.0 * * @global array $wp_settings_sections Storage array of all settings sections added to admin pages. * @global array $wp_settings_fields Storage array of settings fields and info about their pages/sections. * * @param string $page The slug name of the page whose settings sections you want to output. */ function do_settings_sections( $page ) { global $wp_settings_sections, $wp_settings_fields; if ( ! isset( $wp_settings_sections[ $page ] ) ) { return; } foreach ( (array) $wp_settings_sections[ $page ] as $section ) { if ( '' !== $section['before_section'] ) { if ( '' !== $section['section_class'] ) { echo wp_kses_post( sprintf( $section['before_section'], esc_attr( $section['section_class'] ) ) ); } else { echo wp_kses_post( $section['before_section'] ); } } if ( $section['title'] ) { echo "<h2>{$section['title']}</h2>\n"; } if ( $section['callback'] ) { call_user_func( $section['callback'], $section ); } if ( isset( $wp_settings_fields[ $page ][ $section['id'] ] ) ) { echo '<table class="form-table" role="presentation">'; do_settings_fields( $page, $section['id'] ); echo '</table>'; } if ( '' !== $section['after_section'] ) { echo wp_kses_post( $section['after_section'] ); } } } /** * Prints out the settings fields for a particular settings section. * * Part of the Settings API. Use this in a settings page to output * a specific section. Should normally be called by do_settings_sections() * rather than directly. * * @since 2.7.0 * * @global array $wp_settings_fields Storage array of settings fields and their pages/sections. * * @param string $page Slug title of the admin page whose settings fields you want to show. * @param string $section Slug title of the settings section whose fields you want to show. */ function do_settings_fields( $page, $section ) { global $wp_settings_fields; if ( ! isset( $wp_settings_fields[ $page ][ $section ] ) ) { return; } foreach ( (array) $wp_settings_fields[ $page ][ $section ] as $field ) { $class = ''; if ( ! empty( $field['args']['class'] ) ) { $class = ' class="' . esc_attr( $field['args']['class'] ) . '"'; } echo "<tr{$class}>"; if ( ! empty( $field['args']['label_for'] ) ) { echo '<th scope="row"><label for="' . esc_attr( $field['args']['label_for'] ) . '">' . $field['title'] . '</label></th>'; } else { echo '<th scope="row">' . $field['title'] . '</th>'; } echo '<td>'; call_user_func( $field['callback'], $field['args'] ); echo '</td>'; echo '</tr>'; } } /** * Registers a settings error to be displayed to the user. * * Part of the Settings API. Use this to show messages to users about settings validation * problems, missing settings or anything else. * * Settings errors should be added inside the $sanitize_callback function defined in * register_setting() for a given setting to give feedback about the submission. * * By default messages will show immediately after the submission that generated the error. * Additional calls to settings_errors() can be used to show errors even when the settings * page is first accessed. * * @since 3.0.0 * @since 5.3.0 Added `warning` and `info` as possible values for `$type`. * * @global array[] $wp_settings_errors Storage array of errors registered during this pageload * * @param string $setting Slug title of the setting to which this error applies. * @param string $code Slug-name to identify the error. Used as part of 'id' attribute in HTML output. * @param string $message The formatted message text to display to the user (will be shown inside styled * `<div>` and `<p>` tags). * @param string $type Optional. Message type, controls HTML class. Possible values include 'error', * 'success', 'warning', 'info'. Default 'error'. */ function add_settings_error( $setting, $code, $message, $type = 'error' ) { global $wp_settings_errors; $wp_settings_errors[] = array( 'setting' => $setting, 'code' => $code, 'message' => $message, 'type' => $type, ); } /** * Fetches settings errors registered by add_settings_error(). * * Checks the $wp_settings_errors array for any errors declared during the current * pageload and returns them. * * If changes were just submitted ($_GET['settings-updated']) and settings errors were saved * to the 'settings_errors' transient then those errors will be returned instead. This * is used to pass errors back across pageloads. * * Use the $sanitize argument to manually re-sanitize the option before returning errors. * This is useful if you have errors or notices you want to show even when the user * hasn't submitted data (i.e. when they first load an options page, or in the {@see 'admin_notices'} * action hook). * * @since 3.0.0 * * @global array[] $wp_settings_errors Storage array of errors registered during this pageload * * @param string $setting Optional. Slug title of a specific setting whose errors you want. * @param bool $sanitize Optional. Whether to re-sanitize the setting value before returning errors. * @return array[] { * Array of settings error arrays. * * @type array ...$0 { * Associative array of setting error data. * * @type string $setting Slug title of the setting to which this error applies. * @type string $code Slug-name to identify the error. Used as part of 'id' attribute in HTML output. * @type string $message The formatted message text to display to the user (will be shown inside styled * `<div>` and `<p>` tags). * @type string $type Optional. Message type, controls HTML class. Possible values include 'error', * 'success', 'warning', 'info'. Default 'error'. * } * } */ function get_settings_errors( $setting = '', $sanitize = false ) { global $wp_settings_errors; /* * If $sanitize is true, manually re-run the sanitization for this option * This allows the $sanitize_callback from register_setting() to run, adding * any settings errors you want to show by default. */ if ( $sanitize ) { sanitize_option( $setting, get_option( $setting ) ); } // If settings were passed back from options.php then use them. if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] && get_transient( 'settings_errors' ) ) { $wp_settings_errors = array_merge( (array) $wp_settings_errors, get_transient( 'settings_errors' ) ); delete_transient( 'settings_errors' ); } // Check global in case errors have been added on this pageload. if ( empty( $wp_settings_errors ) ) { return array(); } // Filter the results to those of a specific setting if one was set. if ( $setting ) { $setting_errors = array(); foreach ( (array) $wp_settings_errors as $key => $details ) { if ( $setting === $details['setting'] ) { $setting_errors[] = $wp_settings_errors[ $key ]; } } return $setting_errors; } return $wp_settings_errors; } /** * Displays settings errors registered by add_settings_error(). * * Part of the Settings API. Outputs a div for each error retrieved by * get_settings_errors(). * * This is called automatically after a settings page based on the * Settings API is submitted. Errors should be added during the validation * callback function for a setting defined in register_setting(). * * The $sanitize option is passed into get_settings_errors() and will * re-run the setting sanitization * on its current value. * * The $hide_on_update option will cause errors to only show when the settings * page is first loaded. if the user has already saved new values it will be * hidden to avoid repeating messages already shown in the default error * reporting after submission. This is useful to show general errors like * missing settings when the user arrives at the settings page. * * @since 3.0.0 * @since 5.3.0 Legacy `error` and `updated` CSS classes are mapped to * `notice-error` and `notice-success`. * * @param string $setting Optional slug title of a specific setting whose errors you want. * @param bool $sanitize Whether to re-sanitize the setting value before returning errors. * @param bool $hide_on_update If set to true errors will not be shown if the settings page has * already been submitted. */ function settings_errors( $setting = '', $sanitize = false, $hide_on_update = false ) { if ( $hide_on_update && ! empty( $_GET['settings-updated'] ) ) { return; } $settings_errors = get_settings_errors( $setting, $sanitize ); if ( empty( $settings_errors ) ) { return; } $output = ''; foreach ( $settings_errors as $key => $details ) { if ( 'updated' === $details['type'] ) { $details['type'] = 'success'; } if ( in_array( $details['type'], array( 'error', 'success', 'warning', 'info' ), true ) ) { $details['type'] = 'notice-' . $details['type']; } $css_id = sprintf( 'setting-error-%s', esc_attr( $details['code'] ) ); $css_class = sprintf( 'notice %s settings-error is-dismissible', esc_attr( $details['type'] ) ); $output .= "<div id='$css_id' class='$css_class'> \n"; $output .= "<p><strong>{$details['message']}</strong></p>"; $output .= "</div> \n"; } echo $output; } /** * Outputs the modal window used for attaching media to posts or pages in the media-listing screen. * * @since 2.7.0 * * @param string $found_action Optional. The value of the 'found_action' input field. Default empty string. */ function find_posts_div( $found_action = '' ) { ?> <div id="find-posts" class="find-box" style="display: none;"> <div id="find-posts-head" class="find-box-head"> <?php _e( 'Attach to existing content' ); ?> <button type="button" id="find-posts-close"><span class="screen-reader-text"> <?php /* translators: Hidden accessibility text. */ _e( 'Close media attachment panel' ); ?> </span></button> </div> <div class="find-box-inside"> <div class="find-box-search"> <?php if ( $found_action ) { ?> <input type="hidden" name="found_action" value="<?php echo esc_attr( $found_action ); ?>" /> <?php } ?> <input type="hidden" name="affected" id="affected" value="" /> <?php wp_nonce_field( 'find-posts', '_ajax_nonce', false ); ?> <label class="screen-reader-text" for="find-posts-input"> <?php /* translators: Hidden accessibility text. */ _e( 'Search' ); ?> </label> <input type="text" id="find-posts-input" name="ps" value="" /> <span class="spinner"></span> <input type="button" id="find-posts-search" value="<?php esc_attr_e( 'Search' ); ?>" class="button" /> <div class="clear"></div> </div> <div id="find-posts-response"></div> </div> <div class="find-box-buttons"> <?php submit_button( __( 'Select' ), 'primary alignright', 'find-posts-submit', false ); ?> <div class="clear"></div> </div> </div> <?php } /** * Displays the post password. * * The password is passed through esc_attr() to ensure that it is safe for placing in an HTML attribute. * * @since 2.7.0 */ function the_post_password() { $post = get_post(); if ( isset( $post->post_password ) ) { echo esc_attr( $post->post_password ); } } /** * Gets the post title. * * The post title is fetched and if it is blank then a default string is * returned. * * @since 2.7.0 * * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. * @return string The post title if set. */ function _draft_or_post_title( $post = 0 ) { $title = get_the_title( $post ); if ( empty( $title ) ) { $title = __( '(no title)' ); } return esc_html( $title ); } /** * Displays the search query. * * A simple wrapper to display the "s" parameter in a `GET` URI. This function * should only be used when the_search_query() cannot. * * @since 2.7.0 */ function _admin_search_query() { echo isset( $_REQUEST['s'] ) ? esc_attr( wp_unslash( $_REQUEST['s'] ) ) : ''; } /** * Generic Iframe header for use with Thickbox. * * @since 2.7.0 * * @global string $hook_suffix * @global string $admin_body_class * @global string $body_id * @global WP_Locale $wp_locale WordPress date and time locale object. * * @param string $title Optional. Title of the Iframe page. Default empty. * @param bool $deprecated Not used. */ function iframe_header( $title = '', $deprecated = false ) { global $hook_suffix, $admin_body_class, $body_id, $wp_locale; show_admin_bar( false ); $admin_body_class = preg_replace( '/[^a-z0-9_-]+/i', '-', $hook_suffix ); $current_screen = get_current_screen(); header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) ); _wp_admin_html_begin(); ?> <title><?php bloginfo( 'name' ); ?> › <?php echo $title; ?> — <?php _e( 'WordPress' ); ?></title> <?php wp_enqueue_style( 'colors' ); ?> <script> addLoadEvent = function(func){if(typeof jQuery!=='undefined')jQuery(function(){func();});else if(typeof wpOnload!=='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}}; function tb_close(){var win=window.dialogArguments||opener||parent||top;win.tb_remove();} var ajaxurl = '<?php echo esc_js( admin_url( 'admin-ajax.php', 'relative' ) ); ?>', pagenow = '<?php echo esc_js( $current_screen->id ); ?>', typenow = '<?php echo esc_js( $current_screen->post_type ); ?>', adminpage = '<?php echo esc_js( $admin_body_class ); ?>', thousandsSeparator = '<?php echo esc_js( $wp_locale->number_format['thousands_sep'] ); ?>', decimalPoint = '<?php echo esc_js( $wp_locale->number_format['decimal_point'] ); ?>', isRtl = <?php echo (int) is_rtl(); ?>; </script> <?php /** This action is documented in wp-admin/admin-header.php */ do_action( 'admin_enqueue_scripts', $hook_suffix ); /** This action is documented in wp-admin/admin-header.php */ do_action( "admin_print_styles-{$hook_suffix}" ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores /** This action is documented in wp-admin/admin-header.php */ do_action( 'admin_print_styles' ); /** This action is documented in wp-admin/admin-header.php */ do_action( "admin_print_scripts-{$hook_suffix}" ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores /** This action is documented in wp-admin/admin-header.php */ do_action( 'admin_print_scripts' ); /** This action is documented in wp-admin/admin-header.php */ do_action( "admin_head-{$hook_suffix}" ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores /** This action is documented in wp-admin/admin-header.php */ do_action( 'admin_head' ); $admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_user_locale() ) ) ); $admin_body_class .= ' admin-color-' . sanitize_html_class( get_user_option( 'admin_color' ), 'modern' ); if ( is_rtl() ) { $admin_body_class .= ' rtl'; } ?> </head> <?php $admin_body_id = isset( $body_id ) ? 'id="' . $body_id . '" ' : ''; /** This filter is documented in wp-admin/admin-header.php */ $admin_body_classes = apply_filters( 'admin_body_class', '' ); $admin_body_classes = ltrim( $admin_body_classes . ' ' . $admin_body_class ); ?> <body <?php echo $admin_body_id; ?>class="wp-admin wp-core-ui no-js iframe <?php echo esc_attr( $admin_body_classes ); ?>"> <script> (function(){ var c = document.body.className; c = c.replace(/no-js/, 'js'); document.body.className = c; })(); </script> <?php } /** * Generic Iframe footer for use with Thickbox. * * @since 2.7.0 */ function iframe_footer() { /* * We're going to hide any footer output on iFrame pages, * but run the hooks anyway since they output JavaScript * or other needed content. */ /** * @global string $hook_suffix */ global $hook_suffix; ?> <div class="hidden"> <?php /** This action is documented in wp-admin/admin-footer.php */ do_action( 'admin_footer', $hook_suffix ); /** This action is documented in wp-admin/admin-footer.php */ do_action( "admin_print_footer_scripts-{$hook_suffix}" ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores /** This action is documented in wp-admin/admin-footer.php */ do_action( 'admin_print_footer_scripts' ); ?> </div> <script>if(typeof wpOnload==='function')wpOnload();</script> </body> </html> <?php } /** * Echoes or returns the post states as HTML. * * @since 2.7.0 * @since 5.3.0 Added the `$display` parameter and a return value. * * @see get_post_states() * * @param WP_Post $post The post to retrieve states for. * @param bool $display Optional. Whether to display the post states as an HTML string. * Default true. * @return string Post states string. */ function _post_states( $post, $display = true ) { $post_states = get_post_states( $post ); $post_states_html = ''; if ( ! empty( $post_states ) ) { $state_count = count( $post_states ); $separator = wp_get_list_item_separator(); $i = 0; $post_states_html .= ' — '; foreach ( $post_states as $state ) { ++$i; $suffix = ( $i < $state_count ) ? $separator : ''; $post_states_html .= "<span class='post-state'>{$state}{$suffix}</span>"; } } /** * Filters the HTML string of post states. * * @since 6.9.0 * * @param string $post_states_html All relevant post states combined into an HTML string for display. * E.g. `— <span class='post-state'>Draft, </span><span class='post-state'>Sticky</span>`. * @param array<string, string> $post_states A mapping of post state slugs to translated post state labels. * E.g. `array( 'draft' => __( 'Draft' ), 'sticky' => __( 'Sticky' ), ... )`. * @param WP_Post $post The current post object. */ $post_states_html = apply_filters( 'post_states_html', $post_states_html, $post_states, $post ); if ( $display ) { echo $post_states_html; } return $post_states_html; } /** * Retrieves an array of post states from a post. * * @since 5.3.0 * * @param WP_Post $post The post to retrieve states for. * @return string[] Array of post state labels keyed by their state. */ function get_post_states( $post ) { $post_states = array(); if ( ! $post instanceof WP_Post ) { return $post_states; } $post_status = $_REQUEST['post_status'] ?? ''; if ( ! empty( $post->post_password ) ) { $post_states['protected'] = _x( 'Password protected', 'post status' ); } if ( 'private' === $post->post_status && 'private' !== $post_status ) { $post_states['private'] = _x( 'Private', 'post status' ); } if ( 'draft' === $post->post_status ) { if ( get_post_meta( $post->ID, '_customize_changeset_uuid', true ) ) { $post_states[] = __( 'Customization Draft' ); } elseif ( 'draft' !== $post_status ) { $post_states['draft'] = _x( 'Draft', 'post status' ); } } elseif ( 'trash' === $post->post_status && get_post_meta( $post->ID, '_customize_changeset_uuid', true ) ) { $post_states[] = _x( 'Customization Draft', 'post status' ); } if ( 'pending' === $post->post_status && 'pending' !== $post_status ) { $post_states['pending'] = _x( 'Pending', 'post status' ); } if ( is_sticky( $post->ID ) ) { $post_states['sticky'] = _x( 'Sticky', 'post status' ); } if ( 'future' === $post->post_status ) { $post_states['scheduled'] = _x( 'Scheduled', 'post status' ); } if ( 'page' === get_option( 'show_on_front' ) ) { if ( (int) get_option( 'page_on_front' ) === $post->ID ) { $post_states['page_on_front'] = _x( 'Front Page', 'page label' ); } if ( (int) get_option( 'page_for_posts' ) === $post->ID ) { $post_states['page_for_posts'] = _x( 'Posts Page', 'page label' ); } } if ( (int) get_option( 'wp_page_for_privacy_policy' ) === $post->ID ) { $post_states['page_for_privacy_policy'] = _x( 'Privacy Policy Page', 'page label' ); } /** * Filters the default post display states used in the posts list table. * * @since 2.8.0 * @since 3.6.0 Added the `$post` parameter. * @since 5.5.0 Also applied in the Customizer context. If any admin functions * are used within the filter, their existence should be checked * with `function_exists()` before being used. * * @param array<string, string> $post_states A mapping of post state slugs to translated post state labels. * E.g. `array( 'draft' => __( 'Draft' ), 'sticky' => __( 'Sticky' ), ... )`. * @param WP_Post $post The current post object. */ return apply_filters( 'display_post_states', $post_states, $post ); } /** * Outputs the attachment media states as HTML. * * @since 3.2.0 * @since 5.6.0 Added the `$display` parameter and a return value. * * @param WP_Post $post The attachment post to retrieve states for. * @param bool $display Optional. Whether to display the post states as an HTML string. * Default true. * @return string Media states string. */ function _media_states( $post, $display = true ) { $media_states = get_media_states( $post ); $media_states_string = ''; if ( ! empty( $media_states ) ) { $state_count = count( $media_states ); $separator = wp_get_list_item_separator(); $i = 0; $media_states_string .= ' — '; foreach ( $media_states as $state ) { ++$i; $suffix = ( $i < $state_count ) ? $separator : ''; $media_states_string .= "<span class='post-state'>{$state}{$suffix}</span>"; } } if ( $display ) { echo $media_states_string; } return $media_states_string; } /** * Retrieves an array of media states from an attachment. * * @since 5.6.0 * * @param WP_Post $post The attachment to retrieve states for. * @return string[] Array of media state labels keyed by their state. */ function get_media_states( $post ) { static $header_images; $media_states = array(); $stylesheet = get_option( 'stylesheet' ); if ( current_theme_supports( 'custom-header' ) ) { $meta_header = get_post_meta( $post->ID, '_wp_attachment_is_custom_header', true ); if ( is_random_header_image() ) { if ( ! isset( $header_images ) ) { $header_images = wp_list_pluck( get_uploaded_header_images(), 'attachment_id' ); } if ( $meta_header === $stylesheet && in_array( $post->ID, $header_images, true ) ) { $media_states[] = __( 'Header Image' ); } } else { $header_image = get_header_image(); // Display "Header Image" if the image was ever used as a header image. if ( ! empty( $meta_header ) && $meta_header === $stylesheet && wp_get_attachment_url( $post->ID ) !== $header_image ) { $media_states[] = __( 'Header Image' ); } // Display "Current Header Image" if the image is currently the header image. if ( $header_image && wp_get_attachment_url( $post->ID ) === $header_image ) { $media_states[] = __( 'Current Header Image' ); } } if ( get_theme_support( 'custom-header', 'video' ) && has_header_video() ) { $mods = get_theme_mods(); if ( isset( $mods['header_video'] ) && $post->ID === $mods['header_video'] ) { $media_states[] = __( 'Current Header Video' ); } } } if ( current_theme_supports( 'custom-background' ) ) { $meta_background = get_post_meta( $post->ID, '_wp_attachment_is_custom_background', true ); if ( ! empty( $meta_background ) && $meta_background === $stylesheet ) { $media_states[] = __( 'Background Image' ); $background_image = get_background_image(); if ( $background_image && wp_get_attachment_url( $post->ID ) === $background_image ) { $media_states[] = __( 'Current Background Image' ); } } } if ( (int) get_option( 'site_icon' ) === $post->ID ) { $media_states[] = __( 'Site Icon' ); } if ( (int) get_theme_mod( 'custom_logo' ) === $post->ID ) { $media_states[] = __( 'Logo' ); } /** * Filters the default media display states for items in the Media list table. * * @since 3.2.0 * @since 4.8.0 Added the `$post` parameter. * * @param string[] $media_states An array of media states. Default 'Header Image', * 'Background Image', 'Site Icon', 'Logo'. * @param WP_Post $post The current attachment object. */ return apply_filters( 'display_media_states', $media_states, $post ); } /** * Tests support for compressing JavaScript from PHP. * * Outputs JavaScript that tests if compression from PHP works as expected * and sets an option with the result. Has no effect when the current user * is not an administrator. To run the test again the option 'can_compress_scripts' * has to be deleted. * * @since 2.8.0 */ function compression_test() { ?> <script> var compressionNonce = <?php echo wp_json_encode( wp_create_nonce( 'update_can_compress_scripts' ), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ); ?>; var testCompression = { get : function(test) { var x; if ( window.XMLHttpRequest ) { x = new XMLHttpRequest(); } else { try{x=new ActiveXObject('Msxml2.XMLHTTP');}catch(e){try{x=new ActiveXObject('Microsoft.XMLHTTP');}catch(e){};} } if (x) { x.onreadystatechange = function() { var r, h; if ( x.readyState == 4 ) { r = x.responseText.substr(0, 18); h = x.getResponseHeader('Content-Encoding'); testCompression.check(r, h, test); } }; x.open('GET', ajaxurl + '?action=wp-compression-test&test='+test+'&_ajax_nonce='+compressionNonce+'&'+(new Date()).getTime(), true); x.send(''); } }, check : function(r, h, test) { if ( ! r && ! test ) this.get(1); if ( 1 == test ) { if ( h && ( h.match(/deflate/i) || h.match(/gzip/i) ) ) this.get('no'); else this.get(2); return; } if ( 2 == test ) { if ( '"wpCompressionTest' === r ) this.get('yes'); else this.get('no'); } } }; testCompression.check(); </script> <?php } /** * Echoes a submit button, with provided text and appropriate class(es). * * @since 3.1.0 * * @see get_submit_button() * * @param string $text Optional. The text of the button. Defaults to 'Save Changes'. * @param string $type Optional. The type and CSS class(es) of the button. Core values * include 'primary', 'small', and 'large'. Default 'primary'. * @param string $name Optional. The HTML name of the submit button. If no `id` attribute * is given in the `$other_attributes` parameter, `$name` will be used * as the button's `id`. Default 'submit'. * @param bool $wrap Optional. True if the output button should be wrapped in a paragraph tag, * false otherwise. Default true. * @param array|string $other_attributes Optional. Other attributes that should be output with the button, * mapping attributes to their values, e.g. `array( 'id' => 'search-submit' )`. * These key/value attribute pairs will be output as `attribute="value"`, * where attribute is the key. Attributes can also be provided as a string, * e.g. `id="search-submit"`, though the array format is generally preferred. * Default empty string. */ function submit_button( $text = '', $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = '' ) { echo get_submit_button( $text, $type, $name, $wrap, $other_attributes ); } /** * Returns a submit button, with provided text and appropriate class. * * @since 3.1.0 * * @param string $text Optional. The text of the button. Defaults to 'Save Changes'. * @param string $type Optional. The type and CSS class(es) of the button. Core values * include 'primary', 'small', and 'large'. Default 'primary large'. * @param string $name Optional. The HTML name of the submit button. If no `id` attribute * is given in the `$other_attributes` parameter, `$name` will be used * as the button's `id`. Default 'submit'. * @param bool $wrap Optional. True if the output button should be wrapped in a paragraph tag, * false otherwise. Default true. * @param array|string $other_attributes Optional. Other attributes that should be output with the button, * mapping attributes to their values, e.g. `array( 'id' => 'search-submit' )`. * These key/value attribute pairs will be output as `attribute="value"`, * where attribute is the key. Attributes can also be provided as a string, * e.g. `id="search-submit"`, though the array format is generally preferred. * Default empty string. * @return string Submit button HTML. */ function get_submit_button( $text = '', $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = '' ) { if ( ! is_array( $type ) ) { $type = explode( ' ', $type ); } $button_shorthand = array( 'primary', 'small', 'large' ); $classes = array( 'button' ); foreach ( $type as $t ) { if ( 'secondary' === $t || 'button-secondary' === $t ) { continue; } $classes[] = in_array( $t, $button_shorthand, true ) ? 'button-' . $t : $t; } // Remove empty items, remove duplicate items, and finally build a string. $class = implode( ' ', array_unique( array_filter( $classes ) ) ); $text = $text ? $text : __( 'Save Changes' ); // Default the id attribute to $name unless an id was specifically provided in $other_attributes. $id = $name; if ( is_array( $other_attributes ) && isset( $other_attributes['id'] ) ) { $id = $other_attributes['id']; unset( $other_attributes['id'] ); } $attributes = ''; if ( is_array( $other_attributes ) ) { foreach ( $other_attributes as $attribute => $value ) { $attributes .= $attribute . '="' . esc_attr( $value ) . '" '; // Trailing space is important. } } elseif ( ! empty( $other_attributes ) ) { // Attributes provided as a string. $attributes = $other_attributes; } // Don't output empty name and id attributes. $name_attr = $name ? ' name="' . esc_attr( $name ) . '"' : ''; $id_attr = $id ? ' id="' . esc_attr( $id ) . '"' : ''; $button = '<input type="submit"' . $name_attr . $id_attr . ' class="' . esc_attr( $class ); $button .= '" value="' . esc_attr( $text ) . '" ' . $attributes . ' />'; if ( $wrap ) { $button = '<p class="submit">' . $button . '</p>'; } return $button; } /** * Prints out the beginning of the admin HTML header. * * @since 3.3.0 * * @global bool $is_IE */ function _wp_admin_html_begin() { global $is_IE; $admin_html_class = ( is_admin_bar_showing() ) ? 'wp-toolbar' : ''; if ( $is_IE ) { header( 'X-UA-Compatible: IE=edge' ); } ?> <!DOCTYPE html> <html class="<?php echo $admin_html_class; ?>" <?php /** * Fires inside the HTML tag in the admin header. * * @since 2.2.0 */ do_action( 'admin_xml_ns' ); language_attributes(); ?> > <head> <meta http-equiv="Content-Type" content="<?php bloginfo( 'html_type' ); ?>; charset=<?php echo get_option( 'blog_charset' ); ?>" /> <?php } /** * Converts a screen string to a screen object. * * @since 3.0.0 * * @param string $hook_name The hook name (also known as the hook suffix) used to determine the screen. * @return WP_Screen Screen object. */ function convert_to_screen( $hook_name ) { if ( ! class_exists( 'WP_Screen' ) ) { _doing_it_wrong( 'convert_to_screen(), add_meta_box()', sprintf( /* translators: 1: wp-admin/includes/template.php, 2: add_meta_box(), 3: add_meta_boxes */ __( 'Likely direct inclusion of %1$s in order to use %2$s. This is very wrong. Hook the %2$s call into the %3$s action instead.' ), '<code>wp-admin/includes/template.php</code>', '<code>add_meta_box()</code>', '<code>add_meta_boxes</code>' ), '3.3.0' ); return (object) array( 'id' => '_invalid', 'base' => '_are_belong_to_us', ); } return WP_Screen::get( $hook_name ); } /** * Outputs the HTML for restoring the post data from DOM storage * * @since 3.6.0 * @access private */ function _local_storage_notice() { $local_storage_message = '<p class="local-restore">'; $local_storage_message .= __( 'The backup of this post in your browser is different from the version below.' ); $local_storage_message .= '<button type="button" class="button restore-backup">' . __( 'Restore the backup' ) . '</button></p>'; $local_storage_message .= '<p class="help">'; $local_storage_message .= __( 'This will replace the current editor content with the last backup version. You can use undo and redo in the editor to get the old content back or to return to the restored version.' ); $local_storage_message .= '</p>'; wp_admin_notice( $local_storage_message, array( 'id' => 'local-storage-notice', 'additional_classes' => array( 'hidden' ), 'dismissible' => true, 'paragraph_wrap' => false, ) ); } /** * Outputs a HTML element with a star rating for a given rating. * * Outputs a HTML element with the star rating exposed on a 0..5 scale in * half star increments (ie. 1, 1.5, 2 stars). Optionally, if specified, the * number of ratings may also be displayed by passing the $number parameter. * * @since 3.8.0 * @since 4.4.0 Introduced the `echo` parameter. * * @param array $args { * Optional. Array of star ratings arguments. * * @type int|float $rating The rating to display, expressed in either a 0.5 rating increment, * or percentage. Default 0. * @type string $type Format that the $rating is in. Valid values are 'rating' (default), * or, 'percent'. Default 'rating'. * @type int $number The number of ratings that makes up this rating. Default 0. * @type bool $echo Whether to echo the generated markup. False to return the markup instead * of echoing it. Default true. * } * @return string Star rating HTML. */ function wp_star_rating( $args = array() ) { $defaults = array( 'rating' => 0, 'type' => 'rating', 'number' => 0, 'echo' => true, ); $parsed_args = wp_parse_args( $args, $defaults ); // Non-English decimal places when the $rating is coming from a string. $rating = (float) str_replace( ',', '.', $parsed_args['rating'] ); // Convert percentage to star rating, 0..5 in .5 increments. if ( 'percent' === $parsed_args['type'] ) { $rating = round( $rating / 10, 0 ) / 2; } // Calculate the number of each type of star needed. $full_stars = floor( $rating ); $half_stars = ceil( $rating - $full_stars ); $empty_stars = 5 - $full_stars - $half_stars; if ( $parsed_args['number'] ) { /* translators: Hidden accessibility text. 1: The rating, 2: The number of ratings. */ $format = _n( '%1$s rating based on %2$s rating', '%1$s rating based on %2$s ratings', $parsed_args['number'] ); $title = sprintf( $format, number_format_i18n( $rating, 1 ), number_format_i18n( $parsed_args['number'] ) ); } else { /* translators: Hidden accessibility text. %s: The rating. */ $title = sprintf( __( '%s rating' ), number_format_i18n( $rating, 1 ) ); } $output = '<div class="star-rating">'; $output .= '<span class="screen-reader-text">' . $title . '</span>'; $output .= str_repeat( '<div class="star star-full" aria-hidden="true"></div>', $full_stars ); $output .= str_repeat( '<div class="star star-half" aria-hidden="true"></div>', $half_stars ); $output .= str_repeat( '<div class="star star-empty" aria-hidden="true"></div>', $empty_stars ); $output .= '</div>'; if ( $parsed_args['echo'] ) { echo $output; } return $output; } /** * Outputs a notice when editing the page for posts (internal use only). * * @ignore * @since 4.2.0 */ function _wp_posts_page_notice() { wp_admin_notice( __( 'You are currently editing the page that shows your latest posts.' ), array( 'type' => 'warning', 'additional_classes' => array( 'inline' ), ) ); } /** * Outputs a notice when editing the page for posts in the block editor (internal use only). * * @ignore * @since 5.8.0 */ function _wp_block_editor_posts_page_notice() { wp_add_inline_script( 'wp-notices', sprintf( 'wp.data.dispatch( "core/notices" ).createWarningNotice( "%s", { isDismissible: false } )', __( 'You are currently editing the page that shows your latest posts.' ) ), 'after' ); } PK $��\�V$o�Z �Z class-plugin-upgrader.phpnu �[��� <?php /** * Upgrade API: Plugin_Upgrader class * * @package WordPress * @subpackage Upgrader * @since 4.6.0 */ /** * Core class used for upgrading/installing plugins. * * It is designed to upgrade/install plugins from a local zip, remote zip URL, * or uploaded zip file. * * @since 2.8.0 * @since 4.6.0 Moved to its own file from wp-admin/includes/class-wp-upgrader.php. * * @see WP_Upgrader */ class Plugin_Upgrader extends WP_Upgrader { /** * Plugin upgrade result. * * @since 2.8.0 * @var array|WP_Error $result * * @see WP_Upgrader::$result */ public $result; /** * Whether a bulk upgrade/installation is being performed. * * @since 2.9.0 * @var bool $bulk */ public $bulk = false; /** * New plugin info. * * @since 5.5.0 * @var array $new_plugin_data * * @see check_package() */ public $new_plugin_data = array(); /** * Initializes the upgrade strings. * * @since 2.8.0 */ public function upgrade_strings() { $this->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…' ), '<span class="code pre">%s</span>' ); $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.' ); } /** * Initializes 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…' ), '<span class="code pre">%s</span>' ); $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 <strong>%1$s %2$s</strong>.' ); 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; } /** * Upgrades 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. $upgrade_data = $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' => $upgrade_data->package, 'destination' => WP_PLUGIN_DIR, 'clear_destination' => true, 'clear_working' => true, 'hook_extra' => array( 'plugin' => $plugin, 'type' => 'plugin', 'action' => 'update', 'temp_backup' => array( 'slug' => dirname( $plugin ), 'src' => WP_PLUGIN_DIR, 'dir' => 'plugins', ), ), ) ); // Cleanup our hooks, in case something else does an 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; } /** * Upgrades 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() ) { $wp_version = wp_get_wp_version(); $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. $connected = $this->fs_connect( array( WP_CONTENT_DIR, WP_PLUGIN_DIR ) ); if ( ! $connected ) { $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. $upgrade_data = $current->response[ $plugin ]; $this->skin->plugin_active = is_plugin_active( $plugin ); if ( isset( $upgrade_data->requires ) && ! is_wp_version_compatible( $upgrade_data->requires ) ) { $result = new WP_Error( 'incompatible_wp_required_version', sprintf( /* translators: 1: Current WordPress version, 2: WordPress version required by the new plugin version. */ __( 'Your WordPress version is %1$s, however the new plugin version requires %2$s.' ), $wp_version, $upgrade_data->requires ) ); $this->skin->before( $result ); $this->skin->error( $result ); $this->skin->after(); } elseif ( isset( $upgrade_data->requires_php ) && ! is_php_version_compatible( $upgrade_data->requires_php ) ) { $result = new WP_Error( 'incompatible_php_required_version', sprintf( /* translators: 1: Current PHP version, 2: PHP version required by the new plugin version. */ __( 'The PHP version on your server is %1$s, however the new plugin version requires %2$s.' ), PHP_VERSION, $upgrade_data->requires_php ) ); $this->skin->before( $result ); $this->skin->error( $result ); $this->skin->after(); } else { add_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); $result = $this->run( array( 'package' => $upgrade_data->package, 'destination' => WP_PLUGIN_DIR, 'clear_destination' => true, 'clear_working' => true, 'is_multi' => true, 'hook_extra' => array( 'plugin' => $plugin, 'temp_backup' => array( 'slug' => dirname( $plugin ), 'src' => WP_PLUGIN_DIR, 'dir' => 'plugins', ), ), ) ); remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); } $results[ $plugin ] = $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 an 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. * * @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 = wp_get_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 ) ) { // Confidence 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 ) { $new_plugin_data = get_plugin_data( $file, false, false ); if ( ! empty( $new_plugin_data['Name'] ) ) { $this->new_plugin_data = $new_plugin_data; 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 = $new_plugin_data['RequiresPHP'] ?? null; $requires_wp = $new_plugin_data['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.' ), PHP_VERSION, $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; } /** * Retrieves 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. $plugin_files = array_keys( $plugin ); return $this->result['destination_name'] . '/' . $plugin_files[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 $response The installation response before the installation has started. * @param array $plugin Plugin package arguments. * @return bool|WP_Error The original `$response` parameter or WP_Error. */ public function deactivate_plugin_before_upgrade( $response, $plugin ) { if ( is_wp_error( $response ) ) { // Bypass. return $response; } // When in cron (background updates) don't deactivate the plugin, as we require a browser to reactivate it. if ( wp_doing_cron() ) { return $response; } $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 $response; } /** * 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 $response The installation response before the installation has started. * @param array $plugin Plugin package arguments. * @return bool|WP_Error The original `$response` parameter or WP_Error. */ public function active_before( $response, $plugin ) { if ( is_wp_error( $response ) ) { return $response; } // Only enable maintenance mode when in cron (background update). if ( ! wp_doing_cron() ) { return $response; } $plugin = $plugin['plugin'] ?? ''; // Only run if plugin is active. if ( ! is_plugin_active( $plugin ) ) { return $response; } // Change to maintenance mode. Bulk edit handles this separately. if ( ! $this->bulk ) { $this->maintenance_mode( true ); } return $response; } /** * 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 $response The installation response after the installation has finished. * @param array $plugin Plugin package arguments. * @return bool|WP_Error The original `$response` parameter or WP_Error. */ public function active_after( $response, $plugin ) { if ( is_wp_error( $response ) ) { return $response; } // Only disable maintenance mode when in cron (background update). if ( ! wp_doing_cron() ) { return $response; } $plugin = $plugin['plugin'] ?? ''; // Only run if plugin is active. if ( ! is_plugin_active( $plugin ) ) { return $response; } // Time to remove maintenance mode. Bulk edit handles this separately. if ( ! $this->bulk ) { $this->maintenance_mode( false ); } return $response; } /** * 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 = $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 $��\�ݠ6�% �% menu.phpnu �[��� <?php /** * Build Administration Menu. * * @package WordPress * @subpackage Administration */ if ( is_network_admin() ) { /** * Fires before the administration menu loads in the Network Admin. * * The hook fires before menus and sub-menus are removed based on user privileges. * * @since 3.1.0 * @access private */ do_action( '_network_admin_menu' ); } elseif ( is_user_admin() ) { /** * Fires before the administration menu loads in the User Admin. * * The hook fires before menus and sub-menus are removed based on user privileges. * * @since 3.1.0 * @access private */ do_action( '_user_admin_menu' ); } else { /** * Fires before the administration menu loads in the admin. * * The hook fires before menus and sub-menus are removed based on user privileges. * * @since 2.2.0 * @access private */ do_action( '_admin_menu' ); } /** * @global array $menu * @global array $submenu * @global array $compat */ global $menu, $submenu, $compat; // Create list of page plugin hook names. foreach ( $menu as $menu_page ) { $pos = strpos( $menu_page[2], '?' ); if ( false !== $pos ) { // Handle post_type=post|page|foo pages. $hook_name = substr( $menu_page[2], 0, $pos ); $hook_args = substr( $menu_page[2], $pos + 1 ); wp_parse_str( $hook_args, $hook_args ); // Set the hook name to be the post type. if ( isset( $hook_args['post_type'] ) ) { $hook_name = $hook_args['post_type']; } else { $hook_name = basename( $hook_name, '.php' ); } unset( $hook_args ); } else { $hook_name = basename( $menu_page[2], '.php' ); } $hook_name = sanitize_title( $hook_name ); if ( isset( $compat[ $hook_name ] ) ) { $hook_name = $compat[ $hook_name ]; } elseif ( ! $hook_name ) { continue; } $admin_page_hooks[ $menu_page[2] ] = $hook_name; } unset( $menu_page, $compat ); $_wp_submenu_nopriv = array(); $_wp_menu_nopriv = array(); // Loop over submenus and remove pages for which the user does not have privs. foreach ( $submenu as $parent => $sub ) { foreach ( $sub as $index => $data ) { if ( ! current_user_can( $data[1] ) ) { unset( $submenu[ $parent ][ $index ] ); $_wp_submenu_nopriv[ $parent ][ $data[2] ] = true; } } unset( $index, $data ); if ( empty( $submenu[ $parent ] ) ) { unset( $submenu[ $parent ] ); } } unset( $sub, $parent ); /* * Loop over the top-level menu. * Menus for which the original parent is not accessible due to lack of privileges * will have the next submenu in line be assigned as the new menu parent. */ foreach ( $menu as $id => $data ) { if ( empty( $submenu[ $data[2] ] ) ) { continue; } $subs = $submenu[ $data[2] ]; $first_sub = reset( $subs ); $old_parent = $data[2]; $new_parent = $first_sub[2]; /* * If the first submenu is not the same as the assigned parent, * make the first submenu the new parent. */ if ( $new_parent !== $old_parent ) { $_wp_real_parent_file[ $old_parent ] = $new_parent; $menu[ $id ][2] = $new_parent; foreach ( $submenu[ $old_parent ] as $index => $data ) { $submenu[ $new_parent ][ $index ] = $submenu[ $old_parent ][ $index ]; unset( $submenu[ $old_parent ][ $index ] ); } unset( $submenu[ $old_parent ], $index ); if ( isset( $_wp_submenu_nopriv[ $old_parent ] ) ) { $_wp_submenu_nopriv[ $new_parent ] = $_wp_submenu_nopriv[ $old_parent ]; } } } unset( $id, $data, $subs, $first_sub, $old_parent, $new_parent ); if ( is_network_admin() ) { /** * Fires before the administration menu loads in the Network Admin. * * @since 3.1.0 * * @param string $context Empty context. */ do_action( 'network_admin_menu', '' ); } elseif ( is_user_admin() ) { /** * Fires before the administration menu loads in the User Admin. * * @since 3.1.0 * * @param string $context Empty context. */ do_action( 'user_admin_menu', '' ); } else { /** * Fires before the administration menu loads in the admin. * * @since 1.5.0 * * @param string $context Empty context. */ do_action( 'admin_menu', '' ); } /* * Remove menus that have no accessible submenus and require privileges * that the user does not have. Run re-parent loop again. */ foreach ( $menu as $id => $data ) { if ( ! current_user_can( $data[1] ) ) { $_wp_menu_nopriv[ $data[2] ] = true; } /* * If there is only one submenu and it is has same destination as the parent, * remove the submenu. */ if ( ! empty( $submenu[ $data[2] ] ) && 1 === count( $submenu[ $data[2] ] ) ) { $subs = $submenu[ $data[2] ]; $first_sub = reset( $subs ); if ( $data[2] === $first_sub[2] ) { unset( $submenu[ $data[2] ] ); } } // If submenu is empty... if ( empty( $submenu[ $data[2] ] ) ) { // And user doesn't have privs, remove menu. if ( isset( $_wp_menu_nopriv[ $data[2] ] ) ) { unset( $menu[ $id ] ); } } } unset( $id, $data, $subs, $first_sub ); /** * Adds a CSS class to a string. * * @since 2.7.0 * * @param string $class_to_add The CSS class to add. * @param string $classes The string to add the CSS class to. * @return string The string with the CSS class added. */ function add_cssclass( $class_to_add, $classes ) { if ( empty( $classes ) ) { return $class_to_add; } return $classes . ' ' . $class_to_add; } /** * Adds CSS classes for top-level administration menu items. * * The list of added classes includes `.menu-top-first` and `.menu-top-last`. * * @since 2.7.0 * * @param array $menu The array of administration menu items. * @return array The array of administration menu items with the CSS classes added. */ function add_menu_classes( $menu ) { $first_item = false; $last_order = false; $items_count = count( $menu ); $i = 0; foreach ( $menu as $order => $top ) { ++$i; if ( 0 === $order ) { // Dashboard is always shown/single. $menu[0][4] = add_cssclass( 'menu-top-first', $top[4] ); $last_order = 0; continue; } if ( str_starts_with( $top[2], 'separator' ) && false !== $last_order ) { // If separator. $first_item = true; $classes = $menu[ $last_order ][4]; $menu[ $last_order ][4] = add_cssclass( 'menu-top-last', $classes ); continue; } if ( $first_item ) { $first_item = false; $classes = $menu[ $order ][4]; $menu[ $order ][4] = add_cssclass( 'menu-top-first', $classes ); } if ( $i === $items_count ) { // Last item. $classes = $menu[ $order ][4]; $menu[ $order ][4] = add_cssclass( 'menu-top-last', $classes ); } $last_order = $order; } /** * Filters administration menu array with classes added for top-level items. * * @since 2.7.0 * * @param array $menu Associative array of administration menu items. */ return apply_filters( 'add_menu_classes', $menu ); } uksort( $menu, 'strnatcasecmp' ); // Make it all pretty. /** * Filters whether to enable custom ordering of the administration menu. * * See the {@see 'menu_order'} filter for reordering menu items. * * @since 2.8.0 * * @param bool $custom Whether custom ordering is enabled. Default false. */ if ( apply_filters( 'custom_menu_order', false ) ) { $menu_order = array(); foreach ( $menu as $menu_item ) { $menu_order[] = $menu_item[2]; } unset( $menu_item ); $default_menu_order = $menu_order; /** * Filters the order of administration menu items. * * A truthy value must first be passed to the {@see 'custom_menu_order'} filter * for this filter to work. Use the following to enable custom menu ordering: * * add_filter( 'custom_menu_order', '__return_true' ); * * @since 2.8.0 * * @param array $menu_order An ordered array of menu items. */ $menu_order = apply_filters( 'menu_order', $menu_order ); $menu_order = array_flip( $menu_order ); $default_menu_order = array_flip( $default_menu_order ); /** * @global array $menu_order * @global array $default_menu_order * * @param array $a * @param array $b * @return int */ function sort_menu( $a, $b ) { global $menu_order, $default_menu_order; $a = $a[2]; $b = $b[2]; if ( isset( $menu_order[ $a ] ) && ! isset( $menu_order[ $b ] ) ) { return -1; } elseif ( ! isset( $menu_order[ $a ] ) && isset( $menu_order[ $b ] ) ) { return 1; } elseif ( isset( $menu_order[ $a ] ) && isset( $menu_order[ $b ] ) ) { return $menu_order[ $a ] <=> $menu_order[ $b ]; } else { return $default_menu_order[ $a ] <=> $default_menu_order[ $b ]; } } usort( $menu, 'sort_menu' ); unset( $menu_order, $default_menu_order ); } // Prevent adjacent separators. $prev_menu_was_separator = false; foreach ( $menu as $id => $data ) { if ( false === stristr( $data[4], 'wp-menu-separator' ) ) { // This item is not a separator, so falsey the toggler and do nothing. $prev_menu_was_separator = false; } else { // The previous item was a separator, so unset this one. if ( true === $prev_menu_was_separator ) { unset( $menu[ $id ] ); } // This item is a separator, so truthy the toggler and move on. $prev_menu_was_separator = true; } } unset( $id, $data, $prev_menu_was_separator ); // Remove the last menu item if it is a separator. $last_menu_key = array_keys( $menu ); $last_menu_key = array_pop( $last_menu_key ); if ( ! empty( $menu ) && 'wp-menu-separator' === $menu[ $last_menu_key ][4] ) { unset( $menu[ $last_menu_key ] ); } unset( $last_menu_key ); if ( ! user_can_access_admin_page() ) { /** * Fires when access to an admin page is denied. * * @since 2.5.0 */ do_action( 'admin_page_access_denied' ); wp_die( __( 'Sorry, you are not allowed to access this page.' ), 403 ); } $menu = add_menu_classes( $menu ); PK $��\'�':�T �T class-custom-background.phpnu �[��� <?php /** * The custom background script. * * @package WordPress * @subpackage Administration */ /** * The custom background class. * * @since 3.0.0 */ #[AllowDynamicProperties] class Custom_Background { /** * Callback for administration header. * * @since 3.0.0 * @var callable */ public $admin_header_callback; /** * Callback for header div. * * @since 3.0.0 * @var callable */ public $admin_image_div_callback; /** * Used to trigger a success message when settings updated and set to true. * * @since 3.0.0 * @var bool */ private $updated; /** * Constructor - Registers administration header callback. * * @since 3.0.0 * * @param callable $admin_header_callback Optional. Administration header callback. * Default empty string. * @param callable $admin_image_div_callback Optional. Custom image div output callback. * Default empty string. */ public function __construct( $admin_header_callback = '', $admin_image_div_callback = '' ) { $this->admin_header_callback = $admin_header_callback; $this->admin_image_div_callback = $admin_image_div_callback; add_action( 'admin_menu', array( $this, 'init' ) ); add_action( 'wp_ajax_custom-background-add', array( $this, 'ajax_background_add' ) ); // Unused since 3.5.0. add_action( 'wp_ajax_set-background-image', array( $this, 'wp_set_background_image' ) ); } /** * Sets up the hooks for the Custom Background admin page. * * @since 3.0.0 */ public function init() { $page = add_theme_page( _x( 'Background', 'custom background' ), _x( 'Background', 'custom background' ), 'edit_theme_options', 'custom-background', array( $this, 'admin_page' ) ); if ( ! $page ) { return; } add_action( "load-{$page}", array( $this, 'admin_load' ) ); add_action( "load-{$page}", array( $this, 'take_action' ), 49 ); add_action( "load-{$page}", array( $this, 'handle_upload' ), 49 ); if ( $this->admin_header_callback ) { add_action( "admin_head-{$page}", $this->admin_header_callback, 51 ); } } /** * Sets up the enqueue for the CSS & JavaScript files. * * @since 3.0.0 */ public function admin_load() { get_current_screen()->add_help_tab( array( 'id' => 'overview', 'title' => __( 'Overview' ), 'content' => '<p>' . __( '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.' ) . '</p>' . '<p>' . __( '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.' ) . '</p>' . '<p>' . __( '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.' ) . '</p>' . '<p>' . __( 'Do not forget to click on the Save Changes button when you are finished.' ) . '</p>', ) ); get_current_screen()->set_help_sidebar( '<p><strong>' . __( 'For more information:' ) . '</strong></p>' . '<p>' . __( '<a href="https://codex.wordpress.org/Appearance_Background_Screen">Documentation on Custom Background</a>' ) . '</p>' . '<p>' . __( '<a href="https://wordpress.org/support/forums/">Support forums</a>' ) . '</p>' ); wp_enqueue_media(); wp_enqueue_script( 'custom-background' ); wp_enqueue_style( 'wp-color-picker' ); } /** * Executes 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; } /** * Displays the custom background page. * * @since 3.0.0 */ public function admin_page() { ?> <div class="wrap" id="custom-background"> <h1><?php _e( 'Custom Background' ); ?></h1> <?php if ( current_user_can( 'customize' ) ) { $message = sprintf( /* translators: %s: URL to background image configuration in Customizer. */ __( 'You can now manage and live-preview Custom Backgrounds in the <a href="%s">Customizer</a>.' ), admin_url( 'customize.php?autofocus[control]=background_image' ) ); wp_admin_notice( $message, array( 'type' => 'info', 'additional_classes' => array( 'hide-if-no-customize' ), ) ); } if ( ! empty( $this->updated ) ) { $updated_message = sprintf( /* translators: %s: Home URL. */ __( 'Background updated. <a href="%s">Visit your site</a> to see how it looks.' ), esc_url( home_url( '/' ) ) ); wp_admin_notice( $updated_message, array( 'id' => 'message', 'additional_classes' => array( 'updated' ), ) ); } ?> <h2><?php _e( 'Background Image' ); ?></h2> <table class="form-table" role="presentation"> <tbody> <tr> <th scope="row"><?php echo esc_html_x( 'Preview', 'noun' ); ?></th> <td> <?php if ( $this->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: ' . maybe_hash_hex_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;"; } ?> <div id="custom-background-image" style="<?php echo $background_styles; ?>"><?php // Must be double quote, see above. ?> <?php if ( $background_image_thumb ) { ?> <img class="custom-background-image" src="<?php echo $background_image_thumb; ?>" style="visibility:hidden;" alt="" /><br /> <img class="custom-background-image" src="<?php echo $background_image_thumb; ?>" style="visibility:hidden;" alt="" /> <?php } ?> </div> <?php } ?> </td> </tr> <?php if ( get_background_image() ) : ?> <tr> <th scope="row"><?php _e( 'Remove Image' ); ?></th> <td> <form method="post"> <?php wp_nonce_field( 'custom-background-remove', '_wpnonce-custom-background-remove' ); ?> <?php submit_button( __( 'Remove Background Image' ), '', 'remove-background', false ); ?><br /> <?php _e( 'This will remove the background image. You will not be able to restore any customizations.' ); ?> </form> </td> </tr> <?php endif; ?> <?php $default_image = get_theme_support( 'custom-background', 'default-image' ); ?> <?php if ( $default_image && get_background_image() !== $default_image ) : ?> <tr> <th scope="row"><?php _e( 'Restore Original Image' ); ?></th> <td> <form method="post"> <?php wp_nonce_field( 'custom-background-reset', '_wpnonce-custom-background-reset' ); ?> <?php submit_button( __( 'Restore Original Image' ), '', 'reset-background', false ); ?><br /> <?php _e( 'This will restore the original background image. You will not be able to restore any customizations.' ); ?> </form> </td> </tr> <?php endif; ?> <?php if ( current_user_can( 'upload_files' ) ) : ?> <tr> <th scope="row"><?php _e( 'Select Image' ); ?></th> <td><form enctype="multipart/form-data" id="upload-form" class="wp-upload-form" method="post"> <p> <label for="upload"><?php _e( 'Choose an image from your computer:' ); ?></label><br /> <input type="file" id="upload" name="import" /> <input type="hidden" name="action" value="save" /> <?php wp_nonce_field( 'custom-background-upload', '_wpnonce-custom-background-upload' ); ?> <?php submit_button( _x( 'Upload', 'verb' ), '', 'submit', false ); ?> </p> <p> <label for="choose-from-library-link"><?php _e( 'Or choose an image from your media library:' ); ?></label><br /> <button id="choose-from-library-link" class="button" data-choose="<?php esc_attr_e( 'Choose a Background Image' ); ?>" data-update="<?php esc_attr_e( 'Set as background' ); ?>"><?php _e( 'Choose Image' ); ?></button> </p> </form> </td> </tr> <?php endif; ?> </tbody> </table> <h2><?php _e( 'Display Options' ); ?></h2> <form method="post"> <table class="form-table" role="presentation"> <tbody> <?php if ( get_background_image() ) : ?> <input name="background-preset" type="hidden" value="custom"> <?php $background_position_title = __( 'Image Position' ); $background_position = sprintf( '%s %s', get_theme_mod( 'background_position_x', get_theme_support( 'custom-background', 'default-position-x' ) ), get_theme_mod( 'background_position_y', get_theme_support( 'custom-background', 'default-position-y' ) ) ); $background_position_options = array( array( 'left top' => array( 'label' => __( 'Top Left' ), 'icon' => 'dashicons dashicons-arrow-left-alt', ), 'center top' => array( 'label' => __( 'Top' ), 'icon' => 'dashicons dashicons-arrow-up-alt', ), 'right top' => array( 'label' => __( 'Top Right' ), 'icon' => 'dashicons dashicons-arrow-right-alt', ), ), array( 'left center' => array( 'label' => __( 'Left' ), 'icon' => 'dashicons dashicons-arrow-left-alt', ), 'center center' => array( 'label' => __( 'Center' ), 'icon' => 'background-position-center-icon', ), 'right center' => array( 'label' => __( 'Right' ), 'icon' => 'dashicons dashicons-arrow-right-alt', ), ), array( 'left bottom' => array( 'label' => __( 'Bottom Left' ), 'icon' => 'dashicons dashicons-arrow-left-alt', ), 'center bottom' => array( 'label' => __( 'Bottom' ), 'icon' => 'dashicons dashicons-arrow-down-alt', ), 'right bottom' => array( 'label' => __( 'Bottom Right' ), 'icon' => 'dashicons dashicons-arrow-right-alt', ), ), ); ?> <tr> <th scope="row"><?php echo $background_position_title; ?></th> <td><fieldset><legend class="screen-reader-text"><span><?php echo $background_position_title; ?></span></legend> <div class="background-position-control"> <?php foreach ( $background_position_options as $group ) : ?> <div class="button-group"> <?php foreach ( $group as $value => $input ) : ?> <label> <input class="ui-helper-hidden-accessible" name="background-position" type="radio" value="<?php echo esc_attr( $value ); ?>"<?php checked( $value, $background_position ); ?>> <span class="button display-options position"><span class="<?php echo esc_attr( $input['icon'] ); ?>" aria-hidden="true"></span></span> <span class="screen-reader-text"><?php echo $input['label']; ?></span> </label> <?php endforeach; ?> </div> <?php endforeach; ?> </div> </fieldset></td> </tr> <?php $image_size_title = __( 'Image Size' ); ?> <tr> <th scope="row"><label for="background-size"><?php echo $image_size_title; ?></label></th> <td><fieldset><legend class="screen-reader-text"><span><?php echo $image_size_title; ?></span></legend> <select id="background-size" name="background-size"> <option value="auto"<?php selected( 'auto', get_theme_mod( 'background_size', get_theme_support( 'custom-background', 'default-size' ) ) ); ?>><?php _ex( 'Original', 'Original Size' ); ?></option> <option value="contain"<?php selected( 'contain', get_theme_mod( 'background_size', get_theme_support( 'custom-background', 'default-size' ) ) ); ?>><?php _e( 'Fit to Screen' ); ?></option> <option value="cover"<?php selected( 'cover', get_theme_mod( 'background_size', get_theme_support( 'custom-background', 'default-size' ) ) ); ?>><?php _e( 'Fill Screen' ); ?></option> </select> </fieldset></td> </tr> <?php $background_repeat_title = _x( 'Repeat', 'Background Repeat' ); ?> <tr> <th scope="row"><?php echo $background_repeat_title; ?></th> <td><fieldset><legend class="screen-reader-text"><span><?php echo $background_repeat_title; ?></span></legend> <input name="background-repeat" type="hidden" value="no-repeat"> <label><input type="checkbox" name="background-repeat" value="repeat"<?php checked( 'repeat', get_theme_mod( 'background_repeat', get_theme_support( 'custom-background', 'default-repeat' ) ) ); ?>> <?php _e( 'Repeat Background Image' ); ?></label> </fieldset></td> </tr> <?php $background_scroll_title = _x( 'Scroll', 'Background Scroll' ); ?> <tr> <th scope="row"><?php echo $background_scroll_title; ?></th> <td><fieldset><legend class="screen-reader-text"><span><?php echo $background_scroll_title; ?></span></legend> <input name="background-attachment" type="hidden" value="fixed"> <label><input name="background-attachment" type="checkbox" value="scroll" <?php checked( 'scroll', get_theme_mod( 'background_attachment', get_theme_support( 'custom-background', 'default-attachment' ) ) ); ?>> <?php _e( 'Scroll with Page' ); ?></label> </fieldset></td> </tr> <?php endif; // get_background_image() ?> <?php $background_color_title = __( 'Background Color' ); ?> <tr> <th scope="row"><?php echo $background_color_title; ?></th> <td><fieldset><legend class="screen-reader-text"><span><?php echo $background_color_title; ?></span></legend> <?php $default_color = ''; if ( current_theme_supports( 'custom-background', 'default-color' ) ) { $default_color = ' data-default-color="#' . esc_attr( get_theme_support( 'custom-background', 'default-color' ) ) . '"'; } ?> <input type="text" name="background-color" id="background-color" value="#<?php echo esc_attr( get_background_color() ); ?>"<?php echo $default_color; ?>> </fieldset></td> </tr> </tbody> </table> <?php wp_nonce_field( 'custom-background' ); ?> <?php submit_button( null, 'primary', 'save-background-options' ); ?> </form> </div> <?php } /** * Handles an Image upload for the background image. * * @since 3.0.0 */ public function handle_upload() { if ( empty( $_FILES ) ) { return; } check_admin_referer( 'custom-background-upload', '_wpnonce-custom-background-upload' ); $overrides = array( 'test_form' => false ); $uploaded_file = $_FILES['import']; $wp_filetype = wp_check_filetype_and_ext( $uploaded_file['tmp_name'], $uploaded_file['name'] ); if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) { wp_die( __( 'The uploaded file is not a valid image. Please try again.' ) ); } $file = wp_handle_upload( $uploaded_file, $overrides ); if ( isset( $file['error'] ) ) { wp_die( $file['error'] ); } $url = $file['url']; $type = $file['type']; $file = $file['file']; $filename = wp_basename( $file ); // Construct the attachment array. $attachment = array( 'post_title' => $filename, 'post_content' => $url, 'post_mime_type' => $type, 'guid' => $url, 'context' => 'custom-background', ); // Save the data. $id = wp_insert_attachment( $attachment, $file ); // Add the metadata. wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) ); update_post_meta( $id, '_wp_attachment_is_custom_background', get_option( 'stylesheet' ) ); set_theme_mod( 'background_image', sanitize_url( $url ) ); $thumbnail = wp_get_attachment_image_src( $id, 'thumbnail' ); set_theme_mod( 'background_image_thumb', sanitize_url( $thumbnail[0] ) ); /** This filter is documented in wp-admin/includes/class-custom-image-header.php */ $file = apply_filters( 'wp_create_file_in_uploads', $file, $id ); // For replication. $this->updated = true; } /** * Handles Ajax request for adding custom background context to an attachment. * * Triggers when the user adds a new background image from the * Media Manager. * * @since 4.1.0 */ public function ajax_background_add() { check_ajax_referer( 'background-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(); } update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', get_stylesheet() ); wp_send_json_success(); } /** * @since 3.4.0 * @deprecated 3.5.0 * * @param array $form_fields * @return array $form_fields */ public function attachment_fields_to_edit( $form_fields ) { return $form_fields; } /** * @since 3.4.0 * @deprecated 3.5.0 * * @param array $tabs * @return array $tabs */ public function filter_upload_tabs( $tabs ) { return $tabs; } /** * @since 3.4.0 * @deprecated 3.5.0 */ public function wp_set_background_image() { check_ajax_referer( 'custom-background' ); if ( ! current_user_can( 'edit_theme_options' ) || ! isset( $_POST['attachment_id'] ) ) { exit; } $attachment_id = absint( $_POST['attachment_id'] ); $sizes = array_keys( /** This filter is documented in wp-admin/includes/media.php */ apply_filters( 'image_size_names_choose', array( 'thumbnail' => __( 'Thumbnail' ), 'medium' => __( 'Medium' ), 'large' => __( 'Large' ), 'full' => __( 'Full Size' ), ) ) ); $size = 'thumbnail'; if ( in_array( $_POST['size'], $sizes, true ) ) { $size = esc_attr( $_POST['size'] ); } update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', get_option( 'stylesheet' ) ); $url = wp_get_attachment_image_src( $attachment_id, $size ); $thumbnail = wp_get_attachment_image_src( $attachment_id, 'thumbnail' ); set_theme_mod( 'background_image', sanitize_url( $url[0] ) ); set_theme_mod( 'background_image_thumb', sanitize_url( $thumbnail[0] ) ); exit; } } PK $��\�+Ⱦ� � class-plugin-upgrader-skin.phpnu �[��� <?php /** * Upgrader API: Plugin_Upgrader_Skin class * * @package WordPress * @subpackage Upgrader * @since 4.6.0 */ /** * Plugin Upgrader Skin for WordPress Plugin Upgrades. * * @since 2.8.0 * @since 4.6.0 Moved to its own file from wp-admin/includes/class-wp-upgrader-skins.php. * * @see WP_Upgrader_Skin */ class Plugin_Upgrader_Skin extends WP_Upgrader_Skin { /** * Holds the plugin slug in the Plugin Directory. * * @since 2.8.0 * * @var string */ public $plugin = ''; /** * Whether the plugin is active. * * @since 2.8.0 * * @var bool */ public $plugin_active = false; /** * Whether the plugin is active for the entire network. * * @since 2.8.0 * * @var bool */ public $plugin_network_active = false; /** * Constructor. * * Sets up the plugin upgrader skin. * * @since 2.8.0 * * @param array $args Optional. The plugin upgrader skin arguments to * override default options. Default empty array. */ public function __construct( $args = array() ) { $defaults = array( 'url' => '', '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 ); } /** * Performs an action 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( '<iframe title="%s" style="border:0;overflow:hidden" width="100%%" height="170" src="%s"></iframe>', 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( '<a href="%s" target="_parent">%s</a>', wp_nonce_url( 'plugins.php?action=activate&plugin=' . urlencode( $this->plugin ), 'activate-plugin_' . $this->plugin ), __( 'Activate Plugin' ) ), 'plugins_page' => sprintf( '<a href="%s" target="_parent">%s</a>', 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 $��\`��#C� C� class-wp-comments-list-table.phpnu �[��� <?php /** * List Table API: WP_Comments_List_Table class * * @package WordPress * @subpackage Administration * @since 3.1.0 */ /** * Core class used to implement displaying comments in a list table. * * @since 3.1.0 * * @see WP_List_Table */ class WP_Comments_List_Table extends WP_List_Table { public $checkbox = true; public $pending_count = array(); public $extra_items; private $user_can; /** * Constructor. * * @since 3.1.0 * * @see WP_List_Table::__construct() for more information on default arguments. * * @global int $post_id The ID of the post to show comments for. * * @param array $args An associative array of arguments. */ public function __construct( $args = array() ) { global $post_id; $post_id = isset( $_REQUEST['p'] ) ? absint( $_REQUEST['p'] ) : 0; if ( get_option( 'show_avatars' ) ) { add_filter( 'comment_author', array( $this, 'floated_admin_avatar' ), 10, 2 ); } parent::__construct( array( 'plural' => 'comments', 'singular' => 'comment', 'ajax' => true, 'screen' => $args['screen'] ?? null, ) ); } /** * Adds avatars to comment author names. * * @since 3.1.0 * * @param string $name Comment author name. * @param int $comment_id Comment ID. * @return string Avatar with the user name. */ public function floated_admin_avatar( $name, $comment_id ) { $comment = get_comment( $comment_id ); $avatar = get_avatar( $comment, 32, 'mystery' ); return "$avatar $name"; } /** * Checks if the user can edit posts. * * @return bool Whether the user can edit posts. */ public function ajax_user_can() { return current_user_can( 'edit_posts' ); } /** * Prepares the comments list items. * * @global string $mode Current list table display mode. * @global int $post_id Current post ID filter. * @global string $comment_status Comment status filter. * @global string $comment_type Comment type filter. * @global string $search Search term. */ public function prepare_items() { global $mode, $post_id, $comment_status, $comment_type, $search; if ( ! empty( $_REQUEST['mode'] ) ) { $mode = 'excerpt' === $_REQUEST['mode'] ? 'excerpt' : 'list'; set_user_setting( 'posts_list_mode', $mode ); } else { $mode = get_user_setting( 'posts_list_mode', 'list' ); } $comment_status = $_REQUEST['comment_status'] ?? 'all'; if ( ! in_array( $comment_status, array( 'all', 'mine', 'moderated', 'approved', 'spam', 'trash' ), true ) ) { $comment_status = 'all'; } $comment_type = ''; if ( ! empty( $_REQUEST['comment_type'] ) && 'note' !== $_REQUEST['comment_type'] ) { $comment_type = $_REQUEST['comment_type']; } $search = $_REQUEST['s'] ?? ''; $post_type = ( isset( $_REQUEST['post_type'] ) ) ? sanitize_key( $_REQUEST['post_type'] ) : ''; $user_id = $_REQUEST['user_id'] ?? ''; $orderby = $_REQUEST['orderby'] ?? ''; $order = $_REQUEST['order'] ?? ''; $comments_per_page = $this->get_per_page( $comment_status ); $doing_ajax = wp_doing_ajax(); if ( isset( $_REQUEST['number'] ) ) { $number = (int) $_REQUEST['number']; } else { $number = $comments_per_page + min( 8, $comments_per_page ); // Grab a few extra. } $page = $this->get_pagenum(); if ( isset( $_REQUEST['start'] ) ) { $start = $_REQUEST['start']; } else { $start = ( $page - 1 ) * $comments_per_page; } if ( $doing_ajax && isset( $_REQUEST['offset'] ) ) { $start += $_REQUEST['offset']; } $status_map = array( 'mine' => '', 'moderated' => 'hold', 'approved' => 'approve', 'all' => '', ); $args = array( 'status' => $status_map[ $comment_status ] ?? $comment_status, 'search' => $search, 'user_id' => $user_id, 'offset' => $start, 'number' => $number, 'post_id' => $post_id, 'type' => $comment_type, 'type__not_in' => array( 'note' ), 'orderby' => $orderby, 'order' => $order, 'post_type' => $post_type, 'update_comment_post_cache' => true, ); /** * Filters the arguments for the comment query in the comments list table. * * @since 5.1.0 * * @param array $args An array of get_comments() arguments. */ $args = apply_filters( 'comments_list_table_query_args', $args ); $_comments = get_comments( $args ); if ( is_array( $_comments ) ) { $this->items = array_slice( $_comments, 0, $comments_per_page ); $this->extra_items = array_slice( $_comments, $comments_per_page ); $_comment_post_ids = array_unique( wp_list_pluck( $_comments, 'comment_post_ID' ) ); $this->pending_count = get_pending_comments_num( $_comment_post_ids ); } $total_comments = get_comments( array_merge( $args, array( 'count' => true, 'offset' => 0, 'number' => 0, 'orderby' => 'none', ) ) ); $this->set_pagination_args( array( 'total_items' => $total_comments, 'per_page' => $comments_per_page, ) ); } /** * Gets the number of comments to display per page. * * @param string $comment_status Comment status. * @return int Comments per page. */ public function get_per_page( $comment_status = 'all' ) { $comments_per_page = $this->get_items_per_page( 'edit_comments_per_page' ); /** * Filters the number of comments listed per page in the comments list table. * * @since 2.6.0 * * @param int $comments_per_page The number of comments to list per page. * @param string $comment_status The comment status name. Default 'All'. */ return apply_filters( 'comments_per_page', $comments_per_page, $comment_status ); } /** * Displays a message when no comments are found. * @global string $comment_status The current comment status filter. */ public function no_items() { global $comment_status; if ( 'moderated' === $comment_status ) { _e( 'No comments awaiting moderation.' ); } elseif ( 'trash' === $comment_status ) { _e( 'No comments found in Trash.' ); } else { _e( 'No comments found.' ); } } /** * Returns an array of comment status links. * * @global int $post_id The ID of the post to show comments for. * @global string $comment_status The current comment status. * @global string $comment_type The current comment type. * * @return array<string, string> Comment status HTML links keyed by view. */ protected function get_views() { global $post_id, $comment_status, $comment_type; $status_links = array(); $num_comments = ( $post_id ) ? wp_count_comments( $post_id ) : wp_count_comments(); $statuses = array( /* translators: %s: Number of comments. */ 'all' => _nx_noop( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', 'comments' ), // Singular not used. /* translators: %s: Number of comments. */ 'mine' => _nx_noop( 'Mine <span class="count">(%s)</span>', 'Mine <span class="count">(%s)</span>', 'comments' ), /* translators: %s: Number of comments. */ 'moderated' => _nx_noop( 'Pending <span class="count">(%s)</span>', 'Pending <span class="count">(%s)</span>', 'comments' ), /* translators: %s: Number of comments. */ 'approved' => _nx_noop( 'Approved <span class="count">(%s)</span>', 'Approved <span class="count">(%s)</span>', 'comments' ), /* translators: %s: Number of comments. */ 'spam' => _nx_noop( 'Spam <span class="count">(%s)</span>', 'Spam <span class="count">(%s)</span>', 'comments' ), /* translators: %s: Number of comments. */ 'trash' => _nx_noop( 'Trash <span class="count">(%s)</span>', 'Trash <span class="count">(%s)</span>', 'comments' ), ); if ( ! EMPTY_TRASH_DAYS ) { unset( $statuses['trash'] ); } $link = admin_url( 'edit-comments.php' ); if ( ! empty( $comment_type ) && 'all' !== $comment_type ) { $link = add_query_arg( 'comment_type', $comment_type, $link ); } foreach ( $statuses as $status => $label ) { if ( 'mine' === $status ) { $current_user_id = get_current_user_id(); $num_comments->mine = get_comments( array( 'post_id' => $post_id ? $post_id : 0, 'user_id' => $current_user_id, 'count' => true, 'orderby' => 'none', ) ); $link = add_query_arg( 'user_id', $current_user_id, $link ); } else { $link = remove_query_arg( 'user_id', $link ); } if ( ! isset( $num_comments->$status ) ) { $num_comments->$status = 10; } $link = add_query_arg( 'comment_status', $status, $link ); if ( $post_id ) { $link = add_query_arg( 'p', absint( $post_id ), $link ); } /* // I toyed with this, but decided against it. Leaving it in here in case anyone thinks it is a good idea. ~ Mark if ( !empty( $_REQUEST['s'] ) ) $link = add_query_arg( 's', esc_attr( wp_unslash( $_REQUEST['s'] ) ), $link ); */ $status_links[ $status ] = array( 'url' => esc_url( $link ), 'label' => sprintf( translate_nooped_plural( $label, $num_comments->$status ), sprintf( '<span class="%s-count">%s</span>', ( 'moderated' === $status ) ? 'pending' : $status, number_format_i18n( $num_comments->$status ) ) ), 'current' => $status === $comment_status, ); } /** * Filters the comment status links. * * @since 2.5.0 * @since 5.1.0 The 'Mine' link was added. * * @param string[] $status_links An associative array of fully-formed comment status links. Includes 'All', 'Mine', * 'Pending', 'Approved', 'Spam', and 'Trash'. */ return apply_filters( 'comment_status_links', $this->get_views_links( $status_links ) ); } /** * Gets the available bulk actions for the comments list. * * @global string $comment_status Current comment status filter. * * @return array<string, string> Bulk action labels keyed by action name. */ protected function get_bulk_actions() { global $comment_status; if ( ! current_user_can( 'moderate_comments' ) ) { return array(); // Return an empty array if the user doesn't have permission } $actions = array(); if ( in_array( $comment_status, array( 'all', 'approved' ), true ) ) { $actions['unapprove'] = __( 'Unapprove' ); } if ( in_array( $comment_status, array( 'all', 'moderated' ), true ) ) { $actions['approve'] = __( 'Approve' ); } if ( in_array( $comment_status, array( 'all', 'moderated', 'approved', 'trash' ), true ) ) { $actions['spam'] = _x( 'Mark as spam', 'comment' ); } if ( 'trash' === $comment_status ) { $actions['untrash'] = __( 'Restore' ); } elseif ( 'spam' === $comment_status ) { $actions['unspam'] = _x( 'Not spam', 'comment' ); } if ( in_array( $comment_status, array( 'trash', 'spam' ), true ) || ! EMPTY_TRASH_DAYS ) { $actions['delete'] = __( 'Delete permanently' ); } else { $actions['trash'] = __( 'Move to Trash' ); } return $actions; } /** * Displays extra controls between bulk actions and pagination. * * @global string $comment_status Current comment status. * @global string $comment_type Current comment type. * * @param string $which The location of the extra table nav markup: Either 'top' or 'bottom'. */ protected function extra_tablenav( $which ) { global $comment_status, $comment_type; static $has_items; if ( ! isset( $has_items ) ) { $has_items = $this->has_items(); } echo '<div class="alignleft actions">'; if ( 'top' === $which ) { ob_start(); $this->comment_type_dropdown( $comment_type ); /** * Fires just before the Filter submit button for comment types. * * @since 3.5.0 */ do_action( 'restrict_manage_comments' ); $output = ob_get_clean(); if ( ! empty( $output ) && $this->has_items() ) { echo $output; submit_button( __( 'Filter' ), 'button-compact', 'filter_action', false, array( 'id' => 'post-query-submit' ) ); } } if ( ( 'spam' === $comment_status || 'trash' === $comment_status ) && $has_items && current_user_can( 'moderate_comments' ) ) { wp_nonce_field( 'bulk-destroy', '_destroy_nonce' ); $title = ( 'spam' === $comment_status ) ? esc_attr__( 'Empty Spam' ) : esc_attr__( 'Empty Trash' ); submit_button( $title, 'apply', 'delete_all', false ); } /** * Fires after the Filter submit button for comment types. * * @since 2.5.0 * @since 5.6.0 The `$which` parameter was added. * * @param string $comment_status The comment status name. Default 'All'. * @param string $which The location of the extra table nav markup: Either 'top' or 'bottom'. */ do_action( 'manage_comments_nav', $comment_status, $which ); echo '</div>'; } /** * Gets the current action selected from the bulk actions dropdown. * * @return string|false Current action or false if none. */ public function current_action() { if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) ) { return 'delete_all'; } return parent::current_action(); } /** * Gets the list of columns. * * @global int $post_id The ID of the post comments are being shown for. * * @return string[] Array of column titles keyed by their column name. */ public function get_columns() { global $post_id; $columns = array(); if ( $this->checkbox ) { $columns['cb'] = '<input type="checkbox" />'; } $columns['author'] = __( 'Author' ); $columns['comment'] = _x( 'Comment', 'column name' ); if ( ! $post_id ) { /* translators: Column name or table row header. */ $columns['response'] = __( 'In response to' ); } $columns['date'] = _x( 'Submitted on', 'column name' ); return $columns; } /** * Displays a comment type drop-down for filtering on the Comments list table. * * @since 5.5.0 * @since 5.6.0 Renamed from `comment_status_dropdown()` to `comment_type_dropdown()`. * * @param string $comment_type The current comment type slug. */ protected function comment_type_dropdown( $comment_type ) { /** * Filters the comment types shown in the drop-down menu on the Comments list table. * * @since 2.7.0 * * @param string[] $comment_types Array of comment type labels keyed by their name. */ $comment_types = apply_filters( 'admin_comment_types_dropdown', array( 'comment' => __( 'Comments' ), 'pings' => __( 'Pings' ), ) ); if ( $comment_types && is_array( $comment_types ) ) { printf( '<label class="screen-reader-text" for="filter-by-comment-type">%s</label>', /* translators: Hidden accessibility text. */ __( 'Filter by comment type' ) ); echo '<select id="filter-by-comment-type" name="comment_type">'; printf( "\t<option value=''>%s</option>", __( 'All comment types' ) ); foreach ( $comment_types as $type => $label ) { if ( get_comments( array( 'count' => true, 'orderby' => 'none', 'type' => $type, ) ) ) { printf( "\t<option value='%s'%s>%s</option>\n", esc_attr( $type ), selected( $comment_type, $type, false ), esc_html( $label ) ); } } echo '</select>'; } } /** * Gets a list of sortable columns. * * @return array<string, string|array> The sortable columns. */ protected function get_sortable_columns() { return array( 'author' => array( 'comment_author', false, __( 'Author' ), __( 'Table ordered by Comment Author.' ) ), 'response' => array( 'comment_post_ID', false, _x( 'In Response To', 'column name' ), __( 'Table ordered by Post Replied To.' ) ), 'date' => 'comment_date', ); } /** * Gets the name of the default primary column. * * @since 4.3.0 * * @return string Name of the default primary column, in this case, 'comment'. */ protected function get_default_primary_column_name() { return 'comment'; } /** * Displays the comments table. * * Overrides the parent display() method to render extra comments. * * @since 3.1.0 */ public function display() { wp_nonce_field( 'fetch-list-' . get_class( $this ), '_ajax_fetch_list_nonce' ); static $has_items; if ( ! isset( $has_items ) ) { $has_items = $this->has_items(); if ( $has_items ) { $this->display_tablenav( 'top' ); } } $this->screen->render_screen_reader_content( 'heading_list' ); ?> <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>"> <?php if ( ! isset( $_GET['orderby'] ) ) { // In the initial view, Comments are ordered by comment's date but there's no column for that. echo '<caption class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Ordered by Comment Date, descending.' ) . '</caption>'; } else { $this->print_table_description(); } ?> <thead> <tr> <?php $this->print_column_headers(); ?> </tr> </thead> <tbody id="the-comment-list" data-wp-lists="list:comment"> <?php $this->display_rows_or_placeholder(); ?> </tbody> <tbody id="the-extra-comment-list" data-wp-lists="list:comment" style="display: none;"> <?php /* * Back up the items to restore after printing the extra items markup. * The extra items may be empty, which will prevent the table nav from displaying later. */ $items = $this->items; $this->items = $this->extra_items; $this->display_rows_or_placeholder(); $this->items = $items; ?> </tbody> <tfoot> <tr> <?php $this->print_column_headers( false ); ?> </tr> </tfoot> </table> <?php $this->display_tablenav( 'bottom' ); } /** * Generates content for a single row of the table. * * @global WP_Post $post Global post object. * @global WP_Comment $comment Global comment object. * * @param WP_Comment $item The comment object. */ public function single_row( $item ) { global $post, $comment; // Restores the more descriptive, specific name for use within this method. $comment = $item; if ( $comment->comment_post_ID > 0 ) { $post = get_post( $comment->comment_post_ID ); } $edit_post_cap = $post ? 'edit_post' : 'edit_posts'; if ( ! current_user_can( $edit_post_cap, $comment->comment_post_ID ) && ( post_password_required( $comment->comment_post_ID ) || ! current_user_can( 'read_post', $comment->comment_post_ID ) ) ) { // The user has no access to the post and thus cannot see the comments. return false; } $the_comment_class = wp_get_comment_status( $comment ); if ( ! $the_comment_class ) { $the_comment_class = ''; } $the_comment_class = implode( ' ', get_comment_class( $the_comment_class, $comment, $comment->comment_post_ID ) ); $this->user_can = current_user_can( 'edit_comment', $comment->comment_ID ); echo "<tr id='comment-$comment->comment_ID' class='$the_comment_class'>"; $this->single_row_columns( $comment ); echo "</tr>\n"; unset( $GLOBALS['post'], $GLOBALS['comment'] ); } /** * Generates and displays row actions links. * * @since 4.3.0 * @since 5.9.0 Renamed `$comment` to `$item` to match parent class for PHP 8 named parameter support. * * @global string $comment_status Status for the current listed comments. * * @param WP_Comment $item The comment object. * @param string $column_name Current column name. * @param string $primary Primary column name. * @return string Row actions output for comments. An empty string * if the current column is not the primary column, * or if the current user cannot edit the comment. */ protected function handle_row_actions( $item, $column_name, $primary ) { global $comment_status; if ( $primary !== $column_name ) { return ''; } if ( ! $this->user_can ) { return ''; } // Restores the more descriptive, specific name for use within this method. $comment = $item; $the_comment_status = wp_get_comment_status( $comment ); $output = ''; $approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( 'approve-comment_' . $comment->comment_ID ) ); $del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( 'delete-comment_' . $comment->comment_ID ) ); $action_string = 'comment.php?action=%s&c=' . $comment->comment_ID . '&%s'; $approve_url = sprintf( $action_string, 'approvecomment', $approve_nonce ); $unapprove_url = sprintf( $action_string, 'unapprovecomment', $approve_nonce ); $spam_url = sprintf( $action_string, 'spamcomment', $del_nonce ); $unspam_url = sprintf( $action_string, 'unspamcomment', $del_nonce ); $trash_url = sprintf( $action_string, 'trashcomment', $del_nonce ); $untrash_url = sprintf( $action_string, 'untrashcomment', $del_nonce ); $delete_url = sprintf( $action_string, 'deletecomment', $del_nonce ); // Preorder it: Approve | Reply | Quick Edit | Edit | Spam | Trash. $actions = array( 'approve' => '', 'unapprove' => '', 'reply' => '', 'quickedit' => '', 'edit' => '', 'spam' => '', 'unspam' => '', 'trash' => '', 'untrash' => '', 'delete' => '', ); // Not looking at all comments. if ( $comment_status && 'all' !== $comment_status ) { if ( 'approved' === $the_comment_status ) { $actions['unapprove'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-u vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $unapprove_url ), "delete:the-comment-list:comment-{$comment->comment_ID}:e7e7d3:action=dim-comment&new=unapproved", esc_attr__( 'Unapprove this comment' ), __( 'Unapprove' ) ); } elseif ( 'unapproved' === $the_comment_status ) { $actions['approve'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-a vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $approve_url ), "delete:the-comment-list:comment-{$comment->comment_ID}:e7e7d3:action=dim-comment&new=approved", esc_attr__( 'Approve this comment' ), __( 'Approve' ) ); } } else { $actions['approve'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-a aria-button-if-js" aria-label="%s">%s</a>', esc_url( $approve_url ), "dim:the-comment-list:comment-{$comment->comment_ID}:unapproved:e7e7d3:e7e7d3:new=approved", esc_attr__( 'Approve this comment' ), __( 'Approve' ) ); $actions['unapprove'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-u aria-button-if-js" aria-label="%s">%s</a>', esc_url( $unapprove_url ), "dim:the-comment-list:comment-{$comment->comment_ID}:unapproved:e7e7d3:e7e7d3:new=unapproved", esc_attr__( 'Unapprove this comment' ), __( 'Unapprove' ) ); } if ( 'spam' !== $the_comment_status ) { $actions['spam'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-s vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $spam_url ), "delete:the-comment-list:comment-{$comment->comment_ID}::spam=1", esc_attr__( 'Mark this comment as spam' ), /* translators: "Mark as spam" link. */ _x( 'Spam', 'verb' ) ); } elseif ( 'spam' === $the_comment_status ) { $actions['unspam'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-z vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $unspam_url ), "delete:the-comment-list:comment-{$comment->comment_ID}:66cc66:unspam=1", esc_attr__( 'Restore this comment from the spam' ), _x( 'Not Spam', 'comment' ) ); } if ( 'trash' === $the_comment_status ) { $actions['untrash'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-z vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $untrash_url ), "delete:the-comment-list:comment-{$comment->comment_ID}:66cc66:untrash=1", esc_attr__( 'Restore this comment from the Trash' ), __( 'Restore' ) ); } if ( 'spam' === $the_comment_status || 'trash' === $the_comment_status || ! EMPTY_TRASH_DAYS ) { $actions['delete'] = sprintf( '<a href="%s" data-wp-lists="%s" class="delete vim-d vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $delete_url ), "delete:the-comment-list:comment-{$comment->comment_ID}::delete=1", esc_attr__( 'Delete this comment permanently' ), __( 'Delete Permanently' ) ); } else { $actions['trash'] = sprintf( '<a href="%s" data-wp-lists="%s" class="delete vim-d vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $trash_url ), "delete:the-comment-list:comment-{$comment->comment_ID}::trash=1", esc_attr__( 'Move this comment to the Trash' ), _x( 'Trash', 'verb' ) ); } if ( 'spam' !== $the_comment_status && 'trash' !== $the_comment_status ) { $actions['edit'] = sprintf( '<a href="%s" aria-label="%s">%s</a>', "comment.php?action=editcomment&c={$comment->comment_ID}", esc_attr__( 'Edit this comment' ), __( 'Edit' ) ); $format = '<button type="button" data-comment-id="%d" data-post-id="%d" data-action="%s" class="%s button-link" aria-expanded="false" aria-label="%s">%s</button>'; $actions['quickedit'] = sprintf( $format, $comment->comment_ID, $comment->comment_post_ID, 'edit', 'vim-q comment-inline', esc_attr__( 'Quick edit this comment inline' ), __( 'Quick Edit' ) ); $actions['reply'] = sprintf( $format, $comment->comment_ID, $comment->comment_post_ID, 'replyto', 'vim-r comment-inline', esc_attr__( 'Reply to this comment' ), /* translators: Comment reply button text. */ _x( 'Reply', 'verb' ) ); } /** * Filters the action links displayed for each comment in the Comments list table. * * @since 2.6.0 * * @param string[] $actions An array of comment actions. Default actions include: * 'Approve', 'Unapprove', 'Edit', 'Reply', 'Spam', * 'Delete', and 'Trash'. * @param WP_Comment $comment The comment object. */ $actions = apply_filters( 'comment_row_actions', array_filter( $actions ), $comment ); $always_visible = false; $mode = get_user_setting( 'posts_list_mode', 'list' ); if ( 'excerpt' === $mode ) { $always_visible = true; } $output .= '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">'; $i = 0; foreach ( $actions as $action => $link ) { ++$i; if ( ( ( 'approve' === $action || 'unapprove' === $action ) && 2 === $i ) || 1 === $i ) { $separator = ''; } else { $separator = ' | '; } // Reply and quickedit need a hide-if-no-js span when not added with Ajax. if ( ( 'reply' === $action || 'quickedit' === $action ) && ! wp_doing_ajax() ) { $action .= ' hide-if-no-js'; } elseif ( ( 'untrash' === $action && 'trash' === $the_comment_status ) || ( 'unspam' === $action && 'spam' === $the_comment_status ) ) { if ( '1' === get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true ) ) { $action .= ' approve'; } else { $action .= ' unapprove'; } } $output .= "<span class='$action'>{$separator}{$link}</span>"; } $output .= '</div>'; $output .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Show more details' ) . '</span></button>'; return $output; } /** * Outputs the checkbox column. * * @since 5.9.0 Renamed `$comment` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Comment $item The comment object. */ public function column_cb( $item ) { // Restores the more descriptive, specific name for use within this method. $comment = $item; if ( $this->user_can ) { ?> <input id="cb-select-<?php echo $comment->comment_ID; ?>" type="checkbox" name="delete_comments[]" value="<?php echo $comment->comment_ID; ?>" /> <label for="cb-select-<?php echo $comment->comment_ID; ?>"> <span class="screen-reader-text"> <?php /* translators: Hidden accessibility text. */ _e( 'Select comment' ); ?> </span> </label> <?php } } /** * Outputs the comment column. * * @param WP_Comment $comment The comment object. */ public function column_comment( $comment ) { echo '<div class="comment-author">'; $this->column_author( $comment ); echo '</div>'; if ( $comment->comment_parent ) { $parent = get_comment( $comment->comment_parent ); if ( $parent ) { $parent_link = esc_url( get_comment_link( $parent ) ); $name = get_comment_author( $parent ); printf( /* translators: %s: Comment link. */ __( 'In reply to %s.' ), '<a href="' . $parent_link . '">' . $name . '</a>' ); } } comment_text( $comment ); if ( $this->user_can ) { /** This filter is documented in wp-admin/includes/comment.php */ $comment_content = apply_filters( 'comment_edit_pre', $comment->comment_content ); ?> <div id="inline-<?php echo $comment->comment_ID; ?>" class="hidden"> <textarea class="comment" rows="1" cols="1"><?php echo esc_textarea( $comment_content ); ?></textarea> <div class="author-email"><?php echo esc_html( $comment->comment_author_email ); ?></div> <div class="author"><?php echo esc_html( $comment->comment_author ); ?></div> <div class="author-url"><?php echo esc_url( $comment->comment_author_url ); ?></div> <div class="comment_status"><?php echo $comment->comment_approved; ?></div> </div> <?php } } /** * Outputs the author column. * * @global string $comment_status The current comment status. * * @param WP_Comment $comment The comment object. */ public function column_author( $comment ) { global $comment_status; $author_url = get_comment_author_url( $comment ); $author_url_display = untrailingslashit( preg_replace( '|^http(s)?://(www\.)?|i', '', $author_url ) ); if ( strlen( $author_url_display ) > 50 ) { $author_url_display = wp_html_excerpt( $author_url_display, 49, '…' ); } echo '<strong>'; comment_author( $comment ); echo '</strong><br />'; if ( ! empty( $author_url_display ) ) { // Print link to author URL, and disallow referrer information (without using target="_blank"). printf( '<a href="%s" rel="noopener noreferrer">%s</a><br />', esc_url( $author_url ), esc_html( $author_url_display ) ); } if ( $this->user_can ) { if ( ! empty( $comment->comment_author_email ) ) { /** This filter is documented in wp-includes/comment-template.php */ $email = apply_filters( 'comment_email', $comment->comment_author_email, $comment ); if ( ! empty( $email ) && '@' !== $email ) { printf( '<a href="%1$s">%2$s</a><br />', esc_url( 'mailto:' . $email ), esc_html( $email ) ); } } $author_ip = get_comment_author_IP( $comment ); if ( $author_ip ) { $author_ip_url = add_query_arg( array( 's' => $author_ip, 'mode' => 'detail', ), admin_url( 'edit-comments.php' ) ); if ( 'spam' === $comment_status ) { $author_ip_url = add_query_arg( 'comment_status', 'spam', $author_ip_url ); } printf( '<a href="%1$s">%2$s</a>', esc_url( $author_ip_url ), esc_html( $author_ip ) ); } } } /** * Outputs the date column. * * @param WP_Comment $comment The comment object. */ public function column_date( $comment ) { $submitted = sprintf( /* translators: 1: Comment date, 2: Comment time. */ __( '%1$s at %2$s' ), /* translators: Comment date format. See https://www.php.net/manual/datetime.format.php */ get_comment_date( __( 'Y/m/d' ), $comment ), /* translators: Comment time format. See https://www.php.net/manual/datetime.format.php */ get_comment_date( __( 'g:i a' ), $comment ) ); echo '<div class="submitted-on">'; if ( 'approved' === wp_get_comment_status( $comment ) && ! empty( $comment->comment_post_ID ) ) { printf( '<a href="%s">%s</a>', esc_url( get_comment_link( $comment ) ), $submitted ); } else { echo $submitted; } echo '</div>'; } /** * Outputs the response column. * * @param WP_Comment $comment The comment object. */ public function column_response( $comment ) { $post = get_post(); if ( ! $post ) { return; } if ( isset( $this->pending_count[ $post->ID ] ) ) { $pending_comments = $this->pending_count[ $post->ID ]; } else { $_pending_count_temp = get_pending_comments_num( array( $post->ID ) ); $pending_comments = $_pending_count_temp[ $post->ID ]; $this->pending_count[ $post->ID ] = $pending_comments; } if ( current_user_can( 'edit_post', $post->ID ) ) { $post_link = "<a href='" . get_edit_post_link( $post->ID ) . "' class='comments-edit-item-link'>"; $post_link .= esc_html( get_the_title( $post->ID ) ) . '</a>'; } else { $post_link = esc_html( get_the_title( $post->ID ) ); } echo '<div class="response-links">'; if ( 'attachment' === $post->post_type ) { $thumb = wp_get_attachment_image( $post->ID, array( 80, 60 ), true ); if ( $thumb ) { echo $thumb; } } echo $post_link; $post_type_object = get_post_type_object( $post->post_type ); echo "<a href='" . get_permalink( $post->ID ) . "' class='comments-view-item-link'>" . $post_type_object->labels->view_item . '</a>'; echo '<span class="post-com-count-wrapper post-com-count-', $post->ID, '">'; $this->comments_bubble( $post->ID, $pending_comments ); echo '</span> '; echo '</div>'; } /** * Outputs the default column. * * @since 5.9.0 Renamed `$comment` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Comment $item The comment object. * @param string $column_name The custom column's name. */ public function column_default( $item, $column_name ) { // Restores the more descriptive, specific name for use within this method. $comment = $item; /** * Fires when the default column output is displayed for a single row. * * @since 2.8.0 * * @param string $column_name The custom column's name. * @param string $comment_id The comment ID as a numeric string. */ do_action( 'manage_comments_custom_column', $column_name, $comment->comment_ID ); } } PK $��\��L�- �- bookmark.phpnu �[��� <?php /** * WordPress Bookmark Administration API * * @package WordPress * @subpackage Administration */ /** * Adds a link using values provided in $_POST. * * @since 2.0.0 * * @return int The link ID on success. The value 0 on failure. */ function add_link() { return edit_link(); } /** * Updates or inserts a link using values provided in $_POST. * * @since 2.0.0 * * @param int $link_id Optional. ID of the link to edit. Default 0. * @return int The link ID on success. The value 0 on failure. */ function edit_link( $link_id = 0 ) { if ( ! current_user_can( 'manage_links' ) ) { wp_die( '<h1>' . __( 'You need a higher level of permission.' ) . '</h1>' . '<p>' . __( 'Sorry, you are not allowed to edit the links for this site.' ) . '</p>', 403 ); } $_POST['link_url'] = esc_url( $_POST['link_url'] ); $_POST['link_name'] = esc_html( $_POST['link_name'] ); $_POST['link_image'] = esc_html( $_POST['link_image'] ); $_POST['link_rss'] = esc_url( $_POST['link_rss'] ); if ( ! isset( $_POST['link_visible'] ) || 'N' !== $_POST['link_visible'] ) { $_POST['link_visible'] = 'Y'; } if ( ! empty( $link_id ) ) { $_POST['link_id'] = $link_id; return wp_update_link( $_POST ); } else { return wp_insert_link( $_POST ); } } /** * Retrieves the default link for editing. * * @since 2.0.0 * * @return stdClass Default link object. */ function get_default_link_to_edit() { $link = new stdClass(); if ( isset( $_GET['linkurl'] ) ) { $link->link_url = esc_url( wp_unslash( $_GET['linkurl'] ) ); } else { $link->link_url = ''; } if ( isset( $_GET['name'] ) ) { $link->link_name = esc_attr( wp_unslash( $_GET['name'] ) ); } else { $link->link_name = ''; } $link->link_visible = 'Y'; return $link; } /** * Deletes a specified link from the database. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $link_id ID of the link to delete. * @return true Always true. */ function wp_delete_link( $link_id ) { global $wpdb; /** * Fires before a link is deleted. * * @since 2.0.0 * * @param int $link_id ID of the link to delete. */ do_action( 'delete_link', $link_id ); wp_delete_object_term_relationships( $link_id, 'link_category' ); $wpdb->delete( $wpdb->links, array( 'link_id' => $link_id ) ); /** * Fires after a link has been deleted. * * @since 2.2.0 * * @param int $link_id ID of the deleted link. */ do_action( 'deleted_link', $link_id ); clean_bookmark_cache( $link_id ); return true; } /** * Retrieves the link category IDs associated with the link specified. * * @since 2.1.0 * * @param int $link_id Link ID to look up. * @return int[] The IDs of the requested link's categories. */ function wp_get_link_cats( $link_id = 0 ) { $cats = wp_get_object_terms( $link_id, 'link_category', array( 'fields' => 'ids' ) ); return array_unique( $cats ); } /** * Retrieves link data based on its ID. * * @since 2.0.0 * * @param int|stdClass $link Link ID or object to retrieve. * @return object Link object for editing. */ function get_link_to_edit( $link ) { return get_bookmark( $link, OBJECT, 'edit' ); } /** * Inserts a link into the database, or updates an existing link. * * Runs all the necessary sanitizing, provides default values if arguments are missing, * and finally saves the link. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param array $linkdata { * Elements that make up the link to insert. * * @type int $link_id Optional. The ID of the existing link if updating. * @type string $link_url The URL the link points to. * @type string $link_name The title of the link. * @type string $link_image Optional. A URL of an image. * @type string $link_target Optional. The target element for the anchor tag. * @type string $link_description Optional. A short description of the link. * @type string $link_visible Optional. 'Y' means visible, anything else means not. * @type int $link_owner Optional. A user ID. * @type int $link_rating Optional. A rating for the link. * @type string $link_rel Optional. A relationship of the link to you. * @type string $link_notes Optional. An extended description of or notes on the link. * @type string $link_rss Optional. A URL of an associated RSS feed. * @type int $link_category Optional. The term ID of the link category. * If empty, uses default link category. * } * @param bool $wp_error Optional. Whether to return a WP_Error object on failure. Default false. * @return int|WP_Error The link ID on success. The value 0 or WP_Error on failure. */ function wp_insert_link( $linkdata, $wp_error = false ) { global $wpdb; $defaults = array( 'link_id' => 0, 'link_name' => '', 'link_url' => '', 'link_rating' => 0, ); $parsed_args = wp_parse_args( $linkdata, $defaults ); $parsed_args = wp_unslash( sanitize_bookmark( $parsed_args, 'db' ) ); $link_id = $parsed_args['link_id']; $link_name = $parsed_args['link_name']; $link_url = $parsed_args['link_url']; $update = false; if ( ! empty( $link_id ) ) { $update = true; } if ( '' === trim( $link_name ) ) { if ( '' !== trim( $link_url ) ) { $link_name = $link_url; } else { return 0; } } if ( '' === trim( $link_url ) ) { return 0; } $link_rating = ( ! empty( $parsed_args['link_rating'] ) ) ? $parsed_args['link_rating'] : 0; $link_image = ( ! empty( $parsed_args['link_image'] ) ) ? $parsed_args['link_image'] : ''; $link_target = ( ! empty( $parsed_args['link_target'] ) ) ? $parsed_args['link_target'] : ''; $link_visible = ( ! empty( $parsed_args['link_visible'] ) ) ? $parsed_args['link_visible'] : 'Y'; $link_owner = ( ! empty( $parsed_args['link_owner'] ) ) ? $parsed_args['link_owner'] : get_current_user_id(); $link_notes = ( ! empty( $parsed_args['link_notes'] ) ) ? $parsed_args['link_notes'] : ''; $link_description = ( ! empty( $parsed_args['link_description'] ) ) ? $parsed_args['link_description'] : ''; $link_rss = ( ! empty( $parsed_args['link_rss'] ) ) ? $parsed_args['link_rss'] : ''; $link_rel = ( ! empty( $parsed_args['link_rel'] ) ) ? $parsed_args['link_rel'] : ''; $link_category = ( ! empty( $parsed_args['link_category'] ) ) ? $parsed_args['link_category'] : array(); $link_updated = gmdate( 'Y-m-d H:i:s', current_time( 'timestamp', 0 ) ); // Make sure we set a valid category. if ( ! is_array( $link_category ) || 0 === count( $link_category ) ) { $link_category = array( get_option( 'default_link_category' ) ); } if ( $update ) { if ( false === $wpdb->update( $wpdb->links, compact( 'link_url', 'link_name', 'link_image', 'link_target', 'link_description', 'link_visible', 'link_owner', 'link_rating', 'link_rel', 'link_notes', 'link_rss', 'link_updated' ), compact( 'link_id' ) ) ) { if ( $wp_error ) { return new WP_Error( 'db_update_error', __( 'Could not update link in the database.' ), $wpdb->last_error ); } else { return 0; } } } else { if ( false === $wpdb->insert( $wpdb->links, compact( 'link_url', 'link_name', 'link_image', 'link_target', 'link_description', 'link_visible', 'link_owner', 'link_rating', 'link_rel', 'link_notes', 'link_rss', 'link_updated' ) ) ) { if ( $wp_error ) { return new WP_Error( 'db_insert_error', __( 'Could not insert link into the database.' ), $wpdb->last_error ); } else { return 0; } } $link_id = (int) $wpdb->insert_id; } wp_set_link_cats( $link_id, $link_category ); if ( $update ) { /** * Fires after a link was updated in the database. * * @since 2.0.0 * * @param int $link_id ID of the link that was updated. */ do_action( 'edit_link', $link_id ); } else { /** * Fires after a link was added to the database. * * @since 2.0.0 * * @param int $link_id ID of the link that was added. */ do_action( 'add_link', $link_id ); } clean_bookmark_cache( $link_id ); return $link_id; } /** * Updates link with the specified link categories. * * @since 2.1.0 * * @param int $link_id ID of the link to update. * @param int[] $link_categories Array of link category IDs to add the link to. */ function wp_set_link_cats( $link_id = 0, $link_categories = array() ) { // If $link_categories isn't already an array, make it one: if ( ! is_array( $link_categories ) || 0 === count( $link_categories ) ) { $link_categories = array( get_option( 'default_link_category' ) ); } $link_categories = array_map( 'intval', $link_categories ); $link_categories = array_unique( $link_categories ); wp_set_object_terms( $link_id, $link_categories, 'link_category' ); clean_bookmark_cache( $link_id ); } /** * Updates a link in the database. * * @since 2.0.0 * * @param array $linkdata Link data to update. See wp_insert_link() for accepted arguments. * @return int The updated link ID on success. The value 0 on failure. */ function wp_update_link( $linkdata ) { $link_id = (int) $linkdata['link_id']; $link = get_bookmark( $link_id, ARRAY_A ); // Escape data pulled from DB. $link = wp_slash( $link ); // Passed link category list overwrites existing category list if not empty. if ( isset( $linkdata['link_category'] ) && is_array( $linkdata['link_category'] ) && count( $linkdata['link_category'] ) > 0 ) { $link_cats = $linkdata['link_category']; } else { $link_cats = $link['link_category']; } // Merge old and new fields with new fields overwriting old ones. $linkdata = array_merge( $link, $linkdata ); $linkdata['link_category'] = $link_cats; return wp_insert_link( $linkdata ); } /** * Outputs the 'disabled' message for the WordPress Link Manager. * * @since 3.5.0 * @access private * * @global string $pagenow The filename of the current screen. */ function wp_link_manager_disabled_message() { global $pagenow; if ( ! in_array( $pagenow, array( 'link-manager.php', 'link-add.php', 'link.php' ), true ) ) { return; } add_filter( 'pre_option_link_manager_enabled', '__return_true', 100 ); $really_can_manage_links = current_user_can( 'manage_links' ); remove_filter( 'pre_option_link_manager_enabled', '__return_true', 100 ); if ( $really_can_manage_links ) { $plugins = get_plugins(); if ( empty( $plugins['link-manager/link-manager.php'] ) ) { if ( current_user_can( 'install_plugins' ) ) { $install_url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=link-manager' ), 'install-plugin_link-manager' ); wp_die( sprintf( /* translators: %s: A link to install the Link Manager plugin. */ __( 'If you are looking to use the link manager, please install the <a href="%s">Link Manager plugin</a>.' ), esc_url( $install_url ) ) ); } } elseif ( is_plugin_inactive( 'link-manager/link-manager.php' ) ) { if ( current_user_can( 'activate_plugins' ) ) { $activate_url = wp_nonce_url( self_admin_url( 'plugins.php?action=activate&plugin=link-manager/link-manager.php' ), 'activate-plugin_link-manager/link-manager.php' ); wp_die( sprintf( /* translators: %s: A link to activate the Link Manager plugin. */ __( 'Please activate the <a href="%s">Link Manager plugin</a> to use the link manager.' ), esc_url( $activate_url ) ) ); } } } wp_die( __( 'Sorry, you are not allowed to edit the links for this site.' ) ); } PK $��\�;��� �� plugin-install.phpnu �[��� <?php /** * WordPress Plugin Install Administration API * * @package WordPress * @subpackage Administration */ /** * Retrieves plugin installer pages from the WordPress.org Plugins API. * * It is possible for a plugin to override the Plugin API result with three * filters. Assume this is for plugins, which can extend on the Plugin Info to * offer more choices. This is very powerful and must be used with care when * overriding the filters. * * The first filter, {@see 'plugins_api_args'}, is for the args and gives the action * as the second parameter. The hook for {@see 'plugins_api_args'} must ensure that * an object is returned. * * The second filter, {@see 'plugins_api'}, allows a plugin to override the WordPress.org * Plugin Installation API entirely. If `$action` is 'query_plugins' or 'plugin_information', * an object MUST be passed. If `$action` is 'hot_tags', an array MUST be passed. * * Finally, the third filter, {@see 'plugins_api_result'}, makes it possible to filter the * response object or array, depending on the `$action` type. * * Supported arguments per action: * * | Argument Name | query_plugins | plugin_information | hot_tags | * | -------------------- | :-----------: | :----------------: | :------: | * | `$slug` | No | Yes | No | * | `$per_page` | Yes | No | No | * | `$page` | Yes | No | No | * | `$number` | No | No | Yes | * | `$search` | Yes | No | No | * | `$tag` | Yes | No | No | * | `$author` | Yes | No | No | * | `$user` | Yes | No | No | * | `$browse` | Yes | No | No | * | `$locale` | Yes | Yes | No | * | `$installed_plugins` | Yes | No | No | * | `$is_ssl` | Yes | Yes | No | * | `$fields` | Yes | Yes | No | * * @since 2.7.0 * * @param string $action API action to perform: 'query_plugins', 'plugin_information', * or 'hot_tags'. * @param array|object $args { * Optional. Array or object of arguments to serialize for the Plugin Info API. * * @type string $slug The plugin slug. Default empty. * @type int $per_page Number of plugins per page. Default 24. * @type int $page Number of current page. Default 1. * @type int $number Number of tags or categories to be queried. * @type string $search A search term. Default empty. * @type string $tag Tag to filter plugins. Default empty. * @type string $author Username of an plugin author to filter plugins. Default empty. * @type string $user Username to query for their favorites. Default empty. * @type string $browse Browse view: 'popular', 'new', 'beta', 'recommended'. * @type string $locale Locale to provide context-sensitive results. Default is the value * of get_locale(). * @type string $installed_plugins Installed plugins to provide context-sensitive results. * @type bool $is_ssl Whether links should be returned with https or not. Default false. * @type array $fields { * Array of fields which should or should not be returned. * * @type bool $short_description Whether to return the plugin short description. Default true. * @type bool $description Whether to return the plugin full description. Default false. * @type bool $sections Whether to return the plugin readme sections: description, installation, * FAQ, screenshots, other notes, and changelog. Default false. * @type bool $tested Whether to return the 'Compatible up to' value. Default true. * @type bool $requires Whether to return the required WordPress version. Default true. * @type bool $requires_php Whether to return the required PHP version. Default true. * @type bool $rating Whether to return the rating in percent and total number of ratings. * Default true. * @type bool $ratings Whether to return the number of rating for each star (1-5). Default true. * @type bool $downloaded Whether to return the download count. Default true. * @type bool $downloadlink Whether to return the download link for the package. Default true. * @type bool $last_updated Whether to return the date of the last update. Default true. * @type bool $added Whether to return the date when the plugin was added to the wordpress.org * repository. Default true. * @type bool $tags Whether to return the assigned tags. Default true. * @type bool $compatibility Whether to return the WordPress compatibility list. Default true. * @type bool $homepage Whether to return the plugin homepage link. Default true. * @type bool $versions Whether to return the list of all available versions. Default false. * @type bool $donate_link Whether to return the donation link. Default true. * @type bool $reviews Whether to return the plugin reviews. Default false. * @type bool $banners Whether to return the banner images links. Default false. * @type bool $icons Whether to return the icon links. Default false. * @type bool $active_installs Whether to return the number of active installations. Default false. * @type bool $contributors Whether to return the list of contributors. Default false. * } * } * @return object|array|WP_Error Response object or array on success, WP_Error on failure. See the * {@link https://developer.wordpress.org/reference/functions/plugins_api/ function reference article} * for more information on the make-up of possible return values depending on the value of `$action`. */ function plugins_api( $action, $args = array() ) { if ( is_array( $args ) ) { $args = (object) $args; } if ( 'query_plugins' === $action ) { if ( ! isset( $args->per_page ) ) { $args->per_page = 24; } } if ( ! isset( $args->locale ) ) { $args->locale = get_user_locale(); } if ( ! isset( $args->wp_version ) ) { $args->wp_version = substr( wp_get_wp_version(), 0, 3 ); // x.y } /** * Filters the WordPress.org Plugin Installation API arguments. * * Important: An object MUST be returned to this filter. * * @since 2.7.0 * * @param object $args Plugin API arguments. * @param string $action The type of information being requested from the Plugin Installation API. */ $args = apply_filters( 'plugins_api_args', $args, $action ); /** * Filters the response for the current WordPress.org Plugin Installation API request. * * Returning a non-false value will effectively short-circuit the WordPress.org API request. * * If `$action` is 'query_plugins' or 'plugin_information', an object MUST be passed. * If `$action` is 'hot_tags', an array should be passed. * * @since 2.7.0 * * @param false|object|array $result The result object or array. Default false. * @param string $action The type of information being requested from the Plugin Installation API. * @param object $args Plugin API arguments. */ $res = apply_filters( 'plugins_api', false, $action, $args ); if ( false === $res ) { $url = 'http://api.wordpress.org/plugins/info/1.2/'; $url = add_query_arg( array( 'action' => $action, 'request' => $args, ), $url ); $http_url = $url; $ssl = wp_http_supports( array( 'ssl' ) ); if ( $ssl ) { $url = set_url_scheme( $url, 'https' ); } $http_args = array( 'timeout' => 15, 'user-agent' => 'WordPress/' . wp_get_wp_version() . '; ' . home_url( '/' ), ); $request = wp_remote_get( $url, $http_args ); if ( $ssl && is_wp_error( $request ) ) { if ( ! wp_is_json_request() ) { wp_trigger_error( __FUNCTION__, sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), __( 'https://wordpress.org/support/forums/' ) ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE ); } $request = wp_remote_get( $http_url, $http_args ); } if ( is_wp_error( $request ) ) { $res = new WP_Error( 'plugins_api_failed', sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), __( 'https://wordpress.org/support/forums/' ) ), $request->get_error_message() ); } else { $res = json_decode( wp_remote_retrieve_body( $request ), true ); if ( is_array( $res ) ) { // Object casting is required in order to match the info/1.0 format. $res = (object) $res; } elseif ( null === $res ) { $res = new WP_Error( 'plugins_api_failed', sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), __( 'https://wordpress.org/support/forums/' ) ), wp_remote_retrieve_body( $request ) ); } if ( isset( $res->error ) ) { $res = new WP_Error( 'plugins_api_failed', $res->error ); } } } elseif ( ! is_wp_error( $res ) ) { $res->external = true; } /** * Filters the Plugin Installation API response results. * * @since 2.7.0 * * @param object|WP_Error $res Response object or WP_Error. * @param string $action The type of information being requested from the Plugin Installation API. * @param object $args Plugin API arguments. */ return apply_filters( 'plugins_api_result', $res, $action, $args ); } /** * Retrieves popular WordPress plugin tags. * * @since 2.7.0 * * @param array $args * @return array|WP_Error */ function install_popular_tags( $args = array() ) { $key = md5( serialize( $args ) ); $tags = get_site_transient( 'poptags_' . $key ); if ( false !== $tags ) { return $tags; } $tags = plugins_api( 'hot_tags', $args ); if ( is_wp_error( $tags ) ) { return $tags; } set_site_transient( 'poptags_' . $key, $tags, 3 * HOUR_IN_SECONDS ); return $tags; } /** * Displays the Featured tab of Add Plugins screen. * * @since 2.7.0 */ function install_dashboard() { display_plugins_table(); ?> <div class="plugins-popular-tags-wrapper"> <h2><?php _e( 'Popular tags' ); ?></h2> <p><?php _e( 'You may also browse based on the most popular tags in the Plugin Directory:' ); ?></p> <?php $api_tags = install_popular_tags(); echo '<p class="popular-tags">'; if ( is_wp_error( $api_tags ) ) { echo $api_tags->get_error_message(); } else { // Set up the tags in a way which can be interpreted by wp_generate_tag_cloud(). $tags = array(); foreach ( (array) $api_tags as $tag ) { $url = self_admin_url( 'plugin-install.php?tab=search&type=tag&s=' . urlencode( $tag['name'] ) ); $data = array( 'link' => esc_url( $url ), 'name' => $tag['name'], 'slug' => $tag['slug'], 'id' => sanitize_title_with_dashes( $tag['name'] ), 'count' => $tag['count'], ); $tags[ $tag['name'] ] = (object) $data; } echo wp_generate_tag_cloud( $tags, array( /* translators: %s: Number of plugins. */ 'single_text' => __( '%s plugin' ), /* translators: %s: Number of plugins. */ 'multiple_text' => __( '%s plugins' ), ) ); } echo '</p><br class="clear" /></div>'; } /** * Displays a search form for searching plugins. * * @since 2.7.0 * @since 4.6.0 The `$type_selector` parameter was deprecated. * * @param bool $deprecated Not used. */ function install_search_form( $deprecated = true ) { $type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term'; $term = isset( $_REQUEST['s'] ) ? urldecode( wp_unslash( $_REQUEST['s'] ) ) : ''; ?> <form class="search-form search-plugins" method="get"> <input type="hidden" name="tab" value="search" /> <label for="search-plugins"><?php _e( 'Search Plugins' ); ?></label> <input type="search" name="s" id="search-plugins" value="<?php echo esc_attr( $term ); ?>" class="wp-filter-search" /> <label class="screen-reader-text" for="typeselector"> <?php /* translators: Hidden accessibility text. */ _e( 'Search plugins by:' ); ?> </label> <select name="type" id="typeselector"> <option value="term"<?php selected( 'term', $type ); ?>><?php _e( 'Keyword' ); ?></option> <option value="author"<?php selected( 'author', $type ); ?>><?php _e( 'Author' ); ?></option> <option value="tag"<?php selected( 'tag', $type ); ?>><?php _ex( 'Tag', 'Plugin Installer' ); ?></option> </select> <?php submit_button( __( 'Search Plugins' ), 'hide-if-js', false, false, array( 'id' => 'search-submit' ) ); ?> </form> <?php } /** * Displays a form to upload plugins from zip files. * * @since 2.8.0 */ function install_plugins_upload() { ?> <div class="upload-plugin"> <p class="install-help"><?php _e( 'If you have a plugin in a .zip format, you may install or update it by uploading it here.' ); ?></p> <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo esc_url( self_admin_url( 'update.php?action=upload-plugin' ) ); ?>"> <?php wp_nonce_field( 'plugin-upload' ); ?> <label class="screen-reader-text" for="pluginzip"> <?php /* translators: Hidden accessibility text. */ _e( 'Plugin zip file' ); ?> </label> <input type="file" id="pluginzip" name="pluginzip" accept=".zip" /> <?php submit_button( _x( 'Install Now', 'plugin' ), '', 'install-plugin-submit', false ); ?> </form> </div> <?php } /** * Shows a username form for the favorites page. * * @since 3.5.0 */ function install_plugins_favorites_form() { $user = get_user_option( 'wporg_favorites' ); $action = 'save_wporg_username_' . get_current_user_id(); ?> <p><?php _e( 'If you have marked plugins as favorites on WordPress.org, you can browse them here.' ); ?></p> <form method="get"> <input type="hidden" name="tab" value="favorites" /> <p> <label for="user"><?php _e( 'Your WordPress.org username:' ); ?></label> <input type="search" id="user" name="user" value="<?php echo esc_attr( $user ); ?>" /> <input type="submit" class="button" value="<?php esc_attr_e( 'Get Favorites' ); ?>" /> <input type="hidden" id="wporg-username-nonce" name="_wpnonce" value="<?php echo esc_attr( wp_create_nonce( $action ) ); ?>" /> </p> </form> <?php } /** * Displays plugin content based on plugin list. * * @since 2.7.0 * * @global WP_List_Table $wp_list_table */ function display_plugins_table() { global $wp_list_table; switch ( current_filter() ) { case 'install_plugins_beta': printf( /* translators: %s: URL to "Features as Plugins" page. */ '<p>' . __( 'You are using a development version of WordPress. These feature plugins are also under development. <a href="%s">Learn more</a>.' ) . '</p>', 'https://make.wordpress.org/core/handbook/about/release-cycle/features-as-plugins/' ); break; case 'install_plugins_featured': echo '<br>'; break; case 'install_plugins_recommended': echo '<p>' . __( 'These suggestions are based on the plugins you and other users have installed.' ) . '</p>'; break; case 'install_plugins_favorites': if ( empty( $_GET['user'] ) && ! get_user_option( 'wporg_favorites' ) ) { return; } break; } ?> <form id="plugin-filter" method="post"> <?php $wp_list_table->display(); ?> </form> <?php } /** * Determines the status we can perform on a plugin. * * @since 3.0.0 * * @param array|object $api Data about the plugin retrieved from the API. * @param bool $loop Optional. Disable further loops. Default false. * @return array { * Plugin installation status data. * * @type string $status Status of a plugin. Could be one of 'install', 'update_available', 'latest_installed' or 'newer_installed'. * @type string $url Plugin installation URL. * @type string $version The most recent version of the plugin. * @type string $file Plugin filename relative to the plugins directory. * } */ function install_plugin_install_status( $api, $loop = false ) { // This function is called recursively, $loop prevents further loops. if ( is_array( $api ) ) { $api = (object) $api; } // Default to a "new" plugin. $status = 'install'; $url = false; $update_file = false; $version = ''; /* * Check to see if this plugin is known to be installed, * and has an update awaiting it. */ $update_plugins = get_site_transient( 'update_plugins' ); if ( isset( $update_plugins->response ) ) { foreach ( (array) $update_plugins->response as $file => $plugin ) { if ( $plugin->slug === $api->slug ) { $status = 'update_available'; $update_file = $file; $version = $plugin->new_version; if ( current_user_can( 'update_plugins' ) ) { $url = wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' . $update_file ), 'upgrade-plugin_' . $update_file ); } break; } } } if ( 'install' === $status ) { if ( is_dir( WP_PLUGIN_DIR . '/' . $api->slug ) ) { $installed_plugin = get_plugins( '/' . $api->slug ); if ( empty( $installed_plugin ) ) { if ( current_user_can( 'install_plugins' ) ) { $url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $api->slug ), 'install-plugin_' . $api->slug ); } } else { $key = array_keys( $installed_plugin ); /* * Use the first plugin regardless of the name. * Could have issues for multiple plugins in one directory if they share different version numbers. */ $key = reset( $key ); $update_file = $api->slug . '/' . $key; if ( version_compare( $api->version, $installed_plugin[ $key ]['Version'], '=' ) ) { $status = 'latest_installed'; } elseif ( version_compare( $api->version, $installed_plugin[ $key ]['Version'], '<' ) ) { $status = 'newer_installed'; $version = $installed_plugin[ $key ]['Version']; } else { // If the above update check failed, then that probably means that the update checker has out-of-date information, force a refresh. if ( ! $loop ) { delete_site_transient( 'update_plugins' ); wp_update_plugins(); return install_plugin_install_status( $api, true ); } } } } else { // "install" & no directory with that slug. if ( current_user_can( 'install_plugins' ) ) { $url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $api->slug ), 'install-plugin_' . $api->slug ); } } } if ( isset( $_GET['from'] ) ) { $url .= '&from=' . urlencode( wp_unslash( $_GET['from'] ) ); } $file = $update_file; return compact( 'status', 'url', 'version', 'file' ); } /** * Displays plugin information in dialog box form. * * @since 2.7.0 * * @global string $tab */ function install_plugin_information() { global $tab; if ( empty( $_REQUEST['plugin'] ) ) { return; } $api = plugins_api( 'plugin_information', array( 'slug' => wp_unslash( $_REQUEST['plugin'] ), ) ); if ( is_wp_error( $api ) ) { wp_die( $api ); } $plugins_allowedtags = array( 'a' => array( 'href' => array(), 'title' => array(), 'target' => array(), ), 'abbr' => array( 'title' => array() ), 'acronym' => array( 'title' => array() ), 'code' => array(), 'pre' => array(), 'em' => array(), 'strong' => array(), 'div' => array( 'class' => array() ), 'span' => array( 'class' => array() ), 'p' => array(), 'br' => array(), 'ul' => array(), 'ol' => array(), 'li' => array(), 'h1' => array(), 'h2' => array(), 'h3' => array(), 'h4' => array(), 'h5' => array(), 'h6' => array(), 'img' => array( 'src' => array(), 'class' => array(), 'alt' => array(), ), 'blockquote' => array( 'cite' => true ), ); $plugins_section_titles = array( 'description' => _x( 'Description', 'Plugin installer section title' ), 'installation' => _x( 'Installation', 'Plugin installer section title' ), 'faq' => _x( 'FAQ', 'Plugin installer section title' ), 'screenshots' => _x( 'Screenshots', 'Plugin installer section title' ), 'changelog' => _x( 'Changelog', 'Plugin installer section title' ), 'reviews' => _x( 'Reviews', 'Plugin installer section title' ), 'other_notes' => _x( 'Other Notes', 'Plugin installer section title' ), ); // Sanitize HTML. foreach ( (array) $api->sections as $section_name => $content ) { $api->sections[ $section_name ] = wp_kses( $content, $plugins_allowedtags ); } foreach ( array( 'version', 'author', 'requires', 'tested', 'homepage', 'downloaded', 'slug' ) as $key ) { if ( isset( $api->$key ) ) { $api->$key = wp_kses( $api->$key, $plugins_allowedtags ); } } $_tab = esc_attr( $tab ); // Default to the Description tab, Do not translate, API returns English. $section = isset( $_REQUEST['section'] ) ? wp_unslash( $_REQUEST['section'] ) : 'description'; if ( empty( $section ) || ! isset( $api->sections[ $section ] ) ) { $section_titles = array_keys( (array) $api->sections ); $section = reset( $section_titles ); } iframe_header( __( 'Plugin Installation' ) ); $_with_banner = ''; if ( ! empty( $api->banners ) && ( ! empty( $api->banners['low'] ) || ! empty( $api->banners['high'] ) ) ) { $_with_banner = 'with-banner'; $low = empty( $api->banners['low'] ) ? $api->banners['high'] : $api->banners['low']; $high = empty( $api->banners['high'] ) ? $api->banners['low'] : $api->banners['high']; ?> <style> #plugin-information-title.with-banner { background-image: url( <?php echo esc_url( $low ); ?> ); } @media only screen and ( -webkit-min-device-pixel-ratio: 1.5 ) { #plugin-information-title.with-banner { background-image: url( <?php echo esc_url( $high ); ?> ); } } </style> <?php } echo '<div id="plugin-information-scrollable">'; echo "<div id='{$_tab}-title' class='{$_with_banner}'><div class='vignette'></div><h2>{$api->name}</h2></div>"; echo "<div id='{$_tab}-tabs' class='{$_with_banner}'>\n"; foreach ( (array) $api->sections as $section_name => $content ) { if ( 'reviews' === $section_name && ( empty( $api->ratings ) || 0 === array_sum( (array) $api->ratings ) ) ) { continue; } if ( isset( $plugins_section_titles[ $section_name ] ) ) { $title = $plugins_section_titles[ $section_name ]; } else { $title = ucwords( str_replace( '_', ' ', $section_name ) ); } $class = ( $section_name === $section ) ? ' class="current"' : ''; $href = add_query_arg( array( 'tab' => $tab, 'section' => $section_name, ) ); $href = esc_url( $href ); $san_section = esc_attr( $section_name ); echo "\t<a name='$san_section' href='$href' $class>$title</a>\n"; } echo "</div>\n"; ?> <div id="<?php echo $_tab; ?>-content" class='<?php echo $_with_banner; ?>'> <div class="fyi"> <ul> <?php if ( ! empty( $api->version ) ) { ?> <li><strong><?php _e( 'Version:' ); ?></strong> <?php echo $api->version; ?></li> <?php } if ( ! empty( $api->author ) ) { ?> <li><strong><?php _e( 'Author:' ); ?></strong> <?php echo links_add_target( $api->author, '_blank' ); ?></li> <?php } if ( ! empty( $api->last_updated ) ) { ?> <li><strong><?php _e( 'Last Updated:' ); ?></strong> <?php /* translators: %s: Human-readable time difference. */ printf( __( '%s ago' ), human_time_diff( strtotime( $api->last_updated ) ) ); ?> </li> <?php } if ( ! empty( $api->requires ) ) { ?> <li> <strong><?php _e( 'Requires WordPress Version:' ); ?></strong> <?php /* translators: %s: Version number. */ printf( __( '%s or higher' ), $api->requires ); ?> </li> <?php } if ( ! empty( $api->tested ) ) { ?> <li><strong><?php _e( 'Compatible up to:' ); ?></strong> <?php echo $api->tested; ?></li> <?php } if ( ! empty( $api->requires_php ) ) { ?> <li> <strong><?php _e( 'Requires PHP Version:' ); ?></strong> <?php /* translators: %s: Version number. */ printf( __( '%s or higher' ), $api->requires_php ); ?> </li> <?php } if ( isset( $api->active_installs ) ) { ?> <li><strong><?php _e( 'Active Installations:' ); ?></strong> <?php if ( $api->active_installs >= 1000000 ) { $active_installs_millions = floor( $api->active_installs / 1000000 ); printf( /* translators: %s: Number of millions. */ _nx( '%s+ Million', '%s+ Million', $active_installs_millions, 'Active plugin installations' ), number_format_i18n( $active_installs_millions ) ); } elseif ( $api->active_installs < 10 ) { _ex( 'Less Than 10', 'Active plugin installations' ); } else { echo number_format_i18n( $api->active_installs ) . '+'; } ?> </li> <?php } if ( ! empty( $api->slug ) && empty( $api->external ) ) { ?> <li><a target="_blank" href="<?php echo esc_url( __( 'https://wordpress.org/plugins/' ) . $api->slug ); ?>/"><?php _e( 'WordPress.org Plugin Page »' ); ?></a></li> <?php } if ( ! empty( $api->homepage ) ) { ?> <li><a target="_blank" href="<?php echo esc_url( $api->homepage ); ?>"><?php _e( 'Plugin Homepage »' ); ?></a></li> <?php } if ( ! empty( $api->donate_link ) && empty( $api->contributors ) ) { ?> <li><a target="_blank" href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin »' ); ?></a></li> <?php } ?> </ul> <?php if ( ! empty( $api->rating ) ) { ?> <h3><?php _e( 'Average Rating' ); ?></h3> <?php wp_star_rating( array( 'rating' => $api->rating, 'type' => 'percent', 'number' => $api->num_ratings, ) ); ?> <p aria-hidden="true" class="fyi-description"> <?php printf( /* translators: %s: Number of ratings. */ _n( '(based on %s rating)', '(based on %s ratings)', $api->num_ratings ), number_format_i18n( $api->num_ratings ) ); ?> </p> <?php } if ( ! empty( $api->ratings ) && array_sum( (array) $api->ratings ) > 0 ) { ?> <h3><?php _e( 'Reviews' ); ?></h3> <p class="fyi-description"><?php _e( 'Read all reviews on WordPress.org or write your own!' ); ?></p> <?php foreach ( $api->ratings as $key => $ratecount ) { // Avoid div-by-zero. $_rating = $api->num_ratings ? ( $ratecount / $api->num_ratings ) : 0; $aria_label = esc_attr( sprintf( /* translators: 1: Number of stars (used to determine singular/plural), 2: Number of reviews. */ _n( 'Reviews with %1$d star: %2$s. Opens in a new tab.', 'Reviews with %1$d stars: %2$s. Opens in a new tab.', $key ), $key, number_format_i18n( $ratecount ) ) ); ?> <div class="counter-container"> <span class="counter-label"> <?php printf( '<a href="%s" target="_blank" aria-label="%s">%s</a>', "https://wordpress.org/support/plugin/{$api->slug}/reviews/?filter={$key}", $aria_label, /* translators: %s: Number of stars. */ sprintf( _n( '%d star', '%d stars', $key ), $key ) ); ?> </span> <span class="counter-back"> <span class="counter-bar" style="width: <?php echo 92 * $_rating; ?>px;"></span> </span> <span class="counter-count" aria-hidden="true"><?php echo number_format_i18n( $ratecount ); ?></span> </div> <?php } } if ( ! empty( $api->contributors ) ) { ?> <h3><?php _e( 'Contributors' ); ?></h3> <ul class="contributors"> <?php foreach ( (array) $api->contributors as $contrib_username => $contrib_details ) { $contrib_name = $contrib_details['display_name']; if ( ! $contrib_name ) { $contrib_name = $contrib_username; } $contrib_name = esc_html( $contrib_name ); $contrib_profile = esc_url( $contrib_details['profile'] ); $contrib_avatar = esc_url( add_query_arg( 's', '36', $contrib_details['avatar'] ) ); echo "<li><a href='{$contrib_profile}' target='_blank'><img src='{$contrib_avatar}' width='18' height='18' alt='' />{$contrib_name}</a></li>"; } ?> </ul> <?php if ( ! empty( $api->donate_link ) ) { ?> <a target="_blank" href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin »' ); ?></a> <?php } ?> <?php } ?> </div> <div id="section-holder"> <?php $requires_php = $api->requires_php ?? null; $requires_wp = $api->requires ?? null; $compatible_php = is_php_version_compatible( $requires_php ); $compatible_wp = is_wp_version_compatible( $requires_wp ); $tested_wp = ( empty( $api->tested ) || version_compare( get_bloginfo( 'version' ), $api->tested, '<=' ) ); if ( ! $compatible_php ) { $compatible_php_notice_message = '<p>'; $compatible_php_notice_message .= __( '<strong>Error:</strong> This plugin <strong>requires a newer version of PHP</strong>.' ); if ( current_user_can( 'update_php' ) ) { $compatible_php_notice_message .= sprintf( /* translators: %s: URL to Update PHP page. */ ' ' . __( '<a href="%s" target="_blank">Click here to learn more about updating PHP</a>.' ), esc_url( wp_get_update_php_url() ) ) . wp_update_php_annotation( '</p><p><em>', '</em>', false ); } else { $compatible_php_notice_message .= '</p>'; } wp_admin_notice( $compatible_php_notice_message, array( 'type' => 'error', 'additional_classes' => array( 'notice-alt' ), 'paragraph_wrap' => false, ) ); } if ( ! $tested_wp ) { wp_admin_notice( __( '<strong>Warning:</strong> This plugin <strong>has not been tested</strong> with your current version of WordPress.' ), array( 'type' => 'warning', 'additional_classes' => array( 'notice-alt' ), ) ); } elseif ( ! $compatible_wp ) { $compatible_wp_notice_message = __( '<strong>Error:</strong> This plugin <strong>requires a newer version of WordPress</strong>.' ); if ( current_user_can( 'update_core' ) ) { $compatible_wp_notice_message .= sprintf( /* translators: %s: URL to WordPress Updates screen. */ ' ' . __( '<a href="%s" target="_parent">Click here to update WordPress</a>.' ), esc_url( self_admin_url( 'update-core.php' ) ) ); } wp_admin_notice( $compatible_wp_notice_message, array( 'type' => 'error', 'additional_classes' => array( 'notice-alt' ), ) ); } foreach ( (array) $api->sections as $section_name => $content ) { $content = links_add_base_url( $content, 'https://wordpress.org/plugins/' . $api->slug . '/' ); $content = links_add_target( $content, '_blank' ); $san_section = esc_attr( $section_name ); $display = ( $section_name === $section ) ? 'block' : 'none'; echo "\t<div id='section-{$san_section}' class='section' style='display: {$display};'>\n"; echo $content; echo "\t</div>\n"; } echo "</div>\n"; echo "</div>\n"; echo "</div>\n"; // #plugin-information-scrollable echo "<div id='$tab-footer'>\n"; if ( ! empty( $api->download_link ) && ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) ) { $button = wp_get_plugin_action_button( $api->name, $api, $compatible_php, $compatible_wp ); $button = str_replace( 'class="', 'class="right ', $button ); if ( ! str_contains( $button, _x( 'Activate', 'plugin' ) ) ) { $button = str_replace( 'class="', 'id="plugin_install_from_iframe" class="', $button ); } echo wp_kses_post( $button ); } echo "</div>\n"; wp_print_request_filesystem_credentials_modal(); wp_print_admin_notice_templates(); iframe_footer(); exit; } /** * Gets the markup for the plugin install action button. * * @since 6.5.0 * * @param string $name Plugin name. * @param array|object $data { * An array or object of plugin data. Can be retrieved from the API. * * @type string $slug The plugin slug. * @type string[] $requires_plugins An array of plugin dependency slugs. * @type string $version The plugin's version string. Used when getting the install status. * } * @param bool $compatible_php The result of a PHP compatibility check. * @param bool $compatible_wp The result of a WP compatibility check. * @return string The markup for the dependency row button. An empty string if the user does not have capabilities. */ function wp_get_plugin_action_button( $name, $data, $compatible_php, $compatible_wp ) { $button = ''; $data = (object) $data; $status = install_plugin_install_status( $data ); $requires_plugins = $data->requires_plugins ?? array(); // Determine the status of plugin dependencies. $installed_plugins = get_plugins(); $active_plugins = get_option( 'active_plugins', array() ); $plugin_dependencies_count = count( $requires_plugins ); $installed_plugin_dependencies_count = 0; $active_plugin_dependencies_count = 0; foreach ( $requires_plugins as $dependency ) { foreach ( array_keys( $installed_plugins ) as $installed_plugin_file ) { if ( str_contains( $installed_plugin_file, '/' ) && explode( '/', $installed_plugin_file )[0] === $dependency ) { ++$installed_plugin_dependencies_count; } } foreach ( $active_plugins as $active_plugin_file ) { if ( str_contains( $active_plugin_file, '/' ) && explode( '/', $active_plugin_file )[0] === $dependency ) { ++$active_plugin_dependencies_count; } } } $all_plugin_dependencies_installed = $installed_plugin_dependencies_count === $plugin_dependencies_count; $all_plugin_dependencies_active = $active_plugin_dependencies_count === $plugin_dependencies_count; if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) { switch ( $status['status'] ) { case 'install': if ( $status['url'] ) { if ( $compatible_php && $compatible_wp && $all_plugin_dependencies_installed && ! empty( $data->download_link ) ) { $button = sprintf( '<a class="install-now button button-compact" data-slug="%s" href="%s" aria-label="%s" data-name="%s" role="button">%s</a>', esc_attr( $data->slug ), esc_url( $status['url'] ), /* translators: %s: Plugin name and version. */ esc_attr( sprintf( _x( 'Install %s now', 'plugin' ), $name ) ), esc_attr( $name ), _x( 'Install Now', 'plugin' ) ); } else { $button = sprintf( '<button type="button" class="install-now button button-compact button-disabled" disabled="disabled">%s</button>', _x( 'Install Now', 'plugin' ) ); } } break; case 'update_available': if ( $status['url'] ) { if ( $compatible_php && $compatible_wp ) { $button = sprintf( '<a class="update-now button button-compact aria-button-if-js" data-plugin="%s" data-slug="%s" href="%s" aria-label="%s" data-name="%s" role="button">%s</a>', esc_attr( $status['file'] ), esc_attr( $data->slug ), esc_url( $status['url'] ), /* translators: %s: Plugin name and version. */ esc_attr( sprintf( _x( 'Update %s now', 'plugin' ), $name ) ), esc_attr( $name ), _x( 'Update Now', 'plugin' ) ); } else { $button = sprintf( '<button type="button" class="button button-compact button-disabled" disabled="disabled">%s</button>', _x( 'Update Now', 'plugin' ) ); } } break; case 'latest_installed': case 'newer_installed': if ( is_plugin_active( $status['file'] ) ) { $button = sprintf( '<button type="button" class="button button-compact button-disabled" disabled="disabled">%s</button>', _x( 'Active', 'plugin' ) ); } elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) { if ( $compatible_php && $compatible_wp && $all_plugin_dependencies_active ) { $button_text = _x( 'Activate', 'plugin' ); /* translators: %s: Plugin name. */ $button_label = _x( 'Activate %s', 'plugin' ); $activate_url = add_query_arg( array( '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ), 'action' => 'activate', 'plugin' => $status['file'], ), network_admin_url( 'plugins.php' ) ); if ( is_network_admin() ) { $button_text = _x( 'Network Activate', 'plugin' ); /* translators: %s: Plugin name. */ $button_label = _x( 'Network Activate %s', 'plugin' ); $activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url ); } $button = sprintf( '<a href="%1$s" data-name="%2$s" data-slug="%3$s" data-plugin="%4$s" class="button button-compact button-primary activate-now" aria-label="%5$s" role="button">%6$s</a>', esc_url( $activate_url ), esc_attr( $name ), esc_attr( $data->slug ), esc_attr( $status['file'] ), esc_attr( sprintf( $button_label, $name ) ), $button_text ); } else { $button = sprintf( '<button type="button" class="button button-compact button-disabled" disabled="disabled">%s</button>', is_network_admin() ? _x( 'Network Activate', 'plugin' ) : _x( 'Activate', 'plugin' ) ); } } else { $button = sprintf( '<button type="button" class="button button-compact button-disabled" disabled="disabled">%s</button>', _x( 'Installed', 'plugin' ) ); } break; } } return $button; } PK $��\�,��� � dashboard.phpnu �[��� <?php /** * WordPress Dashboard Widget Administration Screen API * * @package WordPress * @subpackage Administration */ /** * Registers dashboard widgets. * * Handles POST data, sets up filters. * * @since 2.5.0 * * @global array $wp_registered_widgets * @global array $wp_registered_widget_controls * @global callable[] $wp_dashboard_control_callbacks */ function wp_dashboard_setup() { global $wp_registered_widgets, $wp_registered_widget_controls, $wp_dashboard_control_callbacks; $screen = get_current_screen(); /* Register Widgets and Controls */ $wp_dashboard_control_callbacks = array(); // Browser version $check_browser = wp_check_browser_version(); if ( $check_browser && $check_browser['upgrade'] ) { add_filter( 'postbox_classes_dashboard_dashboard_browser_nag', 'dashboard_browser_nag_class' ); if ( $check_browser['insecure'] ) { wp_add_dashboard_widget( 'dashboard_browser_nag', __( 'You are using an insecure browser!' ), 'wp_dashboard_browser_nag' ); } else { wp_add_dashboard_widget( 'dashboard_browser_nag', __( 'Your browser is out of date!' ), 'wp_dashboard_browser_nag' ); } } // PHP Version. $check_php = wp_check_php_version(); if ( $check_php && current_user_can( 'update_php' ) ) { // If "not acceptable" the widget will be shown. if ( isset( $check_php['is_acceptable'] ) && ! $check_php['is_acceptable'] ) { add_filter( 'postbox_classes_dashboard_dashboard_php_nag', 'dashboard_php_nag_class' ); if ( $check_php['is_lower_than_future_minimum'] ) { wp_add_dashboard_widget( 'dashboard_php_nag', __( 'PHP Update Required' ), 'wp_dashboard_php_nag' ); } else { wp_add_dashboard_widget( 'dashboard_php_nag', __( 'PHP Update Recommended' ), 'wp_dashboard_php_nag' ); } } } // Site Health. if ( current_user_can( 'view_site_health_checks' ) && ! is_network_admin() ) { if ( ! class_exists( 'WP_Site_Health' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-site-health.php'; } WP_Site_Health::get_instance(); wp_enqueue_style( 'site-health' ); wp_enqueue_script( 'site-health' ); wp_add_dashboard_widget( 'dashboard_site_health', __( 'Site Health Status' ), 'wp_dashboard_site_health' ); } // Right Now. if ( is_blog_admin() && current_user_can( 'edit_posts' ) ) { wp_add_dashboard_widget( 'dashboard_right_now', __( 'At a Glance' ), 'wp_dashboard_right_now' ); } if ( is_network_admin() ) { wp_add_dashboard_widget( 'network_dashboard_right_now', __( 'Right Now' ), 'wp_network_dashboard_right_now' ); } // Activity Widget. if ( is_blog_admin() ) { wp_add_dashboard_widget( 'dashboard_activity', __( 'Activity' ), 'wp_dashboard_site_activity' ); } // QuickPress Widget. if ( is_blog_admin() && current_user_can( get_post_type_object( 'post' )->cap->create_posts ) ) { $quick_draft_title = sprintf( '<span class="hide-if-no-js">%1$s</span> <span class="hide-if-js">%2$s</span>', __( 'Quick Draft' ), __( 'Your Recent Drafts' ) ); wp_add_dashboard_widget( 'dashboard_quick_press', $quick_draft_title, 'wp_dashboard_quick_press' ); } // WordPress Events and News. wp_add_dashboard_widget( 'dashboard_primary', __( 'WordPress Events and News' ), 'wp_dashboard_events_news' ); if ( is_network_admin() ) { /** * Fires after core widgets for the Network Admin dashboard have been registered. * * @since 3.1.0 */ do_action( 'wp_network_dashboard_setup' ); /** * Filters the list of widgets to load for the Network Admin dashboard. * * @since 3.1.0 * * @param string[] $dashboard_widgets An array of dashboard widget IDs. */ $dashboard_widgets = apply_filters( 'wp_network_dashboard_widgets', array() ); } elseif ( is_user_admin() ) { /** * Fires after core widgets for the User Admin dashboard have been registered. * * @since 3.1.0 */ do_action( 'wp_user_dashboard_setup' ); /** * Filters the list of widgets to load for the User Admin dashboard. * * @since 3.1.0 * * @param string[] $dashboard_widgets An array of dashboard widget IDs. */ $dashboard_widgets = apply_filters( 'wp_user_dashboard_widgets', array() ); } else { /** * Fires after core widgets for the admin dashboard have been registered. * * @since 2.5.0 */ do_action( 'wp_dashboard_setup' ); /** * Filters the list of widgets to load for the admin dashboard. * * @since 2.5.0 * * @param string[] $dashboard_widgets An array of dashboard widget IDs. */ $dashboard_widgets = apply_filters( 'wp_dashboard_widgets', array() ); } foreach ( $dashboard_widgets as $widget_id ) { $name = empty( $wp_registered_widgets[ $widget_id ]['all_link'] ) ? $wp_registered_widgets[ $widget_id ]['name'] : $wp_registered_widgets[ $widget_id ]['name'] . " <a href='{$wp_registered_widgets[$widget_id]['all_link']}' class='edit-box open-box'>" . __( 'View all' ) . '</a>'; wp_add_dashboard_widget( $widget_id, $name, $wp_registered_widgets[ $widget_id ]['callback'], $wp_registered_widget_controls[ $widget_id ]['callback'] ); } if ( 'POST' === $_SERVER['REQUEST_METHOD'] && isset( $_POST['widget_id'] ) ) { check_admin_referer( 'edit-dashboard-widget_' . $_POST['widget_id'], 'dashboard-widget-nonce' ); ob_start(); // Hack - but the same hack wp-admin/widgets.php uses. wp_dashboard_trigger_widget_control( $_POST['widget_id'] ); ob_end_clean(); wp_redirect( remove_query_arg( 'edit' ) ); exit; } /** This action is documented in wp-admin/includes/meta-boxes.php */ do_action( 'do_meta_boxes', $screen->id, 'normal', '' ); /** This action is documented in wp-admin/includes/meta-boxes.php */ do_action( 'do_meta_boxes', $screen->id, 'side', '' ); } /** * Adds a new dashboard widget. * * @since 2.7.0 * @since 5.6.0 The `$context` and `$priority` parameters were added. * * @global callable[] $wp_dashboard_control_callbacks * * @param string $widget_id Widget ID (used in the 'id' attribute for the widget). * @param string $widget_name Title of the widget. * @param callable $callback Function that fills the widget with the desired content. * The function should echo its output. * @param callable $control_callback Optional. Function that outputs controls for the widget. Default null. * @param array $callback_args Optional. Data that should be set as the $args property of the widget array * (which is the second parameter passed to your callback). Default null. * @param string $context Optional. The context within the screen where the box should display. * Accepts 'normal', 'side', 'column3', or 'column4'. Default 'normal'. * @param string $priority Optional. The priority within the context where the box should show. * Accepts 'high', 'core', 'default', or 'low'. Default 'core'. */ function wp_add_dashboard_widget( $widget_id, $widget_name, $callback, $control_callback = null, $callback_args = null, $context = 'normal', $priority = 'core' ) { global $wp_dashboard_control_callbacks; $screen = get_current_screen(); $private_callback_args = array( '__widget_basename' => $widget_name ); if ( is_null( $callback_args ) ) { $callback_args = $private_callback_args; } elseif ( is_array( $callback_args ) ) { $callback_args = array_merge( $callback_args, $private_callback_args ); } if ( $control_callback && is_callable( $control_callback ) && current_user_can( 'edit_dashboard' ) ) { $wp_dashboard_control_callbacks[ $widget_id ] = $control_callback; if ( isset( $_GET['edit'] ) && $widget_id === $_GET['edit'] ) { list($url) = explode( '#', add_query_arg( 'edit', false ), 2 ); $widget_name .= ' <span class="postbox-title-action"><a href="' . esc_url( $url ) . '">' . __( 'Cancel' ) . '</a></span>'; $callback = '_wp_dashboard_control_callback'; } else { list($url) = explode( '#', add_query_arg( 'edit', $widget_id ), 2 ); $widget_name .= ' <span class="postbox-title-action"><a href="' . esc_url( "$url#$widget_id" ) . '" class="edit-box open-box">' . __( 'Configure' ) . '</a></span>'; } } $side_widgets = array( 'dashboard_quick_press', 'dashboard_primary' ); if ( in_array( $widget_id, $side_widgets, true ) ) { $context = 'side'; } $high_priority_widgets = array( 'dashboard_browser_nag', 'dashboard_php_nag' ); if ( in_array( $widget_id, $high_priority_widgets, true ) ) { $priority = 'high'; } if ( empty( $context ) ) { $context = 'normal'; } if ( empty( $priority ) ) { $priority = 'core'; } add_meta_box( $widget_id, $widget_name, $callback, $screen, $context, $priority, $callback_args ); } /** * Outputs controls for the current dashboard widget. * * @access private * @since 2.7.0 * * @param mixed $dashboard * @param array $meta_box */ function _wp_dashboard_control_callback( $dashboard, $meta_box ) { echo '<form method="post" class="dashboard-widget-control-form wp-clearfix">'; wp_dashboard_trigger_widget_control( $meta_box['id'] ); wp_nonce_field( 'edit-dashboard-widget_' . $meta_box['id'], 'dashboard-widget-nonce' ); echo '<input type="hidden" name="widget_id" value="' . esc_attr( $meta_box['id'] ) . '" />'; submit_button( __( 'Save Changes' ) ); echo '</form>'; } /** * Displays the dashboard. * * @since 2.5.0 */ function wp_dashboard() { $screen = get_current_screen(); $columns = absint( $screen->get_columns() ); $columns_css = ''; if ( $columns ) { $columns_css = " columns-$columns"; } ?> <div id="dashboard-widgets" class="metabox-holder<?php echo $columns_css; ?>"> <div id="postbox-container-1" class="postbox-container"> <?php do_meta_boxes( $screen->id, 'normal', '' ); ?> </div> <div id="postbox-container-2" class="postbox-container"> <?php do_meta_boxes( $screen->id, 'side', '' ); ?> </div> <div id="postbox-container-3" class="postbox-container"> <?php do_meta_boxes( $screen->id, 'column3', '' ); ?> </div> <div id="postbox-container-4" class="postbox-container"> <?php do_meta_boxes( $screen->id, 'column4', '' ); ?> </div> </div> <?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); } // // Dashboard Widgets. // /** * Dashboard widget that displays some basic stats about the site. * * Formerly 'Right Now'. A streamlined 'At a Glance' as of 3.8. * * @since 2.7.0 */ function wp_dashboard_right_now() { ?> <div class="main"> <ul> <?php // Posts and Pages. foreach ( array( 'post', 'page' ) as $post_type ) { $num_posts = wp_count_posts( $post_type ); if ( $num_posts && $num_posts->publish ) { if ( 'post' === $post_type ) { /* translators: %s: Number of posts. */ $text = _n( '%s Published post', '%s Published posts', $num_posts->publish ); } else { /* translators: %s: Number of pages. */ $text = _n( '%s Published page', '%s Published pages', $num_posts->publish ); } $text = sprintf( $text, number_format_i18n( $num_posts->publish ) ); $post_type_object = get_post_type_object( $post_type ); if ( $post_type_object && current_user_can( $post_type_object->cap->edit_posts ) ) { $url = add_query_arg( array( 'post_status' => 'publish', 'post_type' => $post_type, ), admin_url( 'edit.php' ) ); printf( '<li class="%1$s-count"><a href="%2$s">%3$s</a></li>', $post_type, esc_url( $url ), esc_html( $text ) ); } else { printf( '<li class="%1$s-count"><span>%2$s</span></li>', $post_type, $text ); } } } // Comments. $num_comm = wp_count_comments(); if ( $num_comm && ( $num_comm->approved || $num_comm->moderated ) ) { /* translators: %s: Number of comments. */ $text = sprintf( _n( '%s Comment', '%s Comments', $num_comm->approved ), number_format_i18n( $num_comm->approved ) ); ?> <li class="comment-count"> <a href="edit-comments.php"><?php echo $text; ?></a> </li> <?php $moderated_comments_count_i18n = number_format_i18n( $num_comm->moderated ); /* translators: %s: Number of comments. */ $text = sprintf( _n( '%s Comment in moderation', '%s Comments in moderation', $num_comm->moderated ), $moderated_comments_count_i18n ); ?> <li class="comment-mod-count<?php echo ! $num_comm->moderated ? ' hidden' : ''; ?>"> <a href="edit-comments.php?comment_status=moderated" class="comments-in-moderation-text"><?php echo $text; ?></a> </li> <?php } /** * Filters the array of extra elements to list in the 'At a Glance' * dashboard widget. * * Prior to 3.8.0, the widget was named 'Right Now'. Each element * is wrapped in list-item tags on output. * * @since 3.8.0 * * @param string[] $items Array of extra 'At a Glance' widget items. */ $elements = apply_filters( 'dashboard_glance_items', array() ); if ( $elements ) { echo '<li>' . implode( "</li>\n<li>", $elements ) . "</li>\n"; } ?> </ul> <?php update_right_now_message(); // Check if search engines are asked not to index this site. if ( ! is_network_admin() && ! is_user_admin() && current_user_can( 'manage_options' ) && ! get_option( 'blog_public' ) ) { /** * Filters the link title attribute for the 'Search engines discouraged' * message displayed in the 'At a Glance' dashboard widget. * * Prior to 3.8.0, the widget was named 'Right Now'. * * @since 3.0.0 * @since 4.5.0 The default for `$title` was updated to an empty string. * * @param string $title Default attribute text. */ $title = apply_filters( 'privacy_on_link_title', '' ); /** * Filters the link label for the 'Search engines discouraged' message * displayed in the 'At a Glance' dashboard widget. * * Prior to 3.8.0, the widget was named 'Right Now'. * * @since 3.0.0 * * @param string $content Default text. */ $content = apply_filters( 'privacy_on_link_text', __( 'Search engines discouraged' ) ); $title_attr = '' === $title ? '' : " title='$title'"; echo "<p class='search-engines-info'><a href='options-reading.php'$title_attr>$content</a></p>"; } ?> </div> <?php /* * activity_box_end has a core action, but only prints content when multisite. * Using an output buffer is the only way to really check if anything's displayed here. */ ob_start(); /** * Fires at the end of the 'At a Glance' dashboard widget. * * Prior to 3.8.0, the widget was named 'Right Now'. * * @since 2.5.0 */ do_action( 'rightnow_end' ); /** * Fires at the end of the 'At a Glance' dashboard widget. * * Prior to 3.8.0, the widget was named 'Right Now'. * * @since 2.0.0 */ do_action( 'activity_box_end' ); $actions = ob_get_clean(); if ( ! empty( $actions ) ) : ?> <div class="sub"> <?php echo $actions; ?> </div> <?php endif; } /** * @since 3.1.0 */ function wp_network_dashboard_right_now() { $actions = array(); if ( current_user_can( 'create_sites' ) ) { $actions['create-site'] = '<a href="' . network_admin_url( 'site-new.php' ) . '">' . __( 'Create a New Site' ) . '</a>'; } if ( current_user_can( 'create_users' ) ) { $actions['create-user'] = '<a href="' . network_admin_url( 'user-new.php' ) . '">' . __( 'Create a New User' ) . '</a>'; } $c_users = get_user_count(); $c_blogs = get_blog_count(); /* translators: %s: Number of users on the network. */ $user_text = sprintf( _n( '%s user', '%s users', $c_users ), number_format_i18n( $c_users ) ); /* translators: %s: Number of sites on the network. */ $blog_text = sprintf( _n( '%s site', '%s sites', $c_blogs ), number_format_i18n( $c_blogs ) ); /* translators: 1: Text indicating the number of sites on the network, 2: Text indicating the number of users on the network. */ $sentence = sprintf( __( 'You have %1$s and %2$s.' ), $blog_text, $user_text ); if ( $actions ) { echo '<ul class="subsubsub">'; foreach ( $actions as $class => $action ) { $actions[ $class ] = "\t<li class='$class'>$action"; } echo implode( " |</li>\n", $actions ) . "</li>\n"; echo '</ul>'; } ?> <br class="clear" /> <p class="youhave"><?php echo $sentence; ?></p> <?php /** * Fires in the Network Admin 'Right Now' dashboard widget * just before the user and site search form fields. * * @since MU (3.0.0) */ do_action( 'wpmuadminresult' ); ?> <form action="<?php echo esc_url( network_admin_url( 'users.php' ) ); ?>" method="get"> <p> <label class="screen-reader-text" for="search-users"> <?php /* translators: Hidden accessibility text. */ _e( 'Search Users' ); ?> </label> <input type="search" name="s" value="" size="30" autocomplete="off" id="search-users" /> <?php submit_button( __( 'Search Users' ), '', false, false, array( 'id' => 'submit_users' ) ); ?> </p> </form> <form action="<?php echo esc_url( network_admin_url( 'sites.php' ) ); ?>" method="get"> <p> <label class="screen-reader-text" for="search-sites"> <?php /* translators: Hidden accessibility text. */ _e( 'Search Sites' ); ?> </label> <input type="search" name="s" value="" size="30" autocomplete="off" id="search-sites" /> <?php submit_button( __( 'Search Sites' ), '', false, false, array( 'id' => 'submit_sites' ) ); ?> </p> </form> <?php /** * Fires at the end of the 'Right Now' widget in the Network Admin dashboard. * * @since MU (3.0.0) */ do_action( 'mu_rightnow_end' ); /** * Fires at the end of the 'Right Now' widget in the Network Admin dashboard. * * @since MU (3.0.0) */ do_action( 'mu_activity_box_end' ); } /** * Displays the Quick Draft widget. * * @since 3.8.0 * * @global int $post_ID * * @param string|false $error_msg Optional. Error message. Default false. */ function wp_dashboard_quick_press( $error_msg = false ) { global $post_ID; if ( ! current_user_can( 'edit_posts' ) ) { return; } // Check if a new auto-draft (= no new post_ID) is needed or if the old can be used. $last_post_id = (int) get_user_option( 'dashboard_quick_press_last_post_id' ); // Get the last post_ID. if ( $last_post_id ) { $post = get_post( $last_post_id ); if ( empty( $post ) || 'auto-draft' !== $post->post_status ) { // auto-draft doesn't exist anymore. $post = get_default_post_to_edit( 'post', true ); update_user_option( get_current_user_id(), 'dashboard_quick_press_last_post_id', (int) $post->ID ); // Save post_ID. } else { $post->post_title = ''; // Remove the auto draft title. } } else { $post = get_default_post_to_edit( 'post', true ); $user_id = get_current_user_id(); // Don't create an option if this is a super admin who does not belong to this site. if ( in_array( get_current_blog_id(), array_keys( get_blogs_of_user( $user_id ) ), true ) ) { update_user_option( $user_id, 'dashboard_quick_press_last_post_id', (int) $post->ID ); // Save post_ID. } } $post_ID = (int) $post->ID; ?> <form name="post" action="<?php echo esc_url( admin_url( 'post.php' ) ); ?>" method="post" id="quick-press" class="initial-form hide-if-no-js"> <?php if ( $error_msg ) { wp_admin_notice( $error_msg, array( 'additional_classes' => array( 'error' ), ) ); } ?> <div class="input-text-wrap" id="title-wrap"> <label for="title"> <?php /** This filter is documented in wp-admin/edit-form-advanced.php */ echo apply_filters( 'enter_title_here', __( 'Title' ), $post ); ?> </label> <input type="text" name="post_title" id="title" autocomplete="off" /> </div> <div class="textarea-wrap" id="description-wrap"> <label for="content"><?php _e( 'Content' ); ?></label> <textarea name="content" id="content" placeholder="<?php esc_attr_e( 'What’s on your mind?' ); ?>" class="mceEditor" rows="3" cols="15" autocomplete="off"></textarea> </div> <p class="submit"> <input type="hidden" name="action" id="quickpost-action" value="post-quickdraft-save" /> <input type="hidden" name="post_ID" value="<?php echo $post_ID; ?>" /> <input type="hidden" name="post_type" value="post" /> <?php wp_nonce_field( 'add-post' ); ?> <?php submit_button( __( 'Save Draft' ), 'primary', 'save', false, array( 'id' => 'save-post' ) ); ?> <br class="clear" /> </p> </form> <?php wp_dashboard_recent_drafts(); } /** * Show recent drafts of the user on the dashboard. * * @since 2.7.0 * * @param WP_Post[]|false $drafts Optional. Array of posts to display. Default false. */ function wp_dashboard_recent_drafts( $drafts = false ) { if ( ! $drafts ) { $query_args = array( 'post_type' => 'post', 'post_status' => 'draft', 'author' => get_current_user_id(), 'posts_per_page' => 4, 'orderby' => 'modified', 'order' => 'DESC', ); /** * Filters the post query arguments for the 'Recent Drafts' dashboard widget. * * @since 4.4.0 * * @param array $query_args The query arguments for the 'Recent Drafts' dashboard widget. */ $query_args = apply_filters( 'dashboard_recent_drafts_query_args', $query_args ); $drafts = get_posts( $query_args ); if ( ! $drafts ) { return; } } echo '<div class="drafts">'; if ( count( $drafts ) > 3 ) { printf( '<p class="view-all"><a href="%s">%s</a></p>' . "\n", esc_url( admin_url( 'edit.php?post_status=draft' ) ), __( 'View all drafts' ) ); } echo '<h2 class="hide-if-no-js">' . __( 'Your Recent Drafts' ) . "</h2>\n"; echo '<ul>'; /* translators: Maximum number of words used in a preview of a draft on the dashboard. */ $draft_length = (int) _x( '10', 'draft_length' ); $drafts = array_slice( $drafts, 0, 3 ); foreach ( $drafts as $draft ) { $url = get_edit_post_link( $draft->ID ); $title = _draft_or_post_title( $draft->ID ); echo "<li>\n"; printf( '<div class="draft-title"><a href="%s" aria-label="%s">%s</a><time datetime="%s">%s</time></div>', esc_url( $url ), /* translators: %s: Post title. */ esc_attr( sprintf( __( 'Edit “%s”' ), $title ) ), esc_html( $title ), get_the_time( 'c', $draft ), get_the_time( __( 'F j, Y' ), $draft ) ); $the_content = wp_trim_words( $draft->post_content, $draft_length ); if ( $the_content ) { echo '<p>' . $the_content . '</p>'; } echo "</li>\n"; } echo "</ul>\n"; echo '</div>'; } /** * Outputs a row for the Recent Comments widget. * * @access private * @since 2.7.0 * * @global WP_Comment $comment Global comment object. * * @param WP_Comment $comment The current comment. * @param bool $show_date Optional. Whether to display the date. */ function _wp_dashboard_recent_comments_row( &$comment, $show_date = true ) { $GLOBALS['comment'] = clone $comment; if ( $comment->comment_post_ID > 0 ) { $comment_post_title = _draft_or_post_title( $comment->comment_post_ID ); $comment_post_url = get_the_permalink( $comment->comment_post_ID ); $comment_post_link = '<a href="' . esc_url( $comment_post_url ) . '">' . $comment_post_title . '</a>'; } else { $comment_post_link = ''; } $actions_string = ''; if ( current_user_can( 'edit_comment', $comment->comment_ID ) ) { // Pre-order it: Approve | Reply | Edit | Spam | Trash. $actions = array( 'approve' => '', 'unapprove' => '', 'reply' => '', 'edit' => '', 'spam' => '', 'trash' => '', 'delete' => '', 'view' => '', ); $approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( 'approve-comment_' . $comment->comment_ID ) ); $del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( 'delete-comment_' . $comment->comment_ID ) ); $action_string = 'comment.php?action=%s&p=' . $comment->comment_post_ID . '&c=' . $comment->comment_ID . '&%s'; $approve_url = sprintf( $action_string, 'approvecomment', $approve_nonce ); $unapprove_url = sprintf( $action_string, 'unapprovecomment', $approve_nonce ); $spam_url = sprintf( $action_string, 'spamcomment', $del_nonce ); $trash_url = sprintf( $action_string, 'trashcomment', $del_nonce ); $delete_url = sprintf( $action_string, 'deletecomment', $del_nonce ); $actions['approve'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-a aria-button-if-js" aria-label="%s">%s</a>', esc_url( $approve_url ), "dim:the-comment-list:comment-{$comment->comment_ID}:unapproved:e7e7d3:e7e7d3:new=approved", esc_attr__( 'Approve this comment' ), __( 'Approve' ) ); $actions['unapprove'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-u aria-button-if-js" aria-label="%s">%s</a>', esc_url( $unapprove_url ), "dim:the-comment-list:comment-{$comment->comment_ID}:unapproved:e7e7d3:e7e7d3:new=unapproved", esc_attr__( 'Unapprove this comment' ), __( 'Unapprove' ) ); $actions['edit'] = sprintf( '<a href="%s" aria-label="%s">%s</a>', "comment.php?action=editcomment&c={$comment->comment_ID}", esc_attr__( 'Edit this comment' ), __( 'Edit' ) ); $actions['reply'] = sprintf( '<button type="button" onclick="window.commentReply && commentReply.open(\'%s\',\'%s\');" class="vim-r button-link hide-if-no-js" aria-label="%s">%s</button>', $comment->comment_ID, $comment->comment_post_ID, esc_attr__( 'Reply to this comment' ), /* translators: Comment reply button text. */ _x( 'Reply', 'verb' ) ); $actions['spam'] = sprintf( '<a href="%s" data-wp-lists="%s" class="vim-s vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $spam_url ), "delete:the-comment-list:comment-{$comment->comment_ID}::spam=1", esc_attr__( 'Mark this comment as spam' ), /* translators: "Mark as spam" link. */ _x( 'Spam', 'verb' ) ); if ( ! EMPTY_TRASH_DAYS ) { $actions['delete'] = sprintf( '<a href="%s" data-wp-lists="%s" class="delete vim-d vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $delete_url ), "delete:the-comment-list:comment-{$comment->comment_ID}::trash=1", esc_attr__( 'Delete this comment permanently' ), __( 'Delete Permanently' ) ); } else { $actions['trash'] = sprintf( '<a href="%s" data-wp-lists="%s" class="delete vim-d vim-destructive aria-button-if-js" aria-label="%s">%s</a>', esc_url( $trash_url ), "delete:the-comment-list:comment-{$comment->comment_ID}::trash=1", esc_attr__( 'Move this comment to the Trash' ), _x( 'Trash', 'verb' ) ); } $actions['view'] = sprintf( '<a class="comment-link" href="%s" aria-label="%s">%s</a>', esc_url( get_comment_link( $comment ) ), esc_attr__( 'View this comment' ), __( 'View' ) ); /** This filter is documented in wp-admin/includes/class-wp-comments-list-table.php */ $actions = apply_filters( 'comment_row_actions', array_filter( $actions ), $comment ); $i = 0; foreach ( $actions as $action => $link ) { ++$i; if ( ( ( 'approve' === $action || 'unapprove' === $action ) && 2 === $i ) || 1 === $i ) { $separator = ''; } else { $separator = ' | '; } // Reply and quickedit need a hide-if-no-js span. if ( 'reply' === $action || 'quickedit' === $action ) { $action .= ' hide-if-no-js'; } if ( 'view' === $action && '1' !== $comment->comment_approved ) { $action .= ' hidden'; } $actions_string .= "<span class='$action'>{$separator}{$link}</span>"; } } ?> <li id="comment-<?php echo $comment->comment_ID; ?>" <?php comment_class( array( 'comment-item', wp_get_comment_status( $comment ) ), $comment ); ?>> <?php $comment_row_class = ''; if ( get_option( 'show_avatars' ) ) { echo get_avatar( $comment, 50, 'mystery' ); $comment_row_class .= ' has-avatar'; } ?> <?php if ( ! $comment->comment_type || 'comment' === $comment->comment_type ) : ?> <div class="dashboard-comment-wrap has-row-actions <?php echo $comment_row_class; ?>"> <p class="comment-meta"> <?php // Comments might not have a post they relate to, e.g. programmatically created ones. if ( $comment_post_link ) { printf( /* translators: 1: Comment author, 2: Post link, 3: Notification if the comment is pending. */ __( 'From %1$s on %2$s %3$s' ), '<cite class="comment-author">' . get_comment_author_link( $comment ) . '</cite>', $comment_post_link, '<span class="approve">' . __( '[Pending]' ) . '</span>' ); } else { printf( /* translators: 1: Comment author, 2: Notification if the comment is pending. */ __( 'From %1$s %2$s' ), '<cite class="comment-author">' . get_comment_author_link( $comment ) . '</cite>', '<span class="approve">' . __( '[Pending]' ) . '</span>' ); } ?> </p> <?php else : switch ( $comment->comment_type ) { case 'pingback': $type = __( 'Pingback' ); break; case 'trackback': $type = __( 'Trackback' ); break; default: $type = ucwords( $comment->comment_type ); } $type = esc_html( $type ); ?> <div class="dashboard-comment-wrap has-row-actions"> <p class="comment-meta"> <?php // Pingbacks, Trackbacks or custom comment types might not have a post they relate to, e.g. programmatically created ones. if ( $comment_post_link ) { printf( /* translators: 1: Type of comment, 2: Post link, 3: Notification if the comment is pending. */ _x( '%1$s on %2$s %3$s', 'dashboard' ), "<strong>$type</strong>", $comment_post_link, '<span class="approve">' . __( '[Pending]' ) . '</span>' ); } else { printf( /* translators: 1: Type of comment, 2: Notification if the comment is pending. */ _x( '%1$s %2$s', 'dashboard' ), "<strong>$type</strong>", '<span class="approve">' . __( '[Pending]' ) . '</span>' ); } ?> </p> <p class="comment-author"><?php comment_author_link( $comment ); ?></p> <?php endif; // comment_type ?> <blockquote><p><?php comment_excerpt( $comment ); ?></p></blockquote> <?php if ( $actions_string ) : ?> <p class="row-actions"><?php echo $actions_string; ?></p> <?php endif; ?> </div> </li> <?php $GLOBALS['comment'] = null; } /** * Outputs the Activity widget. * * Callback function for {@see 'dashboard_activity'}. * * @since 3.8.0 */ function wp_dashboard_site_activity() { echo '<div id="activity-widget">'; $future_posts = wp_dashboard_recent_posts( array( 'max' => 5, 'status' => 'future', 'order' => 'ASC', 'title' => __( 'Publishing Soon' ), 'id' => 'future-posts', ) ); $recent_posts = wp_dashboard_recent_posts( array( 'max' => 5, 'status' => 'publish', 'order' => 'DESC', 'title' => __( 'Recently Published' ), 'id' => 'published-posts', ) ); $recent_comments = wp_dashboard_recent_comments(); if ( ! $future_posts && ! $recent_posts && ! $recent_comments ) { echo '<div class="no-activity">'; echo '<p>' . __( 'No activity yet!' ) . '</p>'; echo '</div>'; } echo '</div>'; } /** * Generates Publishing Soon and Recently Published sections. * * @since 3.8.0 * * @param array $args { * An array of query and display arguments. * * @type int $max Number of posts to display. * @type string $status Post status. * @type string $order Designates ascending ('ASC') or descending ('DESC') order. * @type string $title Section title. * @type string $id The container id. * } * @return bool False if no posts were found. True otherwise. */ function wp_dashboard_recent_posts( $args ) { $query_args = array( 'post_type' => 'post', 'post_status' => $args['status'], 'orderby' => 'date', 'order' => $args['order'], 'posts_per_page' => (int) $args['max'], 'no_found_rows' => true, 'cache_results' => true, 'perm' => ( 'future' === $args['status'] ) ? 'editable' : 'readable', ); /** * Filters the query arguments used for the Recent Posts widget. * * @since 4.2.0 * * @param array $query_args The arguments passed to WP_Query to produce the list of posts. */ $query_args = apply_filters( 'dashboard_recent_posts_query_args', $query_args ); $posts = new WP_Query( $query_args ); if ( $posts->have_posts() ) { echo '<div id="' . $args['id'] . '" class="activity-block">'; echo '<h3>' . $args['title'] . '</h3>'; echo '<ul>'; $today = current_time( 'Y-m-d' ); $tomorrow = current_datetime()->modify( '+1 day' )->format( 'Y-m-d' ); $year = current_time( 'Y' ); while ( $posts->have_posts() ) { $posts->the_post(); $time = get_the_time( 'U' ); if ( ! is_int( $time ) ) { /* translators: Date and time format for recent posts on the dashboard, from a different calendar year, see https://www.php.net/manual/datetime.format.php */ $date = get_the_date( __( 'M jS Y' ) ); } elseif ( gmdate( 'Y-m-d', $time ) === $today ) { $date = __( 'Today' ); } elseif ( gmdate( 'Y-m-d', $time ) === $tomorrow ) { $date = __( 'Tomorrow' ); } elseif ( gmdate( 'Y', $time ) !== $year ) { /* translators: Date and time format for recent posts on the dashboard, from a different calendar year, see https://www.php.net/manual/datetime.format.php */ $date = date_i18n( __( 'M jS Y' ), $time ); } else { /* translators: Date and time format for recent posts on the dashboard, see https://www.php.net/manual/datetime.format.php */ $date = date_i18n( __( 'M jS' ), $time ); } // Use the post edit link for those who can edit, the permalink otherwise. $recent_post_link = current_user_can( 'edit_post', get_the_ID() ) ? get_edit_post_link() : get_permalink(); $draft_or_post_title = _draft_or_post_title(); printf( '<li><span>%1$s</span> <a href="%2$s" aria-label="%3$s">%4$s</a></li>', /* translators: 1: Relative date, 2: Time. */ sprintf( _x( '%1$s, %2$s', 'dashboard' ), $date, get_the_time() ), $recent_post_link, /* translators: %s: Post title. */ esc_attr( sprintf( __( 'Edit “%s”' ), $draft_or_post_title ) ), $draft_or_post_title ); } echo '</ul>'; echo '</div>'; } else { return false; } wp_reset_postdata(); return true; } /** * Show Comments section. * * @since 3.8.0 * * @param int $total_items Optional. Number of comments to query. Default 5. * @return bool False if no comments were found. True otherwise. */ function wp_dashboard_recent_comments( $total_items = 5 ) { // Select all comment types and filter out spam later for better query performance. $comments = array(); $comments_query = array( 'number' => $total_items * 5, 'offset' => 0, ); if ( ! current_user_can( 'edit_posts' ) ) { $comments_query['status'] = 'approve'; } $comments_count = 0; do { $possible = get_comments( $comments_query ); if ( empty( $possible ) || ! is_array( $possible ) ) { break; } foreach ( $possible as $comment ) { if ( ! current_user_can( 'edit_post', $comment->comment_post_ID ) && ( post_password_required( $comment->comment_post_ID ) || ! current_user_can( 'read_post', $comment->comment_post_ID ) ) ) { // The user has no access to the post and thus cannot see the comments. continue; } $comments[] = $comment; $comments_count = count( $comments ); if ( $comments_count === $total_items ) { break 2; } } $comments_query['offset'] += $comments_query['number']; $comments_query['number'] = $total_items * 10; } while ( $comments_count < $total_items ); if ( $comments ) { echo '<div id="latest-comments" class="activity-block table-view-list">'; echo '<h3>' . __( 'Recent Comments' ) . '</h3>'; echo '<ul id="the-comment-list" data-wp-lists="list:comment">'; foreach ( $comments as $comment ) { _wp_dashboard_recent_comments_row( $comment ); } echo '</ul>'; if ( current_user_can( 'edit_posts' ) ) { echo '<h3 class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'View more comments' ) . '</h3>'; _get_list_table( 'WP_Comments_List_Table' )->views(); } wp_comment_reply( -1, false, 'dashboard', false ); wp_comment_trashnotice(); echo '</div>'; } else { return false; } return true; } /** * Display generic dashboard RSS widget feed. * * @since 2.5.0 * * @param string $widget_id */ function wp_dashboard_rss_output( $widget_id ) { $widgets = get_option( 'dashboard_widget_options' ); echo '<div class="rss-widget">'; wp_widget_rss_output( $widgets[ $widget_id ] ); echo '</div>'; } /** * Checks to see if all of the feed url in $check_urls are cached. * * If $check_urls is empty, look for the rss feed url found in the dashboard * widget options of $widget_id. If cached, call $callback, a function that * echoes out output for this widget. If not cache, echo a "Loading..." stub * which is later replaced by Ajax call (see top of /wp-admin/index.php) * * @since 2.5.0 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter * by adding it to the function signature. * * @param string $widget_id The widget ID. * @param callable $callback The callback function used to display each feed. * @param array $check_urls RSS feeds. * @param mixed ...$args Optional additional parameters to pass to the callback function. * @return bool True on success, false on failure. */ function wp_dashboard_cached_rss_widget( $widget_id, $callback, $check_urls = array(), ...$args ) { $doing_ajax = wp_doing_ajax(); $loading = '<p class="widget-loading hide-if-no-js">' . __( 'Loading…' ) . '</p>'; $loading .= wp_get_admin_notice( __( 'This widget requires JavaScript.' ), array( 'type' => 'error', 'additional_classes' => array( 'inline', 'hide-if-js' ), ) ); if ( empty( $check_urls ) ) { $widgets = get_option( 'dashboard_widget_options' ); if ( empty( $widgets[ $widget_id ]['url'] ) && ! $doing_ajax ) { echo $loading; return false; } $check_urls = array( $widgets[ $widget_id ]['url'] ); } $locale = get_user_locale(); $cache_key = 'dash_v2_' . md5( $widget_id . '_' . $locale ); $output = get_transient( $cache_key ); if ( false !== $output ) { echo $output; return true; } if ( ! $doing_ajax ) { echo $loading; return false; } if ( $callback && is_callable( $callback ) ) { array_unshift( $args, $widget_id, $check_urls ); ob_start(); call_user_func_array( $callback, $args ); // Default lifetime in cache of 12 hours (same as the feeds). set_transient( $cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS ); } return true; } // // Dashboard Widgets Controls. // /** * Calls widget control callback. * * @since 2.5.0 * * @global callable[] $wp_dashboard_control_callbacks * * @param int|false $widget_control_id Optional. Registered widget ID. Default false. */ function wp_dashboard_trigger_widget_control( $widget_control_id = false ) { global $wp_dashboard_control_callbacks; if ( is_scalar( $widget_control_id ) && $widget_control_id && isset( $wp_dashboard_control_callbacks[ $widget_control_id ] ) && is_callable( $wp_dashboard_control_callbacks[ $widget_control_id ] ) ) { call_user_func( $wp_dashboard_control_callbacks[ $widget_control_id ], '', array( 'id' => $widget_control_id, 'callback' => $wp_dashboard_control_callbacks[ $widget_control_id ], ) ); } } /** * Sets up the RSS dashboard widget control and $args to be used as input to wp_widget_rss_form(). * * Handles POST data from RSS-type widgets. * * @since 2.5.0 * * @param string $widget_id * @param array $form_inputs */ function wp_dashboard_rss_control( $widget_id, $form_inputs = array() ) { $widget_options = get_option( 'dashboard_widget_options' ); if ( ! $widget_options ) { $widget_options = array(); } if ( ! isset( $widget_options[ $widget_id ] ) ) { $widget_options[ $widget_id ] = array(); } $number = 1; // Hack to use wp_widget_rss_form(). $widget_options[ $widget_id ]['number'] = $number; if ( 'POST' === $_SERVER['REQUEST_METHOD'] && isset( $_POST['widget-rss'][ $number ] ) ) { $_POST['widget-rss'][ $number ] = wp_unslash( $_POST['widget-rss'][ $number ] ); $widget_options[ $widget_id ] = wp_widget_rss_process( $_POST['widget-rss'][ $number ] ); $widget_options[ $widget_id ]['number'] = $number; // Title is optional. If black, fill it if possible. if ( ! $widget_options[ $widget_id ]['title'] && isset( $_POST['widget-rss'][ $number ]['title'] ) ) { $rss = fetch_feed( $widget_options[ $widget_id ]['url'] ); if ( is_wp_error( $rss ) ) { $widget_options[ $widget_id ]['title'] = htmlentities( __( 'Unknown Feed' ) ); } else { $widget_options[ $widget_id ]['title'] = htmlentities( strip_tags( $rss->get_title() ) ); $rss->__destruct(); unset( $rss ); } } update_option( 'dashboard_widget_options', $widget_options, false ); $locale = get_user_locale(); $cache_key = 'dash_v2_' . md5( $widget_id . '_' . $locale ); delete_transient( $cache_key ); } wp_widget_rss_form( $widget_options[ $widget_id ], $form_inputs ); } /** * Renders the Events and News dashboard widget. * * @since 4.8.0 */ function wp_dashboard_events_news() { wp_print_community_events_markup(); ?> <div class="wordpress-news hide-if-no-js"> <?php wp_dashboard_primary(); ?> </div> <p class="community-events-footer"> <?php printf( '<a href="%1$s" target="_blank">%2$s <span class="screen-reader-text"> %3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>', 'https://make.wordpress.org/community/meetups-landing-page', __( 'Meetups' ), /* translators: Hidden accessibility text. */ __( '(opens in a new tab)' ) ); ?> | <?php printf( '<a href="%1$s" target="_blank">%2$s <span class="screen-reader-text"> %3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>', 'https://central.wordcamp.org/schedule/', __( 'WordCamps' ), /* translators: Hidden accessibility text. */ __( '(opens in a new tab)' ) ); ?> | <?php printf( '<a href="%1$s" target="_blank">%2$s <span class="screen-reader-text"> %3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>', /* translators: If a Rosetta site exists (e.g. https://es.wordpress.org/news/), then use that. Otherwise, leave untranslated. */ esc_url( _x( 'https://wordpress.org/news/', 'Events and News dashboard widget' ) ), __( 'News' ), /* translators: Hidden accessibility text. */ __( '(opens in a new tab)' ) ); ?> </p> <?php } /** * Prints the markup for the Community Events section of the Events and News Dashboard widget. * * @since 4.8.0 */ function wp_print_community_events_markup() { $community_events_notice = '<p class="hide-if-js">' . ( 'This widget requires JavaScript.' ) . '</p>'; $community_events_notice .= '<p class="community-events-error-occurred" aria-hidden="true">' . __( 'An error occurred. Please try again.' ) . '</p>'; $community_events_notice .= '<p class="community-events-could-not-locate" aria-hidden="true"></p>'; wp_admin_notice( $community_events_notice, array( 'type' => 'error', 'additional_classes' => array( 'community-events-errors', 'inline', 'hide-if-js' ), 'paragraph_wrap' => false, ) ); /* * Hide the main element when the page first loads, because the content * won't be ready until wp.communityEvents.renderEventsTemplate() has run. */ ?> <div id="community-events" class="community-events" aria-hidden="true"> <div class="activity-block"> <p> <span id="community-events-location-message"></span> <button class="button-link community-events-toggle-location" aria-expanded="false"> <span class="dashicons dashicons-location" aria-hidden="true"></span> <span class="community-events-location-edit"><?php _e( 'Select location' ); ?></span> </button> </p> <form class="community-events-form" aria-hidden="true" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>" method="post"> <label for="community-events-location"> <?php _e( 'City:' ); ?> </label> <?php /* translators: Replace with a city related to your locale. * Test that it matches the expected location and has upcoming * events before including it. If no cities related to your * locale have events, then use a city related to your locale * that would be recognizable to most users. Use only the city * name itself, without any region or country. Use the endonym * (native locale name) instead of the English name if possible. */ ?> <input id="community-events-location" class="regular-text" type="text" name="community-events-location" placeholder="<?php esc_attr_e( 'Cincinnati' ); ?>" /> <?php submit_button( __( 'Submit' ), 'secondary', 'community-events-submit', false ); ?> <button class="community-events-cancel button-link" type="button" aria-expanded="false"> <?php _e( 'Cancel' ); ?> </button> <span class="spinner"></span> </form> </div> <ul class="community-events-results activity-block last"></ul> </div> <?php } /** * Renders the events templates for the Event and News widget. * * @since 4.8.0 */ function wp_print_community_events_templates() { ?> <script id="tmpl-community-events-attend-event-near" type="text/template"> <?php printf( /* translators: %s: The name of a city. */ __( 'Attend an upcoming event near %s.' ), '<strong>{{ data.location.description }}</strong>' ); ?> </script> <script id="tmpl-community-events-could-not-locate" type="text/template"> <?php printf( /* translators: %s is the name of the city we couldn't locate. * Replace the examples with cities in your locale, but test * that they match the expected location before including them. * Use endonyms (native locale names) whenever possible. */ __( '%s could not be located. Please try another nearby city. For example: Kansas City; Springfield; Portland.' ), '<em>{{data.unknownCity}}</em>' ); ?> </script> <script id="tmpl-community-events-event-list" type="text/template"> <# _.each( data.events, function( event ) { #> <li class="event event-{{ event.type }} wp-clearfix"> <div class="event-info"> <div class="dashicons event-icon" aria-hidden="true"></div> <div class="event-info-inner"> <a class="event-title" href="{{ event.url }}">{{ event.title }}</a> <# if ( event.type ) { const titleCaseEventType = event.type.replace( /\w\S*/g, function ( type ) { return type.charAt(0).toUpperCase() + type.substr(1).toLowerCase(); } ); #> {{ 'wordcamp' === event.type ? 'WordCamp' : titleCaseEventType }} <span class="ce-separator" aria-hidden="true"></span> <# } #> <span class="event-city">{{ event.location.location }}</span> </div> </div> <div class="event-date-time"> <span class="event-date">{{ event.user_formatted_date }}</span> <# if ( 'meetup' === event.type ) { #> <span class="event-time"> {{ event.user_formatted_time }} {{ event.timeZoneAbbreviation }} </span> <# } #> </div> </li> <# } ) #> <# if ( data.events.length <= 2 ) { #> <li class="event-none"> <?php printf( /* translators: %s: Localized meetup organization documentation URL. */ __( 'Want more events? <a href="%s">Help organize the next one</a>!' ), __( 'https://make.wordpress.org/community/organize-event-landing-page/' ) ); ?> </li> <# } #> </script> <script id="tmpl-community-events-no-upcoming-events" type="text/template"> <li class="event-none"> <# if ( data.location.description ) { #> <?php printf( /* translators: 1: The city the user searched for, 2: Meetup organization documentation URL. */ __( 'There are no events scheduled near %1$s at the moment. Would you like to <a href="%2$s">organize a WordPress event</a>?' ), '{{ data.location.description }}', __( 'https://make.wordpress.org/community/handbook/meetup-organizer/welcome/' ) ); ?> <# } else { #> <?php printf( /* translators: %s: Meetup organization documentation URL. */ __( 'There are no events scheduled near you at the moment. Would you like to <a href="%s">organize a WordPress event</a>?' ), __( 'https://make.wordpress.org/community/handbook/meetup-organizer/welcome/' ) ); ?> <# } #> </li> </script> <?php } /** * 'WordPress Events and News' dashboard widget. * * @since 2.7.0 * @since 4.8.0 Removed popular plugins feed. */ function wp_dashboard_primary() { $feeds = array( 'news' => array( /** * Filters the primary link URL for the 'WordPress Events and News' dashboard widget. * * @since 2.5.0 * * @param string $link The widget's primary link URL. */ 'link' => apply_filters( 'dashboard_primary_link', __( 'https://wordpress.org/news/' ) ), /** * Filters the primary feed URL for the 'WordPress Events and News' dashboard widget. * * @since 2.3.0 * * @param string $url The widget's primary feed URL. */ 'url' => apply_filters( 'dashboard_primary_feed', __( 'https://wordpress.org/news/feed/' ) ), /** * Filters the primary link title for the 'WordPress Events and News' dashboard widget. * * @since 2.3.0 * * @param string $title Title attribute for the widget's primary link. */ 'title' => apply_filters( 'dashboard_primary_title', __( 'WordPress Blog' ) ), 'items' => 2, 'show_summary' => 0, 'show_author' => 0, 'show_date' => 0, ), 'planet' => array( /** * Filters the secondary link URL for the 'WordPress Events and News' dashboard widget. * * @since 2.3.0 * * @param string $link The widget's secondary link URL. */ 'link' => apply_filters( 'dashboard_secondary_link', /* translators: Link to the Planet website of the locale. */ __( 'https://planet.wordpress.org/' ) ), /** * Filters the secondary feed URL for the 'WordPress Events and News' dashboard widget. * * @since 2.3.0 * * @param string $url The widget's secondary feed URL. */ 'url' => apply_filters( 'dashboard_secondary_feed', /* translators: Link to the Planet feed of the locale. */ __( 'https://planet.wordpress.org/feed/' ) ), /** * Filters the secondary link title for the 'WordPress Events and News' dashboard widget. * * @since 2.3.0 * * @param string $title Title attribute for the widget's secondary link. */ 'title' => apply_filters( 'dashboard_secondary_title', __( 'Other WordPress News' ) ), /** * Filters the number of secondary link items for the 'WordPress Events and News' dashboard widget. * * @since 4.4.0 * * @param string $items How many items to show in the secondary feed. */ 'items' => apply_filters( 'dashboard_secondary_items', 3 ), 'show_summary' => 0, 'show_author' => 0, 'show_date' => 0, ), ); wp_dashboard_cached_rss_widget( 'dashboard_primary', 'wp_dashboard_primary_output', $feeds ); } /** * Displays the WordPress events and news feeds. * * @since 3.8.0 * @since 4.8.0 Removed popular plugins feed. * * @param string $widget_id Widget ID. * @param array $feeds Array of RSS feeds. */ function wp_dashboard_primary_output( $widget_id, $feeds ) { foreach ( $feeds as $type => $args ) { $args['type'] = $type; echo '<div class="rss-widget">'; wp_widget_rss_output( $args['url'], $args ); echo '</div>'; } } /** * Displays file upload quota on dashboard. * * Runs on the {@see 'activity_box_end'} hook in wp_dashboard_right_now(). * * @since 3.0.0 * * @return true|void True if not multisite, user can't upload files, or the space check option is disabled. */ function wp_dashboard_quota() { if ( ! is_multisite() || ! current_user_can( 'upload_files' ) || get_site_option( 'upload_space_check_disabled' ) ) { return true; } $quota = get_space_allowed(); $used = get_space_used(); if ( $used > $quota ) { $percentused = '100'; } else { $percentused = ( $used / $quota ) * 100; } $used_class = ( $percentused >= 70 ) ? ' warning' : ''; $used = round( $used, 2 ); $percentused = number_format( $percentused ); ?> <h3 class="mu-storage"><?php _e( 'Storage Space' ); ?></h3> <div class="mu-storage"> <ul> <li class="storage-count"> <?php $text = sprintf( /* translators: %s: Number of megabytes. */ __( '%s MB Space Allowed' ), number_format_i18n( $quota ) ); printf( '<a href="%1$s">%2$s<span class="screen-reader-text"> (%3$s)</span></a>', esc_url( admin_url( 'upload.php' ) ), $text, /* translators: Hidden accessibility text. */ __( 'Manage Uploads' ) ); ?> </li><li class="storage-count <?php echo $used_class; ?>"> <?php $text = sprintf( /* translators: 1: Number of megabytes, 2: Percentage. */ __( '%1$s MB (%2$s%%) Space Used' ), number_format_i18n( $used, 2 ), $percentused ); printf( '<a href="%1$s" class="musublink">%2$s<span class="screen-reader-text"> (%3$s)</span></a>', esc_url( admin_url( 'upload.php' ) ), $text, /* translators: Hidden accessibility text. */ __( 'Manage Uploads' ) ); ?> </li> </ul> </div> <?php } /** * Displays the browser update nag. * * @since 3.2.0 * @since 5.8.0 Added a special message for Internet Explorer users. * * @global bool $is_IE */ function wp_dashboard_browser_nag() { global $is_IE; $notice = ''; $response = wp_check_browser_version(); if ( $response ) { if ( $is_IE ) { $msg = __( 'Internet Explorer does not give you the best WordPress experience. Switch to Microsoft Edge, or another more modern browser to get the most from your site.' ); } elseif ( $response['insecure'] ) { $msg = sprintf( /* translators: %s: Browser name and link. */ __( "It looks like you're using an insecure version of %s. Using an outdated browser makes your computer unsafe. For the best WordPress experience, please update your browser." ), sprintf( '<a href="%s">%s</a>', esc_url( $response['update_url'] ), esc_html( $response['name'] ) ) ); } else { $msg = sprintf( /* translators: %s: Browser name and link. */ __( "It looks like you're using an old version of %s. For the best WordPress experience, please update your browser." ), sprintf( '<a href="%s">%s</a>', esc_url( $response['update_url'] ), esc_html( $response['name'] ) ) ); } $browser_nag_class = ''; if ( ! empty( $response['img_src'] ) ) { $img_src = ( is_ssl() && ! empty( $response['img_src_ssl'] ) ) ? $response['img_src_ssl'] : $response['img_src']; $notice .= '<div class="alignright browser-icon"><img src="' . esc_url( $img_src ) . '" alt="" /></div>'; $browser_nag_class = ' has-browser-icon'; } $notice .= "<p class='browser-update-nag{$browser_nag_class}'>{$msg}</p>"; $browsehappy = 'https://browsehappy.com/'; $locale = get_user_locale(); if ( 'en_US' !== $locale ) { $browsehappy = add_query_arg( 'locale', $locale, $browsehappy ); } if ( $is_IE ) { $msg_browsehappy = sprintf( /* translators: %s: Browse Happy URL. */ __( 'Learn how to <a href="%s" class="update-browser-link">browse happy</a>' ), esc_url( $browsehappy ) ); } else { $msg_browsehappy = sprintf( /* translators: 1: Browser update URL, 2: Browser name, 3: Browse Happy URL. */ __( '<a href="%1$s" class="update-browser-link">Update %2$s</a> or learn how to <a href="%3$s" class="browse-happy-link">browse happy</a>' ), esc_attr( $response['update_url'] ), esc_html( $response['name'] ), esc_url( $browsehappy ) ); } $notice .= '<p>' . $msg_browsehappy . '</p>'; $notice .= '<p class="hide-if-no-js"><a href="" class="dismiss" aria-label="' . esc_attr__( 'Dismiss the browser warning panel' ) . '">' . __( 'Dismiss' ) . '</a></p>'; $notice .= '<div class="clear"></div>'; } /** * Filters the notice output for the 'Browse Happy' nag meta box. * * @since 3.2.0 * * @param string $notice The notice content. * @param array|false $response An array containing web browser information, or * false on failure. See wp_check_browser_version(). */ echo apply_filters( 'browse-happy-notice', $notice, $response ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores } /** * Adds an additional class to the browser nag if the current version is insecure. * * @since 3.2.0 * * @param string[] $classes Array of meta box classes. * @return string[] Modified array of meta box classes. */ function dashboard_browser_nag_class( $classes ) { $response = wp_check_browser_version(); if ( $response && $response['insecure'] ) { $classes[] = 'browser-insecure'; } return $classes; } /** * Checks if the user needs a browser update. * * @since 3.2.0 * * @return array|false Array of browser data on success, false on failure. */ function wp_check_browser_version() { if ( empty( $_SERVER['HTTP_USER_AGENT'] ) ) { return false; } $key = md5( $_SERVER['HTTP_USER_AGENT'] ); $response = get_site_transient( 'browser_' . $key ); if ( false === $response ) { $url = 'http://api.wordpress.org/core/browse-happy/1.1/'; $options = array( 'body' => array( 'useragent' => $_SERVER['HTTP_USER_AGENT'] ), 'user-agent' => 'WordPress/' . wp_get_wp_version() . '; ' . home_url( '/' ), ); if ( wp_http_supports( array( 'ssl' ) ) ) { $url = set_url_scheme( $url, 'https' ); } $response = wp_remote_post( $url, $options ); if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { return false; } /** * Response should be an array with: * 'platform' - string - A user-friendly platform name, if it can be determined * 'name' - string - A user-friendly browser name * 'version' - string - The version of the browser the user is using * 'current_version' - string - The most recent version of the browser * 'upgrade' - boolean - Whether the browser needs an upgrade * 'insecure' - boolean - Whether the browser is deemed insecure * 'update_url' - string - The url to visit to upgrade * 'img_src' - string - An image representing the browser * 'img_src_ssl' - string - An image (over SSL) representing the browser */ $response = json_decode( wp_remote_retrieve_body( $response ), true ); if ( ! is_array( $response ) ) { return false; } set_site_transient( 'browser_' . $key, $response, WEEK_IN_SECONDS ); } return $response; } /** * Displays the PHP update nag. * * @since 5.1.0 */ function wp_dashboard_php_nag() { $response = wp_check_php_version(); if ( ! $response ) { return; } if ( isset( $response['is_secure'] ) && ! $response['is_secure'] ) { // The `is_secure` array key name doesn't actually imply this is a secure version of PHP. It only means it receives security updates. if ( $response['is_lower_than_future_minimum'] ) { $message = sprintf( /* translators: %s: The server PHP version. */ __( 'Your site is running on an outdated version of PHP (%s), which does not receive security updates and soon will not be supported by WordPress. Ensure that PHP is updated on your server as soon as possible. Otherwise you will not be able to upgrade WordPress.' ), PHP_VERSION ); } else { $message = sprintf( /* translators: %s: The server PHP version. */ __( 'Your site is running on an outdated version of PHP (%s), which does not receive security updates. It should be updated.' ), PHP_VERSION ); } } elseif ( $response['is_lower_than_future_minimum'] ) { $message = sprintf( /* translators: %s: The server PHP version. */ __( 'Your site is running on an outdated version of PHP (%s), which soon will not be supported by WordPress. Ensure that PHP is updated on your server as soon as possible. Otherwise you will not be able to upgrade WordPress.' ), PHP_VERSION ); } else { $message = sprintf( /* translators: %s: The server PHP version. */ __( 'Your site is running on an outdated version of PHP (%s), which should be updated.' ), PHP_VERSION ); } ?> <p class="bigger-bolder-text"><?php echo $message; ?></p> <p><?php _e( 'What is PHP and how does it affect my site?' ); ?></p> <p> <?php _e( 'PHP is one of the programming languages used to build WordPress. Newer versions of PHP receive regular security updates and may increase your site’s performance.' ); ?> <?php if ( ! empty( $response['recommended_version'] ) ) { printf( /* translators: %s: The minimum recommended PHP version. */ __( 'The minimum recommended version of PHP is %s.' ), $response['recommended_version'] ); } ?> </p> <p class="button-container"> <?php printf( '<a class="button button-primary" href="%1$s" target="_blank">%2$s<span class="screen-reader-text"> %3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>', esc_url( wp_get_update_php_url() ), __( 'Learn more about updating PHP' ), /* translators: Hidden accessibility text. */ __( '(opens in a new tab)' ) ); ?> </p> <?php wp_update_php_annotation(); wp_direct_php_update_button(); } /** * Adds an additional class to the PHP nag if the current version is insecure. * * @since 5.1.0 * * @param string[] $classes Array of meta box classes. * @return string[] Modified array of meta box classes. */ function dashboard_php_nag_class( $classes ) { $response = wp_check_php_version(); if ( ! $response ) { return $classes; } if ( isset( $response['is_secure'] ) && ! $response['is_secure'] ) { $classes[] = 'php-no-security-updates'; } elseif ( $response['is_lower_than_future_minimum'] ) { $classes[] = 'php-version-lower-than-future-minimum'; } return $classes; } /** * Displays the Site Health Status widget. * * @since 5.4.0 */ function wp_dashboard_site_health() { $get_issues = get_transient( 'health-check-site-status-result' ); $issue_counts = array(); if ( false !== $get_issues ) { $issue_counts = json_decode( $get_issues, true ); } if ( ! is_array( $issue_counts ) || ! $issue_counts ) { $issue_counts = array( 'good' => 0, 'recommended' => 0, 'critical' => 0, ); } $issues_total = $issue_counts['recommended'] + $issue_counts['critical']; ?> <div class="health-check-widget"> <div class="health-check-widget-title-section site-health-progress-wrapper loading hide-if-no-js"> <div class="site-health-progress"> <svg aria-hidden="true" focusable="false" width="100%" height="100%" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg"> <circle r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle> <circle id="bar" r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle> </svg> </div> <div class="site-health-progress-label"> <?php if ( false === $get_issues ) : ?> <?php _e( 'No information yet…' ); ?> <?php else : ?> <?php _e( 'Results are still loading…' ); ?> <?php endif; ?> </div> </div> <div class="site-health-details"> <?php if ( false === $get_issues ) : ?> <p> <?php printf( /* translators: %s: URL to Site Health screen. */ __( 'Site health checks will automatically run periodically to gather information about your site. You can also <a href="%s">visit the Site Health screen</a> to gather information about your site now.' ), esc_url( admin_url( 'site-health.php' ) ) ); ?> </p> <?php else : ?> <p> <?php if ( $issues_total <= 0 ) : ?> <?php _e( 'Great job! Your site currently passes all site health checks.' ); ?> <?php elseif ( 1 === (int) $issue_counts['critical'] ) : ?> <?php _e( 'Your site has a critical issue that should be addressed as soon as possible to improve its performance and security.' ); ?> <?php elseif ( $issue_counts['critical'] > 1 ) : ?> <?php _e( 'Your site has critical issues that should be addressed as soon as possible to improve its performance and security.' ); ?> <?php elseif ( 1 === (int) $issue_counts['recommended'] ) : ?> <?php _e( 'Your site’s health is looking good, but there is still one thing you can do to improve its performance and security.' ); ?> <?php else : ?> <?php _e( 'Your site’s health is looking good, but there are still some things you can do to improve its performance and security.' ); ?> <?php endif; ?> </p> <?php endif; ?> <?php if ( $issues_total > 0 && false !== $get_issues ) : ?> <p> <?php printf( /* translators: 1: Number of issues. 2: URL to Site Health screen. */ _n( 'Take a look at the <strong>%1$d item</strong> on the <a href="%2$s">Site Health screen</a>.', 'Take a look at the <strong>%1$d items</strong> on the <a href="%2$s">Site Health screen</a>.', $issues_total ), $issues_total, esc_url( admin_url( 'site-health.php' ) ) ); ?> </p> <?php endif; ?> </div> </div> <?php } /** * Outputs empty dashboard widget to be populated by JS later. * * Usable by plugins. * * @since 2.5.0 */ function wp_dashboard_empty() {} /** * Displays a welcome panel to introduce users to WordPress. * * @since 3.3.0 * @since 5.9.0 Send users to the Site Editor if the active theme is block-based. */ function wp_welcome_panel() { list( $display_version ) = explode( '-', wp_get_wp_version() ); $can_customize = current_user_can( 'customize' ); $is_block_theme = wp_is_block_theme(); ?> <div class="welcome-panel-content"> <div class="welcome-panel-header-wrap"> <div class="welcome-panel-header"> <div class="welcome-panel-header-image"> <?php echo file_get_contents( dirname( __DIR__ ) . '/images/dashboard-background.svg' ); ?> </div> <h2><?php _e( 'Welcome to WordPress!' ); ?></h2> <p> <a href="<?php echo esc_url( admin_url( 'about.php' ) ); ?>"> <?php /* translators: %s: Current WordPress version. */ printf( __( 'Learn more about the %s version.' ), esc_html( $display_version ) ); ?> </a> </p> </div> </div> <div class="welcome-panel-column-container"> <div class="welcome-panel-column"> <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"> <rect width="48" height="48" rx="4" fill="#1E1E1E"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M32.0668 17.0854L28.8221 13.9454L18.2008 24.671L16.8983 29.0827L21.4257 27.8309L32.0668 17.0854ZM16 32.75H24V31.25H16V32.75Z" fill="white"/> </svg> <div class="welcome-panel-column-content"> <h3><?php _e( 'Author rich content with blocks and patterns' ); ?></h3> <p><?php _e( 'Block patterns are pre-configured block layouts. Use them to get inspired or create new pages in a flash.' ); ?></p> <a href="<?php echo esc_url( admin_url( 'post-new.php?post_type=page' ) ); ?>"><?php _e( 'Add a new page' ); ?></a> </div> </div> <div class="welcome-panel-column"> <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"> <rect width="48" height="48" rx="4" fill="#1E1E1E"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M18 16h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H18a2 2 0 0 1-2-2V18a2 2 0 0 1 2-2zm12 1.5H18a.5.5 0 0 0-.5.5v3h13v-3a.5.5 0 0 0-.5-.5zm.5 5H22v8h8a.5.5 0 0 0 .5-.5v-7.5zm-10 0h-3V30a.5.5 0 0 0 .5.5h2.5v-8z" fill="#fff"/> </svg> <div class="welcome-panel-column-content"> <?php if ( $is_block_theme ) : ?> <h3><?php _e( 'Customize your entire site with block themes' ); ?></h3> <p><?php _e( 'Design everything on your site — from the header down to the footer, all using blocks and patterns.' ); ?></p> <a href="<?php echo esc_url( admin_url( 'site-editor.php' ) ); ?>"><?php _e( 'Open site editor' ); ?></a> <?php else : ?> <h3><?php _e( 'Start Customizing' ); ?></h3> <p><?php _e( 'Configure your site’s logo, header, menus, and more in the Customizer.' ); ?></p> <?php if ( $can_customize ) : ?> <a class="load-customize hide-if-no-customize" href="<?php echo wp_customize_url(); ?>"><?php _e( 'Open the Customizer' ); ?></a> <?php endif; ?> <?php endif; ?> </div> </div> <div class="welcome-panel-column"> <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"> <rect width="48" height="48" rx="4" fill="#1E1E1E"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M31 24a7 7 0 0 1-7 7V17a7 7 0 0 1 7 7zm-7-8a8 8 0 1 1 0 16 8 8 0 0 1 0-16z" fill="#fff"/> </svg> <div class="welcome-panel-column-content"> <?php if ( $is_block_theme ) : ?> <h3><?php _e( 'Switch up your site’s look & feel with Styles' ); ?></h3> <p><?php _e( 'Tweak your site, or give it a whole new look! Get creative — how about a new color palette or font?' ); ?></p> <a href="<?php echo esc_url( add_query_arg( 'p', rawurlencode( '/styles' ), admin_url( 'site-editor.php' ) ) ); ?>"><?php _e( 'Edit styles' ); ?></a> <?php else : ?> <h3><?php _e( 'Discover a new way to build your site.' ); ?></h3> <p><?php _e( 'There is a new kind of WordPress theme, called a block theme, that lets you build the site you’ve always wanted — with blocks and styles.' ); ?></p> <a href="<?php echo esc_url( __( 'https://wordpress.org/documentation/article/block-themes/' ) ); ?>"><?php _e( 'Learn about block themes' ); ?></a> <?php endif; ?> </div> </div> </div> </div> <?php } PK $��\6h� ms-admin-filters.phpnu �[��� <?php /** * Multisite Administration hooks * * @package WordPress * @subpackage Administration * @since 4.3.0 */ // Media hooks. add_filter( 'wp_handle_upload_prefilter', 'check_upload_size' ); // User hooks. add_action( 'user_admin_notices', 'new_user_email_admin_notice' ); add_action( 'network_admin_notices', 'new_user_email_admin_notice' ); add_action( 'admin_page_access_denied', '_access_denied_splash', 99 ); // Site hooks. add_action( 'wpmueditblogaction', 'upload_space_setting' ); // Network hooks. add_action( 'update_site_option_admin_email', 'wp_network_admin_email_change_notification', 10, 4 ); // Post hooks. add_filter( 'wp_insert_post_data', 'avoid_blog_page_permalink_collision', 10, 2 ); // Tools hooks. add_filter( 'import_allow_create_users', 'check_import_new_users' ); // Notices hooks. add_action( 'admin_notices', 'site_admin_notice' ); add_action( 'network_admin_notices', 'site_admin_notice' ); // Update hooks. add_action( 'network_admin_notices', 'update_nag', 3 ); add_action( 'network_admin_notices', 'maintenance_nag', 10 ); // Network Admin hooks. add_action( 'add_site_option_new_admin_email', 'update_network_option_new_admin_email', 10, 2 ); add_action( 'update_site_option_new_admin_email', 'update_network_option_new_admin_email', 10, 2 ); PK $��\8� � � # class-wp-privacy-policy-content.phpnu �[��� <?php /** * WP_Privacy_Policy_Content class. * * @package WordPress * @subpackage Administration * @since 4.9.6 */ #[AllowDynamicProperties] final class WP_Privacy_Policy_Content { private static $policy_content = array(); /** * Constructor * * @since 4.9.6 */ private function __construct() {} /** * Adds content to the postbox shown when editing the privacy policy. * * Plugins and themes should suggest text for inclusion in the site's privacy policy. * The suggested text should contain information about any functionality that affects user privacy, * and will be shown in the Suggested Privacy Policy Content postbox. * * Intended for use from `wp_add_privacy_policy_content()`. * * @since 4.9.6 * * @param string $plugin_name The name of the plugin or theme that is suggesting content for the site's privacy policy. * @param string $policy_text The suggested content for inclusion in the policy. */ public static function add( $plugin_name, $policy_text ) { if ( empty( $plugin_name ) || empty( $policy_text ) ) { return; } $data = array( 'plugin_name' => $plugin_name, 'policy_text' => $policy_text, ); if ( ! in_array( $data, self::$policy_content, true ) ) { self::$policy_content[] = $data; } } /** * Performs a quick check to determine whether any privacy info has changed. * * @since 4.9.6 */ public static function text_change_check() { $policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' ); // The site doesn't have a privacy policy. if ( empty( $policy_page_id ) ) { return false; } if ( ! current_user_can( 'edit_post', $policy_page_id ) ) { return false; } $old = (array) get_post_meta( $policy_page_id, '_wp_suggested_privacy_policy_content' ); // Updates are not relevant if the user has not reviewed any suggestions yet. if ( empty( $old ) ) { return false; } $cached = get_option( '_wp_suggested_policy_text_has_changed' ); /* * When this function is called before `admin_init`, `self::$policy_content` * has not been populated yet, so use the cached result from the last * execution instead. */ if ( ! did_action( 'admin_init' ) ) { return 'changed' === $cached; } $new = self::$policy_content; // Remove the extra values added to the meta. foreach ( $old as $key => $data ) { if ( ! is_array( $data ) || ! empty( $data['removed'] ) ) { unset( $old[ $key ] ); continue; } $old[ $key ] = array( 'plugin_name' => $data['plugin_name'], 'policy_text' => $data['policy_text'], ); } // Normalize the order of texts, to facilitate comparison. sort( $old ); sort( $new ); /* * The == operator (equal, not identical) was used intentionally. * See https://www.php.net/manual/en/language.operators.array.php */ if ( $new != $old ) { /* * A plugin was activated or deactivated, or some policy text has changed. * Show a notice on the relevant screens to inform the admin. */ add_action( 'admin_notices', array( 'WP_Privacy_Policy_Content', 'policy_text_changed_notice' ) ); $state = 'changed'; } else { $state = 'not-changed'; } // Cache the result for use before `admin_init` (see above). if ( $cached !== $state ) { update_option( '_wp_suggested_policy_text_has_changed', $state, false ); } return 'changed' === $state; } /** * Outputs a warning when some privacy info has changed. * * @since 4.9.6 */ public static function policy_text_changed_notice() { $screen = get_current_screen()->id; if ( 'privacy' !== $screen ) { return; } $privacy_message = sprintf( /* translators: %s: Privacy Policy Guide URL. */ __( 'The suggested privacy policy text has changed. Please <a href="%s">review the guide</a> and update your privacy policy.' ), esc_url( admin_url( 'privacy-policy-guide.php?tab=policyguide' ) ) ); wp_admin_notice( $privacy_message, array( 'type' => 'warning', 'additional_classes' => array( 'policy-text-updated' ), 'dismissible' => true, ) ); } /** * Updates the cached policy info when the policy page is updated. * * @since 4.9.6 * @access private * * @param int $post_id The ID of the updated post. */ public static function _policy_page_updated( $post_id ) { $policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' ); if ( ! $policy_page_id || $policy_page_id !== (int) $post_id ) { return; } // Remove updated|removed status. $old = (array) get_post_meta( $policy_page_id, '_wp_suggested_privacy_policy_content' ); $done = array(); $update_cache = false; foreach ( $old as $old_key => $old_data ) { if ( ! empty( $old_data['removed'] ) ) { // Remove the old policy text. $update_cache = true; continue; } if ( ! empty( $old_data['updated'] ) ) { // 'updated' is now 'added'. $done[] = array( 'plugin_name' => $old_data['plugin_name'], 'policy_text' => $old_data['policy_text'], 'added' => $old_data['updated'], ); $update_cache = true; } else { $done[] = $old_data; } } if ( $update_cache ) { delete_post_meta( $policy_page_id, '_wp_suggested_privacy_policy_content' ); // Update the cache. foreach ( $done as $data ) { add_post_meta( $policy_page_id, '_wp_suggested_privacy_policy_content', $data ); } } } /** * Checks for updated, added or removed privacy policy information from plugins. * * Caches the current info in post_meta of the policy page. * * @since 4.9.6 * * @return array The privacy policy text/information added by core and plugins. */ public static function get_suggested_policy_text() { $policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' ); $checked = array(); $time = time(); $update_cache = false; $new = self::$policy_content; $old = array(); if ( $policy_page_id ) { $old = (array) get_post_meta( $policy_page_id, '_wp_suggested_privacy_policy_content' ); } // Check for no-changes and updates. foreach ( $new as $new_key => $new_data ) { foreach ( $old as $old_key => $old_data ) { $found = false; if ( $new_data['policy_text'] === $old_data['policy_text'] ) { // Use the new plugin name in case it was changed, translated, etc. if ( $old_data['plugin_name'] !== $new_data['plugin_name'] ) { $old_data['plugin_name'] = $new_data['plugin_name']; $update_cache = true; } // A plugin was re-activated. if ( ! empty( $old_data['removed'] ) ) { unset( $old_data['removed'] ); $old_data['added'] = $time; $update_cache = true; } $checked[] = $old_data; $found = true; } elseif ( $new_data['plugin_name'] === $old_data['plugin_name'] ) { // The info for the policy was updated. $checked[] = array( 'plugin_name' => $new_data['plugin_name'], 'policy_text' => $new_data['policy_text'], 'updated' => $time, ); $found = true; $update_cache = true; } if ( $found ) { unset( $new[ $new_key ], $old[ $old_key ] ); continue 2; } } } if ( ! empty( $new ) ) { // A plugin was activated. foreach ( $new as $new_data ) { if ( ! empty( $new_data['plugin_name'] ) && ! empty( $new_data['policy_text'] ) ) { $new_data['added'] = $time; $checked[] = $new_data; } } $update_cache = true; } if ( ! empty( $old ) ) { // A plugin was deactivated. foreach ( $old as $old_data ) { if ( ! empty( $old_data['plugin_name'] ) && ! empty( $old_data['policy_text'] ) ) { $data = array( 'plugin_name' => $old_data['plugin_name'], 'policy_text' => $old_data['policy_text'], 'removed' => $time, ); $checked[] = $data; } } $update_cache = true; } if ( $update_cache && $policy_page_id ) { delete_post_meta( $policy_page_id, '_wp_suggested_privacy_policy_content' ); // Update the cache. foreach ( $checked as $data ) { add_post_meta( $policy_page_id, '_wp_suggested_privacy_policy_content', $data ); } } return $checked; } /** * Adds a notice with a link to the guide when editing the privacy policy page. * * @since 4.9.6 * @since 5.0.0 The `$post` parameter was made optional. * * @global WP_Post $post Global post object. * * @param WP_Post|null $post The currently edited post. Default null. */ public static function notice( $post = null ) { if ( is_null( $post ) ) { global $post; } else { $post = get_post( $post ); } if ( ! ( $post instanceof WP_Post ) ) { return; } if ( ! current_user_can( 'manage_privacy_options' ) ) { return; } $current_screen = get_current_screen(); $policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' ); if ( 'post' !== $current_screen->base || $policy_page_id !== $post->ID ) { return; } $message = __( 'Need help putting together your new Privacy Policy page? Check out the guide for recommendations on what content to include, along with policies suggested by your plugins and theme.' ); $url = esc_url( admin_url( 'options-privacy.php?tab=policyguide' ) ); $label = __( 'View Privacy Policy Guide.' ); if ( get_current_screen()->is_block_editor() ) { wp_enqueue_script( 'wp-notices' ); $action = array( 'url' => $url, 'label' => $label, ); wp_add_inline_script( 'wp-notices', sprintf( 'wp.data.dispatch( "core/notices" ).createWarningNotice( "%s", { actions: [ %s ], isDismissible: false } )', $message, wp_json_encode( $action, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ), 'after' ); } else { $message .= sprintf( ' <a href="%s" target="_blank">%s <span class="screen-reader-text">%s</span></a>', $url, $label, /* translators: Hidden accessibility text. */ __( '(opens in a new tab)' ) ); wp_admin_notice( $message, array( 'type' => 'warning', 'additional_classes' => array( 'inline', 'wp-pp-notice' ), ) ); } } /** * Outputs the privacy policy guide together with content from the theme and plugins. * * @since 4.9.6 */ public static function privacy_policy_guide() { $content_array = self::get_suggested_policy_text(); $date_format = __( 'F j, Y' ); $i = 0; foreach ( $content_array as $section ) { ++$i; $removed = ''; if ( ! empty( $section['removed'] ) ) { $badge_class = ' red'; $date = date_i18n( $date_format, $section['removed'] ); /* translators: %s: Date of plugin deactivation. */ $badge_title = sprintf( __( 'Removed %s.' ), $date ); /* translators: %s: Date of plugin deactivation. */ $removed = sprintf( __( 'You deactivated this plugin on %s and may no longer need this policy.' ), $date ); $removed = wp_get_admin_notice( $removed, array( 'type' => 'info', 'additional_classes' => array( 'inline' ), ) ); } elseif ( ! empty( $section['updated'] ) ) { $badge_class = ' blue'; $date = date_i18n( $date_format, $section['updated'] ); /* translators: %s: Date of privacy policy text update. */ $badge_title = sprintf( __( 'Updated %s.' ), $date ); } $plugin_name = esc_html( $section['plugin_name'] ); ?> <h4 class="privacy-settings-accordion-heading"> <button aria-expanded="false" class="privacy-settings-accordion-trigger" aria-controls="privacy-settings-accordion-block-<?php echo $i; ?>" type="button"> <span class="title"><?php echo $plugin_name; ?></span> <?php if ( ! empty( $section['removed'] ) || ! empty( $section['updated'] ) ) : ?> <span class="badge <?php echo $badge_class; ?>"> <?php echo $badge_title; ?></span> <?php endif; ?> <span class="icon"></span> </button> </h4> <div id="privacy-settings-accordion-block-<?php echo $i; ?>" class="privacy-settings-accordion-panel privacy-text-box-body" hidden="hidden"> <?php echo $removed; echo $section['policy_text']; ?> <?php if ( empty( $section['removed'] ) ) : ?> <div class="privacy-settings-accordion-actions"> <span class="success" aria-hidden="true"><?php _e( 'Copied!' ); ?></span> <button type="button" class="privacy-text-copy button"> <span aria-hidden="true"><?php _e( 'Copy suggested policy text to clipboard' ); ?></span> <span class="screen-reader-text"> <?php /* translators: Hidden accessibility text. %s: Plugin name. */ printf( __( 'Copy suggested policy text from %s.' ), $plugin_name ); ?> </span> </button> </div> <?php endif; ?> </div> <?php } } /** * Returns the default suggested privacy policy content. * * @since 4.9.6 * @since 5.0.0 Added the `$blocks` parameter. * * @param bool $description Whether to include the descriptions under the section headings. Default false. * @param bool $blocks Whether to format the content for the block editor. Default true. * @return string The default policy content. */ public static function get_default_content( $description = false, $blocks = true ) { $suggested_text = '<strong class="privacy-policy-tutorial">' . __( 'Suggested text:' ) . ' </strong>'; $content = ''; $strings = array(); // Start of the suggested privacy policy text. if ( $description ) { $strings[] = '<div class="wp-suggested-text">'; } /* translators: Default privacy policy heading. */ $strings[] = '<h2 class="wp-block-heading">' . __( 'Who we are' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this section you should note your site URL, as well as the name of the company, organization, or individual behind it, and some accurate contact information.' ) . '</p>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'The amount of information you may be required to show will vary depending on your local or national business regulations. You may, for example, be required to display a physical address, a registered address, or your company registration number.' ) . '</p>'; } else { /* translators: Default privacy policy text. %s: Site URL. */ $strings[] = '<p>' . $suggested_text . sprintf( __( 'Our website address is: %s.' ), get_bloginfo( 'url', 'display' ) ) . '</p>'; } if ( $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'What personal data we collect and why we collect it' ) . '</h2>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this section you should note what personal data you collect from users and site visitors. This may include personal data, such as name, email address, personal account preferences; transactional data, such as purchase information; and technical data, such as information about cookies.' ) . '</p>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'You should also note any collection and retention of sensitive personal data, such as data concerning health.' ) . '</p>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In addition to listing what personal data you collect, you need to note why you collect it. These explanations must note either the legal basis for your data collection and retention or the active consent the user has given.' ) . '</p>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'Personal data is not just created by a user’s interactions with your site. Personal data is also generated from technical processes such as contact forms, comments, cookies, analytics, and third party embeds.' ) . '</p>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'By default WordPress does not collect any personal data about visitors, and only collects the data shown on the User Profile screen from registered users. However some of your plugins may collect personal data. You should add the relevant information below.' ) . '</p>'; } /* translators: Default privacy policy heading. */ $strings[] = '<h2 class="wp-block-heading">' . __( 'Comments' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this subsection you should note what information is captured through comments. We have noted the data which WordPress collects by default.' ) . '</p>'; } else { /* translators: Default privacy policy text. */ $strings[] = '<p>' . $suggested_text . __( 'When visitors leave comments on the site we collect the data shown in the comments form, and also the visitor’s IP address and browser user agent string to help spam detection.' ) . '</p>'; /* translators: Default privacy policy text. */ $strings[] = '<p>' . __( 'An anonymized string created from your email address (also called a hash) may be provided to the Gravatar service to see if you are using it. The Gravatar service privacy policy is available here: https://automattic.com/privacy/. After approval of your comment, your profile picture is visible to the public in the context of your comment.' ) . '</p>'; } /* translators: Default privacy policy heading. */ $strings[] = '<h2 class="wp-block-heading">' . __( 'Media' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this subsection you should note what information may be disclosed by users who can upload media files. All uploaded files are usually publicly accessible.' ) . '</p>'; } else { /* translators: Default privacy policy text. */ $strings[] = '<p>' . $suggested_text . __( 'If you upload images to the website, you should avoid uploading images with embedded location data (EXIF GPS) included. Visitors to the website can download and extract any location data from images on the website.' ) . '</p>'; } if ( $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'Contact forms' ) . '</h2>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'By default, WordPress does not include a contact form. If you use a contact form plugin, use this subsection to note what personal data is captured when someone submits a contact form, and how long you keep it. For example, you may note that you keep contact form submissions for a certain period for customer service purposes, but you do not use the information submitted through them for marketing purposes.' ) . '</p>'; } /* translators: Default privacy policy heading. */ $strings[] = '<h2 class="wp-block-heading">' . __( 'Cookies' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this subsection you should list the cookies your website uses, including those set by your plugins, social media, and analytics. We have provided the cookies which WordPress installs by default.' ) . '</p>'; } else { /* translators: Default privacy policy text. */ $strings[] = '<p>' . $suggested_text . __( 'If you leave a comment on our site you may opt-in to saving your name, email address and website in cookies. These are for your convenience so that you do not have to fill in your details again when you leave another comment. These cookies will last for one year.' ) . '</p>'; /* translators: Default privacy policy text. */ $strings[] = '<p>' . __( 'If you visit our login page, we will set a temporary cookie to determine if your browser accepts cookies. This cookie contains no personal data and is discarded when you close your browser.' ) . '</p>'; /* translators: Default privacy policy text. */ $strings[] = '<p>' . __( 'When you log in, we will also set up several cookies to save your login information and your screen display choices. Login cookies last for two days, and screen options cookies last for a year. If you select "Remember Me", your login will persist for two weeks. If you log out of your account, the login cookies will be removed.' ) . '</p>'; /* translators: Default privacy policy text. */ $strings[] = '<p>' . __( 'If you edit or publish an article, an additional cookie will be saved in your browser. This cookie includes no personal data and simply indicates the post ID of the article you just edited. It expires after 1 day.' ) . '</p>'; } if ( ! $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2 class="wp-block-heading">' . __( 'Embedded content from other websites' ) . '</h2>'; /* translators: Default privacy policy text. */ $strings[] = '<p>' . $suggested_text . __( 'Articles on this site may include embedded content (e.g. videos, images, articles, etc.). Embedded content from other websites behaves in the exact same way as if the visitor has visited the other website.' ) . '</p>'; /* translators: Default privacy policy text. */ $strings[] = '<p>' . __( 'These websites may collect data about you, use cookies, embed additional third-party tracking, and monitor your interaction with that embedded content, including tracking your interaction with the embedded content if you have an account and are logged in to that website.' ) . '</p>'; } if ( $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'Analytics' ) . '</h2>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this subsection you should note what analytics package you use, how users can opt out of analytics tracking, and a link to your analytics provider’s privacy policy, if any.' ) . '</p>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'By default WordPress does not collect any analytics data. However, many web hosting accounts collect some anonymous analytics data. You may also have installed a WordPress plugin that provides analytics services. In that case, add information from that plugin here.' ) . '</p>'; } /* translators: Default privacy policy heading. */ $strings[] = '<h2 class="wp-block-heading">' . __( 'Who we share your data with' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this section you should name and list all third party providers with whom you share site data, including partners, cloud-based services, payment processors, and third party service providers, and note what data you share with them and why. Link to their own privacy policies if possible.' ) . '</p>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'By default WordPress does not share any personal data with anyone.' ) . '</p>'; } else { /* translators: Default privacy policy text. */ $strings[] = '<p>' . $suggested_text . __( 'If you request a password reset, your IP address will be included in the reset email.' ) . '</p>'; } /* translators: Default privacy policy heading. */ $strings[] = '<h2 class="wp-block-heading">' . __( 'How long we retain your data' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this section you should explain how long you retain personal data collected or processed by the website. While it is your responsibility to come up with the schedule of how long you keep each dataset for and why you keep it, that information does need to be listed here. For example, you may want to say that you keep contact form entries for six months, analytics records for a year, and customer purchase records for ten years.' ) . '</p>'; } else { /* translators: Default privacy policy text. */ $strings[] = '<p>' . $suggested_text . __( 'If you leave a comment, the comment and its metadata are retained indefinitely. This is so we can recognize and approve any follow-up comments automatically instead of holding them in a moderation queue.' ) . '</p>'; /* translators: Default privacy policy text. */ $strings[] = '<p>' . __( 'For users that register on our website (if any), we also store the personal information they provide in their user profile. All users can see, edit, or delete their personal information at any time (except they cannot change their username). Website administrators can also see and edit that information.' ) . '</p>'; } /* translators: Default privacy policy heading. */ $strings[] = '<h2 class="wp-block-heading">' . __( 'What rights you have over your data' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this section you should explain what rights your users have over their data and how they can invoke those rights.' ) . '</p>'; } else { /* translators: Default privacy policy text. */ $strings[] = '<p>' . $suggested_text . __( 'If you have an account on this site, or have left comments, you can request to receive an exported file of the personal data we hold about you, including any data you have provided to us. You can also request that we erase any personal data we hold about you. This does not include any data we are obliged to keep for administrative, legal, or security purposes.' ) . '</p>'; } /* translators: Default privacy policy heading. */ $strings[] = '<h2 class="wp-block-heading">' . __( 'Where your data is sent' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this section you should list all transfers of your site data outside the European Union and describe the means by which that data is safeguarded to European data protection standards. This could include your web hosting, cloud storage, or other third party services.' ) . '</p>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'European data protection law requires data about European residents which is transferred outside the European Union to be safeguarded to the same standards as if the data was in Europe. So in addition to listing where data goes, you should describe how you ensure that these standards are met either by yourself or by your third party providers, whether that is through an agreement such as Privacy Shield, model clauses in your contracts, or binding corporate rules.' ) . '</p>'; } else { /* translators: Default privacy policy text. */ $strings[] = '<p>' . $suggested_text . __( 'Visitor comments may be checked through an automated spam detection service.' ) . '</p>'; } if ( $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'Contact information' ) . '</h2>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this section you should provide a contact method for privacy-specific concerns. If you are required to have a Data Protection Officer, list their name and full contact details here as well.' ) . '</p>'; } if ( $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'Additional information' ) . '</h2>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'If you use your site for commercial purposes and you engage in more complex collection or processing of personal data, you should note the following information in your privacy policy in addition to the information we have already discussed.' ) . '</p>'; } if ( $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'How we protect your data' ) . '</h2>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this section you should explain what measures you have taken to protect your users’ data. This could include technical measures such as encryption; security measures such as two factor authentication; and measures such as staff training in data protection. If you have carried out a Privacy Impact Assessment, you can mention it here too.' ) . '</p>'; } if ( $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'What data breach procedures we have in place' ) . '</h2>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this section you should explain what procedures you have in place to deal with data breaches, either potential or real, such as internal reporting systems, contact mechanisms, or bug bounties.' ) . '</p>'; } if ( $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'What third parties we receive data from' ) . '</h2>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'If your website receives data about users from third parties, including advertisers, this information must be included within the section of your privacy policy dealing with third party data.' ) . '</p>'; } if ( $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'What automated decision making and/or profiling we do with user data' ) . '</h2>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'If your website provides a service which includes automated decision making - for example, allowing customers to apply for credit, or aggregating their data into an advertising profile - you must note that this is taking place, and include information about how that information is used, what decisions are made with that aggregated data, and what rights users have over decisions made without human intervention.' ) . '</p>'; } if ( $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'Industry regulatory disclosure requirements' ) . '</h2>'; /* translators: Privacy policy tutorial. */ $strings[] = '<p class="privacy-policy-tutorial">' . __( 'If you are a member of a regulated industry, or if you are subject to additional privacy laws, you may be required to disclose that information here.' ) . '</p>'; $strings[] = '</div>'; } if ( $blocks ) { foreach ( $strings as $key => $string ) { if ( str_starts_with( $string, '<p>' ) ) { $strings[ $key ] = "<!-- wp:paragraph -->\n" . $string . "\n<!-- /wp:paragraph -->\n"; } if ( str_starts_with( $string, '<h2 ' ) ) { $strings[ $key ] = "<!-- wp:heading -->\n" . $string . "\n<!-- /wp:heading -->\n"; } } } $content = implode( '', $strings ); // End of the suggested privacy policy text. /** * Filters the default content suggested for inclusion in a privacy policy. * * @since 4.9.6 * @since 5.0.0 Added the `$strings`, `$description`, and `$blocks` parameters. * @deprecated 5.7.0 Use wp_add_privacy_policy_content() instead. * * @param string $content The default policy content. * @param string[] $strings An array of privacy policy content strings. * @param bool $description Whether policy descriptions should be included. * @param bool $blocks Whether the content should be formatted for the block editor. */ return apply_filters_deprecated( 'wp_get_default_privacy_policy_content', array( $content, $strings, $description, $blocks ), '5.7.0', 'wp_add_privacy_policy_content()' ); } /** * Adds the suggested privacy policy text to the policy postbox. * * @since 4.9.6 */ public static function add_suggested_content() { $content = self::get_default_content( false, false ); wp_add_privacy_policy_content( __( 'WordPress' ), $content ); } } PK $��\�;`�| | noop.phpnu �[��� <?php /** * Noop functions for load-scripts.php and load-styles.php. * * @package WordPress * @subpackage Administration * @since 4.4.0 */ /** * @ignore */ function __() {} /** * @ignore */ function _x() {} /** * @ignore */ function add_filter() {} /** * @ignore */ function has_filter() { return false; } /** * @ignore */ function esc_attr() {} /** * @ignore */ function apply_filters() {} /** * @ignore */ function get_option() {} /** * @ignore */ function is_lighttpd_before_150() {} /** * @ignore */ function add_action() {} /** * @ignore */ function did_action() {} /** * @ignore */ function do_action_ref_array() {} /** * @ignore */ function get_bloginfo() {} /** * @ignore */ function is_admin() { return true; } /** * @ignore */ function site_url() {} /** * @ignore */ function admin_url() {} /** * @ignore */ function home_url() {} /** * @ignore */ function includes_url() {} /** * @ignore */ function wp_guess_url() {} function get_file( $path ) { $path = realpath( $path ); if ( ! $path || ! @is_file( $path ) ) { return ''; } return @file_get_contents( $path ); } PK $��\�8. class-wp-site-icon.phpnu �[��� <?php /** * Administration API: WP_Site_Icon class * * @package WordPress * @subpackage Administration * @since 4.3.0 */ /** * Core class used to implement site icon functionality. * * @since 4.3.0 */ #[AllowDynamicProperties] class WP_Site_Icon { /** * The minimum size of the site icon. * * @since 4.3.0 * @var int */ public $min_size = 512; /** * The size to which to crop the image so that we can display it in the UI nicely. * * @since 4.3.0 * @var int */ public $page_crop = 512; /** * List of site icon sizes. * * @since 4.3.0 * @var int[] */ public $site_icon_sizes = array( /* * Square, medium sized tiles for IE11+. * * See https://msdn.microsoft.com/library/dn455106(v=vs.85).aspx */ 270, /* * App icon for Android/Chrome. * * @link https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android * @link https://developer.chrome.com/multidevice/android/installtohomescreen */ 192, /* * App icons up to iPhone 6 Plus. * * See https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/MobileHIG/IconMatrix.html */ 180, // Our regular Favicon. 32, ); /** * Registers actions and filters. * * @since 4.3.0 */ public function __construct() { add_action( 'delete_attachment', array( $this, 'delete_attachment_data' ) ); add_filter( 'get_post_metadata', array( $this, 'get_post_metadata' ), 10, 4 ); } /** * Creates an attachment 'object'. * * @since 4.3.0 * @deprecated 6.5.0 * * @param string $cropped Cropped image URL. * @param int $parent_attachment_id Attachment ID of parent image. * @return array An array with attachment object data. */ public function create_attachment_object( $cropped, $parent_attachment_id ) { _deprecated_function( __METHOD__, '6.5.0', 'wp_copy_parent_attachment_properties()' ); $parent = get_post( $parent_attachment_id ); $parent_url = wp_get_attachment_url( $parent->ID ); $url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url ); $size = wp_getimagesize( $cropped ); $image_type = ( $size ) ? $size['mime'] : 'image/jpeg'; $attachment = array( 'ID' => $parent_attachment_id, 'post_title' => wp_basename( $cropped ), 'post_content' => $url, 'post_mime_type' => $image_type, 'guid' => $url, 'context' => 'site-icon', ); return $attachment; } /** * Inserts an attachment. * * @since 4.3.0 * * @param array $attachment An array with attachment object data. * @param string $file File path of the attached image. * @return int Attachment ID. */ public function insert_attachment( $attachment, $file ) { $attachment_id = wp_insert_attachment( $attachment, $file ); $metadata = wp_generate_attachment_metadata( $attachment_id, $file ); /** * Filters the site icon attachment metadata. * * @since 4.3.0 * * @see wp_generate_attachment_metadata() * * @param array $metadata Attachment metadata. */ $metadata = apply_filters( 'site_icon_attachment_metadata', $metadata ); wp_update_attachment_metadata( $attachment_id, $metadata ); return $attachment_id; } /** * Adds additional sizes to be made when creating the site icon images. * * @since 4.3.0 * * @param array[] $sizes Array of arrays containing information for additional sizes. * @return array[] Array of arrays containing additional image sizes. */ public function additional_sizes( $sizes = array() ) { $only_crop_sizes = array(); /** * Filters the different dimensions that a site icon is saved in. * * @since 4.3.0 * * @param int[] $site_icon_sizes Array of sizes available for the Site Icon. */ $this->site_icon_sizes = apply_filters( 'site_icon_image_sizes', $this->site_icon_sizes ); // Use a natural sort of numbers. natsort( $this->site_icon_sizes ); $this->site_icon_sizes = array_reverse( $this->site_icon_sizes ); // Ensure that we only resize the image into sizes that allow cropping. foreach ( $sizes as $name => $size_array ) { if ( isset( $size_array['crop'] ) ) { $only_crop_sizes[ $name ] = $size_array; } } foreach ( $this->site_icon_sizes as $size ) { if ( $size < $this->min_size ) { $only_crop_sizes[ 'site_icon-' . $size ] = array( 'width ' => $size, 'height' => $size, 'crop' => true, ); } } return $only_crop_sizes; } /** * Adds Site Icon sizes to the array of image sizes on demand. * * @since 4.3.0 * * @param string[] $sizes Array of image size names. * @return string[] Array of image size names. */ public function intermediate_image_sizes( $sizes = array() ) { /** This filter is documented in wp-admin/includes/class-wp-site-icon.php */ $this->site_icon_sizes = apply_filters( 'site_icon_image_sizes', $this->site_icon_sizes ); foreach ( $this->site_icon_sizes as $size ) { $sizes[] = 'site_icon-' . $size; } return $sizes; } /** * Deletes the Site Icon when the image file is deleted. * * @since 4.3.0 * * @param int $post_id Attachment ID. */ public function delete_attachment_data( $post_id ) { $site_icon_id = (int) get_option( 'site_icon' ); if ( $site_icon_id && $post_id === $site_icon_id ) { delete_option( 'site_icon' ); } } /** * Adds custom image sizes when meta data for an image is requested, that happens to be used as Site Icon. * * @since 4.3.0 * * @param null|array|string $value The value get_metadata() should return a single metadata value, or an * array of values. * @param int $post_id Post ID. * @param string $meta_key Meta key. * @param bool $single Whether to return only the first value of the specified `$meta_key`. * @return array|null|string The attachment metadata value, array of values, or null. */ public function get_post_metadata( $value, $post_id, $meta_key, $single ) { if ( $single && '_wp_attachment_backup_sizes' === $meta_key ) { $site_icon_id = (int) get_option( 'site_icon' ); if ( $post_id === $site_icon_id ) { add_filter( 'intermediate_image_sizes', array( $this, 'intermediate_image_sizes' ) ); } } return $value; } } PK $��\�'�� � deprecated.phpnu �[��� <?php /** * Deprecated admin functions from past WordPress versions. You shouldn't use these * functions and look for the alternatives instead. The functions will be removed * in a later version. * * @package WordPress * @subpackage Deprecated */ /* * Deprecated functions come here to die. */ /** * @since 2.1.0 * @deprecated 2.1.0 Use wp_editor() * @see wp_editor() */ function tinymce_include() { _deprecated_function( __FUNCTION__, '2.1.0', 'wp_editor()' ); wp_tiny_mce(); } /** * Unused Admin function. * * @since 2.0.0 * @deprecated 2.5.0 * */ function documentation_link() { _deprecated_function( __FUNCTION__, '2.5.0' ); } /** * Calculates the new dimensions for a downsampled image. * * @since 2.0.0 * @deprecated 3.0.0 Use wp_constrain_dimensions() * @see wp_constrain_dimensions() * * @param int $width Current width of the image * @param int $height Current height of the image * @param int $wmax Maximum wanted width * @param int $hmax Maximum wanted height * @return array Shrunk dimensions (width, height). */ function wp_shrink_dimensions( $width, $height, $wmax = 128, $hmax = 96 ) { _deprecated_function( __FUNCTION__, '3.0.0', 'wp_constrain_dimensions()' ); return wp_constrain_dimensions( $width, $height, $wmax, $hmax ); } /** * Calculates the new dimensions for a downsampled image. * * @since 2.0.0 * @deprecated 3.5.0 Use wp_constrain_dimensions() * @see wp_constrain_dimensions() * * @param int $width Current width of the image * @param int $height Current height of the image * @return array Shrunk dimensions (width, height). */ function get_udims( $width, $height ) { _deprecated_function( __FUNCTION__, '3.5.0', 'wp_constrain_dimensions()' ); return wp_constrain_dimensions( $width, $height, 128, 96 ); } /** * Legacy function used to generate the categories checklist control. * * @since 0.71 * @deprecated 2.6.0 Use wp_category_checklist() * @see wp_category_checklist() * * @global int $post_ID * * @param int $default_category Unused. * @param int $category_parent Unused. * @param array $popular_ids Unused. */ function dropdown_categories( $default_category = 0, $category_parent = 0, $popular_ids = array() ) { _deprecated_function( __FUNCTION__, '2.6.0', 'wp_category_checklist()' ); global $post_ID; wp_category_checklist( $post_ID ); } /** * Legacy function used to generate a link categories checklist control. * * @since 2.1.0 * @deprecated 2.6.0 Use wp_link_category_checklist() * @see wp_link_category_checklist() * * @global int $link_id * * @param int $default_link_category Unused. */ function dropdown_link_categories( $default_link_category = 0 ) { _deprecated_function( __FUNCTION__, '2.6.0', 'wp_link_category_checklist()' ); global $link_id; wp_link_category_checklist( $link_id ); } /** * Get the real filesystem path to a file to edit within the admin. * * @since 1.5.0 * @deprecated 2.9.0 * @uses WP_CONTENT_DIR Full filesystem path to the wp-content directory. * * @param string $file Filesystem path relative to the wp-content directory. * @return string Full filesystem path to edit. */ function get_real_file_to_edit( $file ) { _deprecated_function( __FUNCTION__, '2.9.0' ); return WP_CONTENT_DIR . $file; } /** * Legacy function used for generating a categories drop-down control. * * @since 1.2.0 * @deprecated 3.0.0 Use wp_dropdown_categories() * @see wp_dropdown_categories() * * @param int $current_cat Optional. ID of the current category. Default 0. * @param int $current_parent Optional. Current parent category ID. Default 0. * @param int $category_parent Optional. Parent ID to retrieve categories for. Default 0. * @param int $level Optional. Number of levels deep to display. Default 0. * @param array $categories Optional. Categories to include in the control. Default 0. * @return void|false Void on success, false if no categories were found. */ function wp_dropdown_cats( $current_cat = 0, $current_parent = 0, $category_parent = 0, $level = 0, $categories = 0 ) { _deprecated_function( __FUNCTION__, '3.0.0', 'wp_dropdown_categories()' ); if (!$categories ) $categories = get_categories( array('hide_empty' => 0) ); if ( $categories ) { foreach ( $categories as $category ) { if ( $current_cat != $category->term_id && $category_parent == $category->parent) { $pad = str_repeat( '– ', $level ); $category->name = esc_html( $category->name ); echo "\n\t<option value='$category->term_id'"; if ( $current_parent == $category->term_id ) echo " selected='selected'"; echo ">$pad$category->name</option>"; wp_dropdown_cats( $current_cat, $current_parent, $category->term_id, $level +1, $categories ); } } } else { return false; } } /** * Register a setting and its sanitization callback * * @since 2.7.0 * @deprecated 3.0.0 Use register_setting() * @see register_setting() * * @param string $option_group A settings group name. Should correspond to an allowed option key name. * Default allowed option key names include 'general', 'discussion', 'media', * 'reading', 'writing', and 'options'. * @param string $option_name The name of an option to sanitize and save. * @param callable $sanitize_callback Optional. A callback function that sanitizes the option's value. */ function add_option_update_handler( $option_group, $option_name, $sanitize_callback = '' ) { _deprecated_function( __FUNCTION__, '3.0.0', 'register_setting()' ); register_setting( $option_group, $option_name, $sanitize_callback ); } /** * Unregister a setting * * @since 2.7.0 * @deprecated 3.0.0 Use unregister_setting() * @see unregister_setting() * * @param string $option_group The settings group name used during registration. * @param string $option_name The name of the option to unregister. * @param callable $sanitize_callback Optional. Deprecated. */ function remove_option_update_handler( $option_group, $option_name, $sanitize_callback = '' ) { _deprecated_function( __FUNCTION__, '3.0.0', 'unregister_setting()' ); unregister_setting( $option_group, $option_name, $sanitize_callback ); } /** * Determines the language to use for CodePress syntax highlighting. * * @since 2.8.0 * @deprecated 3.0.0 * * @param string $filename */ function codepress_get_lang( $filename ) { _deprecated_function( __FUNCTION__, '3.0.0' ); } /** * Adds JavaScript required to make CodePress work on the theme/plugin file editors. * * @since 2.8.0 * @deprecated 3.0.0 */ function codepress_footer_js() { _deprecated_function( __FUNCTION__, '3.0.0' ); } /** * Determine whether to use CodePress. * * @since 2.8.0 * @deprecated 3.0.0 */ function use_codepress() { _deprecated_function( __FUNCTION__, '3.0.0' ); } /** * Get all user IDs. * * @deprecated 3.1.0 Use get_users() * * @global wpdb $wpdb WordPress database abstraction object. * * @return array List of user IDs. */ function get_author_user_ids() { _deprecated_function( __FUNCTION__, '3.1.0', 'get_users()' ); global $wpdb; if ( !is_multisite() ) $level_key = $wpdb->get_blog_prefix() . 'user_level'; else $level_key = $wpdb->get_blog_prefix() . 'capabilities'; // WPMU site admins don't have user_levels. return $wpdb->get_col( $wpdb->prepare("SELECT user_id FROM $wpdb->usermeta WHERE meta_key = %s AND meta_value != '0'", $level_key) ); } /** * Gets author users who can edit posts. * * @deprecated 3.1.0 Use get_users() * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $user_id User ID. * @return array|false List of editable authors. False if no editable users. */ function get_editable_authors( $user_id ) { _deprecated_function( __FUNCTION__, '3.1.0', 'get_users()' ); global $wpdb; $editable = get_editable_user_ids( $user_id ); if ( !$editable ) { return false; } else { $editable = join(',', $editable); $authors = $wpdb->get_results( "SELECT * FROM $wpdb->users WHERE ID IN ($editable) ORDER BY display_name" ); } return apply_filters('get_editable_authors', $authors); } /** * Gets the IDs of any users who can edit posts. * * @deprecated 3.1.0 Use get_users() * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $user_id User ID. * @param bool $exclude_zeros Optional. Whether to exclude zeroes. Default true. * @return array Array of editable user IDs, empty array otherwise. */ function get_editable_user_ids( $user_id, $exclude_zeros = true, $post_type = 'post' ) { _deprecated_function( __FUNCTION__, '3.1.0', 'get_users()' ); global $wpdb; if ( ! $user = get_userdata( $user_id ) ) return array(); $post_type_obj = get_post_type_object($post_type); if ( ! $user->has_cap($post_type_obj->cap->edit_others_posts) ) { if ( $user->has_cap($post_type_obj->cap->edit_posts) || ! $exclude_zeros ) return array($user->ID); else return array(); } if ( !is_multisite() ) $level_key = $wpdb->get_blog_prefix() . 'user_level'; else $level_key = $wpdb->get_blog_prefix() . 'capabilities'; // WPMU site admins don't have user_levels. $query = $wpdb->prepare("SELECT user_id FROM $wpdb->usermeta WHERE meta_key = %s", $level_key); if ( $exclude_zeros ) $query .= " AND meta_value != '0'"; return $wpdb->get_col( $query ); } /** * Gets all users who are not authors. * * @deprecated 3.1.0 Use get_users() * * @global wpdb $wpdb WordPress database abstraction object. */ function get_nonauthor_user_ids() { _deprecated_function( __FUNCTION__, '3.1.0', 'get_users()' ); global $wpdb; if ( !is_multisite() ) $level_key = $wpdb->get_blog_prefix() . 'user_level'; else $level_key = $wpdb->get_blog_prefix() . 'capabilities'; // WPMU site admins don't have user_levels. return $wpdb->get_col( $wpdb->prepare("SELECT user_id FROM $wpdb->usermeta WHERE meta_key = %s AND meta_value = '0'", $level_key) ); } if ( ! class_exists( 'WP_User_Search', false ) ) : /** * WordPress User Search class. * * @since 2.1.0 * @deprecated 3.1.0 Use WP_User_Query */ class WP_User_Search { /** * {@internal Missing Description}} * * @since 2.1.0 * @access private * @var mixed */ var $results; /** * {@internal Missing Description}} * * @since 2.1.0 * @access private * @var string */ var $search_term; /** * Page number. * * @since 2.1.0 * @access private * @var int */ var $page; /** * Role name that users have. * * @since 2.5.0 * @access private * @var string */ var $role; /** * Raw page number. * * @since 2.1.0 * @access private * @var int|bool */ var $raw_page; /** * Amount of users to display per page. * * @since 2.1.0 * @access public * @var int */ var $users_per_page = 50; /** * {@internal Missing Description}} * * @since 2.1.0 * @access private * @var int */ var $first_user; /** * {@internal Missing Description}} * * @since 2.1.0 * @access private * @var int */ var $last_user; /** * {@internal Missing Description}} * * @since 2.1.0 * @access private * @var string */ var $query_limit; /** * {@internal Missing Description}} * * @since 3.0.0 * @access private * @var string */ var $query_orderby; /** * {@internal Missing Description}} * * @since 3.0.0 * @access private * @var string */ var $query_from; /** * {@internal Missing Description}} * * @since 3.0.0 * @access private * @var string */ var $query_where; /** * {@internal Missing Description}} * * @since 2.1.0 * @access private * @var int */ var $total_users_for_query = 0; /** * {@internal Missing Description}} * * @since 2.1.0 * @access private * @var bool */ var $too_many_total_users = false; /** * {@internal Missing Description}} * * @since 2.1.0 * @access private * @var WP_Error */ var $search_errors; /** * {@internal Missing Description}} * * @since 2.7.0 * @access private * @var string */ var $paging_text; /** * PHP5 Constructor - Sets up the object properties. * * @since 2.1.0 * * @param string $search_term Search terms string. * @param int $page Optional. Page ID. * @param string $role Role name. * @return WP_User_Search */ function __construct( $search_term = '', $page = '', $role = '' ) { _deprecated_class( 'WP_User_Search', '3.1.0', 'WP_User_Query' ); $this->search_term = wp_unslash( $search_term ); $this->raw_page = ( '' == $page ) ? false : (int) $page; $this->page = ( '' == $page ) ? 1 : (int) $page; $this->role = $role; $this->prepare_query(); $this->query(); $this->do_paging(); } /** * PHP4 Constructor - Sets up the object properties. * * @since 2.1.0 * * @param string $search_term Search terms string. * @param int $page Optional. Page ID. * @param string $role Role name. * @return WP_User_Search */ public function WP_User_Search( $search_term = '', $page = '', $role = '' ) { _deprecated_constructor( 'WP_User_Search', '3.1.0', get_class( $this ) ); self::__construct( $search_term, $page, $role ); } /** * Prepares the user search query (legacy). * * @since 2.1.0 * @access public * * @global wpdb $wpdb WordPress database abstraction object. */ public function prepare_query() { global $wpdb; $this->first_user = ($this->page - 1) * $this->users_per_page; $this->query_limit = $wpdb->prepare(" LIMIT %d, %d", $this->first_user, $this->users_per_page); $this->query_orderby = ' ORDER BY user_login'; $search_sql = ''; if ( $this->search_term ) { $searches = array(); $search_sql = 'AND ('; foreach ( array('user_login', 'user_nicename', 'user_email', 'user_url', 'display_name') as $col ) $searches[] = $wpdb->prepare( $col . ' LIKE %s', '%' . like_escape($this->search_term) . '%' ); $search_sql .= implode(' OR ', $searches); $search_sql .= ')'; } $this->query_from = " FROM $wpdb->users"; $this->query_where = " WHERE 1=1 $search_sql"; if ( $this->role ) { $this->query_from .= " INNER JOIN $wpdb->usermeta ON $wpdb->users.ID = $wpdb->usermeta.user_id"; $this->query_where .= $wpdb->prepare(" AND $wpdb->usermeta.meta_key = '{$wpdb->prefix}capabilities' AND $wpdb->usermeta.meta_value LIKE %s", '%' . $this->role . '%'); } elseif ( is_multisite() ) { $level_key = $wpdb->prefix . 'capabilities'; // WPMU site admins don't have user_levels. $this->query_from .= ", $wpdb->usermeta"; $this->query_where .= " AND $wpdb->users.ID = $wpdb->usermeta.user_id AND meta_key = '{$level_key}'"; } do_action_ref_array( 'pre_user_search', array( &$this ) ); } /** * Executes the user search query. * * @since 2.1.0 * @access public * * @global wpdb $wpdb WordPress database abstraction object. */ public function query() { global $wpdb; $this->results = $wpdb->get_col("SELECT DISTINCT($wpdb->users.ID)" . $this->query_from . $this->query_where . $this->query_orderby . $this->query_limit); if ( $this->results ) $this->total_users_for_query = $wpdb->get_var("SELECT COUNT(DISTINCT($wpdb->users.ID))" . $this->query_from . $this->query_where); // No limit. else $this->search_errors = new WP_Error('no_matching_users_found', __('No users found.')); } /** * Prepares variables for use in templates. * * @since 2.1.0 * @access public */ function prepare_vars_for_template_usage() {} /** * Handles paging for the user search query. * * @since 2.1.0 * @access public */ public function do_paging() { if ( $this->total_users_for_query > $this->users_per_page ) { // Have to page the results. $args = array(); if ( ! empty($this->search_term) ) $args['usersearch'] = urlencode($this->search_term); if ( ! empty($this->role) ) $args['role'] = urlencode($this->role); $this->paging_text = paginate_links( array( 'total' => ceil($this->total_users_for_query / $this->users_per_page), 'current' => $this->page, 'base' => 'users.php?%_%', 'format' => 'userspage=%#%', 'add_args' => $args ) ); if ( $this->paging_text ) { $this->paging_text = sprintf( /* translators: 1: Starting number of users on the current page, 2: Ending number of users, 3: Total number of users. */ '<span class="displaying-num">' . __( 'Displaying %1$s–%2$s of %3$s' ) . '</span>%s', number_format_i18n( ( $this->page - 1 ) * $this->users_per_page + 1 ), number_format_i18n( min( $this->page * $this->users_per_page, $this->total_users_for_query ) ), number_format_i18n( $this->total_users_for_query ), $this->paging_text ); } } } /** * Retrieves the user search query results. * * @since 2.1.0 * @access public * * @return array */ public function get_results() { return (array) $this->results; } /** * Displaying paging text. * * @see do_paging() Builds paging text. * * @since 2.1.0 * @access public */ function page_links() { echo $this->paging_text; } /** * Whether paging is enabled. * * @see do_paging() Builds paging text. * * @since 2.1.0 * @access public * * @return bool */ function results_are_paged() { if ( $this->paging_text ) return true; return false; } /** * Whether there are search terms. * * @since 2.1.0 * @access public * * @return bool */ function is_search() { if ( $this->search_term ) return true; return false; } } endif; /** * Retrieves editable posts from other users. * * @since 2.3.0 * @deprecated 3.1.0 Use get_posts() * @see get_posts() * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $user_id User ID to not retrieve posts from. * @param string $type Optional. Post type to retrieve. Accepts 'draft', 'pending' or 'any' (all). * Default 'any'. * @return array List of posts from others. */ function get_others_unpublished_posts( $user_id, $type = 'any' ) { _deprecated_function( __FUNCTION__, '3.1.0' ); global $wpdb; $editable = get_editable_user_ids( $user_id ); if ( in_array($type, array('draft', 'pending')) ) $type_sql = " post_status = '$type' "; else $type_sql = " ( post_status = 'draft' OR post_status = 'pending' ) "; $dir = ( 'pending' == $type ) ? 'ASC' : 'DESC'; if ( !$editable ) { $other_unpubs = ''; } else { $editable = join(',', $editable); $other_unpubs = $wpdb->get_results( $wpdb->prepare("SELECT ID, post_title, post_author FROM $wpdb->posts WHERE post_type = 'post' AND $type_sql AND post_author IN ($editable) AND post_author != %d ORDER BY post_modified $dir", $user_id) ); } return apply_filters('get_others_drafts', $other_unpubs); } /** * Retrieve drafts from other users. * * @deprecated 3.1.0 Use get_posts() * @see get_posts() * * @param int $user_id User ID. * @return array List of drafts from other users. */ function get_others_drafts($user_id) { _deprecated_function( __FUNCTION__, '3.1.0' ); return get_others_unpublished_posts($user_id, 'draft'); } /** * Retrieve pending review posts from other users. * * @deprecated 3.1.0 Use get_posts() * @see get_posts() * * @param int $user_id User ID. * @return array List of posts with pending review post type from other users. */ function get_others_pending($user_id) { _deprecated_function( __FUNCTION__, '3.1.0' ); return get_others_unpublished_posts($user_id, 'pending'); } /** * Output the QuickPress dashboard widget. * * @since 3.0.0 * @deprecated 3.2.0 Use wp_dashboard_quick_press() * @see wp_dashboard_quick_press() */ function wp_dashboard_quick_press_output() { _deprecated_function( __FUNCTION__, '3.2.0', 'wp_dashboard_quick_press()' ); wp_dashboard_quick_press(); } /** * Outputs the TinyMCE editor. * * @since 2.7.0 * @deprecated 3.3.0 Use wp_editor() * @see wp_editor() */ function wp_tiny_mce( $teeny = false, $settings = false ) { _deprecated_function( __FUNCTION__, '3.3.0', 'wp_editor()' ); static $num = 1; if ( ! class_exists( '_WP_Editors', false ) ) require_once ABSPATH . WPINC . '/class-wp-editor.php'; $editor_id = 'content' . $num++; $set = array( 'teeny' => $teeny, 'tinymce' => $settings ? $settings : true, 'quicktags' => false ); $set = _WP_Editors::parse_settings($editor_id, $set); _WP_Editors::editor_settings($editor_id, $set); } /** * Preloads TinyMCE dialogs. * * @deprecated 3.3.0 Use wp_editor() * @see wp_editor() */ function wp_preload_dialogs() { _deprecated_function( __FUNCTION__, '3.3.0', 'wp_editor()' ); } /** * Prints TinyMCE editor JS. * * @deprecated 3.3.0 Use wp_editor() * @see wp_editor() */ function wp_print_editor_js() { _deprecated_function( __FUNCTION__, '3.3.0', 'wp_editor()' ); } /** * Handles quicktags. * * @deprecated 3.3.0 Use wp_editor() * @see wp_editor() */ function wp_quicktags() { _deprecated_function( __FUNCTION__, '3.3.0', 'wp_editor()' ); } /** * Returns the screen layout options. * * @since 2.8.0 * @deprecated 3.3.0 WP_Screen::render_screen_layout() * @see WP_Screen::render_screen_layout() */ function screen_layout( $screen ) { _deprecated_function( __FUNCTION__, '3.3.0', '$current_screen->render_screen_layout()' ); $current_screen = get_current_screen(); if ( ! $current_screen ) return ''; ob_start(); $current_screen->render_screen_layout(); return ob_get_clean(); } /** * Returns the screen's per-page options. * * @since 2.8.0 * @deprecated 3.3.0 Use WP_Screen::render_per_page_options() * @see WP_Screen::render_per_page_options() */ function screen_options( $screen ) { _deprecated_function( __FUNCTION__, '3.3.0', '$current_screen->render_per_page_options()' ); $current_screen = get_current_screen(); if ( ! $current_screen ) return ''; ob_start(); $current_screen->render_per_page_options(); return ob_get_clean(); } /** * Renders the screen's help. * * @since 2.7.0 * @deprecated 3.3.0 Use WP_Screen::render_screen_meta() * @see WP_Screen::render_screen_meta() */ function screen_meta( $screen ) { $current_screen = get_current_screen(); $current_screen->render_screen_meta(); } /** * Favorite actions were deprecated in version 3.2. Use the admin bar instead. * * @since 2.7.0 * @deprecated 3.2.0 Use WP_Admin_Bar * @see WP_Admin_Bar */ function favorite_actions() { _deprecated_function( __FUNCTION__, '3.2.0', 'WP_Admin_Bar' ); } /** * Handles uploading an image. * * @deprecated 3.3.0 Use wp_media_upload_handler() * @see wp_media_upload_handler() * * @return null|string */ function media_upload_image() { _deprecated_function( __FUNCTION__, '3.3.0', 'wp_media_upload_handler()' ); return wp_media_upload_handler(); } /** * Handles uploading an audio file. * * @deprecated 3.3.0 Use wp_media_upload_handler() * @see wp_media_upload_handler() * * @return null|string */ function media_upload_audio() { _deprecated_function( __FUNCTION__, '3.3.0', 'wp_media_upload_handler()' ); return wp_media_upload_handler(); } /** * Handles uploading a video file. * * @deprecated 3.3.0 Use wp_media_upload_handler() * @see wp_media_upload_handler() * * @return null|string */ function media_upload_video() { _deprecated_function( __FUNCTION__, '3.3.0', 'wp_media_upload_handler()' ); return wp_media_upload_handler(); } /** * Handles uploading a generic file. * * @deprecated 3.3.0 Use wp_media_upload_handler() * @see wp_media_upload_handler() * * @return null|string */ function media_upload_file() { _deprecated_function( __FUNCTION__, '3.3.0', 'wp_media_upload_handler()' ); return wp_media_upload_handler(); } /** * Handles retrieving the insert-from-URL form for an image. * * @deprecated 3.3.0 Use wp_media_insert_url_form() * @see wp_media_insert_url_form() * * @return string */ function type_url_form_image() { _deprecated_function( __FUNCTION__, '3.3.0', "wp_media_insert_url_form('image')" ); return wp_media_insert_url_form( 'image' ); } /** * Handles retrieving the insert-from-URL form for an audio file. * * @deprecated 3.3.0 Use wp_media_insert_url_form() * @see wp_media_insert_url_form() * * @return string */ function type_url_form_audio() { _deprecated_function( __FUNCTION__, '3.3.0', "wp_media_insert_url_form('audio')" ); return wp_media_insert_url_form( 'audio' ); } /** * Handles retrieving the insert-from-URL form for a video file. * * @deprecated 3.3.0 Use wp_media_insert_url_form() * @see wp_media_insert_url_form() * * @return string */ function type_url_form_video() { _deprecated_function( __FUNCTION__, '3.3.0', "wp_media_insert_url_form('video')" ); return wp_media_insert_url_form( 'video' ); } /** * Handles retrieving the insert-from-URL form for a generic file. * * @deprecated 3.3.0 Use wp_media_insert_url_form() * @see wp_media_insert_url_form() * * @return string */ function type_url_form_file() { _deprecated_function( __FUNCTION__, '3.3.0', "wp_media_insert_url_form('file')" ); return wp_media_insert_url_form( 'file' ); } /** * Add contextual help text for a page. * * Creates an 'Overview' help tab. * * @since 2.7.0 * @deprecated 3.3.0 Use WP_Screen::add_help_tab() * @see WP_Screen::add_help_tab() * * @param string $screen The handle for the screen to add help to. This is usually * the hook name returned by the `add_*_page()` functions. * @param string $help The content of an 'Overview' help tab. */ function add_contextual_help( $screen, $help ) { _deprecated_function( __FUNCTION__, '3.3.0', 'get_current_screen()->add_help_tab()' ); if ( is_string( $screen ) ) $screen = convert_to_screen( $screen ); WP_Screen::add_old_compat_help( $screen, $help ); } /** * Get the allowed themes for the current site. * * @since 3.0.0 * @deprecated 3.4.0 Use wp_get_themes() * @see wp_get_themes() * * @return WP_Theme[] Array of WP_Theme objects keyed by their name. */ function get_allowed_themes() { _deprecated_function( __FUNCTION__, '3.4.0', "wp_get_themes( array( 'allowed' => true ) )" ); $themes = wp_get_themes( array( 'allowed' => true ) ); $wp_themes = array(); foreach ( $themes as $theme ) { $wp_themes[ $theme->get('Name') ] = $theme; } return $wp_themes; } /** * Retrieves a list of broken themes. * * @since 1.5.0 * @deprecated 3.4.0 Use wp_get_themes() * @see wp_get_themes() * * @return array */ function get_broken_themes() { _deprecated_function( __FUNCTION__, '3.4.0', "wp_get_themes( array( 'errors' => true )" ); $themes = wp_get_themes( array( 'errors' => true ) ); $broken = array(); foreach ( $themes as $theme ) { $name = $theme->get('Name'); $broken[ $name ] = array( 'Name' => $name, 'Title' => $name, 'Description' => $theme->errors()->get_error_message(), ); } return $broken; } /** * Retrieves information on the current active theme. * * @since 2.0.0 * @deprecated 3.4.0 Use wp_get_theme() * @see wp_get_theme() * * @return WP_Theme */ function current_theme_info() { _deprecated_function( __FUNCTION__, '3.4.0', 'wp_get_theme()' ); return wp_get_theme(); } /** * This was once used to display an 'Insert into Post' button. * * Now it is deprecated and stubbed. * * @deprecated 3.5.0 */ function _insert_into_post_button( $type ) { _deprecated_function( __FUNCTION__, '3.5.0' ); } /** * This was once used to display a media button. * * Now it is deprecated and stubbed. * * @deprecated 3.5.0 */ function _media_button($title, $icon, $type, $id) { _deprecated_function( __FUNCTION__, '3.5.0' ); } /** * Gets an existing post and format it for editing. * * @since 2.0.0 * @deprecated 3.5.0 Use get_post() * @see get_post() * * @param int $id * @return WP_Post */ function get_post_to_edit( $id ) { _deprecated_function( __FUNCTION__, '3.5.0', 'get_post()' ); return get_post( $id, OBJECT, 'edit' ); } /** * Gets the default page information to use. * * @since 2.5.0 * @deprecated 3.5.0 Use get_default_post_to_edit() * @see get_default_post_to_edit() * * @return WP_Post Post object containing all the default post data as attributes */ function get_default_page_to_edit() { _deprecated_function( __FUNCTION__, '3.5.0', "get_default_post_to_edit( 'page' )" ); $page = get_default_post_to_edit(); $page->post_type = 'page'; return $page; } /** * This was once used to create a thumbnail from an Image given a maximum side size. * * @since 1.2.0 * @deprecated 3.5.0 Use image_resize() * @see image_resize() * * @param mixed $file Filename of the original image, Or attachment ID. * @param int $max_side Maximum length of a single side for the thumbnail. * @param mixed $deprecated Never used. * @return string Thumbnail path on success, Error string on failure. */ function wp_create_thumbnail( $file, $max_side, $deprecated = '' ) { _deprecated_function( __FUNCTION__, '3.5.0', 'image_resize()' ); return apply_filters( 'wp_create_thumbnail', image_resize( $file, $max_side, $max_side ) ); } /** * This was once used to display a meta box for the nav menu theme locations. * * Deprecated in favor of a 'Manage Locations' tab added to nav menus management screen. * * @since 3.0.0 * @deprecated 3.6.0 */ function wp_nav_menu_locations_meta_box() { _deprecated_function( __FUNCTION__, '3.6.0' ); } /** * This was once used to kick-off the Core Updater. * * Deprecated in favor of instantiating a Core_Upgrader instance directly, * and calling the 'upgrade' method. * * @since 2.7.0 * @deprecated 3.7.0 Use Core_Upgrader * @see Core_Upgrader */ function wp_update_core($current, $feedback = '') { _deprecated_function( __FUNCTION__, '3.7.0', 'new Core_Upgrader();' ); if ( !empty($feedback) ) add_filter('update_feedback', $feedback); require ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; $upgrader = new Core_Upgrader(); return $upgrader->upgrade($current); } /** * This was once used to kick-off the Plugin Updater. * * Deprecated in favor of instantiating a Plugin_Upgrader instance directly, * and calling the 'upgrade' method. * Unused since 2.8.0. * * @since 2.5.0 * @deprecated 3.7.0 Use Plugin_Upgrader * @see Plugin_Upgrader */ function wp_update_plugin($plugin, $feedback = '') { _deprecated_function( __FUNCTION__, '3.7.0', 'new Plugin_Upgrader();' ); if ( !empty($feedback) ) add_filter('update_feedback', $feedback); require ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; $upgrader = new Plugin_Upgrader(); return $upgrader->upgrade($plugin); } /** * This was once used to kick-off the Theme Updater. * * Deprecated in favor of instantiating a Theme_Upgrader instance directly, * and calling the 'upgrade' method. * Unused since 2.8.0. * * @since 2.7.0 * @deprecated 3.7.0 Use Theme_Upgrader * @see Theme_Upgrader */ function wp_update_theme($theme, $feedback = '') { _deprecated_function( __FUNCTION__, '3.7.0', 'new Theme_Upgrader();' ); if ( !empty($feedback) ) add_filter('update_feedback', $feedback); require ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; $upgrader = new Theme_Upgrader(); return $upgrader->upgrade($theme); } /** * This was once used to display attachment links. Now it is deprecated and stubbed. * * @since 2.0.0 * @deprecated 3.7.0 * * @param int|bool $id */ function the_attachment_links( $id = false ) { _deprecated_function( __FUNCTION__, '3.7.0' ); } /** * Displays a screen icon. * * @since 2.7.0 * @deprecated 3.8.0 */ function screen_icon() { _deprecated_function( __FUNCTION__, '3.8.0' ); echo get_screen_icon(); } /** * Retrieves the screen icon (no longer used in 3.8+). * * @since 3.2.0 * @deprecated 3.8.0 * * @return string An HTML comment explaining that icons are no longer used. */ function get_screen_icon() { _deprecated_function( __FUNCTION__, '3.8.0' ); return '<!-- Screen icons are no longer used as of WordPress 3.8. -->'; } /** * Deprecated dashboard widget controls. * * @since 2.5.0 * @deprecated 3.8.0 */ function wp_dashboard_incoming_links_output() {} /** * Deprecated dashboard secondary output. * * @deprecated 3.8.0 */ function wp_dashboard_secondary_output() {} /** * Deprecated dashboard widget controls. * * @since 2.7.0 * @deprecated 3.8.0 */ function wp_dashboard_incoming_links() {} /** * Deprecated dashboard incoming links control. * * @deprecated 3.8.0 */ function wp_dashboard_incoming_links_control() {} /** * Deprecated dashboard plugins control. * * @deprecated 3.8.0 */ function wp_dashboard_plugins() {} /** * Deprecated dashboard primary control. * * @deprecated 3.8.0 */ function wp_dashboard_primary_control() {} /** * Deprecated dashboard recent comments control. * * @deprecated 3.8.0 */ function wp_dashboard_recent_comments_control() {} /** * Deprecated dashboard secondary section. * * @deprecated 3.8.0 */ function wp_dashboard_secondary() {} /** * Deprecated dashboard secondary control. * * @deprecated 3.8.0 */ function wp_dashboard_secondary_control() {} /** * Display plugins text for the WordPress news widget. * * @since 2.5.0 * @deprecated 4.8.0 * * @param string $rss The RSS feed URL. * @param array $args Array of arguments for this RSS feed. */ function wp_dashboard_plugins_output( $rss, $args = array() ) { _deprecated_function( __FUNCTION__, '4.8.0' ); // Plugin feeds plus link to install them. $popular = fetch_feed( $args['url']['popular'] ); if ( false === $plugin_slugs = get_transient( 'plugin_slugs' ) ) { $plugin_slugs = array_keys( get_plugins() ); set_transient( 'plugin_slugs', $plugin_slugs, DAY_IN_SECONDS ); } echo '<ul>'; foreach ( array( $popular ) as $feed ) { if ( is_wp_error( $feed ) || ! $feed->get_item_quantity() ) continue; $items = $feed->get_items(0, 5); // Pick a random, non-installed plugin. while ( true ) { // Abort this foreach loop iteration if there's no plugins left of this type. if ( 0 === count($items) ) continue 2; $item_key = array_rand($items); $item = $items[$item_key]; list($link, $frag) = explode( '#', $item->get_link() ); $link = esc_url($link); if ( preg_match( '|/([^/]+?)/?$|', $link, $matches ) ) $slug = $matches[1]; else { unset( $items[$item_key] ); continue; } // Is this random plugin's slug already installed? If so, try again. reset( $plugin_slugs ); foreach ( $plugin_slugs as $plugin_slug ) { if ( str_starts_with( $plugin_slug, $slug ) ) { unset( $items[$item_key] ); continue 2; } } // If we get to this point, then the random plugin isn't installed and we can stop the while(). break; } // Eliminate some common badly formed plugin descriptions. while ( ( null !== $item_key = array_rand($items) ) && str_contains( $items[$item_key]->get_description(), 'Plugin Name:' ) ) unset($items[$item_key]); if ( !isset($items[$item_key]) ) continue; $raw_title = $item->get_title(); $ilink = wp_nonce_url('plugin-install.php?tab=plugin-information&plugin=' . $slug, 'install-plugin_' . $slug) . '&TB_iframe=true&width=600&height=800'; echo '<li class="dashboard-news-plugin"><span>' . __( 'Popular Plugin' ) . ':</span> ' . esc_html( $raw_title ) . ' <a href="' . $ilink . '" class="thickbox open-plugin-details-modal" aria-label="' . /* translators: %s: Plugin name. */ esc_attr( sprintf( _x( 'Install %s', 'plugin' ), $raw_title ) ) . '">(' . __( 'Install' ) . ')</a></li>'; $feed->__destruct(); unset( $feed ); } echo '</ul>'; } /** * This was once used to move child posts to a new parent. * * @since 2.3.0 * @deprecated 3.9.0 * @access private * * @param int $old_ID * @param int $new_ID */ function _relocate_children( $old_ID, $new_ID ) { _deprecated_function( __FUNCTION__, '3.9.0' ); } /** * Add a top-level menu page in the 'objects' section. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 2.7.0 * * @deprecated 4.5.0 Use add_menu_page() * @see add_menu_page() * @global int $_wp_last_object_menu * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param string $icon_url Optional. The URL to the icon to be used for this menu. * @return string The resulting page's hook_suffix. */ function add_object_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $icon_url = '') { _deprecated_function( __FUNCTION__, '4.5.0', 'add_menu_page()' ); global $_wp_last_object_menu; $_wp_last_object_menu++; return add_menu_page($page_title, $menu_title, $capability, $menu_slug, $callback, $icon_url, $_wp_last_object_menu); } /** * Add a top-level menu page in the 'utility' section. * * This function takes a capability which will be used to determine whether * or not a page is included in the menu. * * The function which is hooked in to handle the output of the page must check * that the user has the required capability as well. * * @since 2.7.0 * * @deprecated 4.5.0 Use add_menu_page() * @see add_menu_page() * @global int $_wp_last_utility_menu * * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected. * @param string $menu_title The text to be used for the menu. * @param string $capability The capability required for this menu to be displayed to the user. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu). * @param callable $callback Optional. The function to be called to output the content for this page. * @param string $icon_url Optional. The URL to the icon to be used for this menu. * @return string The resulting page's hook_suffix. */ function add_utility_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $icon_url = '') { _deprecated_function( __FUNCTION__, '4.5.0', 'add_menu_page()' ); global $_wp_last_utility_menu; $_wp_last_utility_menu++; return add_menu_page($page_title, $menu_title, $capability, $menu_slug, $callback, $icon_url, $_wp_last_utility_menu); } /** * Disables autocomplete on the 'post' form (Add/Edit Post screens) for WebKit browsers, * as they disregard the autocomplete setting on the editor textarea. That can break the editor * when the user navigates to it with the browser's Back button. See #28037 * * Replaced with wp_page_reload_on_back_button_js() that also fixes this problem. * * @since 4.0.0 * @deprecated 4.6.0 * * @link https://core.trac.wordpress.org/ticket/35852 * * @global bool $is_safari * @global bool $is_chrome */ function post_form_autocomplete_off() { global $is_safari, $is_chrome; _deprecated_function( __FUNCTION__, '4.6.0' ); if ( $is_safari || $is_chrome ) { echo ' autocomplete="off"'; } } /** * Display JavaScript on the page. * * @since 3.5.0 * @deprecated 4.9.0 */ function options_permalink_add_js() { ?> <script> jQuery( function() { jQuery('.permalink-structure input:radio').change(function() { if ( 'custom' == this.value ) return; jQuery('#permalink_structure').val( this.value ); }); jQuery( '#permalink_structure' ).on( 'click input', function() { jQuery( '#custom_selection' ).prop( 'checked', true ); }); } ); </script> <?php } /** * Previous class for list table for privacy data export requests. * * @since 4.9.6 * @deprecated 5.3.0 */ class WP_Privacy_Data_Export_Requests_Table extends WP_Privacy_Data_Export_Requests_List_Table { function __construct( $args ) { _deprecated_function( __CLASS__, '5.3.0', 'WP_Privacy_Data_Export_Requests_List_Table' ); if ( ! isset( $args['screen'] ) || $args['screen'] === 'export_personal_data' ) { $args['screen'] = 'export-personal-data'; } parent::__construct( $args ); } } /** * Previous class for list table for privacy data erasure requests. * * @since 4.9.6 * @deprecated 5.3.0 */ class WP_Privacy_Data_Removal_Requests_Table extends WP_Privacy_Data_Removal_Requests_List_Table { function __construct( $args ) { _deprecated_function( __CLASS__, '5.3.0', 'WP_Privacy_Data_Removal_Requests_List_Table' ); if ( ! isset( $args['screen'] ) || $args['screen'] === 'remove_personal_data' ) { $args['screen'] = 'erase-personal-data'; } parent::__construct( $args ); } } /** * Was used to add options for the privacy requests screens before they were separate files. * * @since 4.9.8 * @access private * @deprecated 5.3.0 */ function _wp_privacy_requests_screen_options() { _deprecated_function( __FUNCTION__, '5.3.0' ); } /** * Was used to filter input from media_upload_form_handler() and to assign a default * post_title from the file name if none supplied. * * @since 2.5.0 * @deprecated 6.0.0 * * @param array $post The WP_Post attachment object converted to an array. * @param array $attachment An array of attachment metadata. * @return array Attachment post object converted to an array. */ function image_attachment_fields_to_save( $post, $attachment ) { _deprecated_function( __FUNCTION__, '6.0.0' ); return $post; } PK $��\.ΐBv v ! class-wp-ms-themes-list-table.phpnu �[��� <?php /** * List Table API: WP_MS_Themes_List_Table class * * @package WordPress * @subpackage Administration * @since 3.1.0 */ /** * Core class used to implement displaying themes in a list table for the network admin. * * @since 3.1.0 * * @see WP_List_Table */ class WP_MS_Themes_List_Table extends WP_List_Table { public $site_id; public $is_site_themes; private $has_items; /** * Whether to show the auto-updates UI. * * @since 5.5.0 * * @var bool True if auto-updates UI is to be shown, false otherwise. */ protected $show_autoupdates = true; /** * Constructor. * * @since 3.1.0 * * @see WP_List_Table::__construct() for more information on default arguments. * * @global string $status The current theme status. * @global int $page The current page number. * * @param array $args An associative array of arguments. */ public function __construct( $args = array() ) { global $status, $page; parent::__construct( array( 'plural' => 'themes', 'screen' => $args['screen'] ?? null, ) ); $status = $_REQUEST['theme_status'] ?? 'all'; if ( ! in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken', 'auto-update-enabled', 'auto-update-disabled' ), true ) ) { $status = 'all'; } $page = $this->get_pagenum(); $this->is_site_themes = ( 'site-themes-network' === $this->screen->id ) ? true : false; if ( $this->is_site_themes ) { $this->site_id = isset( $_REQUEST['id'] ) ? (int) $_REQUEST['id'] : 0; } $this->show_autoupdates = wp_is_auto_update_enabled_for_type( 'theme' ) && ! $this->is_site_themes && current_user_can( 'update_themes' ); } /** * Gets the list of CSS classes for the table tag. * * @return string[] The list of CSS classes. */ protected function get_table_classes() { // @todo Remove and add CSS for .themes. return array( 'widefat', 'plugins' ); } /** * Checks if the current user has permissions to perform AJAX actions. * * @return bool True if the current user has permissions, false otherwise. */ public function ajax_user_can() { if ( $this->is_site_themes ) { return current_user_can( 'manage_sites' ); } else { return current_user_can( 'manage_network_themes' ); } } /** * Prepares the themes list for display. * * @global string $status The current theme status. * @global array<string, int> $totals An array of theme counts for each status. * @global int $page The current page number. * @global string $orderby The column to order the themes list by. * @global string $order The order of the themes list (ASC or DESC). * @global string $s The search string. */ public function prepare_items() { global $status, $totals, $page, $orderby, $order, $s; $orderby = ! empty( $_REQUEST['orderby'] ) ? sanitize_text_field( $_REQUEST['orderby'] ) : ''; $order = ! empty( $_REQUEST['order'] ) ? sanitize_text_field( $_REQUEST['order'] ) : ''; $s = ! empty( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : ''; $themes = array( /** * Filters the full array of WP_Theme objects to list in the Multisite * themes list table. * * @since 3.1.0 * * @param WP_Theme[] $all Array of WP_Theme objects to display in the list table. */ 'all' => apply_filters( 'all_themes', wp_get_themes() ), 'search' => array(), 'enabled' => array(), 'disabled' => array(), 'upgrade' => array(), 'broken' => $this->is_site_themes ? array() : wp_get_themes( array( 'errors' => true ) ), ); if ( $this->show_autoupdates ) { $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); $themes['auto-update-enabled'] = array(); $themes['auto-update-disabled'] = array(); } if ( $this->is_site_themes ) { $themes_per_page = $this->get_items_per_page( 'site_themes_network_per_page' ); $allowed_where = 'site'; } else { $themes_per_page = $this->get_items_per_page( 'themes_network_per_page' ); $allowed_where = 'network'; } $current = get_site_transient( 'update_themes' ); $maybe_update = current_user_can( 'update_themes' ) && ! $this->is_site_themes && $current; foreach ( (array) $themes['all'] as $key => $theme ) { if ( $this->is_site_themes && $theme->is_allowed( 'network' ) ) { unset( $themes['all'][ $key ] ); continue; } if ( $maybe_update && isset( $current->response[ $key ] ) ) { $themes['all'][ $key ]->update = true; $themes['upgrade'][ $key ] = $themes['all'][ $key ]; } $filter = $theme->is_allowed( $allowed_where, $this->site_id ) ? 'enabled' : 'disabled'; $themes[ $filter ][ $key ] = $themes['all'][ $key ]; $theme_data = array( 'update_supported' => $theme->update_supported ?? true, ); // Extra info if known. array_merge() ensures $theme_data has precedence if keys collide. if ( isset( $current->response[ $key ] ) ) { $theme_data = array_merge( (array) $current->response[ $key ], $theme_data ); } elseif ( isset( $current->no_update[ $key ] ) ) { $theme_data = array_merge( (array) $current->no_update[ $key ], $theme_data ); } else { $theme_data['update_supported'] = false; } $theme->update_supported = $theme_data['update_supported']; /* * Create the expected payload for the auto_update_theme filter, this is the same data * as contained within $updates or $no_updates but used when the Theme is not known. */ $filter_payload = array( 'theme' => $key, 'new_version' => '', 'url' => '', 'package' => '', 'requires' => '', 'requires_php' => '', ); $filter_payload = (object) array_merge( $filter_payload, array_intersect_key( $theme_data, $filter_payload ) ); $auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, $filter_payload ); if ( ! is_null( $auto_update_forced ) ) { $theme->auto_update_forced = $auto_update_forced; } if ( $this->show_autoupdates ) { $enabled = in_array( $key, $auto_updates, true ) && $theme->update_supported; if ( isset( $theme->auto_update_forced ) ) { $enabled = (bool) $theme->auto_update_forced; } if ( $enabled ) { $themes['auto-update-enabled'][ $key ] = $theme; } else { $themes['auto-update-disabled'][ $key ] = $theme; } } } if ( $s ) { $status = 'search'; $themes['search'] = array_filter( array_merge( $themes['all'], $themes['broken'] ), array( $this, '_search_callback' ) ); } $totals = array(); $js_themes = array(); foreach ( $themes as $type => $list ) { $totals[ $type ] = count( $list ); $js_themes[ $type ] = array_keys( $list ); } if ( empty( $themes[ $status ] ) && ! in_array( $status, array( 'all', 'search' ), true ) ) { $status = 'all'; } $this->items = $themes[ $status ]; WP_Theme::sort_by_name( $this->items ); $this->has_items = ! empty( $themes['all'] ); $total_this_page = $totals[ $status ]; wp_localize_script( 'updates', '_wpUpdatesItemCounts', array( 'themes' => $js_themes, 'totals' => wp_get_update_data(), ) ); if ( $orderby ) { $orderby = ucfirst( $orderby ); $order = strtoupper( $order ); if ( 'Name' === $orderby ) { if ( 'ASC' === $order ) { $this->items = array_reverse( $this->items ); } } else { uasort( $this->items, array( $this, '_order_callback' ) ); } } $start = ( $page - 1 ) * $themes_per_page; if ( $total_this_page > $themes_per_page ) { $this->items = array_slice( $this->items, $start, $themes_per_page, true ); } $this->set_pagination_args( array( 'total_items' => $total_this_page, 'per_page' => $themes_per_page, ) ); } /** * Filters a theme by the search term. * * @param WP_Theme $theme The WP_Theme object to check. * @return bool True if the theme matches the search term, false otherwise. */ public function _search_callback( $theme ) { static $term = null; if ( is_null( $term ) ) { $term = wp_unslash( $_REQUEST['s'] ); } foreach ( array( 'Name', 'Description', 'Author', 'Author', 'AuthorURI' ) as $field ) { // Don't mark up; Do translate. if ( false !== stripos( $theme->display( $field, false, true ), $term ) ) { return true; } } if ( false !== stripos( $theme->get_stylesheet(), $term ) ) { return true; } if ( false !== stripos( $theme->get_template(), $term ) ) { return true; } return false; } // Not used by any core columns. /** * Compares the order of two themes by a specific field. * * @global string $orderby The column to order the themes list by. * @global string $order The order of the themes list (ASC or DESC). * * @param WP_Theme $theme_a The first theme to compare. * @param WP_Theme $theme_b The second theme to compare. * @return int 0 if equal, -1 if the first is less than the second, 1 if more. */ public function _order_callback( $theme_a, $theme_b ) { global $orderby, $order; $a = $theme_a[ $orderby ]; $b = $theme_b[ $orderby ]; return 'DESC' === $order ? $b <=> $a : $a <=> $b; } /** * Displays the message when there are no items to list. */ public function no_items() { if ( $this->has_items ) { _e( 'No themes found.' ); } else { _e( 'No themes are currently available.' ); } } /** * Gets the list of columns for the list table. * * @return array<string, string> Array of column titles keyed by their column name. */ public function get_columns() { $columns = array( 'cb' => '<input type="checkbox" />', 'name' => __( 'Theme' ), 'description' => __( 'Description' ), ); if ( $this->show_autoupdates ) { $columns['auto-updates'] = __( 'Automatic Updates' ); } return $columns; } /** * Gets the list of sortable columns for the list table. * * @return array<string, array<int, mixed>> An array of sortable columns. */ protected function get_sortable_columns() { return array( 'name' => array( 'name', false, __( 'Theme' ), __( 'Table ordered by Theme Name.' ), 'asc' ), ); } /** * Gets the name of the primary column. * * @since 4.3.0 * * @return string Unalterable name of the primary column name, in this case, 'name'. */ protected function get_primary_column_name() { return 'name'; } /** * Gets the list of views (statuses) for the list table. * * @global array<string, int> $totals An array of theme counts for each status. * @global string $status The current theme status. * * @return array<string, string> The list of views. */ protected function get_views() { global $totals, $status; $status_links = array(); foreach ( $totals as $type => $count ) { if ( ! $count ) { continue; } switch ( $type ) { case 'all': /* translators: %s: Number of themes. */ $text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'themes' ); break; case 'enabled': /* translators: %s: Number of themes. */ $text = _nx( 'Enabled <span class="count">(%s)</span>', 'Enabled <span class="count">(%s)</span>', $count, 'themes' ); break; case 'disabled': /* translators: %s: Number of themes. */ $text = _nx( 'Disabled <span class="count">(%s)</span>', 'Disabled <span class="count">(%s)</span>', $count, 'themes' ); break; case 'upgrade': /* translators: %s: Number of themes. */ $text = _nx( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count, 'themes' ); break; case 'broken': /* translators: %s: Number of themes. */ $text = _nx( 'Broken <span class="count">(%s)</span>', 'Broken <span class="count">(%s)</span>', $count, 'themes' ); break; case 'auto-update-enabled': /* translators: %s: Number of themes. */ $text = _n( 'Auto-updates Enabled <span class="count">(%s)</span>', 'Auto-updates Enabled <span class="count">(%s)</span>', $count ); break; case 'auto-update-disabled': /* translators: %s: Number of themes. */ $text = _n( 'Auto-updates Disabled <span class="count">(%s)</span>', 'Auto-updates Disabled <span class="count">(%s)</span>', $count ); break; } if ( $this->is_site_themes ) { $url = 'site-themes.php?id=' . $this->site_id; } else { $url = 'themes.php'; } if ( 'search' !== $type ) { $status_links[ $type ] = array( 'url' => esc_url( add_query_arg( 'theme_status', $type, $url ) ), 'label' => sprintf( $text, number_format_i18n( $count ) ), 'current' => $type === $status, ); } } return $this->get_views_links( $status_links ); } /** * Gets the list of bulk actions for the list table. * * @global string $status The current theme status. * * @return array<string, string> The list of bulk actions. */ protected function get_bulk_actions() { global $status; $actions = array(); if ( 'enabled' !== $status ) { $actions['enable-selected'] = $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' ); } if ( 'disabled' !== $status ) { $actions['disable-selected'] = $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ); } if ( ! $this->is_site_themes ) { if ( current_user_can( 'update_themes' ) ) { $actions['update-selected'] = __( 'Update' ); } if ( current_user_can( 'delete_themes' ) ) { $actions['delete-selected'] = __( 'Delete' ); } } if ( $this->show_autoupdates ) { if ( 'auto-update-enabled' !== $status ) { $actions['enable-auto-update-selected'] = __( 'Enable Auto-updates' ); } if ( 'auto-update-disabled' !== $status ) { $actions['disable-auto-update-selected'] = __( 'Disable Auto-updates' ); } } return $actions; } /** * Generates the list table rows. * * @since 3.1.0 */ public function display_rows() { foreach ( $this->items as $theme ) { $this->single_row( $theme ); } } /** * Handles the checkbox column output. * * @since 4.3.0 * @since 5.9.0 Renamed `$theme` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Theme $item The current WP_Theme object. */ public function column_cb( $item ) { // Restores the more descriptive, specific name for use within this method. $theme = $item; $checkbox_id = 'checkbox_' . md5( $theme->get( 'Name' ) ); ?> <input type="checkbox" name="checked[]" value="<?php echo esc_attr( $theme->get_stylesheet() ); ?>" id="<?php echo $checkbox_id; ?>" /> <label for="<?php echo $checkbox_id; ?>" > <span class="screen-reader-text"> <?php printf( /* translators: Hidden accessibility text. %s: Theme name */ __( 'Select %s' ), $theme->display( 'Name' ) ); ?> </span> </label> <?php } /** * Handles the name column output. * * @since 4.3.0 * * @global string $status The current theme status. * @global int $page The current page number. * @global string $s The search string. * * @param WP_Theme $theme The current WP_Theme object. */ public function column_name( $theme ) { global $status, $page, $s; $context = $status; if ( $this->is_site_themes ) { $url = "site-themes.php?id={$this->site_id}&"; $allowed = $theme->is_allowed( 'site', $this->site_id ); } else { $url = 'themes.php?'; $allowed = $theme->is_allowed( 'network' ); } // Pre-order. $actions = array( 'enable' => '', 'disable' => '', 'delete' => '', ); $stylesheet = $theme->get_stylesheet(); $theme_key = urlencode( $stylesheet ); if ( ! $allowed ) { if ( ! $theme->errors() ) { $url = add_query_arg( array( 'action' => 'enable', 'theme' => $theme_key, 'paged' => $page, 's' => $s, ), $url ); if ( $this->is_site_themes ) { /* translators: %s: Theme name. */ $aria_label = sprintf( __( 'Enable %s' ), $theme->display( 'Name' ) ); } else { /* translators: %s: Theme name. */ $aria_label = sprintf( __( 'Network Enable %s' ), $theme->display( 'Name' ) ); } $actions['enable'] = sprintf( '<a href="%s" class="edit" aria-label="%s">%s</a>', esc_url( wp_nonce_url( $url, 'enable-theme_' . $stylesheet ) ), esc_attr( $aria_label ), ( $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' ) ) ); } } else { $url = add_query_arg( array( 'action' => 'disable', 'theme' => $theme_key, 'paged' => $page, 's' => $s, ), $url ); if ( $this->is_site_themes ) { /* translators: %s: Theme name. */ $aria_label = sprintf( __( 'Disable %s' ), $theme->display( 'Name' ) ); } else { /* translators: %s: Theme name. */ $aria_label = sprintf( __( 'Network Disable %s' ), $theme->display( 'Name' ) ); } $actions['disable'] = sprintf( '<a href="%s" aria-label="%s">%s</a>', esc_url( wp_nonce_url( $url, 'disable-theme_' . $stylesheet ) ), esc_attr( $aria_label ), ( $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ) ) ); } if ( ! $allowed && ! $this->is_site_themes && current_user_can( 'delete_themes' ) && get_option( 'stylesheet' ) !== $stylesheet && get_option( 'template' ) !== $stylesheet ) { $url = add_query_arg( array( 'action' => 'delete-selected', 'checked[]' => $theme_key, 'theme_status' => $context, 'paged' => $page, 's' => $s, ), 'themes.php' ); /* translators: %s: Theme name. */ $aria_label = sprintf( _x( 'Delete %s', 'theme' ), $theme->display( 'Name' ) ); $actions['delete'] = sprintf( '<a href="%s" class="delete" aria-label="%s">%s</a>', esc_url( wp_nonce_url( $url, 'bulk-themes' ) ), esc_attr( $aria_label ), __( 'Delete' ) ); } /** * Filters the action links displayed for each theme in the Multisite * themes list table. * * The action links displayed are determined by the theme's status, and * which Multisite themes list table is being displayed - the Network * themes list table (themes.php), which displays all installed themes, * or the Site themes list table (site-themes.php), which displays the * non-network enabled themes when editing a site in the Network admin. * * The default action links for the Network themes list table include * 'Network Enable', 'Network Disable', and 'Delete'. * * The default action links for the Site themes list table include * 'Enable', and 'Disable'. * * @since 2.8.0 * * @param string[] $actions An array of action links. * @param WP_Theme $theme The current WP_Theme object. * @param string $context Status of the theme, one of 'all', 'enabled', or 'disabled'. */ $actions = apply_filters( 'theme_action_links', array_filter( $actions ), $theme, $context ); /** * Filters the action links of a specific theme in the Multisite themes * list table. * * The dynamic portion of the hook name, `$stylesheet`, refers to the * directory name of the theme, which in most cases is synonymous * with the template name. * * @since 3.1.0 * * @param string[] $actions An array of action links. * @param WP_Theme $theme The current WP_Theme object. * @param string $context Status of the theme, one of 'all', 'enabled', or 'disabled'. */ $actions = apply_filters( "theme_action_links_{$stylesheet}", $actions, $theme, $context ); echo $this->row_actions( $actions, true ); } /** * Handles the description column output. * * @since 4.3.0 * * @global string $status The current theme status. * @global array<string, int> $totals An array of theme counts for each status. * * @param WP_Theme $theme The current WP_Theme object. */ public function column_description( $theme ) { global $status, $totals; if ( $theme->errors() ) { $pre = 'broken' === $status ? '<strong class="error-message">' . __( 'Broken Theme:' ) . '</strong> ' : ''; wp_admin_notice( $pre . $theme->errors()->get_error_message(), array( 'type' => 'error', 'additional_classes' => 'inline', ) ); } if ( $this->is_site_themes ) { $allowed = $theme->is_allowed( 'site', $this->site_id ); } else { $allowed = $theme->is_allowed( 'network' ); } $class = ! $allowed ? 'inactive' : 'active'; if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) ) { $class .= ' update'; } echo "<div class='theme-description'><p>" . $theme->display( 'Description' ) . "</p></div> <div class='$class second theme-version-author-uri'>"; $stylesheet = $theme->get_stylesheet(); $theme_meta = array(); if ( $theme->get( 'Version' ) ) { /* translators: %s: Theme version. */ $theme_meta[] = sprintf( __( 'Version %s' ), $theme->display( 'Version' ) ); } /* translators: %s: Theme author. */ $theme_meta[] = sprintf( __( 'By %s' ), $theme->display( 'Author' ) ); if ( $theme->get( 'ThemeURI' ) ) { /* translators: %s: Theme name. */ $aria_label = sprintf( __( 'Visit theme site for %s' ), $theme->display( 'Name' ) ); $theme_meta[] = sprintf( '<a href="%s" aria-label="%s">%s</a>', $theme->display( 'ThemeURI' ), esc_attr( $aria_label ), __( 'Visit Theme Site' ) ); } if ( $theme->parent() ) { $theme_meta[] = sprintf( /* translators: %s: Theme name. */ __( 'Child theme of %s' ), '<strong>' . $theme->parent()->display( 'Name' ) . '</strong>' ); } /** * Filters the array of row meta for each theme in the Multisite themes * list table. * * @since 3.1.0 * * @param string[] $theme_meta An array of the theme's metadata, including * the version, author, and theme URI. * @param string $stylesheet Directory name of the theme. * @param WP_Theme $theme WP_Theme object. * @param string $status Status of the theme. */ $theme_meta = apply_filters( 'theme_row_meta', $theme_meta, $stylesheet, $theme, $status ); echo implode( ' | ', $theme_meta ); echo '</div>'; } /** * Handles the auto-updates column output. * * @since 5.5.0 * * @global string $status The current theme status. * @global int $page The current page number. * * @param WP_Theme $theme The current WP_Theme object. */ public function column_autoupdates( $theme ) { global $status, $page; static $auto_updates, $available_updates; if ( ! $auto_updates ) { $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); } if ( ! $available_updates ) { $available_updates = get_site_transient( 'update_themes' ); } $stylesheet = $theme->get_stylesheet(); if ( isset( $theme->auto_update_forced ) ) { if ( $theme->auto_update_forced ) { // Forced on. $text = __( 'Auto-updates enabled' ); } else { $text = __( 'Auto-updates disabled' ); } $action = 'unavailable'; $time_class = ' hidden'; } elseif ( empty( $theme->update_supported ) ) { $text = ''; $action = 'unavailable'; $time_class = ' hidden'; } elseif ( in_array( $stylesheet, $auto_updates, true ) ) { $text = __( 'Disable auto-updates' ); $action = 'disable'; $time_class = ''; } else { $text = __( 'Enable auto-updates' ); $action = 'enable'; $time_class = ' hidden'; } $query_args = array( 'action' => "{$action}-auto-update", 'theme' => $stylesheet, 'paged' => $page, 'theme_status' => $status, ); $url = add_query_arg( $query_args, 'themes.php' ); if ( 'unavailable' === $action ) { $html[] = '<span class="label">' . $text . '</span>'; } else { $html[] = sprintf( '<a href="%s" class="toggle-auto-update aria-button-if-js" data-wp-action="%s">', wp_nonce_url( $url, 'updates' ), $action ); $html[] = '<span class="dashicons dashicons-update spin hidden" aria-hidden="true"></span>'; $html[] = '<span class="label">' . $text . '</span>'; $html[] = '</a>'; } if ( isset( $available_updates->response[ $stylesheet ] ) ) { $html[] = sprintf( '<div class="auto-update-time%s">%s</div>', $time_class, wp_get_auto_update_message() ); } $html = implode( '', $html ); /** * Filters the HTML of the auto-updates setting for each theme in the Themes list table. * * @since 5.5.0 * * @param string $html The HTML for theme's auto-update setting, including * toggle auto-update action link and time to next update. * @param string $stylesheet Directory name of the theme. * @param WP_Theme $theme WP_Theme object. */ echo apply_filters( 'theme_auto_update_setting_html', $html, $stylesheet, $theme ); wp_admin_notice( '', array( 'type' => 'error', 'additional_classes' => array( 'notice-alt', 'inline', 'hidden' ), ) ); } /** * Handles default column output. * * @since 4.3.0 * @since 5.9.0 Renamed `$theme` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Theme $item The current WP_Theme object. * @param string $column_name The current column name. */ public function column_default( $item, $column_name ) { // Restores the more descriptive, specific name for use within this method. $theme = $item; $stylesheet = $theme->get_stylesheet(); /** * Fires inside each custom column of the Multisite themes list table. * * @since 3.1.0 * * @param string $column_name Name of the column. * @param string $stylesheet Directory name of the theme. * @param WP_Theme $theme Current WP_Theme object. */ do_action( 'manage_themes_custom_column', $column_name, $stylesheet, $theme ); } /** * Handles the output for a single table row. * * @since 4.3.0 * * @param WP_Theme $item The current WP_Theme object. */ public function single_row_columns( $item ) { list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info(); foreach ( $columns as $column_name => $column_display_name ) { $extra_classes = ''; if ( in_array( $column_name, $hidden, true ) ) { $extra_classes .= ' hidden'; } switch ( $column_name ) { case 'cb': echo '<th scope="row" class="check-column">'; $this->column_cb( $item ); echo '</th>'; break; case 'name': $active_theme_label = ''; /* The presence of the site_id property means that this is a subsite view and a label for the active theme needs to be added */ if ( ! empty( $this->site_id ) ) { $stylesheet = get_blog_option( $this->site_id, 'stylesheet' ); $template = get_blog_option( $this->site_id, 'template' ); /* Add a label for the active template */ if ( $item->get_template() === $template ) { $active_theme_label = ' — ' . __( 'Active Theme' ); } /* In case this is a child theme, label it properly */ if ( $stylesheet !== $template && $item->get_stylesheet() === $stylesheet ) { $active_theme_label = ' — ' . __( 'Active Child Theme' ); } } echo "<td class='theme-title column-primary{$extra_classes}'><strong>" . $item->display( 'Name' ) . $active_theme_label . '</strong>'; $this->column_name( $item ); echo '</td>'; break; case 'description': echo "<td class='column-description desc{$extra_classes}'>"; $this->column_description( $item ); echo '</td>'; break; case 'auto-updates': echo "<td class='column-auto-updates{$extra_classes}'>"; $this->column_autoupdates( $item ); echo '</td>'; break; default: echo "<td class='$column_name column-$column_name{$extra_classes}'>"; $this->column_default( $item, $column_name ); echo '</td>'; break; } } } /** * Handles the output for a single table row. * * @global string $status The current theme status. * @global array<string, int> $totals An array of theme counts for each status. * * @param WP_Theme $theme The current WP_Theme object. */ public function single_row( $theme ) { global $status, $totals; if ( $this->is_site_themes ) { $allowed = $theme->is_allowed( 'site', $this->site_id ); } else { $allowed = $theme->is_allowed( 'network' ); } $stylesheet = $theme->get_stylesheet(); $class = ! $allowed ? 'inactive' : 'active'; if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) ) { $class .= ' update'; } printf( '<tr class="%s" data-slug="%s">', esc_attr( $class ), esc_attr( $stylesheet ) ); $this->single_row_columns( $theme ); echo '</tr>'; if ( $this->is_site_themes ) { remove_action( "after_theme_row_$stylesheet", 'wp_theme_update_row' ); } /** * Fires after each row in the Multisite themes list table. * * @since 3.1.0 * * @param string $stylesheet Directory name of the theme. * @param WP_Theme $theme Current WP_Theme object. * @param string $status Status of the theme. */ do_action( 'after_theme_row', $stylesheet, $theme, $status ); /** * Fires after each specific row in the Multisite themes list table. * * The dynamic portion of the hook name, `$stylesheet`, refers to the * directory name of the theme, most often synonymous with the template * name of the theme. * * @since 3.5.0 * * @param string $stylesheet Directory name of the theme. * @param WP_Theme $theme Current WP_Theme object. * @param string $status Status of the theme. */ do_action( "after_theme_row_{$stylesheet}", $stylesheet, $theme, $status ); } } PK $��\̇3L� � edit-tag-messages.phpnu �[��� <?php /** * Edit Tags Administration: Messages * * @package WordPress * @subpackage Administration * @since 4.4.0 */ $messages = array(); // 0 = unused. Messages start at index 1. $messages['_item'] = array( 0 => '', 1 => __( 'Item added.' ), 2 => __( 'Item deleted.' ), 3 => __( 'Item updated.' ), 4 => __( 'Item not added.' ), 5 => __( 'Item not updated.' ), 6 => __( 'Items deleted.' ), ); $messages['category'] = array( 0 => '', 1 => __( 'Category added.' ), 2 => __( 'Category deleted.' ), 3 => __( 'Category updated.' ), 4 => __( 'Category not added.' ), 5 => __( 'Category not updated.' ), 6 => __( 'Categories deleted.' ), ); $messages['post_tag'] = array( 0 => '', 1 => __( 'Tag added.' ), 2 => __( 'Tag deleted.' ), 3 => __( 'Tag updated.' ), 4 => __( 'Tag not added.' ), 5 => __( 'Tag not updated.' ), 6 => __( 'Tags deleted.' ), ); /** * Filters the messages displayed when a tag is updated. * * @since 3.7.0 * * @param array[] $messages Array of arrays of messages to be displayed, keyed by taxonomy name. */ $messages = apply_filters( 'term_updated_messages', $messages ); $message = false; if ( isset( $_REQUEST['message'] ) && (int) $_REQUEST['message'] ) { $msg = (int) $_REQUEST['message']; if ( isset( $messages[ $taxonomy ][ $msg ] ) ) { $message = $messages[ $taxonomy ][ $msg ]; } elseif ( ! isset( $messages[ $taxonomy ] ) && isset( $messages['_item'][ $msg ] ) ) { $message = $messages['_item'][ $msg ]; } } PK $��\��@!� � class-wp-list-table-compat.phpnu �[��� <?php /** * Helper functions for displaying a list of items in an ajaxified HTML table. * * @package WordPress * @subpackage List_Table * @since 4.7.0 */ /** * Helper class to be used only by back compat functions. * * @since 3.1.0 */ class _WP_List_Table_Compat extends WP_List_Table { public $_screen; public $_columns; /** * Constructor. * * @since 3.1.0 * * @param string|WP_Screen $screen The screen hook name or screen object. * @param string[] $columns An array of columns with column IDs as the keys * and translated column names as the values. */ public function __construct( $screen, $columns = array() ) { if ( is_string( $screen ) ) { $screen = convert_to_screen( $screen ); } $this->_screen = $screen; if ( ! empty( $columns ) ) { $this->_columns = $columns; add_filter( 'manage_' . $screen->id . '_columns', array( $this, 'get_columns' ), 0 ); } } /** * Gets a list of all, hidden, and sortable columns. * * @since 3.1.0 * * @return array */ protected function get_column_info() { $columns = get_column_headers( $this->_screen ); $hidden = get_hidden_columns( $this->_screen ); $sortable = array(); $primary = $this->get_default_primary_column_name(); return array( $columns, $hidden, $sortable, $primary ); } /** * Gets a list of columns. * * @since 3.1.0 * * @return array */ public function get_columns() { return $this->_columns; } } PK $��\�zS� � 4 class-wp-privacy-data-export-requests-list-table.phpnu �[��� <?php /** * List Table API: WP_Privacy_Data_Export_Requests_List_Table class * * @package WordPress * @subpackage Administration * @since 4.9.6 */ if ( ! class_exists( 'WP_Privacy_Requests_Table' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-requests-table.php'; } /** * WP_Privacy_Data_Export_Requests_Table class. * * @since 4.9.6 */ class WP_Privacy_Data_Export_Requests_List_Table extends WP_Privacy_Requests_Table { /** * Action name for the requests this table will work with. * * @since 4.9.6 * * @var string $request_type Name of action. */ protected $request_type = 'export_personal_data'; /** * Post type for the requests. * * @since 4.9.6 * * @var string $post_type The post type. */ protected $post_type = 'user_request'; /** * Actions column. * * @since 4.9.6 * * @param WP_User_Request $item Item being shown. * @return string Email column markup. */ public function column_email( $item ) { /** This filter is documented in wp-admin/includes/ajax-actions.php */ $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() ); $exporters_count = count( $exporters ); $status = $item->status; $request_id = $item->ID; $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id ); $download_data_markup = '<span class="export-personal-data" ' . 'data-exporters-count="' . esc_attr( $exporters_count ) . '" ' . 'data-request-id="' . esc_attr( $request_id ) . '" ' . 'data-nonce="' . esc_attr( $nonce ) . '">'; $download_data_markup .= '<span class="export-personal-data-idle"><button type="button" class="button-link export-personal-data-handle">' . __( 'Download personal data' ) . '</button></span>' . '<span class="export-personal-data-processing hidden">' . __( 'Downloading data...' ) . ' <span class="export-progress"></span></span>' . '<span class="export-personal-data-success hidden"><button type="button" class="button-link export-personal-data-handle">' . __( 'Download personal data again' ) . '</button></span>' . '<span class="export-personal-data-failed hidden">' . __( 'Download failed.' ) . ' <button type="button" class="button-link export-personal-data-handle">' . __( 'Retry' ) . '</button></span>'; $download_data_markup .= '</span>'; $row_actions['download-data'] = $download_data_markup; if ( 'request-completed' !== $status ) { $complete_request_markup = '<span>'; $complete_request_markup .= sprintf( '<a href="%s" class="complete-request" aria-label="%s">%s</a>', esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'complete', 'request_id' => array( $request_id ), ), admin_url( 'export-personal-data.php' ) ), 'bulk-privacy_requests' ) ), esc_attr( sprintf( /* translators: %s: Request email. */ __( 'Mark export request for “%s” as completed.' ), $item->email ) ), __( 'Complete request' ) ); $complete_request_markup .= '</span>'; } if ( ! empty( $complete_request_markup ) ) { $row_actions['complete-request'] = $complete_request_markup; } return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) ); } /** * Displays the next steps column. * * @since 4.9.6 * * @param WP_User_Request $item Item being shown. */ public function column_next_steps( $item ) { $status = $item->status; switch ( $status ) { case 'request-pending': esc_html_e( 'Waiting for confirmation' ); break; case 'request-confirmed': /** This filter is documented in wp-admin/includes/ajax-actions.php */ $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() ); $exporters_count = count( $exporters ); $request_id = $item->ID; $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id ); echo '<div class="export-personal-data" ' . 'data-send-as-email="1" ' . 'data-exporters-count="' . esc_attr( $exporters_count ) . '" ' . 'data-request-id="' . esc_attr( $request_id ) . '" ' . 'data-nonce="' . esc_attr( $nonce ) . '">'; ?> <span class="export-personal-data-idle"><button type="button" class="button-link export-personal-data-handle"><?php _e( 'Send export link' ); ?></button></span> <span class="export-personal-data-processing hidden"><?php _e( 'Sending email...' ); ?> <span class="export-progress"></span></span> <span class="export-personal-data-success success-message hidden"><?php _e( 'Email sent.' ); ?></span> <span class="export-personal-data-failed hidden"><?php _e( 'Email could not be sent.' ); ?> <button type="button" class="button-link export-personal-data-handle"><?php _e( 'Retry' ); ?></button></span> <?php echo '</div>'; break; case 'request-failed': echo '<button type="submit" class="button-link" name="privacy_action_email_retry[' . $item->ID . ']" id="privacy_action_email_retry[' . $item->ID . ']">' . __( 'Retry' ) . '</button>'; break; case 'request-completed': echo '<a href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'delete', 'request_id' => array( $item->ID ), ), admin_url( 'export-personal-data.php' ) ), 'bulk-privacy_requests' ) ) . '">' . esc_html__( 'Remove request' ) . '</a>'; break; } } } PK $��\H-��Z_ Z_ class-wp-filesystem-base.phpnu �[��� <?php /** * Base WordPress Filesystem * * @package WordPress * @subpackage Filesystem */ /** * Base WordPress Filesystem class which Filesystem implementations extend. * * @since 2.5.0 */ #[AllowDynamicProperties] class WP_Filesystem_Base { /** * Whether to display debug data for the connection. * * @since 2.5.0 * @var bool */ public $verbose = false; /** * Cached list of local filepaths to mapped remote filepaths. * * @since 2.7.0 * @var array */ public $cache = array(); /** * The Access method of the current connection, Set automatically. * * @since 2.5.0 * @var string */ public $method = ''; /** * @var WP_Error */ public $errors = null; /** */ public $options = array(); /** * Returns the path on the remote filesystem of ABSPATH. * * @since 2.7.0 * * @return string The location of the remote path. */ public function abspath() { $folder = $this->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 Optional. The folder to start searching from. Default '.'. * @param bool $verbose Optional. True to display debug information. Default false. * @return string The location of the remote path. */ public function find_base_dir( $base = '.', $verbose = false ) { _deprecated_function( __FUNCTION__, '2.7.0', 'WP_Filesystem_Base::abspath() or WP_Filesystem_Base::wp_*_dir()' ); $this->verbose = $verbose; 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 Optional. The folder to start searching from. Default '.'. * @param bool $verbose Optional. True to display debug information. Default false. * @return string The location of the remote path. */ public function get_base_dir( $base = '.', $verbose = false ) { _deprecated_function( __FUNCTION__, '2.7.0', 'WP_Filesystem_Base::abspath() or WP_Filesystem_Base::wp_*_dir()' ); $this->verbose = $verbose; 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 sanitization. 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 sanitization. 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' ) . "<br />\n", $folder, $base ); } $folder_parts = explode( '/', $folder ); $folder_part_keys = array_keys( $folder_parts ); $last_index = array_pop( $folder_part_keys ); $last_path = $folder_parts[ $last_index ]; $files = $this->dirlist( $base ); foreach ( $folder_parts as $index => $key ) { if ( $index === $last_index ) { continue; // We want this to be caught by the next code block. } /* * Working from /home/ to /user/ to /wordpress/ see if that file exists within * the current folder, If it's found, change into it and follow through looking * for it. If it can't find WordPress down that route, it'll continue onto the next * folder level, and see if that matches, and so on. If it reaches the end, and still * can't find it, it'll return false for the entire function. */ if ( isset( $files[ $key ] ) ) { // Let's try that folder: $newdir = trailingslashit( path_join( $base, $key ) ); if ( $this->verbose ) { /* translators: %s: Directory name. */ printf( "\n" . __( 'Changing to %s' ) . "<br />\n", $newdir ); } // Only search for the remaining path tokens in the directory, not the full path again. $newfolder = implode( '/', array_slice( $folder_parts, $index + 1 ) ); $ret = $this->search_for_folder( $newfolder, $newdir, $loop ); if ( $ret ) { return $ret; } } } /* * Only check this as a last resort, to prevent locating the incorrect install. * All above procedures will fail quickly if this is the right branch to take. */ if ( isset( $files[ $last_path ] ) ) { if ( $this->verbose ) { /* translators: %s: Directory name. */ printf( "\n" . __( 'Found %s' ) . "<br />\n", $base . $last_path ); } return trailingslashit( $base . $last_path ); } /* * Prevent this function from looping again. * No need to proceed if we've just searched in `/`. */ if ( $loop || '/' === $base ) { return false; } /* * As an extra last resort, Change back to / if the folder wasn't found. * This comes into effect when the CWD is /home/user/ but WP is at /var/www/.... */ return $this->search_for_folder( $folder, '/', true ); } /** * Returns the *nix-style file permissions for a file. * * From the PHP documentation page for fileperms(). * * @link https://www.php.net/manual/en/function.fileperms.php * * @since 2.5.0 * * @param string $file String filename. * @return string The *nix-style representation of permissions. */ public function gethchmod( $file ) { $perms = intval( $this->getchmod( $file ), 8 ); if ( ( $perms & 0xC000 ) === 0xC000 ) { // Socket. $info = 's'; } elseif ( ( $perms & 0xA000 ) === 0xA000 ) { // Symbolic Link. $info = 'l'; } elseif ( ( $perms & 0x8000 ) === 0x8000 ) { // Regular. $info = '-'; } elseif ( ( $perms & 0x6000 ) === 0x6000 ) { // Block special. $info = 'b'; } elseif ( ( $perms & 0x4000 ) === 0x4000 ) { // Directory. $info = 'd'; } elseif ( ( $perms & 0x2000 ) === 0x2000 ) { // Character special. $info = 'c'; } elseif ( ( $perms & 0x1000 ) === 0x1000 ) { // FIFO pipe. $info = 'p'; } else { // Unknown. $info = 'u'; } // Owner. $info .= ( ( $perms & 0x0100 ) ? 'r' : '-' ); $info .= ( ( $perms & 0x0080 ) ? 'w' : '-' ); $info .= ( ( $perms & 0x0040 ) ? ( ( $perms & 0x0800 ) ? 's' : 'x' ) : ( ( $perms & 0x0800 ) ? 'S' : '-' ) ); // Group. $info .= ( ( $perms & 0x0020 ) ? 'r' : '-' ); $info .= ( ( $perms & 0x0010 ) ? 'w' : '-' ); $info .= ( ( $perms & 0x0008 ) ? ( ( $perms & 0x0400 ) ? 's' : 'x' ) : ( ( $perms & 0x0400 ) ? 'S' : '-' ) ); // World. $info .= ( ( $perms & 0x0004 ) ? 'r' : '-' ); $info .= ( ( $perms & 0x0002 ) ? 'w' : '-' ); $info .= ( ( $perms & 0x0001 ) ? ( ( $perms & 0x0200 ) ? 't' : 'x' ) : ( ( $perms & 0x0200 ) ? 'T' : '-' ) ); return $info; } /** * Gets the permissions of the specified file or filepath in their octal format. * * @since 2.5.0 * * @param string $file Path to the file. * @return string Mode of the file (the last 3 digits). */ public function getchmod( $file ) { return '777'; } /** * Converts *nix-style file permissions to an octal number. * * Converts '-rw-r--r--' to 0644 * From "info at rvgate dot nl"'s comment on the PHP documentation for chmod() * * @link https://www.php.net/manual/en/function.chmod.php#49614 * * @since 2.5.0 * * @param string $mode string The *nix-style file permissions. * @return string Octal representation of permissions. */ public function getnumchmodfromh( $mode ) { $realmode = ''; $legal = array( '', 'w', 'r', 'x', '-' ); $attarray = preg_split( '//', $mode ); for ( $i = 0, $c = count( $attarray ); $i < $c; $i++ ) { $key = array_search( $attarray[ $i ], $legal, true ); if ( $key ) { $realmode .= $legal[ $key ]; } } $mode = str_pad( $realmode, 10, '-', STR_PAD_LEFT ); $trans = array( '-' => '0', 'r' => '4', 'w' => '2', 'x' => '1', ); $mode = strtr( $mode, $trans ); $newmode = $mode[0]; $newmode .= $mode[1] + $mode[2] + $mode[3]; $newmode .= $mode[4] + $mode[5] + $mode[6]; $newmode .= $mode[7] + $mode[8] + $mode[9]; return $newmode; } /** * Determines if the string provided contains binary characters. * * @since 2.7.0 * * @param string $text String to test against. * @return bool True if string is binary, false otherwise. */ public function is_binary( $text ) { return (bool) preg_match( '|[^\x20-\x7E]|', $text ); // chr(32)..chr(127) } /** * Changes the owner of a file or directory. * * Default behavior is to do nothing, override this in your subclass, if desired. * * @since 2.5.0 * * @param string $file Path to the file or directory. * @param string|int $owner A user name or number. * @param bool $recursive Optional. If set to true, changes file owner recursively. * Default false. * @return bool True on success, false on failure. */ public function chown( $file, $owner, $recursive = false ) { return false; } /** * Connects filesystem. * * @since 2.5.0 * @abstract * * @return bool True on success, false on failure (always true for WP_Filesystem_Direct). */ public function connect() { return true; } /** * Reads entire file into a string. * * @since 2.5.0 * @abstract * * @param string $file Name of the file to read. * @return string|false Read data on success, false on failure. */ public function get_contents( $file ) { return false; } /** * Reads entire file into an array. * * @since 2.5.0 * @abstract * * @param string $file Path to the file. * @return array|false File contents in an array on success, false on failure. */ public function get_contents_array( $file ) { return false; } /** * Writes a string to a file. * * @since 2.5.0 * @abstract * * @param string $file Remote path to the file where to write the data. * @param string $contents The data to write. * @param int|false $mode Optional. The file permissions as octal number, usually 0644. * Default false. * @return bool True on success, false on failure. */ public function put_contents( $file, $contents, $mode = false ) { return false; } /** * Gets the current working directory. * * @since 2.5.0 * @abstract * * @return string|false The current working directory on success, false on failure. */ public function cwd() { return false; } /** * Changes current directory. * * @since 2.5.0 * @abstract * * @param string $dir The new current directory. * @return bool True on success, false on failure. */ public function chdir( $dir ) { return false; } /** * Changes the file group. * * @since 2.5.0 * @abstract * * @param string $file Path to the file. * @param string|int $group A group name or number. * @param bool $recursive Optional. If set to true, changes file group recursively. * Default false. * @return bool True on success, false on failure. */ public function chgrp( $file, $group, $recursive = false ) { return false; } /** * Changes filesystem permissions. * * @since 2.5.0 * @abstract * * @param string $file Path to the file. * @param int|false $mode Optional. The permissions as octal number, usually 0644 for files, * 0755 for directories. Default false. * @param bool $recursive Optional. If set to true, changes file permissions recursively. * Default false. * @return bool True on success, false on failure. */ public function chmod( $file, $mode = false, $recursive = false ) { return false; } /** * Gets the file owner. * * @since 2.5.0 * @abstract * * @param string $file Path to the file. * @return string|false Username of the owner on success, false on failure. */ public function owner( $file ) { return false; } /** * Gets the file's group. * * @since 2.5.0 * @abstract * * @param string $file Path to the file. * @return string|false The group on success, false on failure. */ public function group( $file ) { return false; } /** * Copies a file. * * @since 2.5.0 * @abstract * * @param string $source Path to the source file. * @param string $destination Path to the destination file. * @param bool $overwrite Optional. Whether to overwrite the destination file if it exists. * Default false. * @param int|false $mode Optional. The permissions as octal number, usually 0644 for files, * 0755 for dirs. Default false. * @return bool True on success, false on failure. */ public function copy( $source, $destination, $overwrite = false, $mode = false ) { return false; } /** * Moves a file. * * @since 2.5.0 * @abstract * * @param string $source Path to the source file. * @param string $destination Path to the destination file. * @param bool $overwrite Optional. Whether to overwrite the destination file if it exists. * Default false. * @return bool True on success, false on failure. */ public function move( $source, $destination, $overwrite = false ) { return false; } /** * Deletes a file or directory. * * @since 2.5.0 * @abstract * * @param string $file Path to the file or directory. * @param bool $recursive Optional. If set to true, deletes files and folders recursively. * Default false. * @param string|false $type Type of resource. 'f' for file, 'd' for directory. * Default false. * @return bool True on success, false on failure. */ public function delete( $file, $recursive = false, $type = false ) { return false; } /** * Checks if a file or directory exists. * * @since 2.5.0 * @abstract * * @param string $path Path to file or directory. * @return bool Whether $path exists or not. */ public function exists( $path ) { return false; } /** * Checks if resource is a file. * * @since 2.5.0 * @abstract * * @param string $file File path. * @return bool Whether $file is a file. */ public function is_file( $file ) { return false; } /** * Checks if resource is a directory. * * @since 2.5.0 * @abstract * * @param string $path Directory path. * @return bool Whether $path is a directory. */ public function is_dir( $path ) { return false; } /** * Checks if a file is readable. * * @since 2.5.0 * @abstract * * @param string $file Path to file. * @return bool Whether $file is readable. */ public function is_readable( $file ) { return false; } /** * Checks if a file or directory is writable. * * @since 2.5.0 * @abstract * * @param string $path Path to file or directory. * @return bool Whether $path is writable. */ public function is_writable( $path ) { return false; } /** * Gets the file's last access time. * * @since 2.5.0 * @abstract * * @param string $file Path to file. * @return int|false Unix timestamp representing last access time, false on failure. */ public function atime( $file ) { return false; } /** * Gets the file modification time. * * @since 2.5.0 * @abstract * * @param string $file Path to file. * @return int|false Unix timestamp representing modification time, false on failure. */ public function mtime( $file ) { return false; } /** * Gets the file size (in bytes). * * @since 2.5.0 * @abstract * * @param string $file Path to file. * @return int|false Size of the file in bytes on success, false on failure. */ public function size( $file ) { return false; } /** * Sets the access and modification times of a file. * * Note: If $file doesn't exist, it will be created. * * @since 2.5.0 * @abstract * * @param string $file Path to file. * @param int $time Optional. Modified time to set for file. * Default 0. * @param int $atime Optional. Access time to set for file. * Default 0. * @return bool True on success, false on failure. */ public function touch( $file, $time = 0, $atime = 0 ) { return false; } /** * Creates a directory. * * @since 2.5.0 * @abstract * * @param string $path Path for new directory. * @param int|false $chmod Optional. The permissions as octal number (or false to skip chmod). * Default false. * @param string|int|false $chown Optional. A user name or number (or false to skip chown). * Default false. * @param string|int|false $chgrp Optional. A group name or number (or false to skip chgrp). * Default false. * @return bool True on success, false on failure. */ public function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) { return false; } /** * Deletes a directory. * * @since 2.5.0 * @abstract * * @param string $path Path to directory. * @param bool $recursive Optional. Whether to recursively remove files/directories. * Default false. * @return bool True on success, false on failure. */ public function rmdir( $path, $recursive = false ) { return false; } /** * Gets details for files in a directory or a specific file. * * @since 2.5.0 * @abstract * * @param string $path Path to directory or file. * @param bool $include_hidden Optional. Whether to include details of hidden ("." prefixed) files. * Default true. * @param bool $recursive Optional. Whether to recursively include file details in nested directories. * Default false. * @return array|false { * Array of arrays containing file information. False if unable to list directory contents. * * @type array ...$0 { * Array of file information. Note that some elements may not be available on all filesystems. * * @type string $name Name of the file or directory. * @type string $perms *nix representation of permissions. * @type string $permsn Octal representation of permissions. * @type int|string|false $number File number. May be a numeric string. False if not available. * @type string|false $owner Owner name or ID, or false if not available. * @type string|false $group File permissions group, or false if not available. * @type int|string|false $size Size of file in bytes. May be a numeric string. * False if not available. * @type int|string|false $lastmodunix Last modified unix timestamp. May be a numeric string. * False if not available. * @type string|false $lastmod Last modified month (3 letters) and day (without leading 0), or * false if not available. * @type string|false $time Last modified time, or false if not available. * @type string $type Type of resource. 'f' for file, 'd' for directory, 'l' for link. * @type array|false $files If a directory and `$recursive` is true, contains another array of * files. False if unable to list directory contents. * } * } */ public function dirlist( $path, $include_hidden = true, $recursive = false ) { return false; } } PK $��\��+k, , admin.phpnu �[��� <?php /** * Core Administration API * * @package WordPress * @subpackage Administration * @since 2.3.0 */ if ( ! defined( 'WP_ADMIN' ) ) { /* * This file is being included from a file other than wp-admin/admin.php, so * some setup was skipped. Make sure the admin message catalog is loaded since * load_default_textdomain() will not have done so in this context. */ $admin_locale = get_locale(); load_textdomain( 'default', WP_LANG_DIR . '/admin-' . $admin_locale . '.mo', $admin_locale ); unset( $admin_locale ); } /** WordPress Administration Hooks */ require_once ABSPATH . 'wp-admin/includes/admin-filters.php'; /** WordPress Bookmark Administration API */ require_once ABSPATH . 'wp-admin/includes/bookmark.php'; /** WordPress Comment Administration API */ require_once ABSPATH . 'wp-admin/includes/comment.php'; /** WordPress Administration File API */ require_once ABSPATH . 'wp-admin/includes/file.php'; /** WordPress Image Administration API */ require_once ABSPATH . 'wp-admin/includes/image.php'; /** WordPress Media Administration API */ require_once ABSPATH . 'wp-admin/includes/media.php'; /** WordPress Import Administration API */ require_once ABSPATH . 'wp-admin/includes/import.php'; /** WordPress Misc Administration API */ require_once ABSPATH . 'wp-admin/includes/misc.php'; /** WordPress Misc Administration API */ require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-policy-content.php'; /** WordPress Options Administration API */ require_once ABSPATH . 'wp-admin/includes/options.php'; /** WordPress Plugin Administration API */ require_once ABSPATH . 'wp-admin/includes/plugin.php'; /** WordPress Post Administration API */ require_once ABSPATH . 'wp-admin/includes/post.php'; /** WordPress Administration Screen API */ require_once ABSPATH . 'wp-admin/includes/class-wp-screen.php'; require_once ABSPATH . 'wp-admin/includes/screen.php'; /** WordPress Taxonomy Administration API */ require_once ABSPATH . 'wp-admin/includes/taxonomy.php'; /** WordPress Template Administration API */ require_once ABSPATH . 'wp-admin/includes/template.php'; /** WordPress List Table Administration API and base class */ require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php'; require_once ABSPATH . 'wp-admin/includes/class-wp-list-table-compat.php'; require_once ABSPATH . 'wp-admin/includes/list-table.php'; /** WordPress Theme Administration API */ require_once ABSPATH . 'wp-admin/includes/theme.php'; /** WordPress Privacy Functions */ require_once ABSPATH . 'wp-admin/includes/privacy-tools.php'; /** WordPress Privacy List Table classes. */ // Previously in wp-admin/includes/user.php. Need to be loaded for backward compatibility. require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-requests-table.php'; require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-data-export-requests-list-table.php'; require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-data-removal-requests-list-table.php'; /** WordPress User Administration API */ require_once ABSPATH . 'wp-admin/includes/user.php'; /** WordPress Site Icon API */ require_once ABSPATH . 'wp-admin/includes/class-wp-site-icon.php'; /** WordPress Update Administration API */ require_once ABSPATH . 'wp-admin/includes/update.php'; /** WordPress Deprecated Administration API */ require_once ABSPATH . 'wp-admin/includes/deprecated.php'; /** WordPress Multisite support API */ if ( is_multisite() ) { require_once ABSPATH . 'wp-admin/includes/ms-admin-filters.php'; require_once ABSPATH . 'wp-admin/includes/ms.php'; require_once ABSPATH . 'wp-admin/includes/ms-deprecated.php'; } PK $��\�W��S S 5 class-wp-privacy-data-removal-requests-list-table.phpnu �[��� <?php /** * List Table API: WP_Privacy_Data_Removal_Requests_List_Table class * * @package WordPress * @subpackage Administration * @since 4.9.6 */ if ( ! class_exists( 'WP_Privacy_Requests_Table' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-requests-table.php'; } /** * WP_Privacy_Data_Removal_Requests_List_Table class. * * @since 4.9.6 */ class WP_Privacy_Data_Removal_Requests_List_Table extends WP_Privacy_Requests_Table { /** * Action name for the requests this table will work with. * * @since 4.9.6 * * @var string $request_type Name of action. */ protected $request_type = 'remove_personal_data'; /** * Post type for the requests. * * @since 4.9.6 * * @var string $post_type The post type. */ protected $post_type = 'user_request'; /** * Outputs the Actions column. * * @since 4.9.6 * * @param WP_User_Request $item Item being shown. * @return string Email column markup. */ public function column_email( $item ) { $row_actions = array(); // Allow the administrator to "force remove" the personal data even if confirmation has not yet been received. $status = $item->status; $request_id = $item->ID; $row_actions = array(); if ( 'request-confirmed' !== $status ) { /** This filter is documented in wp-admin/includes/ajax-actions.php */ $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() ); $erasers_count = count( $erasers ); $nonce = wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id ); $remove_data_markup = '<span class="remove-personal-data force-remove-personal-data" ' . 'data-erasers-count="' . esc_attr( $erasers_count ) . '" ' . 'data-request-id="' . esc_attr( $request_id ) . '" ' . 'data-nonce="' . esc_attr( $nonce ) . '">'; $remove_data_markup .= '<span class="remove-personal-data-idle"><button type="button" class="button-link remove-personal-data-handle">' . __( 'Force erase personal data' ) . '</button></span>' . '<span class="remove-personal-data-processing hidden">' . __( 'Erasing data...' ) . ' <span class="erasure-progress"></span></span>' . '<span class="remove-personal-data-success hidden">' . __( 'Erasure completed.' ) . '</span>' . '<span class="remove-personal-data-failed hidden">' . __( 'Force erasure has failed.' ) . ' <button type="button" class="button-link remove-personal-data-handle">' . __( 'Retry' ) . '</button></span>'; $remove_data_markup .= '</span>'; $row_actions['remove-data'] = $remove_data_markup; } if ( 'request-completed' !== $status ) { $complete_request_markup = '<span>'; $complete_request_markup .= sprintf( '<a href="%s" class="complete-request" aria-label="%s">%s</a>', esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'complete', 'request_id' => array( $request_id ), ), admin_url( 'erase-personal-data.php' ) ), 'bulk-privacy_requests' ) ), esc_attr( sprintf( /* translators: %s: Request email. */ __( 'Mark export request for “%s” as completed.' ), $item->email ) ), __( 'Complete request' ) ); $complete_request_markup .= '</span>'; } if ( ! empty( $complete_request_markup ) ) { $row_actions['complete-request'] = $complete_request_markup; } return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) ); } /** * Outputs the Next steps column. * * @since 4.9.6 * * @param WP_User_Request $item Item being shown. */ public function column_next_steps( $item ) { $status = $item->status; switch ( $status ) { case 'request-pending': esc_html_e( 'Waiting for confirmation' ); break; case 'request-confirmed': /** This filter is documented in wp-admin/includes/ajax-actions.php */ $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() ); $erasers_count = count( $erasers ); $request_id = $item->ID; $nonce = wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id ); echo '<div class="remove-personal-data" ' . 'data-force-erase="1" ' . 'data-erasers-count="' . esc_attr( $erasers_count ) . '" ' . 'data-request-id="' . esc_attr( $request_id ) . '" ' . 'data-nonce="' . esc_attr( $nonce ) . '">'; ?> <span class="remove-personal-data-idle"><button type="button" class="button-link remove-personal-data-handle"><?php _e( 'Erase personal data' ); ?></button></span> <span class="remove-personal-data-processing hidden"><?php _e( 'Erasing data...' ); ?> <span class="erasure-progress"></span></span> <span class="remove-personal-data-success success-message hidden" ><?php _e( 'Erasure completed.' ); ?></span> <span class="remove-personal-data-failed hidden"><?php _e( 'Data erasure has failed.' ); ?> <button type="button" class="button-link remove-personal-data-handle"><?php _e( 'Retry' ); ?></button></span> <?php echo '</div>'; break; case 'request-failed': echo '<button type="submit" class="button-link" name="privacy_action_email_retry[' . $item->ID . ']" id="privacy_action_email_retry[' . $item->ID . ']">' . __( 'Retry' ) . '</button>'; break; case 'request-completed': echo '<a href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'delete', 'request_id' => array( $item->ID ), ), admin_url( 'erase-personal-data.php' ) ), 'bulk-privacy_requests' ) ) . '">' . esc_html__( 'Remove request' ) . '</a>'; break; } } } PK $��\��a� � update-core.phpnu �[��� <?php /** * WordPress core upgrade functionality. * * Note: Newly introduced functions and methods cannot be used here. * All functions must be present in the previous version being upgraded from * as this file is used there too. * * @package WordPress * @subpackage Administration * @since 2.7.0 */ /** * Stores files to be deleted. * * Bundled theme files should not be included in this list. * * @since 2.7.0 * * @global string[] $_old_files * @var string[] * @name $_old_files */ global $_old_files; $_old_files = array( // 2.0 'wp-admin/import-b2.php', 'wp-admin/import-blogger.php', 'wp-admin/import-greymatter.php', 'wp-admin/import-livejournal.php', 'wp-admin/import-mt.php', 'wp-admin/import-rss.php', 'wp-admin/import-textpattern.php', 'wp-admin/quicktags.js', 'wp-images/fade-butt.png', 'wp-images/get-firefox.png', 'wp-images/header-shadow.png', 'wp-images/smilies', 'wp-images/wp-small.png', 'wp-images/wpminilogo.png', 'wp.php', // 2.1 'wp-admin/edit-form-ajax-cat.php', 'wp-admin/execute-pings.php', 'wp-admin/inline-uploading.php', 'wp-admin/link-categories.php', 'wp-admin/list-manipulation.js', 'wp-admin/list-manipulation.php', 'wp-includes/comment-functions.php', 'wp-includes/feed-functions.php', 'wp-includes/functions-compat.php', 'wp-includes/functions-formatting.php', 'wp-includes/functions-post.php', 'wp-includes/js/dbx-key.js', 'wp-includes/links.php', 'wp-includes/pluggable-functions.php', 'wp-includes/template-functions-author.php', 'wp-includes/template-functions-category.php', 'wp-includes/template-functions-general.php', 'wp-includes/template-functions-links.php', 'wp-includes/template-functions-post.php', 'wp-includes/wp-l10n.php', // 2.2 'wp-admin/cat-js.php', 'wp-includes/js/autosave-js.php', 'wp-includes/js/list-manipulation-js.php', 'wp-includes/js/wp-ajax-js.php', // 2.3 'wp-admin/admin-db.php', 'wp-admin/cat.js', 'wp-admin/categories.js', 'wp-admin/custom-fields.js', 'wp-admin/dbx-admin-key.js', 'wp-admin/edit-comments.js', 'wp-admin/install-rtl.css', 'wp-admin/install.css', 'wp-admin/upgrade-schema.php', 'wp-admin/upload-functions.php', 'wp-admin/upload-rtl.css', 'wp-admin/upload.css', 'wp-admin/upload.js', 'wp-admin/users.js', 'wp-admin/widgets-rtl.css', 'wp-admin/widgets.css', 'wp-admin/xfn.js', 'wp-includes/js/tinymce/license.html', // 2.5 'wp-admin/css/upload.css', 'wp-admin/images/box-bg-left.gif', 'wp-admin/images/box-bg-right.gif', 'wp-admin/images/box-bg.gif', 'wp-admin/images/box-butt-left.gif', 'wp-admin/images/box-butt-right.gif', 'wp-admin/images/box-butt.gif', 'wp-admin/images/box-head-left.gif', 'wp-admin/images/box-head-right.gif', 'wp-admin/images/box-head.gif', 'wp-admin/images/heading-bg.gif', 'wp-admin/images/login-bkg-bottom.gif', 'wp-admin/images/login-bkg-tile.gif', 'wp-admin/images/notice.gif', 'wp-admin/images/toggle.gif', 'wp-admin/includes/upload.php', 'wp-admin/js/dbx-admin-key.js', 'wp-admin/js/link-cat.js', 'wp-admin/profile-update.php', 'wp-admin/templates.php', 'wp-includes/js/dbx.js', 'wp-includes/js/fat.js', 'wp-includes/js/list-manipulation.js', 'wp-includes/js/tinymce/langs/en.js', 'wp-includes/js/tinymce/plugins/directionality/images', 'wp-includes/js/tinymce/plugins/directionality/langs', 'wp-includes/js/tinymce/plugins/paste/images', 'wp-includes/js/tinymce/plugins/paste/jscripts', 'wp-includes/js/tinymce/plugins/paste/langs', 'wp-includes/js/tinymce/plugins/wordpress/images', 'wp-includes/js/tinymce/plugins/wordpress/langs', 'wp-includes/js/tinymce/plugins/wordpress/wordpress.css', 'wp-includes/js/tinymce/plugins/wphelp', // 2.5.1 'wp-includes/js/tinymce/tiny_mce_gzip.php', // 2.6 'wp-admin/bookmarklet.php', 'wp-includes/js/jquery/jquery.dimensions.min.js', 'wp-includes/js/tinymce/plugins/wordpress/popups.css', 'wp-includes/js/wp-ajax.js', // 2.7 'wp-admin/css/press-this-ie-rtl.css', 'wp-admin/css/press-this-ie.css', 'wp-admin/css/upload-rtl.css', 'wp-admin/edit-form.php', 'wp-admin/images/comment-pill.gif', 'wp-admin/images/comment-stalk-classic.gif', 'wp-admin/images/comment-stalk-fresh.gif', 'wp-admin/images/comment-stalk-rtl.gif', 'wp-admin/images/del.png', 'wp-admin/images/gear.png', 'wp-admin/images/media-button-gallery.gif', 'wp-admin/images/media-buttons.gif', 'wp-admin/images/postbox-bg.gif', 'wp-admin/images/tab.png', 'wp-admin/images/tail.gif', 'wp-admin/js/forms.js', 'wp-admin/js/upload.js', 'wp-admin/link-import.php', 'wp-includes/images/audio.png', 'wp-includes/images/css.png', 'wp-includes/images/default.png', 'wp-includes/images/doc.png', 'wp-includes/images/exe.png', 'wp-includes/images/html.png', 'wp-includes/images/js.png', 'wp-includes/images/pdf.png', 'wp-includes/images/swf.png', 'wp-includes/images/tar.png', 'wp-includes/images/text.png', 'wp-includes/images/video.png', 'wp-includes/images/zip.png', 'wp-includes/js/tinymce/tiny_mce_config.php', 'wp-includes/js/tinymce/tiny_mce_ext.js', // 2.8 'wp-admin/js/users.js', 'wp-includes/js/swfupload/swfupload_f9.swf', 'wp-includes/js/tinymce/plugins/autosave', 'wp-includes/js/tinymce/plugins/paste/css', 'wp-includes/js/tinymce/utils/mclayer.js', 'wp-includes/js/tinymce/wordpress.css', // 2.9 'wp-admin/js/page.dev.js', 'wp-admin/js/page.js', 'wp-admin/js/set-post-thumbnail-handler.dev.js', 'wp-admin/js/set-post-thumbnail-handler.js', 'wp-admin/js/slug.dev.js', 'wp-admin/js/slug.js', 'wp-includes/gettext.php', 'wp-includes/js/tinymce/plugins/wordpress/js', 'wp-includes/streams.php', // MU 'README.txt', 'htaccess.dist', 'index-install.php', 'wp-admin/css/mu-rtl.css', 'wp-admin/css/mu.css', 'wp-admin/images/site-admin.png', 'wp-admin/includes/mu.php', 'wp-admin/wpmu-admin.php', 'wp-admin/wpmu-blogs.php', 'wp-admin/wpmu-edit.php', 'wp-admin/wpmu-options.php', 'wp-admin/wpmu-themes.php', 'wp-admin/wpmu-upgrade-site.php', 'wp-admin/wpmu-users.php', 'wp-includes/images/wordpress-mu.png', 'wp-includes/wpmu-default-filters.php', 'wp-includes/wpmu-functions.php', 'wpmu-settings.php', // 3.0 'wp-admin/categories.php', 'wp-admin/edit-category-form.php', 'wp-admin/edit-page-form.php', 'wp-admin/edit-pages.php', 'wp-admin/images/admin-header-footer.png', 'wp-admin/images/browse-happy.gif', 'wp-admin/images/ico-add.png', 'wp-admin/images/ico-close.png', 'wp-admin/images/ico-edit.png', 'wp-admin/images/ico-viewpage.png', 'wp-admin/images/fav-top.png', 'wp-admin/images/screen-options-left.gif', 'wp-admin/images/wp-logo-vs.gif', 'wp-admin/images/wp-logo.gif', 'wp-admin/import', 'wp-admin/js/wp-gears.dev.js', 'wp-admin/js/wp-gears.js', 'wp-admin/options-misc.php', 'wp-admin/page-new.php', 'wp-admin/page.php', 'wp-admin/rtl.css', 'wp-admin/rtl.dev.css', 'wp-admin/update-links.php', 'wp-admin/wp-admin.css', 'wp-admin/wp-admin.dev.css', 'wp-includes/js/codepress', 'wp-includes/js/jquery/autocomplete.dev.js', 'wp-includes/js/jquery/autocomplete.js', 'wp-includes/js/jquery/interface.js', // Following file added back in 5.1, see #45645. //'wp-includes/js/tinymce/wp-tinymce.js', // 3.1 'wp-admin/edit-attachment-rows.php', 'wp-admin/edit-link-categories.php', 'wp-admin/edit-link-category-form.php', 'wp-admin/edit-post-rows.php', 'wp-admin/images/button-grad-active-vs.png', 'wp-admin/images/button-grad-vs.png', 'wp-admin/images/fav-arrow-vs-rtl.gif', 'wp-admin/images/fav-arrow-vs.gif', 'wp-admin/images/fav-top-vs.gif', 'wp-admin/images/list-vs.png', 'wp-admin/images/screen-options-right-up.gif', 'wp-admin/images/screen-options-right.gif', 'wp-admin/images/visit-site-button-grad-vs.gif', 'wp-admin/images/visit-site-button-grad.gif', 'wp-admin/link-category.php', 'wp-admin/sidebar.php', 'wp-includes/classes.php', 'wp-includes/js/tinymce/blank.htm', 'wp-includes/js/tinymce/plugins/media/img', 'wp-includes/js/tinymce/plugins/safari', // 3.2 'wp-admin/images/logo-login.gif', 'wp-admin/images/star.gif', 'wp-admin/js/list-table.dev.js', 'wp-admin/js/list-table.js', 'wp-includes/default-embeds.php', // 3.3 'wp-admin/css/colors-classic-rtl.css', 'wp-admin/css/colors-classic-rtl.dev.css', 'wp-admin/css/colors-fresh-rtl.css', 'wp-admin/css/colors-fresh-rtl.dev.css', 'wp-admin/css/dashboard-rtl.dev.css', 'wp-admin/css/dashboard.dev.css', 'wp-admin/css/global-rtl.css', 'wp-admin/css/global-rtl.dev.css', 'wp-admin/css/global.css', 'wp-admin/css/global.dev.css', 'wp-admin/css/install-rtl.dev.css', 'wp-admin/css/login-rtl.dev.css', 'wp-admin/css/login.dev.css', 'wp-admin/css/ms.css', 'wp-admin/css/ms.dev.css', 'wp-admin/css/nav-menu-rtl.css', 'wp-admin/css/nav-menu-rtl.dev.css', 'wp-admin/css/nav-menu.css', 'wp-admin/css/nav-menu.dev.css', 'wp-admin/css/plugin-install-rtl.css', 'wp-admin/css/plugin-install-rtl.dev.css', 'wp-admin/css/plugin-install.css', 'wp-admin/css/plugin-install.dev.css', 'wp-admin/css/press-this-rtl.dev.css', 'wp-admin/css/press-this.dev.css', 'wp-admin/css/theme-editor-rtl.css', 'wp-admin/css/theme-editor-rtl.dev.css', 'wp-admin/css/theme-editor.css', 'wp-admin/css/theme-editor.dev.css', 'wp-admin/css/theme-install-rtl.css', 'wp-admin/css/theme-install-rtl.dev.css', 'wp-admin/css/theme-install.css', 'wp-admin/css/theme-install.dev.css', 'wp-admin/css/widgets-rtl.dev.css', 'wp-admin/css/widgets.dev.css', 'wp-admin/includes/internal-linking.php', 'wp-includes/images/admin-bar-sprite-rtl.png', 'wp-includes/js/jquery/ui.button.js', 'wp-includes/js/jquery/ui.core.js', 'wp-includes/js/jquery/ui.dialog.js', 'wp-includes/js/jquery/ui.draggable.js', 'wp-includes/js/jquery/ui.droppable.js', 'wp-includes/js/jquery/ui.mouse.js', 'wp-includes/js/jquery/ui.position.js', 'wp-includes/js/jquery/ui.resizable.js', 'wp-includes/js/jquery/ui.selectable.js', 'wp-includes/js/jquery/ui.sortable.js', 'wp-includes/js/jquery/ui.tabs.js', 'wp-includes/js/jquery/ui.widget.js', 'wp-includes/js/l10n.dev.js', 'wp-includes/js/l10n.js', 'wp-includes/js/tinymce/plugins/wplink/css', 'wp-includes/js/tinymce/plugins/wplink/img', 'wp-includes/js/tinymce/plugins/wplink/js', // Don't delete, yet: 'wp-rss.php', // Don't delete, yet: 'wp-rdf.php', // Don't delete, yet: 'wp-rss2.php', // Don't delete, yet: 'wp-commentsrss2.php', // Don't delete, yet: 'wp-atom.php', // Don't delete, yet: 'wp-feed.php', // 3.4 'wp-admin/images/gray-star.png', 'wp-admin/images/logo-login.png', 'wp-admin/images/star.png', 'wp-admin/index-extra.php', 'wp-admin/network/index-extra.php', 'wp-admin/user/index-extra.php', 'wp-includes/css/editor-buttons.css', 'wp-includes/css/editor-buttons.dev.css', 'wp-includes/js/tinymce/plugins/paste/blank.htm', 'wp-includes/js/tinymce/plugins/wordpress/css', 'wp-includes/js/tinymce/plugins/wordpress/editor_plugin.dev.js', 'wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin.dev.js', 'wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin.dev.js', 'wp-includes/js/tinymce/plugins/wpgallery/editor_plugin.dev.js', 'wp-includes/js/tinymce/plugins/wplink/editor_plugin.dev.js', // Don't delete, yet: 'wp-pass.php', // Don't delete, yet: 'wp-register.php', // 3.5 'wp-admin/gears-manifest.php', 'wp-admin/includes/manifest.php', 'wp-admin/images/archive-link.png', 'wp-admin/images/blue-grad.png', 'wp-admin/images/button-grad-active.png', 'wp-admin/images/button-grad.png', 'wp-admin/images/ed-bg-vs.gif', 'wp-admin/images/ed-bg.gif', 'wp-admin/images/fade-butt.png', 'wp-admin/images/fav-arrow-rtl.gif', 'wp-admin/images/fav-arrow.gif', 'wp-admin/images/fav-vs.png', 'wp-admin/images/fav.png', 'wp-admin/images/gray-grad.png', 'wp-admin/images/loading-publish.gif', 'wp-admin/images/logo-ghost.png', 'wp-admin/images/logo.gif', 'wp-admin/images/menu-arrow-frame-rtl.png', 'wp-admin/images/menu-arrow-frame.png', 'wp-admin/images/menu-arrows.gif', 'wp-admin/images/menu-bits-rtl-vs.gif', 'wp-admin/images/menu-bits-rtl.gif', 'wp-admin/images/menu-bits-vs.gif', 'wp-admin/images/menu-bits.gif', 'wp-admin/images/menu-dark-rtl-vs.gif', 'wp-admin/images/menu-dark-rtl.gif', 'wp-admin/images/menu-dark-vs.gif', 'wp-admin/images/menu-dark.gif', 'wp-admin/images/required.gif', 'wp-admin/images/screen-options-toggle-vs.gif', 'wp-admin/images/screen-options-toggle.gif', 'wp-admin/images/toggle-arrow-rtl.gif', 'wp-admin/images/toggle-arrow.gif', 'wp-admin/images/upload-classic.png', 'wp-admin/images/upload-fresh.png', 'wp-admin/images/white-grad-active.png', 'wp-admin/images/white-grad.png', 'wp-admin/images/widgets-arrow-vs.gif', 'wp-admin/images/widgets-arrow.gif', 'wp-admin/images/wpspin_dark.gif', 'wp-includes/images/upload.png', 'wp-includes/js/prototype.js', 'wp-includes/js/scriptaculous', 'wp-admin/css/wp-admin-rtl.dev.css', 'wp-admin/css/wp-admin.dev.css', 'wp-admin/css/media-rtl.dev.css', 'wp-admin/css/media.dev.css', 'wp-admin/css/colors-classic.dev.css', 'wp-admin/css/customize-controls-rtl.dev.css', 'wp-admin/css/customize-controls.dev.css', 'wp-admin/css/ie-rtl.dev.css', 'wp-admin/css/ie.dev.css', 'wp-admin/css/install.dev.css', 'wp-admin/css/colors-fresh.dev.css', 'wp-includes/js/customize-base.dev.js', 'wp-includes/js/json2.dev.js', 'wp-includes/js/comment-reply.dev.js', 'wp-includes/js/customize-preview.dev.js', 'wp-includes/js/wplink.dev.js', 'wp-includes/js/tw-sack.dev.js', 'wp-includes/js/wp-list-revisions.dev.js', 'wp-includes/js/autosave.dev.js', 'wp-includes/js/admin-bar.dev.js', 'wp-includes/js/quicktags.dev.js', 'wp-includes/js/wp-ajax-response.dev.js', 'wp-includes/js/wp-pointer.dev.js', 'wp-includes/js/hoverIntent.dev.js', 'wp-includes/js/colorpicker.dev.js', 'wp-includes/js/wp-lists.dev.js', 'wp-includes/js/customize-loader.dev.js', 'wp-includes/js/jquery/jquery.table-hotkeys.dev.js', 'wp-includes/js/jquery/jquery.color.dev.js', 'wp-includes/js/jquery/jquery.color.js', 'wp-includes/js/jquery/jquery.hotkeys.dev.js', 'wp-includes/js/jquery/jquery.form.dev.js', 'wp-includes/js/jquery/suggest.dev.js', 'wp-admin/js/xfn.dev.js', 'wp-admin/js/set-post-thumbnail.dev.js', 'wp-admin/js/comment.dev.js', 'wp-admin/js/theme.dev.js', 'wp-admin/js/cat.dev.js', 'wp-admin/js/password-strength-meter.dev.js', 'wp-admin/js/user-profile.dev.js', 'wp-admin/js/theme-preview.dev.js', 'wp-admin/js/post.dev.js', 'wp-admin/js/media-upload.dev.js', 'wp-admin/js/word-count.dev.js', 'wp-admin/js/plugin-install.dev.js', 'wp-admin/js/edit-comments.dev.js', 'wp-admin/js/media-gallery.dev.js', 'wp-admin/js/custom-fields.dev.js', 'wp-admin/js/custom-background.dev.js', 'wp-admin/js/common.dev.js', 'wp-admin/js/inline-edit-tax.dev.js', 'wp-admin/js/gallery.dev.js', 'wp-admin/js/utils.dev.js', 'wp-admin/js/widgets.dev.js', 'wp-admin/js/wp-fullscreen.dev.js', 'wp-admin/js/nav-menu.dev.js', 'wp-admin/js/dashboard.dev.js', 'wp-admin/js/link.dev.js', 'wp-admin/js/user-suggest.dev.js', 'wp-admin/js/postbox.dev.js', 'wp-admin/js/tags.dev.js', 'wp-admin/js/image-edit.dev.js', 'wp-admin/js/media.dev.js', 'wp-admin/js/customize-controls.dev.js', 'wp-admin/js/inline-edit-post.dev.js', 'wp-admin/js/categories.dev.js', 'wp-admin/js/editor.dev.js', 'wp-includes/js/plupload/handlers.dev.js', 'wp-includes/js/plupload/wp-plupload.dev.js', 'wp-includes/js/swfupload/handlers.dev.js', 'wp-includes/js/jcrop/jquery.Jcrop.dev.js', 'wp-includes/js/jcrop/jquery.Jcrop.js', 'wp-includes/js/jcrop/jquery.Jcrop.css', 'wp-includes/js/imgareaselect/jquery.imgareaselect.dev.js', 'wp-includes/css/wp-pointer.dev.css', 'wp-includes/css/editor.dev.css', 'wp-includes/css/jquery-ui-dialog.dev.css', 'wp-includes/css/admin-bar-rtl.dev.css', 'wp-includes/css/admin-bar.dev.css', 'wp-includes/js/jquery/ui/jquery.effects.clip.min.js', 'wp-includes/js/jquery/ui/jquery.effects.scale.min.js', 'wp-includes/js/jquery/ui/jquery.effects.blind.min.js', 'wp-includes/js/jquery/ui/jquery.effects.core.min.js', 'wp-includes/js/jquery/ui/jquery.effects.shake.min.js', 'wp-includes/js/jquery/ui/jquery.effects.fade.min.js', 'wp-includes/js/jquery/ui/jquery.effects.explode.min.js', 'wp-includes/js/jquery/ui/jquery.effects.slide.min.js', 'wp-includes/js/jquery/ui/jquery.effects.drop.min.js', 'wp-includes/js/jquery/ui/jquery.effects.highlight.min.js', 'wp-includes/js/jquery/ui/jquery.effects.bounce.min.js', 'wp-includes/js/jquery/ui/jquery.effects.pulsate.min.js', 'wp-includes/js/jquery/ui/jquery.effects.transfer.min.js', 'wp-includes/js/jquery/ui/jquery.effects.fold.min.js', 'wp-admin/js/utils.js', // Added back in 5.3 [45448], see #43895. // 'wp-admin/options-privacy.php', 'wp-app.php', 'wp-includes/class-wp-atom-server.php', // 3.5.2 'wp-includes/js/swfupload/swfupload-all.js', // 3.6 'wp-admin/js/revisions-js.php', 'wp-admin/images/screenshots', 'wp-admin/js/categories.js', 'wp-admin/js/categories.min.js', 'wp-admin/js/custom-fields.js', 'wp-admin/js/custom-fields.min.js', // 3.7 'wp-admin/js/cat.js', 'wp-admin/js/cat.min.js', // 3.8 'wp-includes/js/thickbox/tb-close-2x.png', 'wp-includes/js/thickbox/tb-close.png', 'wp-includes/images/wpmini-blue-2x.png', 'wp-includes/images/wpmini-blue.png', 'wp-admin/css/colors-fresh.css', 'wp-admin/css/colors-classic.css', 'wp-admin/css/colors-fresh.min.css', 'wp-admin/css/colors-classic.min.css', 'wp-admin/js/about.min.js', 'wp-admin/js/about.js', 'wp-admin/images/arrows-dark-vs-2x.png', 'wp-admin/images/wp-logo-vs.png', 'wp-admin/images/arrows-dark-vs.png', 'wp-admin/images/wp-logo.png', 'wp-admin/images/arrows-pr.png', 'wp-admin/images/arrows-dark.png', 'wp-admin/images/press-this.png', 'wp-admin/images/press-this-2x.png', 'wp-admin/images/arrows-vs-2x.png', 'wp-admin/images/welcome-icons.png', 'wp-admin/images/wp-logo-2x.png', 'wp-admin/images/stars-rtl-2x.png', 'wp-admin/images/arrows-dark-2x.png', 'wp-admin/images/arrows-pr-2x.png', 'wp-admin/images/menu-shadow-rtl.png', 'wp-admin/images/arrows-vs.png', 'wp-admin/images/about-search-2x.png', 'wp-admin/images/bubble_bg-rtl-2x.gif', 'wp-admin/images/wp-badge-2x.png', 'wp-admin/images/wordpress-logo-2x.png', 'wp-admin/images/bubble_bg-rtl.gif', 'wp-admin/images/wp-badge.png', 'wp-admin/images/menu-shadow.png', 'wp-admin/images/about-globe-2x.png', 'wp-admin/images/welcome-icons-2x.png', 'wp-admin/images/stars-rtl.png', 'wp-admin/images/wp-logo-vs-2x.png', 'wp-admin/images/about-updates-2x.png', // 3.9 'wp-admin/css/colors.css', 'wp-admin/css/colors.min.css', 'wp-admin/css/colors-rtl.css', 'wp-admin/css/colors-rtl.min.css', // Following files added back in 4.5, see #36083. // 'wp-admin/css/media-rtl.min.css', // 'wp-admin/css/media.min.css', // 'wp-admin/css/farbtastic-rtl.min.css', 'wp-admin/images/lock-2x.png', 'wp-admin/images/lock.png', 'wp-admin/js/theme-preview.js', 'wp-admin/js/theme-install.min.js', 'wp-admin/js/theme-install.js', 'wp-admin/js/theme-preview.min.js', 'wp-includes/js/plupload/plupload.html4.js', 'wp-includes/js/plupload/plupload.html5.js', 'wp-includes/js/plupload/changelog.txt', 'wp-includes/js/plupload/plupload.silverlight.js', 'wp-includes/js/plupload/plupload.flash.js', // Added back in 4.9 [41328], see #41755. // 'wp-includes/js/plupload/plupload.js', 'wp-includes/js/tinymce/plugins/spellchecker', 'wp-includes/js/tinymce/plugins/inlinepopups', 'wp-includes/js/tinymce/plugins/media/js', 'wp-includes/js/tinymce/plugins/media/css', 'wp-includes/js/tinymce/plugins/wordpress/img', 'wp-includes/js/tinymce/plugins/wpdialogs/js', 'wp-includes/js/tinymce/plugins/wpeditimage/img', 'wp-includes/js/tinymce/plugins/wpeditimage/js', 'wp-includes/js/tinymce/plugins/wpeditimage/css', 'wp-includes/js/tinymce/plugins/wpgallery/img', 'wp-includes/js/tinymce/plugins/paste/js', 'wp-includes/js/tinymce/themes/advanced', 'wp-includes/js/tinymce/tiny_mce.js', 'wp-includes/js/tinymce/mark_loaded_src.js', 'wp-includes/js/tinymce/wp-tinymce-schema.js', 'wp-includes/js/tinymce/plugins/media/editor_plugin.js', 'wp-includes/js/tinymce/plugins/media/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/media/media.htm', 'wp-includes/js/tinymce/plugins/wpview/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wpview/editor_plugin.js', 'wp-includes/js/tinymce/plugins/directionality/editor_plugin.js', 'wp-includes/js/tinymce/plugins/directionality/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wordpress/editor_plugin.js', 'wp-includes/js/tinymce/plugins/wordpress/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin.js', 'wp-includes/js/tinymce/plugins/wpeditimage/editimage.html', 'wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin.js', 'wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/fullscreen/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/fullscreen/fullscreen.htm', 'wp-includes/js/tinymce/plugins/fullscreen/editor_plugin.js', 'wp-includes/js/tinymce/plugins/wplink/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wplink/editor_plugin.js', 'wp-includes/js/tinymce/plugins/wpgallery/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/wpgallery/editor_plugin.js', 'wp-includes/js/tinymce/plugins/tabfocus/editor_plugin.js', 'wp-includes/js/tinymce/plugins/tabfocus/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/paste/editor_plugin.js', 'wp-includes/js/tinymce/plugins/paste/pasteword.htm', 'wp-includes/js/tinymce/plugins/paste/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/paste/pastetext.htm', 'wp-includes/js/tinymce/langs/wp-langs.php', // 4.1 'wp-includes/js/jquery/ui/jquery.ui.accordion.min.js', 'wp-includes/js/jquery/ui/jquery.ui.autocomplete.min.js', 'wp-includes/js/jquery/ui/jquery.ui.button.min.js', 'wp-includes/js/jquery/ui/jquery.ui.core.min.js', 'wp-includes/js/jquery/ui/jquery.ui.datepicker.min.js', 'wp-includes/js/jquery/ui/jquery.ui.dialog.min.js', 'wp-includes/js/jquery/ui/jquery.ui.draggable.min.js', 'wp-includes/js/jquery/ui/jquery.ui.droppable.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-blind.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-bounce.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-clip.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-drop.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-explode.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-fade.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-fold.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-highlight.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-pulsate.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-scale.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-shake.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-slide.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect-transfer.min.js', 'wp-includes/js/jquery/ui/jquery.ui.effect.min.js', 'wp-includes/js/jquery/ui/jquery.ui.menu.min.js', 'wp-includes/js/jquery/ui/jquery.ui.mouse.min.js', 'wp-includes/js/jquery/ui/jquery.ui.position.min.js', 'wp-includes/js/jquery/ui/jquery.ui.progressbar.min.js', 'wp-includes/js/jquery/ui/jquery.ui.resizable.min.js', 'wp-includes/js/jquery/ui/jquery.ui.selectable.min.js', 'wp-includes/js/jquery/ui/jquery.ui.slider.min.js', 'wp-includes/js/jquery/ui/jquery.ui.sortable.min.js', 'wp-includes/js/jquery/ui/jquery.ui.spinner.min.js', 'wp-includes/js/jquery/ui/jquery.ui.tabs.min.js', 'wp-includes/js/jquery/ui/jquery.ui.tooltip.min.js', 'wp-includes/js/jquery/ui/jquery.ui.widget.min.js', 'wp-includes/js/tinymce/skins/wordpress/images/dashicon-no-alt.png', // 4.3 'wp-admin/js/wp-fullscreen.js', 'wp-admin/js/wp-fullscreen.min.js', 'wp-includes/js/tinymce/wp-mce-help.php', 'wp-includes/js/tinymce/plugins/wpfullscreen', // 4.5 'wp-includes/theme-compat/comments-popup.php', // 4.6 'wp-admin/includes/class-wp-automatic-upgrader.php', // Wrong file name, see #37628. // 4.8 'wp-includes/js/tinymce/plugins/wpembed', 'wp-includes/js/tinymce/plugins/media/moxieplayer.swf', 'wp-includes/js/tinymce/skins/lightgray/fonts/readme.md', 'wp-includes/js/tinymce/skins/lightgray/fonts/tinymce-small.json', 'wp-includes/js/tinymce/skins/lightgray/fonts/tinymce.json', 'wp-includes/js/tinymce/skins/lightgray/skin.ie7.min.css', // 4.9 'wp-admin/css/press-this-editor-rtl.css', 'wp-admin/css/press-this-editor-rtl.min.css', 'wp-admin/css/press-this-editor.css', 'wp-admin/css/press-this-editor.min.css', 'wp-admin/css/press-this-rtl.css', 'wp-admin/css/press-this-rtl.min.css', 'wp-admin/css/press-this.css', 'wp-admin/css/press-this.min.css', 'wp-admin/includes/class-wp-press-this.php', 'wp-admin/js/bookmarklet.js', 'wp-admin/js/bookmarklet.min.js', 'wp-admin/js/press-this.js', 'wp-admin/js/press-this.min.js', 'wp-includes/js/mediaelement/background.png', 'wp-includes/js/mediaelement/bigplay.png', 'wp-includes/js/mediaelement/bigplay.svg', 'wp-includes/js/mediaelement/controls.png', 'wp-includes/js/mediaelement/controls.svg', 'wp-includes/js/mediaelement/flashmediaelement.swf', 'wp-includes/js/mediaelement/froogaloop.min.js', 'wp-includes/js/mediaelement/jumpforward.png', 'wp-includes/js/mediaelement/loading.gif', 'wp-includes/js/mediaelement/silverlightmediaelement.xap', 'wp-includes/js/mediaelement/skipback.png', 'wp-includes/js/plupload/plupload.flash.swf', 'wp-includes/js/plupload/plupload.full.min.js', 'wp-includes/js/plupload/plupload.silverlight.xap', 'wp-includes/js/swfupload/plugins', 'wp-includes/js/swfupload/swfupload.swf', // 4.9.2 'wp-includes/js/mediaelement/lang', 'wp-includes/js/mediaelement/mediaelement-flash-audio-ogg.swf', 'wp-includes/js/mediaelement/mediaelement-flash-audio.swf', 'wp-includes/js/mediaelement/mediaelement-flash-video-hls.swf', 'wp-includes/js/mediaelement/mediaelement-flash-video-mdash.swf', 'wp-includes/js/mediaelement/mediaelement-flash-video.swf', 'wp-includes/js/mediaelement/renderers/dailymotion.js', 'wp-includes/js/mediaelement/renderers/dailymotion.min.js', 'wp-includes/js/mediaelement/renderers/facebook.js', 'wp-includes/js/mediaelement/renderers/facebook.min.js', 'wp-includes/js/mediaelement/renderers/soundcloud.js', 'wp-includes/js/mediaelement/renderers/soundcloud.min.js', 'wp-includes/js/mediaelement/renderers/twitch.js', 'wp-includes/js/mediaelement/renderers/twitch.min.js', // 5.0 'wp-includes/js/codemirror/jshint.js', // 5.1 'wp-includes/js/tinymce/wp-tinymce.js.gz', // 5.3 'wp-includes/js/wp-a11y.js', // Moved to: wp-includes/js/dist/a11y.js 'wp-includes/js/wp-a11y.min.js', // Moved to: wp-includes/js/dist/a11y.min.js // 5.4 'wp-admin/js/wp-fullscreen-stub.js', 'wp-admin/js/wp-fullscreen-stub.min.js', // 5.5 'wp-admin/css/ie.css', 'wp-admin/css/ie.min.css', 'wp-admin/css/ie-rtl.css', 'wp-admin/css/ie-rtl.min.css', // 5.6 'wp-includes/js/jquery/ui/position.min.js', 'wp-includes/js/jquery/ui/widget.min.js', // 5.7 'wp-includes/blocks/classic/block.json', // 5.8 'wp-admin/images/freedoms.png', 'wp-admin/images/privacy.png', 'wp-admin/images/about-badge.svg', 'wp-admin/images/about-color-palette.svg', 'wp-admin/images/about-color-palette-vert.svg', 'wp-admin/images/about-header-brushes.svg', 'wp-includes/block-patterns/large-header.php', 'wp-includes/block-patterns/heading-paragraph.php', 'wp-includes/block-patterns/quote.php', 'wp-includes/block-patterns/text-three-columns-buttons.php', 'wp-includes/block-patterns/two-buttons.php', 'wp-includes/block-patterns/two-images.php', 'wp-includes/block-patterns/three-buttons.php', 'wp-includes/block-patterns/text-two-columns-with-images.php', 'wp-includes/block-patterns/text-two-columns.php', 'wp-includes/block-patterns/large-header-button.php', 'wp-includes/blocks/subhead', 'wp-includes/css/dist/editor/editor-styles.css', 'wp-includes/css/dist/editor/editor-styles.min.css', 'wp-includes/css/dist/editor/editor-styles-rtl.css', 'wp-includes/css/dist/editor/editor-styles-rtl.min.css', // 5.9 'wp-includes/blocks/heading/editor.css', 'wp-includes/blocks/heading/editor.min.css', 'wp-includes/blocks/heading/editor-rtl.css', 'wp-includes/blocks/heading/editor-rtl.min.css', 'wp-includes/blocks/query-title/editor.css', 'wp-includes/blocks/query-title/editor.min.css', 'wp-includes/blocks/query-title/editor-rtl.css', 'wp-includes/blocks/query-title/editor-rtl.min.css', /* * Restored in WordPress 6.7 * * 'wp-includes/blocks/tag-cloud/editor.css', * 'wp-includes/blocks/tag-cloud/editor.min.css', * 'wp-includes/blocks/tag-cloud/editor-rtl.css', * 'wp-includes/blocks/tag-cloud/editor-rtl.min.css', */ // 6.1 'wp-includes/blocks/post-comments.php', 'wp-includes/blocks/post-comments', 'wp-includes/blocks/comments-query-loop', // 6.3 'wp-includes/images/wlw', 'wp-includes/wlwmanifest.xml', 'wp-includes/random_compat', // 6.4 'wp-includes/navigation-fallback.php', 'wp-includes/blocks/navigation/view-modal.min.js', 'wp-includes/blocks/navigation/view-modal.js', // 6.5 'wp-includes/ID3/license.commercial.txt', 'wp-includes/blocks/query/style-rtl.min.css', 'wp-includes/blocks/query/style.min.css', 'wp-includes/blocks/query/style-rtl.css', 'wp-includes/blocks/query/style.css', 'wp-admin/images/about-header-privacy.svg', 'wp-admin/images/about-header-about.svg', 'wp-admin/images/about-header-credits.svg', 'wp-admin/images/about-header-freedoms.svg', 'wp-admin/images/about-header-contribute.svg', 'wp-admin/images/about-header-background.svg', // 6.6 'wp-includes/blocks/block/editor.css', 'wp-includes/blocks/block/editor.min.css', 'wp-includes/blocks/block/editor-rtl.css', 'wp-includes/blocks/block/editor-rtl.min.css', /* * 6.7 * * WordPress 6.7 included a SimplePie upgrade that included a major * refactoring of the file structure and library. The old files are * split in to two sections to account for this: files and directories. * * See https://core.trac.wordpress.org/changeset/59141 */ // 6.7 - files 'wp-includes/js/dist/interactivity-router.asset.php', 'wp-includes/js/dist/interactivity-router.js', 'wp-includes/js/dist/interactivity-router.min.js', 'wp-includes/js/dist/interactivity-router.min.asset.php', 'wp-includes/js/dist/interactivity.js', 'wp-includes/js/dist/interactivity.min.js', 'wp-includes/js/dist/vendor/react-dom.min.js.LICENSE.txt', 'wp-includes/js/dist/vendor/react.min.js.LICENSE.txt', 'wp-includes/js/dist/vendor/wp-polyfill-importmap.js', 'wp-includes/js/dist/vendor/wp-polyfill-importmap.min.js', 'wp-includes/sodium_compat/src/Core/Base64/Common.php', 'wp-includes/SimplePie/Author.php', 'wp-includes/SimplePie/Cache.php', 'wp-includes/SimplePie/Caption.php', 'wp-includes/SimplePie/Category.php', 'wp-includes/SimplePie/Copyright.php', 'wp-includes/SimplePie/Core.php', 'wp-includes/SimplePie/Credit.php', 'wp-includes/SimplePie/Enclosure.php', 'wp-includes/SimplePie/Exception.php', 'wp-includes/SimplePie/File.php', 'wp-includes/SimplePie/gzdecode.php', 'wp-includes/SimplePie/IRI.php', 'wp-includes/SimplePie/Item.php', 'wp-includes/SimplePie/Locator.php', 'wp-includes/SimplePie/Misc.php', 'wp-includes/SimplePie/Parser.php', 'wp-includes/SimplePie/Rating.php', 'wp-includes/SimplePie/Registry.php', 'wp-includes/SimplePie/Restriction.php', 'wp-includes/SimplePie/Sanitize.php', 'wp-includes/SimplePie/Source.php', // 6.7 - directories 'wp-includes/SimplePie/Cache/', 'wp-includes/SimplePie/Content/', 'wp-includes/SimplePie/Decode/', 'wp-includes/SimplePie/HTTP/', 'wp-includes/SimplePie/Net/', 'wp-includes/SimplePie/Parse/', 'wp-includes/SimplePie/XML/', // 6.8 'wp-includes/blocks/post-content/editor.css', 'wp-includes/blocks/post-content/editor.min.css', 'wp-includes/blocks/post-content/editor-rtl.css', 'wp-includes/blocks/post-content/editor-rtl.min.css', 'wp-includes/blocks/post-template/editor.css', 'wp-includes/blocks/post-template/editor.min.css', 'wp-includes/blocks/post-template/editor-rtl.css', 'wp-includes/blocks/post-template/editor-rtl.min.css', 'wp-includes/js/dist/fields.min.js', 'wp-includes/js/dist/fields.js', // 6.9 'wp-includes/SimplePie/src/Decode', 'wp-includes/SimplePie/src/Core.php', // 7.0 'wp-includes/assets/script-loader-packages.min.php', 'wp-includes/assets/script-loader-react-refresh-entry.php', 'wp-includes/assets/script-loader-react-refresh-entry.min.php', 'wp-includes/assets/script-loader-react-refresh-runtime.php', 'wp-includes/assets/script-loader-react-refresh-runtime.min.php', 'wp-includes/assets/script-modules-packages.min.php', 'wp-includes/blocks/archives/editor.css', 'wp-includes/blocks/archives/editor.min.css', 'wp-includes/blocks/archives/editor-rtl.css', 'wp-includes/blocks/archives/editor-rtl.min.css', 'wp-includes/blocks/file/view.asset.php', 'wp-includes/blocks/file/view.min.asset.php', 'wp-includes/blocks/file/view.js', 'wp-includes/blocks/file/view.min.js', 'wp-includes/blocks/image/view.asset.php', 'wp-includes/blocks/image/view.min.asset.php', 'wp-includes/blocks/image/view.js', 'wp-includes/blocks/image/view.min.js', 'wp-includes/blocks/navigation/view.asset.php', 'wp-includes/blocks/navigation/view.min.asset.php', 'wp-includes/blocks/navigation/view.js', 'wp-includes/blocks/navigation/view.min.js', 'wp-includes/blocks/navigation/view-modal.asset.php', 'wp-includes/blocks/navigation/view-modal.min.asset.php', 'wp-includes/blocks/query/view.asset.php', 'wp-includes/blocks/query/view.min.asset.php', 'wp-includes/blocks/query/view.js', 'wp-includes/blocks/query/view.min.js', 'wp-includes/blocks/search/view.asset.php', 'wp-includes/blocks/search/view.min.asset.php', 'wp-includes/blocks/search/view.js', 'wp-includes/blocks/search/view.min.js', 'wp-includes/blocks/tag-cloud/editor.css', 'wp-includes/blocks/tag-cloud/editor.min.css', 'wp-includes/blocks/tag-cloud/editor-rtl.css', 'wp-includes/blocks/tag-cloud/editor-rtl.min.css', 'wp-includes/css/dist/admin-ui/style.css', 'wp-includes/css/dist/admin-ui/style.min.css', 'wp-includes/css/dist/admin-ui/style-rtl.css', 'wp-includes/css/dist/admin-ui/style-rtl.min.css', 'wp-includes/css/dist/admin-ui/', 'wp-includes/css/dist/edit-site/posts.css', 'wp-includes/css/dist/edit-site/posts.min.css', 'wp-includes/css/dist/edit-site/posts-rtl.css', 'wp-includes/css/dist/edit-site/posts-rtl.min.css', 'wp-includes/js/dist/admin-ui.js', 'wp-includes/js/dist/admin-ui.min.js', 'wp-includes/js/dist/latex-to-mathml.js', 'wp-includes/js/dist/latex-to-mathml.min.js', 'wp-includes/js/dist/views.js', 'wp-includes/js/dist/views.min.js', 'wp-includes/js/dist/script-modules/interactivity/debug.js', 'wp-includes/js/dist/script-modules/interactivity/debug.min.js', 'wp-includes/js/dist/vendor/react-jsx-runtime.min.js.LICENSE.txt', // 7.0.2 'wp-includes/collaboration', 'wp-includes/collaboration.php', 'wp-includes/js/dist/sync.js', 'wp-includes/js/dist/sync.min.js', ); /** * Stores Requests files to be preloaded and deleted. * * For classes/interfaces, use the class/interface name * as the array key. * * All other files/directories should not have a key. * * @since 6.2.0 * * @global string[] $_old_requests_files * @var string[] * @name $_old_requests_files */ global $_old_requests_files; $_old_requests_files = array( // Interfaces. 'Requests_Auth' => 'wp-includes/Requests/Auth.php', 'Requests_Hooker' => 'wp-includes/Requests/Hooker.php', 'Requests_Proxy' => 'wp-includes/Requests/Proxy.php', 'Requests_Transport' => 'wp-includes/Requests/Transport.php', // Classes. 'Requests_Auth_Basic' => 'wp-includes/Requests/Auth/Basic.php', 'Requests_Cookie_Jar' => 'wp-includes/Requests/Cookie/Jar.php', 'Requests_Exception_HTTP' => 'wp-includes/Requests/Exception/HTTP.php', 'Requests_Exception_Transport' => 'wp-includes/Requests/Exception/Transport.php', 'Requests_Exception_HTTP_304' => 'wp-includes/Requests/Exception/HTTP/304.php', 'Requests_Exception_HTTP_305' => 'wp-includes/Requests/Exception/HTTP/305.php', 'Requests_Exception_HTTP_306' => 'wp-includes/Requests/Exception/HTTP/306.php', 'Requests_Exception_HTTP_400' => 'wp-includes/Requests/Exception/HTTP/400.php', 'Requests_Exception_HTTP_401' => 'wp-includes/Requests/Exception/HTTP/401.php', 'Requests_Exception_HTTP_402' => 'wp-includes/Requests/Exception/HTTP/402.php', 'Requests_Exception_HTTP_403' => 'wp-includes/Requests/Exception/HTTP/403.php', 'Requests_Exception_HTTP_404' => 'wp-includes/Requests/Exception/HTTP/404.php', 'Requests_Exception_HTTP_405' => 'wp-includes/Requests/Exception/HTTP/405.php', 'Requests_Exception_HTTP_406' => 'wp-includes/Requests/Exception/HTTP/406.php', 'Requests_Exception_HTTP_407' => 'wp-includes/Requests/Exception/HTTP/407.php', 'Requests_Exception_HTTP_408' => 'wp-includes/Requests/Exception/HTTP/408.php', 'Requests_Exception_HTTP_409' => 'wp-includes/Requests/Exception/HTTP/409.php', 'Requests_Exception_HTTP_410' => 'wp-includes/Requests/Exception/HTTP/410.php', 'Requests_Exception_HTTP_411' => 'wp-includes/Requests/Exception/HTTP/411.php', 'Requests_Exception_HTTP_412' => 'wp-includes/Requests/Exception/HTTP/412.php', 'Requests_Exception_HTTP_413' => 'wp-includes/Requests/Exception/HTTP/413.php', 'Requests_Exception_HTTP_414' => 'wp-includes/Requests/Exception/HTTP/414.php', 'Requests_Exception_HTTP_415' => 'wp-includes/Requests/Exception/HTTP/415.php', 'Requests_Exception_HTTP_416' => 'wp-includes/Requests/Exception/HTTP/416.php', 'Requests_Exception_HTTP_417' => 'wp-includes/Requests/Exception/HTTP/417.php', 'Requests_Exception_HTTP_418' => 'wp-includes/Requests/Exception/HTTP/418.php', 'Requests_Exception_HTTP_428' => 'wp-includes/Requests/Exception/HTTP/428.php', 'Requests_Exception_HTTP_429' => 'wp-includes/Requests/Exception/HTTP/429.php', 'Requests_Exception_HTTP_431' => 'wp-includes/Requests/Exception/HTTP/431.php', 'Requests_Exception_HTTP_500' => 'wp-includes/Requests/Exception/HTTP/500.php', 'Requests_Exception_HTTP_501' => 'wp-includes/Requests/Exception/HTTP/501.php', 'Requests_Exception_HTTP_502' => 'wp-includes/Requests/Exception/HTTP/502.php', 'Requests_Exception_HTTP_503' => 'wp-includes/Requests/Exception/HTTP/503.php', 'Requests_Exception_HTTP_504' => 'wp-includes/Requests/Exception/HTTP/504.php', 'Requests_Exception_HTTP_505' => 'wp-includes/Requests/Exception/HTTP/505.php', 'Requests_Exception_HTTP_511' => 'wp-includes/Requests/Exception/HTTP/511.php', 'Requests_Exception_HTTP_Unknown' => 'wp-includes/Requests/Exception/HTTP/Unknown.php', 'Requests_Exception_Transport_cURL' => 'wp-includes/Requests/Exception/Transport/cURL.php', 'Requests_Proxy_HTTP' => 'wp-includes/Requests/Proxy/HTTP.php', 'Requests_Response_Headers' => 'wp-includes/Requests/Response/Headers.php', 'Requests_Transport_cURL' => 'wp-includes/Requests/Transport/cURL.php', 'Requests_Transport_fsockopen' => 'wp-includes/Requests/Transport/fsockopen.php', 'Requests_Utility_CaseInsensitiveDictionary' => 'wp-includes/Requests/Utility/CaseInsensitiveDictionary.php', 'Requests_Utility_FilteredIterator' => 'wp-includes/Requests/Utility/FilteredIterator.php', 'Requests_Cookie' => 'wp-includes/Requests/Cookie.php', 'Requests_Exception' => 'wp-includes/Requests/Exception.php', 'Requests_Hooks' => 'wp-includes/Requests/Hooks.php', 'Requests_IDNAEncoder' => 'wp-includes/Requests/IDNAEncoder.php', 'Requests_IPv6' => 'wp-includes/Requests/IPv6.php', 'Requests_IRI' => 'wp-includes/Requests/IRI.php', 'Requests_Response' => 'wp-includes/Requests/Response.php', 'Requests_SSL' => 'wp-includes/Requests/SSL.php', 'Requests_Session' => 'wp-includes/Requests/Session.php', // Directories. 'wp-includes/Requests/Auth/', 'wp-includes/Requests/Cookie/', 'wp-includes/Requests/Exception/HTTP/', 'wp-includes/Requests/Exception/Transport/', 'wp-includes/Requests/Exception/', 'wp-includes/Requests/Proxy/', 'wp-includes/Requests/Response/', 'wp-includes/Requests/Transport/', 'wp-includes/Requests/Utility/', ); /** * Stores new files in wp-content to copy * * The contents of this array indicate any new bundled plugins/themes which * should be installed with the WordPress Upgrade. These items will not be * re-installed in future upgrades, this behavior is controlled by the * introduced version present here being older than the current installed version. * * The content of this array should follow the following format: * Filename (relative to wp-content) => Introduced version * Directories should be noted by suffixing it with a trailing slash (/) * * @since 3.2.0 * @since 4.7.0 New themes were not automatically installed for 4.4-4.6 on * upgrade. New themes are now installed again. To disable new * themes from being installed on upgrade, explicitly define * CORE_UPGRADE_SKIP_NEW_BUNDLED as true. * @global string[] $_new_bundled_files * @var string[] * @name $_new_bundled_files */ global $_new_bundled_files; $_new_bundled_files = array( 'plugins/akismet/' => '2.0', 'themes/twentyten/' => '3.0', 'themes/twentyeleven/' => '3.2', 'themes/twentytwelve/' => '3.5', 'themes/twentythirteen/' => '3.6', 'themes/twentyfourteen/' => '3.8', 'themes/twentyfifteen/' => '4.1', 'themes/twentysixteen/' => '4.4', 'themes/twentyseventeen/' => '4.7', 'themes/twentynineteen/' => '5.0', 'themes/twentytwenty/' => '5.3', 'themes/twentytwentyone/' => '5.6', 'themes/twentytwentytwo/' => '5.9', 'themes/twentytwentythree/' => '6.1', 'themes/twentytwentyfour/' => '6.4', 'themes/twentytwentyfive/' => '6.7', ); /** * Upgrades the core of WordPress. * * This will create a .maintenance file at the base of the WordPress directory * to ensure that people can not access the website, when the files are being * copied to their locations. * * The files in the `$_old_files` list will be removed and the new files * copied from the zip file after the database is upgraded. * * The files in the `$_new_bundled_files` list will be added to the installation * if the version is greater than or equal to the old version being upgraded. * * The steps for the upgrader for after the new release is downloaded and * unzipped is: * * 1. Test unzipped location for select files to ensure that unzipped worked. * 2. Create the .maintenance file in current WordPress base. * 3. Copy new WordPress directory over old WordPress files. * 4. Upgrade WordPress to new version. * 1. Copy all files/folders other than wp-content * 2. Copy any language files to `WP_LANG_DIR` (which may differ from `WP_CONTENT_DIR` * 3. Copy any new bundled themes/plugins to their respective locations * 5. Delete new WordPress directory path. * 6. Delete .maintenance file. * 7. Remove old files. * 8. Delete 'update_core' option. * * There are several areas of failure. For instance if PHP times out before step * 6, then you will not be able to access any portion of your site. Also, since * the upgrade will not continue where it left off, you will not be able to * automatically remove old files and remove the 'update_core' option. This * isn't that bad. * * If the copy of the new WordPress over the old fails, then the worse is that * the new WordPress directory will remain. * * If it is assumed that every file will be copied over, including plugins and * themes, then if you edit the default theme, you should rename it, so that * your changes remain. * * @since 2.7.0 * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * @global string[] $_old_files * @global string[] $_old_requests_files * @global string[] $_new_bundled_files * @global wpdb $wpdb WordPress database abstraction object. * @global string $wp_version The WordPress version string. * * @param string $from New release unzipped path. * @param string $to Path to old WordPress installation. * @return string|WP_Error New WordPress version on success, WP_Error on failure. */ function update_core( $from, $to ) { global $wp_filesystem, $_old_files, $_old_requests_files, $_new_bundled_files, $wpdb; /* * Give core update script an additional 300 seconds (5 minutes) * to finish updating large files when running on slower servers. */ if ( function_exists( 'set_time_limit' ) ) { set_time_limit( 300 ); } /* * Merge the old Requests files and directories into the `$_old_files`. * Then preload these Requests files first, before the files are deleted * and replaced to ensure the code is in memory if needed. */ $_old_files = array_merge( $_old_files, array_values( $_old_requests_files ) ); _preload_old_requests_classes_and_interfaces( $to ); /** * Filters feedback messages displayed during the core update process. * * The filter is first evaluated after the zip file for the latest version * has been downloaded and unzipped. It is evaluated five more times during * the process: * * 1. Before WordPress begins the core upgrade process. * 2. Before Maintenance Mode is enabled. * 3. Before WordPress begins copying over the necessary files. * 4. Before Maintenance Mode is disabled. * 5. Before the database is upgraded. * * @since 2.5.0 * * @param string $feedback The core update feedback messages. */ apply_filters( 'update_feedback', __( 'Verifying the unpacked files…' ) ); // Confidence check the unzipped distribution. $distro = ''; $roots = array( '/wordpress/', '/wordpress-mu/' ); foreach ( $roots as $root ) { if ( $wp_filesystem->exists( $from . $root . 'readme.html' ) && $wp_filesystem->exists( $from . $root . 'wp-includes/version.php' ) ) { $distro = $root; break; } } if ( ! $distro ) { $wp_filesystem->delete( $from, true ); return new WP_Error( 'insane_distro', __( 'The update could not be unpacked' ) ); } /* * Import $wp_version, $required_php_version, $required_php_extensions, and $required_mysql_version from the new version. * DO NOT globalize any variables imported from `version-current.php` in this function. * * BC Note: $wp_filesystem->wp_content_dir() returned unslashed pre-2.8. */ $versions_file = trailingslashit( $wp_filesystem->wp_content_dir() ) . 'upgrade/version-current.php'; if ( ! $wp_filesystem->copy( $from . $distro . 'wp-includes/version.php', $versions_file ) ) { $wp_filesystem->delete( $from, true ); return new WP_Error( 'copy_failed_for_version_file', __( 'The update cannot be installed because some files could not be copied. This is usually due to inconsistent file permissions.' ), 'wp-includes/version.php' ); } $wp_filesystem->chmod( $versions_file, FS_CHMOD_FILE ); /* * `wp_opcache_invalidate()` only exists in WordPress 5.5 or later, * so don't run it when upgrading from older versions. */ if ( function_exists( 'wp_opcache_invalidate' ) ) { wp_opcache_invalidate( $versions_file ); } require WP_CONTENT_DIR . '/upgrade/version-current.php'; $wp_filesystem->delete( $versions_file ); $php_version = PHP_VERSION; $mysql_version = $wpdb->db_version(); $old_wp_version = $GLOBALS['wp_version']; // The version of WordPress we're updating from. /* * Note: str_contains() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ $development_build = ( false !== strpos( $old_wp_version . $wp_version, '-' ) ); // A dash in the version indicates a development release. $php_compat = version_compare( $php_version, $required_php_version, '>=' ); if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) ) { $mysql_compat = true; } else { $mysql_compat = version_compare( $mysql_version, $required_mysql_version, '>=' ); } if ( ! $mysql_compat || ! $php_compat ) { $wp_filesystem->delete( $from, true ); } $php_update_message = ''; if ( function_exists( 'wp_get_update_php_url' ) ) { $php_update_message = '</p><p>' . sprintf( /* translators: %s: URL to Update PHP page. */ __( '<a href="%s">Learn more about updating PHP</a>.' ), esc_url( wp_get_update_php_url() ) ); if ( function_exists( 'wp_get_update_php_annotation' ) ) { $annotation = wp_get_update_php_annotation(); if ( $annotation ) { $php_update_message .= '</p><p><em>' . $annotation . '</em>'; } } } if ( ! $mysql_compat && ! $php_compat ) { return new WP_Error( 'php_mysql_not_compatible', sprintf( /* translators: 1: WordPress version number, 2: Minimum required PHP version number, 3: Minimum required MySQL version number, 4: Current PHP version number, 5: Current MySQL version number. */ __( 'The update cannot be installed because WordPress %1$s requires PHP version %2$s or higher and MySQL version %3$s or higher. You are running PHP version %4$s and MySQL version %5$s.' ), $wp_version, $required_php_version, $required_mysql_version, $php_version, $mysql_version ) . $php_update_message ); } elseif ( ! $php_compat ) { return new WP_Error( 'php_not_compatible', sprintf( /* translators: 1: WordPress version number, 2: Minimum required PHP version number, 3: Current PHP version number. */ __( 'The update cannot be installed because WordPress %1$s requires PHP version %2$s or higher. You are running version %3$s.' ), $wp_version, $required_php_version, $php_version ) . $php_update_message ); } elseif ( ! $mysql_compat ) { return new WP_Error( 'mysql_not_compatible', sprintf( /* translators: 1: WordPress version number, 2: Minimum required MySQL version number, 3: Current MySQL version number. */ __( 'The update cannot be installed because WordPress %1$s requires MySQL version %2$s or higher. You are running version %3$s.' ), $wp_version, $required_mysql_version, $mysql_version ) ); } if ( isset( $required_php_extensions ) && is_array( $required_php_extensions ) ) { $missing_extensions = new WP_Error(); foreach ( $required_php_extensions as $extension ) { if ( extension_loaded( $extension ) ) { continue; } $missing_extensions->add( "php_not_compatible_{$extension}", sprintf( /* translators: 1: WordPress version number, 2: The PHP extension name needed. */ __( 'The update cannot be installed because WordPress %1$s requires the %2$s PHP extension.' ), $wp_version, $extension ) ); } // Add a warning when required PHP extensions are missing. if ( ! empty( $missing_extensions->errors ) ) { return $missing_extensions; } } /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', __( 'Preparing to install the latest version…' ) ); /* * Don't copy wp-content, we'll deal with that below. * We also copy version.php last so failed updates report their old version. */ $skip = array( 'wp-content', 'wp-includes/version.php' ); $check_is_writable = array(); // Check to see which files don't really need updating - only available for 3.7 and higher. if ( function_exists( 'get_core_checksums' ) ) { // Find the local version of the working directory. $working_dir_local = WP_CONTENT_DIR . '/upgrade/' . basename( $from ) . $distro; $checksums = get_core_checksums( $wp_version, $wp_local_package ?? 'en_US' ); if ( is_array( $checksums ) && isset( $checksums[ $wp_version ] ) ) { $checksums = $checksums[ $wp_version ]; // Compat code for 3.7-beta2. } if ( is_array( $checksums ) ) { foreach ( $checksums as $file => $checksum ) { /* * Note: str_starts_with() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ if ( 'wp-content' === substr( $file, 0, 10 ) ) { continue; } if ( ! file_exists( ABSPATH . $file ) ) { continue; } if ( ! file_exists( $working_dir_local . $file ) ) { continue; } if ( '.' === dirname( $file ) && in_array( pathinfo( $file, PATHINFO_EXTENSION ), array( 'html', 'txt' ), true ) ) { continue; } if ( md5_file( ABSPATH . $file ) === $checksum ) { $skip[] = $file; } else { $check_is_writable[ $file ] = ABSPATH . $file; } } } } // If we're using the direct method, we can predict write failures that are due to permissions. if ( $check_is_writable && 'direct' === $wp_filesystem->method ) { $files_writable = array_filter( $check_is_writable, array( $wp_filesystem, 'is_writable' ) ); if ( $files_writable !== $check_is_writable ) { $files_not_writable = array_diff_key( $check_is_writable, $files_writable ); foreach ( $files_not_writable as $relative_file_not_writable => $file_not_writable ) { // If the writable check failed, chmod file to 0644 and try again, same as copy_dir(). $wp_filesystem->chmod( $file_not_writable, FS_CHMOD_FILE ); if ( $wp_filesystem->is_writable( $file_not_writable ) ) { unset( $files_not_writable[ $relative_file_not_writable ] ); } } // Store package-relative paths (the key) of non-writable files in the WP_Error object. $error_data = version_compare( $old_wp_version, '3.7-beta2', '>' ) ? array_keys( $files_not_writable ) : ''; if ( $files_not_writable ) { return new WP_Error( 'files_not_writable', __( 'The update cannot be installed because your site is unable to copy some files. This is usually due to inconsistent file permissions.' ), implode( ', ', $error_data ) ); } } } /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', __( 'Enabling Maintenance mode…' ) ); // Create maintenance file to signal that we are upgrading. $maintenance_string = '<?php $upgrading = ' . time() . '; ?>'; $maintenance_file = $to . '.maintenance'; $wp_filesystem->delete( $maintenance_file ); $wp_filesystem->put_contents( $maintenance_file, $maintenance_string, FS_CHMOD_FILE ); /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', __( 'Copying the required files…' ) ); // Copy new versions of WP files into place. $result = copy_dir( $from . $distro, $to, $skip ); if ( is_wp_error( $result ) ) { $result = new WP_Error( $result->get_error_code(), $result->get_error_message(), substr( $result->get_error_data(), strlen( $to ) ) ); } // Since we know the core files have copied over, we can now copy the version file. if ( ! is_wp_error( $result ) ) { if ( ! $wp_filesystem->copy( $from . $distro . 'wp-includes/version.php', $to . 'wp-includes/version.php', true /* overwrite */ ) ) { $wp_filesystem->delete( $from, true ); $result = new WP_Error( 'copy_failed_for_version_file', __( 'The update cannot be installed because your site is unable to copy some files. This is usually due to inconsistent file permissions.' ), 'wp-includes/version.php' ); } $wp_filesystem->chmod( $to . 'wp-includes/version.php', FS_CHMOD_FILE ); /* * `wp_opcache_invalidate()` only exists in WordPress 5.5 or later, * so don't run it when upgrading from older versions. */ if ( function_exists( 'wp_opcache_invalidate' ) ) { wp_opcache_invalidate( $to . 'wp-includes/version.php' ); } } // Check to make sure everything copied correctly, ignoring the contents of wp-content. $skip = array( 'wp-content' ); $failed = array(); if ( isset( $checksums ) && is_array( $checksums ) ) { foreach ( $checksums as $file => $checksum ) { /* * Note: str_starts_with() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ if ( 'wp-content' === substr( $file, 0, 10 ) ) { continue; } if ( ! file_exists( $working_dir_local . $file ) ) { continue; } if ( '.' === dirname( $file ) && in_array( pathinfo( $file, PATHINFO_EXTENSION ), array( 'html', 'txt' ), true ) ) { $skip[] = $file; continue; } if ( file_exists( ABSPATH . $file ) && md5_file( ABSPATH . $file ) === $checksum ) { $skip[] = $file; } else { $failed[] = $file; } } } // Some files didn't copy properly. if ( ! empty( $failed ) ) { $total_size = 0; foreach ( $failed as $file ) { if ( file_exists( $working_dir_local . $file ) ) { $total_size += filesize( $working_dir_local . $file ); } } /* * If we don't have enough free space, it isn't worth trying again. * Unlikely to be hit due to the check in unzip_file(). */ $available_space = function_exists( 'disk_free_space' ) ? @disk_free_space( ABSPATH ) : false; if ( $available_space && $total_size >= $available_space ) { $result = new WP_Error( 'disk_full', __( 'There is not enough free disk space to complete the update.' ) ); } else { $result = copy_dir( $from . $distro, $to, $skip ); if ( is_wp_error( $result ) ) { $result = new WP_Error( $result->get_error_code() . '_retry', $result->get_error_message(), substr( $result->get_error_data(), strlen( $to ) ) ); } } } /* * Custom content directory needs updating now. * Copy languages. */ if ( ! is_wp_error( $result ) && $wp_filesystem->is_dir( $from . $distro . 'wp-content/languages' ) ) { if ( WP_LANG_DIR !== ABSPATH . WPINC . '/languages' || @is_dir( WP_LANG_DIR ) ) { $lang_dir = WP_LANG_DIR; } else { $lang_dir = WP_CONTENT_DIR . '/languages'; } /* * Note: str_starts_with() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ // Check if the language directory exists first. if ( ! @is_dir( $lang_dir ) && 0 === strpos( $lang_dir, ABSPATH ) ) { // If it's within the ABSPATH we can handle it here, otherwise they're out of luck. $wp_filesystem->mkdir( $to . str_replace( ABSPATH, '', $lang_dir ), FS_CHMOD_DIR ); clearstatcache(); // For FTP, need to clear the stat cache. } if ( @is_dir( $lang_dir ) ) { $wp_lang_dir = $wp_filesystem->find_folder( $lang_dir ); if ( $wp_lang_dir ) { $result = copy_dir( $from . $distro . 'wp-content/languages/', $wp_lang_dir ); if ( is_wp_error( $result ) ) { $result = new WP_Error( $result->get_error_code() . '_languages', $result->get_error_message(), substr( $result->get_error_data(), strlen( $wp_lang_dir ) ) ); } } } } /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', __( 'Disabling Maintenance mode…' ) ); // Remove maintenance file, we're done with potential site-breaking changes. $wp_filesystem->delete( $maintenance_file ); /* * 3.5 -> 3.5+ - an empty twentytwelve directory was created upon upgrade to 3.5 for some users, * preventing installation of Twenty Twelve. */ if ( '3.5' === $old_wp_version ) { if ( is_dir( WP_CONTENT_DIR . '/themes/twentytwelve' ) && ! file_exists( WP_CONTENT_DIR . '/themes/twentytwelve/style.css' ) ) { $wp_filesystem->delete( $wp_filesystem->wp_themes_dir() . 'twentytwelve/' ); } } /* * Copy new bundled plugins & themes. * This gives us the ability to install new plugins & themes bundled with * future versions of WordPress whilst avoiding the re-install upon upgrade issue. * $development_build controls us overwriting bundled themes and plugins when a non-stable release is being updated. */ if ( ! is_wp_error( $result ) && ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) ) { foreach ( (array) $_new_bundled_files as $file => $introduced_version ) { // If a $development_build or if $introduced version is greater than what the site was previously running. if ( $development_build || version_compare( $introduced_version, $old_wp_version, '>' ) ) { $directory = ( '/' === $file[ strlen( $file ) - 1 ] ); list( $type, $filename ) = explode( '/', $file, 2 ); // Check to see if the bundled items exist before attempting to copy them. if ( ! $wp_filesystem->exists( $from . $distro . 'wp-content/' . $file ) ) { continue; } if ( 'plugins' === $type ) { $dest = $wp_filesystem->wp_plugins_dir(); } elseif ( 'themes' === $type ) { // Back-compat, ::wp_themes_dir() did not return trailingslash'd pre-3.2. $dest = trailingslashit( $wp_filesystem->wp_themes_dir() ); } else { continue; } if ( ! $directory ) { if ( ! $development_build && $wp_filesystem->exists( $dest . $filename ) ) { continue; } if ( ! $wp_filesystem->copy( $from . $distro . 'wp-content/' . $file, $dest . $filename, FS_CHMOD_FILE ) ) { $result = new WP_Error( "copy_failed_for_new_bundled_$type", __( 'Could not copy file.' ), $dest . $filename ); } } else { if ( ! $development_build && $wp_filesystem->is_dir( $dest . $filename ) ) { continue; } $wp_filesystem->mkdir( $dest . $filename, FS_CHMOD_DIR ); $_result = copy_dir( $from . $distro . 'wp-content/' . $file, $dest . $filename ); /* * If an error occurs partway through this final step, * keep the error flowing through, but keep the process going. */ if ( is_wp_error( $_result ) ) { if ( ! is_wp_error( $result ) ) { $result = new WP_Error(); } $result->add( $_result->get_error_code() . "_$type", $_result->get_error_message(), substr( $_result->get_error_data(), strlen( $dest ) ) ); } } } } // End foreach. } // Handle $result error from the above blocks. if ( is_wp_error( $result ) ) { $wp_filesystem->delete( $from, true ); return $result; } // Remove old files. foreach ( $_old_files as $old_file ) { $old_file = $to . $old_file; if ( ! $wp_filesystem->exists( $old_file ) ) { continue; } // If the file isn't deleted, try writing an empty string to the file instead. if ( ! $wp_filesystem->delete( $old_file, true ) && $wp_filesystem->is_file( $old_file ) ) { $wp_filesystem->put_contents( $old_file, '' ); } } // Remove any Genericons example.html's from the filesystem. _upgrade_422_remove_genericons(); // Deactivate the REST API plugin if its version is 2.0 Beta 4 or lower. _upgrade_440_force_deactivate_incompatible_plugins(); // Deactivate incompatible plugins. _upgrade_core_deactivate_incompatible_plugins(); // Upgrade DB with separate request. /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', __( 'Upgrading database…' ) ); $db_upgrade_url = admin_url( 'upgrade.php?step=upgrade_db' ); wp_remote_post( $db_upgrade_url, array( 'timeout' => 60 ) ); // Clear the cache to prevent an update_option() from saving a stale db_version to the cache. wp_cache_flush(); // Not all cache back ends listen to 'flush'. wp_cache_delete( 'alloptions', 'options' ); // Remove working directory. $wp_filesystem->delete( $from, true ); // Force refresh of update information. if ( function_exists( 'delete_site_transient' ) ) { delete_site_transient( 'update_core' ); } else { delete_option( 'update_core' ); } /** * Fires after WordPress core has been successfully updated. * * @since 3.3.0 * * @param string $wp_version The current WordPress version. */ do_action( '_core_updated_successfully', $wp_version ); // Clear the option that blocks auto-updates after failures, now that we've been successful. if ( function_exists( 'delete_site_option' ) ) { delete_site_option( 'auto_core_update_failed' ); } return $wp_version; } /** * Preloads old Requests classes and interfaces. * * This function preloads the old Requests code into memory before the * upgrade process deletes the files. Why? Requests code is loaded into * memory via an autoloader, meaning when a class or interface is needed * If a request is in process, Requests could attempt to access code. If * the file is not there, a fatal error could occur. If the file was * replaced, the new code is not compatible with the old, resulting in * a fatal error. Preloading ensures the code is in memory before the * code is updated. * * @since 6.2.0 * * @global string[] $_old_requests_files Requests files to be preloaded. * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * @global string $wp_version The WordPress version string. * * @param string $to Path to old WordPress installation. */ function _preload_old_requests_classes_and_interfaces( $to ) { global $_old_requests_files, $wp_filesystem, $wp_version; /* * Requests was introduced in WordPress 4.6. * * Skip preloading if the website was previously using * an earlier version of WordPress. */ if ( version_compare( $wp_version, '4.6', '<' ) ) { return; } if ( ! defined( 'REQUESTS_SILENCE_PSR0_DEPRECATIONS' ) ) { define( 'REQUESTS_SILENCE_PSR0_DEPRECATIONS', true ); } foreach ( $_old_requests_files as $name => $file ) { // Skip files that aren't interfaces or classes. if ( is_int( $name ) ) { continue; } // Skip if it's already loaded. if ( class_exists( $name ) || interface_exists( $name ) ) { continue; } // Skip if the file is missing. if ( ! $wp_filesystem->is_file( $to . $file ) ) { continue; } require_once $to . $file; } } /** * Redirect to the About WordPress page after a successful upgrade. * * This function is only needed when the existing installation is older than 3.4.0. * * @since 3.3.0 * * @global string $wp_version The WordPress version string. * @global string $pagenow The filename of the current screen. * @global string $action * * @param string $new_version */ function _redirect_to_about_wordpress( $new_version ) { global $wp_version, $pagenow, $action; if ( version_compare( $wp_version, '3.4-RC1', '>=' ) ) { return; } // Ensure we only run this on the update-core.php page. The Core_Upgrader may be used in other contexts. if ( 'update-core.php' !== $pagenow ) { return; } if ( 'do-core-upgrade' !== $action && 'do-core-reinstall' !== $action ) { return; } // Load the updated default text localization domain for new strings. load_default_textdomain(); // See do_core_upgrade(). show_message( __( 'WordPress updated successfully.' ) ); // self_admin_url() won't exist when upgrading from <= 3.0, so relative URLs are intentional. show_message( '<span class="hide-if-no-js">' . sprintf( /* translators: 1: WordPress version, 2: URL to About screen. */ __( 'Welcome to WordPress %1$s. You will be redirected to the About WordPress screen. If not, click <a href="%2$s">here</a>.' ), $new_version, 'about.php?updated' ) . '</span>' ); show_message( '<span class="hide-if-js">' . sprintf( /* translators: 1: WordPress version, 2: URL to About screen. */ __( 'Welcome to WordPress %1$s. <a href="%2$s">Learn more</a>.' ), $new_version, 'about.php?updated' ) . '</span>' ); echo '</div>'; ?> <script> window.location = 'about.php?updated'; </script> <?php // Include admin-footer.php and exit. require_once ABSPATH . 'wp-admin/admin-footer.php'; exit; } /** * Cleans up Genericons example files. * * @since 4.2.2 * * @global string[] $wp_theme_directories * @global WP_Filesystem_Base $wp_filesystem */ function _upgrade_422_remove_genericons() { global $wp_theme_directories, $wp_filesystem; // A list of the affected files using the filesystem absolute paths. $affected_files = array(); // Themes. foreach ( $wp_theme_directories as $directory ) { $affected_theme_files = _upgrade_422_find_genericons_files_in_folder( $directory ); $affected_files = array_merge( $affected_files, $affected_theme_files ); } // Plugins. $affected_plugin_files = _upgrade_422_find_genericons_files_in_folder( WP_PLUGIN_DIR ); $affected_files = array_merge( $affected_files, $affected_plugin_files ); foreach ( $affected_files as $file ) { $gen_dir = $wp_filesystem->find_folder( trailingslashit( dirname( $file ) ) ); if ( empty( $gen_dir ) ) { continue; } // The path when the file is accessed via WP_Filesystem may differ in the case of FTP. $remote_file = $gen_dir . basename( $file ); if ( ! $wp_filesystem->exists( $remote_file ) ) { continue; } if ( ! $wp_filesystem->delete( $remote_file, false, 'f' ) ) { $wp_filesystem->put_contents( $remote_file, '' ); } } } /** * Recursively find Genericons example files in a given folder. * * @ignore * @since 4.2.2 * * @param string $directory Directory path. Expects trailingslashed. * @return string[] */ function _upgrade_422_find_genericons_files_in_folder( $directory ) { $directory = trailingslashit( $directory ); $files = array(); if ( file_exists( "{$directory}example.html" ) /* * Note: str_contains() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ && false !== strpos( file_get_contents( "{$directory}example.html" ), '<title>Genericons</title>' ) ) { $files[] = "{$directory}example.html"; } $dirs = glob( $directory . '*', GLOB_ONLYDIR ); $dirs = array_filter( $dirs, static function ( $dir ) { /* * Skip any node_modules directories. * * Note: str_contains() is not used here, as this file is included * when updating from older WordPress versions, in which case * the polyfills from wp-includes/compat.php may not be available. */ return false === strpos( $dir, 'node_modules' ); } ); if ( $dirs ) { foreach ( $dirs as $dir ) { $files = array_merge( $files, _upgrade_422_find_genericons_files_in_folder( $dir ) ); } } return $files; } /** * @ignore * @since 4.4.0 */ function _upgrade_440_force_deactivate_incompatible_plugins() { if ( defined( 'REST_API_VERSION' ) && version_compare( REST_API_VERSION, '2.0-beta4', '<=' ) ) { deactivate_plugins( array( 'rest-api/plugin.php' ), true ); } } /** * @access private * @ignore * @since 5.8.0 * @since 5.9.0 The minimum compatible version of Gutenberg is 11.9. * @since 6.1.1 The minimum compatible version of Gutenberg is 14.1. * @since 6.4.0 The minimum compatible version of Gutenberg is 16.5. * @since 6.5.0 The minimum compatible version of Gutenberg is 17.6. */ function _upgrade_core_deactivate_incompatible_plugins() { if ( defined( 'GUTENBERG_VERSION' ) && version_compare( GUTENBERG_VERSION, '17.6', '<' ) ) { $deactivated_gutenberg['gutenberg'] = array( 'plugin_name' => 'Gutenberg', 'version_deactivated' => GUTENBERG_VERSION, 'version_compatible' => '17.6', ); if ( is_plugin_active_for_network( 'gutenberg/gutenberg.php' ) ) { $deactivated_plugins = get_site_option( 'wp_force_deactivated_plugins', array() ); $deactivated_plugins = array_merge( $deactivated_plugins, $deactivated_gutenberg ); update_site_option( 'wp_force_deactivated_plugins', $deactivated_plugins ); } else { $deactivated_plugins = get_option( 'wp_force_deactivated_plugins', array() ); $deactivated_plugins = array_merge( $deactivated_plugins, $deactivated_gutenberg ); update_option( 'wp_force_deactivated_plugins', $deactivated_plugins, false ); } deactivate_plugins( array( 'gutenberg/gutenberg.php' ), true ); } } PK $��\�� � � update.phpnu �[��� <?php /** * WordPress Administration Update API * * @package WordPress * @subpackage Administration */ /** * Selects the first update version from the update_core option. * * @since 2.7.0 * * @return object|array|false The response from the API on success, false on failure. */ function get_preferred_from_update_core() { $updates = get_core_updates(); if ( ! is_array( $updates ) ) { return false; } if ( empty( $updates ) ) { return (object) array( 'response' => 'latest' ); } return $updates[0]; } /** * Gets available core updates. * * @since 2.7.0 * * @param array $options Set $options['dismissed'] to true to show dismissed upgrades too, * set $options['available'] to false to skip not-dismissed updates. * @return array<object>|false Array of the update objects on success, false on failure. */ function get_core_updates( $options = array() ) { $options = array_merge( array( 'available' => true, 'dismissed' => false, ), $options ); $dismissed = get_site_option( 'dismissed_update_core' ); if ( ! is_array( $dismissed ) ) { $dismissed = array(); } $from_api = get_site_transient( 'update_core' ); if ( ! isset( $from_api->updates ) || ! is_array( $from_api->updates ) ) { return false; } $updates = $from_api->updates; $result = array(); foreach ( $updates as $update ) { if ( 'autoupdate' === $update->response ) { continue; } if ( array_key_exists( $update->current . '|' . $update->locale, $dismissed ) ) { if ( $options['dismissed'] ) { $update->dismissed = true; $result[] = $update; } } else { if ( $options['available'] ) { $update->dismissed = false; $result[] = $update; } } } return $result; } /** * Gets the best available (and enabled) Auto-Update for WordPress core. * * If there's 1.2.3 and 1.3 on offer, it'll choose 1.3 if the installation allows it, else, 1.2.3. * * @since 3.7.0 * * @return object|false The core update offering on success, false on failure. */ function find_core_auto_update() { $updates = get_site_transient( 'update_core' ); if ( ! $updates || empty( $updates->updates ) ) { return false; } require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; $auto_update = false; $upgrader = new WP_Automatic_Updater(); foreach ( $updates->updates as $update ) { if ( 'autoupdate' !== $update->response ) { continue; } if ( ! $upgrader->should_update( 'core', $update, ABSPATH ) ) { continue; } if ( ! $auto_update || version_compare( $update->current, $auto_update->current, '>' ) ) { $auto_update = $update; } } return $auto_update; } /** * Gets and caches the checksums for the given version of WordPress. * * @since 3.7.0 * * @param string $version Version string to query. * @param string $locale Locale to query. * @return array<string, string>|false An array of checksums on success, false on failure. */ function get_core_checksums( $version, $locale ) { $http_url = 'http://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), '', '&' ); $url = $http_url; $ssl = wp_http_supports( array( 'ssl' ) ); if ( $ssl ) { $url = set_url_scheme( $url, 'https' ); } $options = array( 'timeout' => wp_doing_cron() ? 30 : 3, ); $response = wp_remote_get( $url, $options ); if ( $ssl && is_wp_error( $response ) ) { wp_trigger_error( __FUNCTION__, sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), __( 'https://wordpress.org/support/forums/' ) ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE ); $response = wp_remote_get( $http_url, $options ); } if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { return false; } $body = trim( wp_remote_retrieve_body( $response ) ); $body = json_decode( $body, true ); if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) { return false; } return $body['checksums']; } /** * Dismisses core update. * * @since 2.7.0 * * @param object $update * @return bool True if the option was updated, false otherwise. */ function dismiss_core_update( $update ) { $dismissed = get_site_option( 'dismissed_update_core' ); $dismissed[ $update->current . '|' . $update->locale ] = true; return update_site_option( 'dismissed_update_core', $dismissed ); } /** * Undismisses core update. * * @since 2.7.0 * * @param string $version * @param string $locale * @return bool True if the option was updated, false otherwise. */ function undismiss_core_update( $version, $locale ) { $dismissed = get_site_option( 'dismissed_update_core' ); $key = $version . '|' . $locale; if ( ! isset( $dismissed[ $key ] ) ) { return false; } unset( $dismissed[ $key ] ); return update_site_option( 'dismissed_update_core', $dismissed ); } /** * Finds the available update for WordPress core. * * @since 2.7.0 * * @param string $version Version string to find the update for. * @param string $locale Locale to find the update for. * @return object|false The core update offering on success, false on failure. */ function find_core_update( $version, $locale ) { $from_api = get_site_transient( 'update_core' ); if ( ! isset( $from_api->updates ) || ! is_array( $from_api->updates ) ) { return false; } $updates = $from_api->updates; foreach ( $updates as $update ) { if ( $update->current === $version && $update->locale === $locale ) { return $update; } } return false; } /** * Returns core update footer message. * * @since 2.3.0 * * @param string $msg * @return string The core update footer message. */ function core_update_footer( $msg = '' ) { if ( ! current_user_can( 'update_core' ) ) { /* translators: %s: WordPress version. */ return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) ); } $cur = get_preferred_from_update_core(); if ( ! is_object( $cur ) ) { $cur = new stdClass(); } if ( ! isset( $cur->current ) ) { $cur->current = ''; } if ( ! isset( $cur->response ) ) { $cur->response = ''; } $is_development_version = preg_match( '/alpha|beta|RC/', wp_get_wp_version() ); if ( $is_development_version ) { return sprintf( /* translators: 1: WordPress version number, 2: URL to WordPress Updates screen. */ __( 'You are using a development version (%1$s). Cool! Please <a href="%2$s">stay updated</a>.' ), get_bloginfo( 'version', 'display' ), network_admin_url( 'update-core.php' ) ); } switch ( $cur->response ) { case 'upgrade': return sprintf( '<strong><a href="%s">%s</a></strong>', network_admin_url( 'update-core.php' ), /* translators: %s: WordPress version. */ sprintf( __( 'Get Version %s' ), $cur->current ) ); case 'latest': default: /* translators: %s: WordPress version. */ return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) ); } } /** * Returns core update notification message. * * @since 2.3.0 * * @global string $pagenow The filename of the current screen. * @return void|false Void on success, false if the update nag should not be displayed. */ function update_nag() { global $pagenow; if ( is_multisite() && ! current_user_can( 'update_core' ) ) { return false; } if ( 'update-core.php' === $pagenow ) { return; } $cur = get_preferred_from_update_core(); if ( ! isset( $cur->response ) || 'upgrade' !== $cur->response ) { return false; } $version_url = sprintf( /* translators: %s: WordPress version. */ esc_url( __( 'https://wordpress.org/documentation/wordpress-version/version-%s/' ) ), sanitize_title( $cur->current ) ); if ( current_user_can( 'update_core' ) ) { $msg = sprintf( /* translators: 1: URL to WordPress release notes, 2: New WordPress version, 3: URL to network admin, 4: Accessibility text. */ __( '<a href="%1$s">WordPress %2$s</a> is available! <a href="%3$s" aria-label="%4$s">Please update now</a>.' ), $version_url, $cur->current, network_admin_url( 'update-core.php' ), esc_attr__( 'Please update WordPress now' ) ); } else { $msg = sprintf( /* translators: 1: URL to WordPress release notes, 2: New WordPress version. */ __( '<a href="%1$s">WordPress %2$s</a> is available! Please notify the site administrator.' ), $version_url, $cur->current ); } wp_admin_notice( $msg, array( 'type' => 'warning', 'additional_classes' => array( 'update-nag', 'inline' ), 'paragraph_wrap' => false, ) ); } /** * Displays WordPress version and active theme in the 'At a Glance' dashboard widget. * * @since 2.5.0 */ function update_right_now_message() { $theme_name = wp_get_theme(); if ( current_user_can( 'switch_themes' ) ) { $theme_name = sprintf( '<a href="themes.php">%1$s</a>', $theme_name ); } $msg = ''; if ( current_user_can( 'update_core' ) ) { $cur = get_preferred_from_update_core(); if ( isset( $cur->response ) && 'upgrade' === $cur->response ) { $msg .= sprintf( '<a href="%s" class="button" aria-describedby="wp-version">%s</a> ', network_admin_url( 'update-core.php' ), /* translators: %s: WordPress version number, or 'Latest' string. */ sprintf( __( 'Update to %s' ), $cur->current ? $cur->current : __( 'Latest' ) ) ); } } /* translators: 1: Version number, 2: Theme name. */ $content = __( 'WordPress %1$s running %2$s theme.' ); /** * Filters the text displayed in the 'At a Glance' dashboard widget. * * Prior to 3.8.0, the widget was named 'Right Now'. * * @since 4.4.0 * * @param string $content Default text. */ $content = apply_filters( 'update_right_now_text', $content ); $msg .= sprintf( '<span id="wp-version">' . $content . '</span>', get_bloginfo( 'version', 'display' ), $theme_name ); echo "<p id='wp-version-message'>$msg</p>"; } /** * Retrieves plugins with updates available. * * @since 2.9.0 * * @return array<string, object> Array of plugin objects with available updates. */ function get_plugin_updates() { $all_plugins = get_plugins(); $upgrade_plugins = array(); $current = get_site_transient( 'update_plugins' ); foreach ( (array) $all_plugins as $plugin_file => $plugin_data ) { if ( isset( $current->response[ $plugin_file ] ) ) { $upgrade_plugins[ $plugin_file ] = (object) $plugin_data; $upgrade_plugins[ $plugin_file ]->update = $current->response[ $plugin_file ]; } } return $upgrade_plugins; } /** * Adds a callback to display update information for plugins with updates available. * * @since 2.9.0 */ function wp_plugin_update_rows() { if ( ! current_user_can( 'update_plugins' ) ) { return; } $plugins = get_site_transient( 'update_plugins' ); if ( isset( $plugins->response ) && is_array( $plugins->response ) ) { $plugins = array_keys( $plugins->response ); foreach ( $plugins as $plugin_file ) { add_action( "after_plugin_row_{$plugin_file}", 'wp_plugin_update_row', 10, 2 ); } } } /** * Displays update information for a plugin. * * @since 2.3.0 * * @param string $file Plugin basename. * @param array $plugin_data Plugin information. * @return void|false Void on success, false if the plugin update is not available. */ function wp_plugin_update_row( $file, $plugin_data ) { $current = get_site_transient( 'update_plugins' ); if ( ! isset( $current->response[ $file ] ) ) { return false; } $response = $current->response[ $file ]; $plugins_allowedtags = array( 'a' => array( 'href' => array(), 'title' => array(), ), 'abbr' => array( 'title' => array() ), 'acronym' => array( 'title' => array() ), 'code' => array(), 'em' => array(), 'strong' => array(), ); $plugin_name = wp_kses( $plugin_data['Name'], $plugins_allowedtags ); $plugin_slug = $response->slug ?? $response->id; if ( isset( $response->slug ) ) { $details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $plugin_slug . '§ion=changelog' ); } elseif ( isset( $response->url ) ) { $details_url = $response->url; } else { $details_url = $plugin_data['PluginURI']; } $details_url = add_query_arg( array( 'TB_iframe' => 'true', 'width' => 600, 'height' => 800, ), $details_url ); /** @var WP_Plugins_List_Table $wp_list_table */ $wp_list_table = _get_list_table( 'WP_Plugins_List_Table', array( 'screen' => get_current_screen(), ) ); if ( is_network_admin() || ! is_multisite() ) { if ( is_network_admin() ) { $active_class = is_plugin_active_for_network( $file ) ? ' active' : ''; } else { $active_class = is_plugin_active( $file ) ? ' active' : ''; } $requires_php = $response->requires_php ?? null; $compatible_php = is_php_version_compatible( $requires_php ); $notice_type = $compatible_php ? 'notice-warning' : 'notice-error'; printf( '<tr class="plugin-update-tr%s" id="%s" data-slug="%s" data-plugin="%s">' . '<td colspan="%s" class="plugin-update colspanchange">' . '<div class="update-message notice inline %s notice-alt"><p>', $active_class, esc_attr( $plugin_slug . '-update' ), esc_attr( $plugin_slug ), esc_attr( $file ), esc_attr( $wp_list_table->get_column_count() ), $notice_type ); if ( ! current_user_can( 'update_plugins' ) ) { printf( /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.' ), $plugin_name, esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Plugin name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) ), esc_attr( $response->new_version ) ); } elseif ( empty( $response->package ) ) { printf( /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this plugin.</em>' ), $plugin_name, esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Plugin name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) ), esc_attr( $response->new_version ) ); } else { if ( $compatible_php ) { printf( /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number, 5: Update URL, 6: Additional link attributes. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ), $plugin_name, esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Plugin name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) ), esc_attr( $response->new_version ), wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $file, 'upgrade-plugin_' . $file ), sprintf( 'class="update-link" aria-label="%s"', /* translators: %s: Plugin name. */ esc_attr( sprintf( _x( 'Update %s now', 'plugin' ), $plugin_name ) ) ) ); } else { printf( /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number 5: URL to Update PHP page. */ __( 'There is a new version of %1$s available, but it does not work with your version of PHP. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s">learn more about updating PHP</a>.' ), $plugin_name, esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Plugin name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) ), esc_attr( $response->new_version ), esc_url( wp_get_update_php_url() ) ); wp_update_php_annotation( '<br><em>', '</em>' ); } } /** * Fires at the end of the update message container in each * row of the plugins list table. * * The dynamic portion of the hook name, `$file`, refers to the path * of the plugin's primary file relative to the plugins directory. * * @since 2.8.0 * * @param array $plugin_data An array of plugin metadata. See get_plugin_data() * and the {@see 'plugin_row_meta'} filter for the list * of possible values. * @param object $response { * An object of metadata about the available plugin update. * * @type string $id Plugin ID, e.g. `w.org/plugins/[plugin-name]`. * @type string $slug Plugin slug. * @type string $plugin Plugin basename. * @type string $new_version New plugin version. * @type string $url Plugin URL. * @type string $package Plugin update package URL. * @type string[] $icons An array of plugin icon URLs. * @type string[] $banners An array of plugin banner URLs. * @type string[] $banners_rtl An array of plugin RTL banner URLs. * @type string $requires The version of WordPress which the plugin requires. * @type string $tested The version of WordPress the plugin is tested against. * @type string $requires_php The version of PHP which the plugin requires. * } */ do_action( "in_plugin_update_message-{$file}", $plugin_data, $response ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores echo '</p></div></td></tr>'; } } /** * Retrieves themes with updates available. * * @since 2.9.0 * * @return array<string, WP_Theme> Array of theme objects with available updates. */ function get_theme_updates() { $current = get_site_transient( 'update_themes' ); if ( ! isset( $current->response ) ) { return array(); } $update_themes = array(); foreach ( $current->response as $stylesheet => $data ) { $update_themes[ $stylesheet ] = wp_get_theme( $stylesheet ); $update_themes[ $stylesheet ]->update = $data; } return $update_themes; } /** * Adds a callback to display update information for themes with updates available. * * @since 3.1.0 */ function wp_theme_update_rows() { if ( ! current_user_can( 'update_themes' ) ) { return; } $themes = get_site_transient( 'update_themes' ); if ( isset( $themes->response ) && is_array( $themes->response ) ) { $themes = array_keys( $themes->response ); foreach ( $themes as $theme ) { add_action( "after_theme_row_{$theme}", 'wp_theme_update_row', 10, 2 ); } } } /** * Displays update information for a theme. * * @since 3.1.0 * * @param string $theme_key Theme stylesheet. * @param WP_Theme $theme Theme object. * @return void|false Void on success, false if the theme update is not available. */ function wp_theme_update_row( $theme_key, $theme ) { $current = get_site_transient( 'update_themes' ); if ( ! isset( $current->response[ $theme_key ] ) ) { return false; } $response = $current->response[ $theme_key ]; $details_url = add_query_arg( array( 'TB_iframe' => 'true', 'width' => 1024, 'height' => 800, ), $current->response[ $theme_key ]['url'] ); /** @var WP_MS_Themes_List_Table $wp_list_table */ $wp_list_table = _get_list_table( 'WP_MS_Themes_List_Table' ); $active = $theme->is_allowed( 'network' ) ? ' active' : ''; $requires_wp = $response['requires'] ?? null; $requires_php = $response['requires_php'] ?? null; $compatible_wp = is_wp_version_compatible( $requires_wp ); $compatible_php = is_php_version_compatible( $requires_php ); printf( '<tr class="plugin-update-tr%s" id="%s" data-slug="%s">' . '<td colspan="%s" class="plugin-update colspanchange">' . '<div class="update-message notice inline notice-warning notice-alt"><p>', $active, esc_attr( $theme->get_stylesheet() . '-update' ), esc_attr( $theme->get_stylesheet() ), $wp_list_table->get_column_count() ); if ( $compatible_wp && $compatible_php ) { if ( ! current_user_can( 'update_themes' ) ) { printf( /* translators: 1: Theme name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.' ), $theme['Name'], esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Theme name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) ), $response['new_version'] ); } elseif ( empty( $response['package'] ) ) { printf( /* translators: 1: Theme name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>' ), $theme['Name'], esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Theme name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) ), $response['new_version'] ); } else { printf( /* translators: 1: Theme name, 2: Details URL, 3: Additional link attributes, 4: Version number, 5: Update URL, 6: Additional link attributes. */ __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ), $theme['Name'], esc_url( $details_url ), sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', /* translators: 1: Theme name, 2: Version number. */ esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) ), $response['new_version'], wp_nonce_url( self_admin_url( 'update.php?action=upgrade-theme&theme=' ) . $theme_key, 'upgrade-theme_' . $theme_key ), sprintf( 'class="update-link" aria-label="%s"', /* translators: %s: Theme name. */ esc_attr( sprintf( _x( 'Update %s now', 'theme' ), $theme['Name'] ) ) ) ); } } else { if ( ! $compatible_wp && ! $compatible_php ) { printf( /* translators: %s: Theme name. */ __( 'There is a new version of %s available, but it does not work with your versions of WordPress and PHP.' ), $theme['Name'] ); if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) { printf( /* translators: 1: URL to WordPress Updates screen, 2: URL to Update PHP page. */ ' ' . __( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.' ), self_admin_url( 'update-core.php' ), esc_url( wp_get_update_php_url() ) ); wp_update_php_annotation( '</p><p><em>', '</em>' ); } elseif ( current_user_can( 'update_core' ) ) { printf( /* translators: %s: URL to WordPress Updates screen. */ ' ' . __( '<a href="%s">Please update WordPress</a>.' ), self_admin_url( 'update-core.php' ) ); } elseif ( current_user_can( 'update_php' ) ) { printf( /* translators: %s: URL to Update PHP page. */ ' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ), esc_url( wp_get_update_php_url() ) ); wp_update_php_annotation( '</p><p><em>', '</em>' ); } } elseif ( ! $compatible_wp ) { printf( /* translators: %s: Theme name. */ __( 'There is a new version of %s available, but it does not work with your version of WordPress.' ), $theme['Name'] ); if ( current_user_can( 'update_core' ) ) { printf( /* translators: %s: URL to WordPress Updates screen. */ ' ' . __( '<a href="%s">Please update WordPress</a>.' ), self_admin_url( 'update-core.php' ) ); } } elseif ( ! $compatible_php ) { printf( /* translators: %s: Theme name. */ __( 'There is a new version of %s available, but it does not work with your version of PHP.' ), $theme['Name'] ); if ( current_user_can( 'update_php' ) ) { printf( /* translators: %s: URL to Update PHP page. */ ' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ), esc_url( wp_get_update_php_url() ) ); wp_update_php_annotation( '</p><p><em>', '</em>' ); } } } /** * Fires at the end of the update message container in each * row of the themes list table. * * The dynamic portion of the hook name, `$theme_key`, refers to * the theme slug as found in the WordPress.org themes repository. * * @since 3.1.0 * * @param WP_Theme $theme The WP_Theme object. * @param array $response { * An array of metadata about the available theme update. * * @type string $new_version New theme version. * @type string $url Theme URL. * @type string $package Theme update package URL. * } */ do_action( "in_theme_update_message-{$theme_key}", $theme, $response ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores echo '</p></div></td></tr>'; } /** * Displays maintenance nag HTML message. * * @since 2.7.0 * * @global int $upgrading * * @return void|false Void on success, false if the maintenance nag should not be displayed. */ function maintenance_nag() { global $upgrading; $nag = isset( $upgrading ); if ( ! $nag ) { $failed = get_site_option( 'auto_core_update_failed' ); /* * If an update failed critically, we may have copied over version.php but not other files. * In that case, if the installation claims we're running the version we attempted, nag. * This is serious enough to err on the side of nagging. * * If we simply failed to update before we tried to copy any files, then assume things are * OK if they are now running the latest. * * This flag is cleared whenever a successful update occurs using Core_Upgrader. */ $comparison = ! empty( $failed['critical'] ) ? '>=' : '>'; if ( isset( $failed['attempted'] ) && version_compare( $failed['attempted'], wp_get_wp_version(), $comparison ) ) { $nag = true; } } if ( ! $nag ) { return false; } if ( current_user_can( 'update_core' ) ) { $msg = sprintf( /* translators: %s: URL to WordPress Updates screen. */ __( 'An automated WordPress update has failed to complete - <a href="%s">please attempt the update again now</a>.' ), 'update-core.php' ); } else { $msg = __( 'An automated WordPress update has failed to complete! Please notify the site administrator.' ); } wp_admin_notice( $msg, array( 'type' => 'warning', 'additional_classes' => array( 'update-nag', 'inline' ), 'paragraph_wrap' => false, ) ); } /** * Prints the JavaScript templates for update admin notices. * * @since 4.6.0 * * Template takes one argument with four values: * * param {object} data { * Arguments for admin notice. * * @type string id ID of the notice. * @type string className Class names for the notice. * @type string message The notice's message. * @type string type The type of update the notice is for. Either 'plugin' or 'theme'. * } */ function wp_print_admin_notice_templates() { ?> <script id="tmpl-wp-updates-admin-notice" type="text/html"> <div <# if ( data.id ) { #>id="{{ data.id }}"<# } #> class="notice {{ data.className }}"><p>{{{ data.message }}}</p></div> </script> <script id="tmpl-wp-bulk-updates-admin-notice" type="text/html"> <div id="{{ data.id }}" class="{{ data.className }} notice <# if ( data.errorMessage ) { #>notice-error<# } else { #>notice-success<# } #>"> <p> <# if ( data.successMessage ) { #> {{{ data.successMessage }}} <# } #> <# if ( data.errorMessage ) { #> <button class="button-link bulk-action-errors-collapsed" aria-expanded="false"> {{{ data.errorMessage }}} <span class="screen-reader-text"> <?php /* translators: Hidden accessibility text. */ _e( 'Show more details' ); ?> </span> <span class="toggle-indicator" aria-hidden="true"></span> </button> <# } #> </p> <# if ( data.errorMessages ) { #> <ul class="bulk-action-errors hidden"> <# _.each( data.errorMessages, function( errorMessage ) { #> <li>{{ errorMessage }}</li> <# } ); #> </ul> <# } #> </div> </script> <?php } /** * Prints the JavaScript templates for update and deletion rows in list tables. * * @since 4.6.0 * * The update template takes one argument with four values: * * param {object} data { * Arguments for the update row * * @type string slug Plugin slug. * @type string plugin Plugin base name. * @type string colspan The number of table columns this row spans. * @type string content The row content. * } * * The delete template takes one argument with four values: * * param {object} data { * Arguments for the update row * * @type string slug Plugin slug. * @type string plugin Plugin base name. * @type string name Plugin name. * @type string colspan The number of table columns this row spans. * } */ function wp_print_update_row_templates() { ?> <script id="tmpl-item-update-row" type="text/template"> <tr class="plugin-update-tr update" id="{{ data.slug }}-update" data-slug="{{ data.slug }}" <# if ( data.plugin ) { #>data-plugin="{{ data.plugin }}"<# } #>> <td colspan="{{ data.colspan }}" class="plugin-update colspanchange"> {{{ data.content }}} </td> </tr> </script> <script id="tmpl-item-deleted-row" type="text/template"> <tr class="plugin-deleted-tr inactive deleted" id="{{ data.slug }}-deleted" data-slug="{{ data.slug }}" <# if ( data.plugin ) { #>data-plugin="{{ data.plugin }}"<# } #>> <td colspan="{{ data.colspan }}" class="plugin-update colspanchange"> <# if ( data.plugin ) { #> <?php printf( /* translators: %s: Plugin name. */ _x( '%s was successfully deleted.', 'plugin' ), '<strong>{{{ data.name }}}</strong>' ); ?> <# } else { #> <?php printf( /* translators: %s: Theme name. */ _x( '%s was successfully deleted.', 'theme' ), '<strong>{{{ data.name }}}</strong>' ); ?> <# } #> </td> </tr> </script> <?php } /** * Displays a notice when the user is in recovery mode. * * @since 5.2.0 */ function wp_recovery_mode_nag() { if ( ! wp_is_recovery_mode() ) { return; } $url = wp_login_url(); $url = add_query_arg( 'action', WP_Recovery_Mode::EXIT_ACTION, $url ); $url = wp_nonce_url( $url, WP_Recovery_Mode::EXIT_ACTION ); $message = sprintf( /* translators: %s: Recovery Mode exit link. */ __( 'You are in recovery mode. This means there may be an error with a theme or plugin. To exit recovery mode, log out or use the Exit button. <a href="%s">Exit Recovery Mode</a>' ), esc_url( $url ) ); wp_admin_notice( $message, array( 'type' => 'info' ) ); } /** * Checks whether auto-updates are enabled. * * @since 5.5.0 * * @param string $type The type of update being checked: Either 'theme' or 'plugin'. * @return bool True if auto-updates are enabled for `$type`, false otherwise. */ function wp_is_auto_update_enabled_for_type( $type ) { if ( ! class_exists( 'WP_Automatic_Updater' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-automatic-updater.php'; } $updater = new WP_Automatic_Updater(); $enabled = ! $updater->is_disabled(); switch ( $type ) { case 'plugin': /** * Filters whether plugins auto-update is enabled. * * @since 5.5.0 * * @param bool $enabled True if plugins auto-update is enabled, false otherwise. */ return apply_filters( 'plugins_auto_update_enabled', $enabled ); case 'theme': /** * Filters whether themes auto-update is enabled. * * @since 5.5.0 * * @param bool $enabled True if themes auto-update is enabled, false otherwise. */ return apply_filters( 'themes_auto_update_enabled', $enabled ); } return false; } /** * Checks whether auto-updates are forced for an item. * * @since 5.6.0 * * @param string $type The type of update being checked: Either 'theme' or 'plugin'. * @param bool|null $update Whether to update. The value of null is internally used * to detect whether nothing has hooked into this filter. * @param object $item The update offer. * @return bool True if auto-updates are forced for `$item`, false otherwise. */ function wp_is_auto_update_forced_for_item( $type, $update, $item ) { /** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */ return apply_filters( "auto_update_{$type}", $update, $item ); } /** * Determines the appropriate auto-update message to be displayed. * * @since 5.5.0 * * @return string The update message to be shown. */ function wp_get_auto_update_message() { $next_update_time = wp_next_scheduled( 'wp_version_check' ); // Check if the event exists. if ( false === $next_update_time ) { $message = __( 'Automatic update not scheduled. There may be a problem with WP-Cron.' ); } else { $time_to_next_update = human_time_diff( (int) $next_update_time ); // See if cron is overdue. $overdue = ( time() - $next_update_time ) > 0; if ( $overdue ) { $message = sprintf( /* translators: %s: Duration that WP-Cron has been overdue. */ __( 'Automatic update overdue by %s. There may be a problem with WP-Cron.' ), $time_to_next_update ); } else { $message = sprintf( /* translators: %s: Time until the next update. */ __( 'Automatic update scheduled in %s.' ), $time_to_next_update ); } } return $message; } PK $��\�]=S2 2 class-ftp-pure.phpnu �[��� <?php /** * PemFTP - An Ftp implementation in pure PHP * * @package PemFTP * @since 2.5.0 * * @version 1.0 * @copyright Alexey Dotsenko * @author Alexey Dotsenko * @link https://www.phpclasses.org/package/1743-PHP-FTP-client-in-pure-PHP.html * @license LGPL https://opensource.org/licenses/lgpl-license.html */ /** * FTP implementation using fsockopen to connect. * * @package PemFTP * @subpackage Pure * @since 2.5.0 * * @version 1.0 * @copyright Alexey Dotsenko * @author Alexey Dotsenko * @link https://www.phpclasses.org/package/1743-PHP-FTP-client-in-pure-PHP.html * @license LGPL https://opensource.org/licenses/lgpl-license.html */ class ftp_pure extends ftp_base { function __construct($verb=FALSE, $le=FALSE) { parent::__construct(false, $verb, $le); } // <!-- --------------------------------------------------------------------------------------- --> // <!-- Private functions --> // <!-- --------------------------------------------------------------------------------------- --> 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 $��\�y�H �H class-wp-community-events.phpnu �[��� <?php /** * Administration: Community Events class. * * @package WordPress * @subpackage Administration * @since 4.8.0 */ /** * Class WP_Community_Events. * * A client for api.wordpress.org/events. * * @since 4.8.0 */ #[AllowDynamicProperties] class WP_Community_Events { /** * ID for a WordPress user account. * * @since 4.8.0 * * @var int */ protected $user_id = 0; /** * Stores location data for the user. * * @since 4.8.0 * * @var false|array */ protected $user_location = false; /** * Constructor for WP_Community_Events. * * @since 4.8.0 * * @param int $user_id WP user ID. * @param false|array $user_location { * Stored location data for the user. false to pass no location. * * @type string $description The name of the location * @type string $latitude The latitude in decimal degrees notation, without the degree * symbol. e.g.: 47.615200. * @type string $longitude The longitude in decimal degrees notation, without the degree * symbol. e.g.: -122.341100. * @type string $country The ISO 3166-1 alpha-2 country code. e.g.: BR * } */ public function __construct( $user_id, $user_location = false ) { $this->user_id = absint( $user_id ); $this->user_location = $user_location; } /** * Gets data about events near a particular location. * * Cached events will be immediately returned if the `user_location` property * is set for the current user, and cached events exist for that location. * * Otherwise, this method sends a request to the w.org Events API with location * data. The API will send back a recognized location based on the data, along * with nearby events. * * The browser's request for events is proxied with this method, rather * than having the browser make the request directly to api.wordpress.org, * because it allows results to be cached server-side and shared with other * users and sites in the network. This makes the process more efficient, * since increasing the number of visits that get cached data means users * don't have to wait as often; if the user's browser made the request * directly, it would also need to make a second request to WP in order to * pass the data for caching. Having WP make the request also introduces * the opportunity to anonymize the IP before sending it to w.org, which * mitigates possible privacy concerns. * * @since 4.8.0 * @since 5.5.2 Response no longer contains formatted date field. They're added * in `wp.communityEvents.populateDynamicEventFields()` now. * * @param string $location_search Optional. City name to help determine the location. * e.g., "Seattle". Default empty string. * @param string $timezone Optional. Timezone to help determine the location. * Default empty string. * @return array|WP_Error A WP_Error on failure; an array with location and events on * success. */ public function get_events( $location_search = '', $timezone = '' ) { $cached_events = $this->get_cached_events(); if ( ! $location_search && $cached_events ) { return $cached_events; } // Include an unmodified $wp_version. require ABSPATH . WPINC . '/version.php'; $api_url = 'http://api.wordpress.org/events/1.0/'; $request_args = $this->get_request_args( $location_search, $timezone ); $request_args['user-agent'] = 'WordPress/' . $wp_version . '; ' . home_url( '/' ); if ( wp_http_supports( array( 'ssl' ) ) ) { $api_url = set_url_scheme( $api_url, 'https' ); } $response = wp_remote_get( $api_url, $request_args ); $response_code = wp_remote_retrieve_response_code( $response ); $response_body = json_decode( wp_remote_retrieve_body( $response ), true ); $response_error = null; if ( is_wp_error( $response ) ) { $response_error = $response; } elseif ( 200 !== $response_code ) { $response_error = new WP_Error( 'api-error', /* translators: %d: Numeric HTTP status code, e.g. 400, 403, 500, 504, etc. */ sprintf( __( 'Invalid API response code (%d).' ), $response_code ) ); } elseif ( ! isset( $response_body['location'], $response_body['events'] ) ) { $response_error = new WP_Error( 'api-invalid-response', $response_body['error'] ?? __( 'Unknown API error.' ) ); } if ( is_wp_error( $response_error ) ) { return $response_error; } else { $expiration = false; if ( isset( $response_body['ttl'] ) ) { $expiration = $response_body['ttl']; unset( $response_body['ttl'] ); } /* * The IP in the response is usually the same as the one that was sent * in the request, but in some cases it is different. In those cases, * it's important to reset it back to the IP from the request. * * For example, if the IP sent in the request is private (e.g., 192.168.1.100), * then the API will ignore that and use the corresponding public IP instead, * and the public IP will get returned. If the public IP were saved, though, * then get_cached_events() would always return `false`, because the transient * would be generated based on the public IP when saving the cache, but generated * based on the private IP when retrieving the cache. */ if ( ! empty( $response_body['location']['ip'] ) ) { $response_body['location']['ip'] = $request_args['body']['ip']; } /* * The API doesn't return a description for latitude/longitude requests, * but the description is already saved in the user location, so that * one can be used instead. */ if ( $this->coordinates_match( $request_args['body'], $response_body['location'] ) && empty( $response_body['location']['description'] ) ) { $response_body['location']['description'] = $this->user_location['description']; } /* * Store the raw response, because events will expire before the cache does. * The response will need to be processed every page load. */ $this->cache_events( $response_body, $expiration ); $response_body['events'] = $this->trim_events( $response_body['events'] ); return $response_body; } } /** * Builds an array of args to use in an HTTP request to the w.org Events API. * * @since 4.8.0 * * @param string $search Optional. City search string. Default empty string. * @param string $timezone Optional. Timezone string. Default empty string. * @return array The request args. */ protected function get_request_args( $search = '', $timezone = '' ) { $args = array( 'number' => 5, // Get more than three in case some get trimmed out. 'ip' => self::get_unsafe_client_ip(), ); /* * Include the minimal set of necessary arguments, in order to increase the * chances of a cache-hit on the API side. */ if ( empty( $search ) && isset( $this->user_location['latitude'], $this->user_location['longitude'] ) ) { $args['latitude'] = $this->user_location['latitude']; $args['longitude'] = $this->user_location['longitude']; } else { $args['locale'] = get_user_locale( $this->user_id ); if ( $timezone ) { $args['timezone'] = $timezone; } if ( $search ) { $args['location'] = $search; } } // Wrap the args in an array compatible with the second parameter of `wp_remote_get()`. return array( 'body' => $args, ); } /** * Determines the user's actual IP address and attempts to partially * anonymize an IP address by converting it to a network ID. * * Geolocating the network ID usually returns a similar location as the * actual IP, but provides some privacy for the user. * * $_SERVER['REMOTE_ADDR'] cannot be used in all cases, such as when the user * is making their request through a proxy, or when the web server is behind * a proxy. In those cases, $_SERVER['REMOTE_ADDR'] is set to the proxy address rather * than the user's actual address. * * Modified from https://stackoverflow.com/a/2031935/450127, MIT license. * Modified from https://github.com/geertw/php-ip-anonymizer, MIT license. * * SECURITY WARNING: This function is _NOT_ intended to be used in * circumstances where the authenticity of the IP address matters. This does * _NOT_ guarantee that the returned address is valid or accurate, and it can * be easily spoofed. * * @since 4.8.0 * * @return string|false The anonymized address on success; the given address * or false on failure. */ public static function get_unsafe_client_ip() { $client_ip = false; // In order of preference, with the best ones for this purpose first. $address_headers = array( 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR', ); foreach ( $address_headers as $header ) { if ( array_key_exists( $header, $_SERVER ) ) { /* * HTTP_X_FORWARDED_FOR can contain a chain of comma-separated * addresses. The first one is the original client. It can't be * trusted for authenticity, but we don't need to for this purpose. */ $address_chain = explode( ',', $_SERVER[ $header ] ); $client_ip = trim( $address_chain[0] ); break; } } if ( ! $client_ip ) { return false; } $anon_ip = wp_privacy_anonymize_ip( $client_ip, true ); if ( '0.0.0.0' === $anon_ip || '::' === $anon_ip ) { return false; } return $anon_ip; } /** * Test if two pairs of latitude/longitude coordinates match each other. * * @since 4.8.0 * * @param array $a The first pair, with indexes 'latitude' and 'longitude'. * @param array $b The second pair, with indexes 'latitude' and 'longitude'. * @return bool True if they match, false if they don't. */ protected function coordinates_match( $a, $b ) { if ( ! isset( $a['latitude'], $a['longitude'], $b['latitude'], $b['longitude'] ) ) { return false; } return $a['latitude'] === $b['latitude'] && $a['longitude'] === $b['longitude']; } /** * Generates a transient key based on user location. * * This could be reduced to a one-liner in the calling functions, but it's * intentionally a separate function because it's called from multiple * functions, and having it abstracted keeps the logic consistent and DRY, * which is less prone to errors. * * @since 4.8.0 * * @param array $location Should contain 'latitude' and 'longitude' indexes. * @return string|false Transient key on success, false on failure. */ protected function get_events_transient_key( $location ) { $key = false; if ( isset( $location['ip'] ) ) { $key = 'community-events-' . md5( $location['ip'] ); } elseif ( isset( $location['latitude'], $location['longitude'] ) ) { $key = 'community-events-' . md5( $location['latitude'] . $location['longitude'] ); } return $key; } /** * Caches an array of events data from the Events API. * * @since 4.8.0 * * @param array $events Response body from the API request. * @param int|false $expiration Optional. Amount of time to cache the events. Defaults to false. * @return bool true if events were cached; false if not. */ protected function cache_events( $events, $expiration = false ) { $set = false; $transient_key = $this->get_events_transient_key( $events['location'] ); $cache_expiration = $expiration ? absint( $expiration ) : HOUR_IN_SECONDS * 12; if ( $transient_key ) { $set = set_site_transient( $transient_key, $events, $cache_expiration ); } return $set; } /** * Gets cached events. * * @since 4.8.0 * @since 5.5.2 Response no longer contains formatted date field. They're added * in `wp.communityEvents.populateDynamicEventFields()` now. * * @return array|false An array containing `location` and `events` items * on success, false on failure. */ public function get_cached_events() { $transient_key = $this->get_events_transient_key( $this->user_location ); if ( ! $transient_key ) { return false; } $cached_response = get_site_transient( $transient_key ); if ( isset( $cached_response['events'] ) ) { $cached_response['events'] = $this->trim_events( $cached_response['events'] ); } return $cached_response; } /** * Adds formatted date and time items for each event in an API response. * * This has to be called after the data is pulled from the cache, because * the cached events are shared by all users. If it was called before storing * the cache, then all users would see the events in the localized data/time * of the user who triggered the cache refresh, rather than their own. * * @since 4.8.0 * @deprecated 5.5.2 No longer used in core. * * @param array $response_body The response which contains the events. * @return array The response with dates and times formatted. */ protected function format_event_data_time( $response_body ) { _deprecated_function( __METHOD__, '5.5.2' ); if ( isset( $response_body['events'] ) ) { foreach ( $response_body['events'] as $key => $event ) { $timestamp = strtotime( $event['date'] ); /* * The `date_format` option is not used because it's important * in this context to keep the day of the week in the formatted date, * so that users can tell at a glance if the event is on a day they * are available, without having to open the link. */ /* translators: Date format for upcoming events on the dashboard. Include the day of the week. See https://www.php.net/manual/datetime.format.php */ $formatted_date = date_i18n( __( 'l, M j, Y' ), $timestamp ); $formatted_time = date_i18n( get_option( 'time_format' ), $timestamp ); if ( isset( $event['end_date'] ) ) { $end_timestamp = strtotime( $event['end_date'] ); $formatted_end_date = date_i18n( __( 'l, M j, Y' ), $end_timestamp ); if ( 'meetup' !== $event['type'] && $formatted_end_date !== $formatted_date ) { /* translators: Upcoming events month format. See https://www.php.net/manual/datetime.format.php */ $start_month = date_i18n( _x( 'F', 'upcoming events month format' ), $timestamp ); $end_month = date_i18n( _x( 'F', 'upcoming events month format' ), $end_timestamp ); if ( $start_month === $end_month ) { $formatted_date = sprintf( /* translators: Date string for upcoming events. 1: Month, 2: Starting day, 3: Ending day, 4: Year. */ __( '%1$s %2$d–%3$d, %4$d' ), $start_month, /* translators: Upcoming events day format. See https://www.php.net/manual/datetime.format.php */ date_i18n( _x( 'j', 'upcoming events day format' ), $timestamp ), date_i18n( _x( 'j', 'upcoming events day format' ), $end_timestamp ), /* translators: Upcoming events year format. See https://www.php.net/manual/datetime.format.php */ date_i18n( _x( 'Y', 'upcoming events year format' ), $timestamp ) ); } else { $formatted_date = sprintf( /* translators: Date string for upcoming events. 1: Starting month, 2: Starting day, 3: Ending month, 4: Ending day, 5: Year. */ __( '%1$s %2$d – %3$s %4$d, %5$d' ), $start_month, date_i18n( _x( 'j', 'upcoming events day format' ), $timestamp ), $end_month, date_i18n( _x( 'j', 'upcoming events day format' ), $end_timestamp ), date_i18n( _x( 'Y', 'upcoming events year format' ), $timestamp ) ); } $formatted_date = wp_maybe_decline_date( $formatted_date, 'F j, Y' ); } } $response_body['events'][ $key ]['formatted_date'] = $formatted_date; $response_body['events'][ $key ]['formatted_time'] = $formatted_time; } } return $response_body; } /** * Prepares the event list for presentation. * * Discards expired events, and makes WordCamps "sticky." Attendees need more * advanced notice about WordCamps than they do for meetups, so camps should * appear in the list sooner. If a WordCamp is coming up, the API will "stick" * it in the response, even if it wouldn't otherwise appear. When that happens, * the event will be at the end of the list, and will need to be moved into a * higher position, so that it doesn't get trimmed off. * * @since 4.8.0 * @since 4.9.7 Stick a WordCamp to the final list. * @since 5.5.2 Accepts and returns only the events, rather than an entire HTTP response. * @since 6.0.0 Decode HTML entities from the event title. * * @param array $events The events that will be prepared. * @return array The response body with events trimmed. */ protected function trim_events( array $events ) { $future_events = array(); foreach ( $events as $event ) { /* * The API's `date` and `end_date` fields are in the _event's_ local timezone, but UTC is needed so * it can be converted to the _user's_ local time. */ $end_time = (int) $event['end_unix_timestamp']; if ( time() < $end_time ) { // Decode HTML entities from the event title. $event['title'] = html_entity_decode( $event['title'], ENT_QUOTES, 'UTF-8' ); array_push( $future_events, $event ); } } $future_wordcamps = array_filter( $future_events, static function ( $wordcamp ) { return 'wordcamp' === $wordcamp['type']; } ); $future_wordcamps = array_values( $future_wordcamps ); // Remove gaps in indices. $trimmed_events = array_slice( $future_events, 0, 3 ); $trimmed_event_types = wp_list_pluck( $trimmed_events, 'type' ); // Make sure the soonest upcoming WordCamp is pinned in the list. if ( $future_wordcamps && ! in_array( 'wordcamp', $trimmed_event_types, true ) ) { array_pop( $trimmed_events ); array_push( $trimmed_events, $future_wordcamps[0] ); } return $trimmed_events; } /** * Logs responses to Events API requests. * * @since 4.8.0 * @deprecated 4.9.0 Use a plugin instead. See #41217 for an example. * * @param string $message A description of what occurred. * @param array $details Details that provide more context for the * log entry. */ protected function maybe_log_events_response( $message, $details ) { _deprecated_function( __METHOD__, '4.9.0' ); if ( ! WP_DEBUG_LOG ) { return; } error_log( sprintf( '%s: %s. Details: %s', __METHOD__, trim( $message, '.' ), wp_json_encode( $details ) ) ); } } PK $��\j��s� s� image.phpnu �[��� <?php /** * File contains all the administration image manipulation functions. * * @package WordPress * @subpackage Administration */ /** * Crops an image to a given size. * * @since 2.1.0 * * @param string|int $src The source file or Attachment ID. * @param int $src_x The start x position to crop from. * @param int $src_y The start y position to crop from. * @param int $src_w The width to crop. * @param int $src_h The height to crop. * @param int $dst_w The destination width. * @param int $dst_h The destination height. * @param bool|false $src_abs Optional. If the source crop points are absolute. * @param string|false $dst_file Optional. The destination file to write to. * @return string|WP_Error New filepath on success, WP_Error on failure. */ function wp_crop_image( $src, $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs = false, $dst_file = false ) { $src_file = $src; if ( is_numeric( $src ) ) { // Handle int as attachment ID. $src_file = get_attached_file( $src ); if ( ! file_exists( $src_file ) ) { /* * If the file doesn't exist, attempt a URL fopen on the src link. * This can occur with certain file replication plugins. */ $src = _load_image_to_edit_path( $src, 'full' ); } else { $src = $src_file; } } $editor = wp_get_image_editor( $src ); if ( is_wp_error( $editor ) ) { return $editor; } $src = $editor->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs ); if ( is_wp_error( $src ) ) { return $src; } if ( ! $dst_file ) { $dst_file = str_replace( wp_basename( $src_file ), 'cropped-' . wp_basename( $src_file ), $src_file ); } /* * The directory containing the original file may no longer exist when * using a replication plugin. */ wp_mkdir_p( dirname( $dst_file ) ); $dst_file = dirname( $dst_file ) . '/' . wp_unique_filename( dirname( $dst_file ), wp_basename( $dst_file ) ); $result = $editor->save( $dst_file ); if ( is_wp_error( $result ) ) { return $result; } if ( ! empty( $result['path'] ) ) { return $result['path']; } return $dst_file; } /** * Compare the existing image sub-sizes (as saved in the attachment meta) * to the currently registered image sub-sizes, and return the difference. * * Registered sub-sizes that are larger than the image are skipped. * * @since 5.3.0 * * @param int $attachment_id The image attachment post ID. * @return array[] Associative array of arrays of image sub-size information for * missing image sizes, keyed by image size name. */ function wp_get_missing_image_subsizes( $attachment_id ) { if ( ! wp_attachment_is_image( $attachment_id ) ) { return array(); } $registered_sizes = wp_get_registered_image_subsizes(); $image_meta = wp_get_attachment_metadata( $attachment_id ); // Meta error? if ( empty( $image_meta ) ) { return $registered_sizes; } // Use the originally uploaded image dimensions as full_width and full_height. if ( ! empty( $image_meta['original_image'] ) ) { $image_file = wp_get_original_image_path( $attachment_id ); $imagesize = wp_getimagesize( $image_file ); } if ( ! empty( $imagesize ) ) { $full_width = $imagesize[0]; $full_height = $imagesize[1]; } else { $full_width = (int) $image_meta['width']; $full_height = (int) $image_meta['height']; } $possible_sizes = array(); // Skip registered sizes that are too large for the uploaded image. foreach ( $registered_sizes as $size_name => $size_data ) { if ( image_resize_dimensions( $full_width, $full_height, $size_data['width'], $size_data['height'], $size_data['crop'] ) ) { $possible_sizes[ $size_name ] = $size_data; } } if ( empty( $image_meta['sizes'] ) ) { $image_meta['sizes'] = array(); } /* * Remove sizes that already exist. Only checks for matching "size names". * It is possible that the dimensions for a particular size name have changed. * For example the user has changed the values on the Settings -> Media screen. * However we keep the old sub-sizes with the previous dimensions * as the image may have been used in an older post. */ $missing_sizes = array_diff_key( $possible_sizes, $image_meta['sizes'] ); /** * Filters the array of missing image sub-sizes for an uploaded image. * * @since 5.3.0 * * @param array[] $missing_sizes Associative array of arrays of image sub-size information for * missing image sizes, keyed by image size name. * @param array $image_meta The image meta data. * @param int $attachment_id The image attachment post ID. */ return apply_filters( 'wp_get_missing_image_subsizes', $missing_sizes, $image_meta, $attachment_id ); } /** * If any of the currently registered image sub-sizes are missing, * create them and update the image meta data. * * @since 5.3.0 * * @param int $attachment_id The image attachment post ID. * @return array|WP_Error The updated image meta data array or WP_Error object * if both the image meta and the attached file are missing. */ function wp_update_image_subsizes( $attachment_id ) { $image_meta = wp_get_attachment_metadata( $attachment_id ); $image_file = wp_get_original_image_path( $attachment_id ); if ( empty( $image_meta ) || ! is_array( $image_meta ) ) { /* * Previously failed upload? * If there is an uploaded file, make all sub-sizes and generate all of the attachment meta. */ if ( ! empty( $image_file ) ) { $image_meta = wp_create_image_subsizes( $image_file, $attachment_id ); } else { return new WP_Error( 'invalid_attachment', __( 'The attached file cannot be found.' ) ); } } else { $missing_sizes = wp_get_missing_image_subsizes( $attachment_id ); if ( empty( $missing_sizes ) ) { return $image_meta; } // This also updates the image meta. $image_meta = _wp_make_subsizes( $missing_sizes, $image_file, $image_meta, $attachment_id ); } /** This filter is documented in wp-admin/includes/image.php */ $image_meta = apply_filters( 'wp_generate_attachment_metadata', $image_meta, $attachment_id, 'update' ); // Save the updated metadata. wp_update_attachment_metadata( $attachment_id, $image_meta ); return $image_meta; } /** * Updates the attached file and image meta data when the original image was edited. * * @since 5.3.0 * @since 6.0.0 The `$filesize` value was added to the returned array. * @access private * * @param array $saved_data The data returned from WP_Image_Editor after successfully saving an image. * @param string $original_file Path to the original file. * @param array $image_meta The image meta data. * @param int $attachment_id The attachment post ID. * @return array The updated image meta data. */ function _wp_image_meta_replace_original( $saved_data, $original_file, $image_meta, $attachment_id ) { $new_file = $saved_data['path']; // Update the attached file meta. update_attached_file( $attachment_id, $new_file ); // Width and height of the new image. $image_meta['width'] = $saved_data['width']; $image_meta['height'] = $saved_data['height']; // Make the file path relative to the upload dir. $image_meta['file'] = _wp_relative_upload_path( $new_file ); // Add image file size. $image_meta['filesize'] = wp_filesize( $new_file ); // Store the original image file name in image_meta. $image_meta['original_image'] = wp_basename( $original_file ); return $image_meta; } /** * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata. * * Intended for use after an image is uploaded. Saves/updates the image metadata after each * sub-size is created. If there was an error, it is added to the returned image metadata array. * * @since 5.3.0 * * @param string $file Full path to the image file. * @param int $attachment_id Attachment ID to process. * @return array The image attachment meta data. */ function wp_create_image_subsizes( $file, $attachment_id ) { $imagesize = wp_getimagesize( $file ); if ( empty( $imagesize ) ) { // File is not an image. return array(); } // Default image meta. $image_meta = array( 'width' => $imagesize[0], 'height' => $imagesize[1], 'file' => _wp_relative_upload_path( $file ), 'filesize' => wp_filesize( $file ), 'sizes' => array(), ); // Fetch additional metadata from EXIF/IPTC. $exif_meta = wp_read_image_metadata( $file ); if ( $exif_meta ) { $image_meta['image_meta'] = $exif_meta; } /** * Filters the "BIG image" threshold value. * * If the original image width or height is above the threshold, it will be scaled down. The threshold is * used as max width and max height. The scaled down image will be used as the largest available size, including * the `_wp_attached_file` post meta value. * * Returning `false` from the filter callback will disable the scaling. * * @since 5.3.0 * * @param int $threshold The threshold value in pixels. Default 2560. * @param array $imagesize { * Indexed array of the image width and height in pixels. * * @type int $0 The image width. * @type int $1 The image height. * } * @param string $file Full path to the uploaded image file. * @param int $attachment_id Attachment post ID. */ $threshold = (int) apply_filters( 'big_image_size_threshold', 2560, $imagesize, $file, $attachment_id ); /* * If the original image's dimensions are over the threshold, * scale the image and use it as the "full" size. */ $scale_down = false; $convert = false; if ( $threshold && ( $image_meta['width'] > $threshold || $image_meta['height'] > $threshold ) ) { // The image will be converted if needed on saving. $scale_down = true; } else { // The image may need to be converted regardless of its dimensions. $output_format = wp_get_image_editor_output_format( $file, $imagesize['mime'] ); if ( is_array( $output_format ) && array_key_exists( $imagesize['mime'], $output_format ) && $output_format[ $imagesize['mime'] ] !== $imagesize['mime'] ) { $convert = true; } } if ( $scale_down || $convert ) { $editor = wp_get_image_editor( $file ); if ( is_wp_error( $editor ) ) { // This image cannot be edited. return $image_meta; } if ( $scale_down ) { // Resize the image. This will also convet it if needed. $resized = $editor->resize( $threshold, $threshold ); } elseif ( $convert ) { // The image will be converted (if possible) when saved. $resized = true; } $rotated = null; // If there is EXIF data, rotate according to EXIF Orientation. if ( ! is_wp_error( $resized ) && is_array( $exif_meta ) ) { $resized = $editor->maybe_exif_rotate(); $rotated = $resized; // bool true or WP_Error } if ( ! is_wp_error( $resized ) ) { /* * Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg". * This doesn't affect the sub-sizes names as they are generated from the original image (for best quality). */ if ( $scale_down ) { $saved = $editor->save( $editor->generate_filename( 'scaled' ) ); } elseif ( $convert ) { // Pass an empty string to avoid adding a suffix to converted file names. $saved = $editor->save( $editor->generate_filename( '' ) ); } else { $saved = $editor->save(); } if ( ! is_wp_error( $saved ) ) { $image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id ); // If the image was rotated update the stored EXIF data. if ( true === $rotated && ! empty( $image_meta['image_meta']['orientation'] ) ) { $image_meta['image_meta']['orientation'] = 1; } } else { // TODO: Log errors. } } else { // TODO: Log errors. } } elseif ( ! empty( $exif_meta['orientation'] ) && 1 !== (int) $exif_meta['orientation'] ) { // Rotate the whole original image if there is EXIF data and "orientation" is not 1. $editor = wp_get_image_editor( $file ); if ( is_wp_error( $editor ) ) { // This image cannot be edited. return $image_meta; } // Rotate the image. $rotated = $editor->maybe_exif_rotate(); if ( true === $rotated ) { // Append `-rotated` to the image file name. $saved = $editor->save( $editor->generate_filename( 'rotated' ) ); if ( ! is_wp_error( $saved ) ) { $image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id ); // Update the stored EXIF data. if ( ! empty( $image_meta['image_meta']['orientation'] ) ) { $image_meta['image_meta']['orientation'] = 1; } } else { // TODO: Log errors. } } } /* * Initial save of the new metadata. * At this point the file was uploaded and moved to the uploads directory * but the image sub-sizes haven't been created yet and the `sizes` array is empty. */ wp_update_attachment_metadata( $attachment_id, $image_meta ); $new_sizes = wp_get_registered_image_subsizes(); /** * Filters the image sizes automatically generated when uploading an image. * * @since 2.9.0 * @since 4.4.0 Added the `$image_meta` argument. * @since 5.3.0 Added the `$attachment_id` argument. * * @param array $new_sizes Associative array of image sizes to be created. * @param array $image_meta The image meta data: width, height, file, sizes, etc. * @param int $attachment_id The attachment post ID for the image. */ $new_sizes = apply_filters( 'intermediate_image_sizes_advanced', $new_sizes, $image_meta, $attachment_id ); return _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ); } /** * Low-level function to create image sub-sizes. * * Updates the image meta after each sub-size is created. * Errors are stored in the returned image metadata array. * * @since 5.3.0 * @access private * * @param array $new_sizes Array defining what sizes to create. * @param string $file Full path to the image file. * @param array $image_meta The attachment meta data array. * @param int $attachment_id Attachment ID to process. * @return array The attachment meta data with updated `sizes` array. Includes an array of errors encountered while resizing. */ function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) { if ( empty( $image_meta ) || ! is_array( $image_meta ) ) { // Not an image attachment. return array(); } // Check if any of the new sizes already exist. if ( isset( $image_meta['sizes'] ) && is_array( $image_meta['sizes'] ) ) { foreach ( $image_meta['sizes'] as $size_name => $size_meta ) { /* * Only checks "size name" so we don't override existing images even if the dimensions * don't match the currently defined size with the same name. * To change the behavior, unset changed/mismatched sizes in the `sizes` array in image meta. */ if ( array_key_exists( $size_name, $new_sizes ) ) { unset( $new_sizes[ $size_name ] ); } } } else { $image_meta['sizes'] = array(); } if ( empty( $new_sizes ) ) { // Nothing to do... return $image_meta; } /* * Sort the image sub-sizes in order of priority when creating them. * This ensures there is an appropriate sub-size the user can access immediately * even when there was an error and not all sub-sizes were created. */ $priority = array( 'medium' => null, 'large' => null, 'thumbnail' => null, 'medium_large' => null, ); $new_sizes = array_filter( array_merge( $priority, $new_sizes ) ); $editor = wp_get_image_editor( $file ); if ( is_wp_error( $editor ) ) { // The image cannot be edited. return $image_meta; } // If stored EXIF data exists, rotate the source image before creating sub-sizes. if ( ! empty( $image_meta['image_meta'] ) ) { $rotated = $editor->maybe_exif_rotate(); if ( is_wp_error( $rotated ) ) { // TODO: Log errors. } } if ( method_exists( $editor, 'make_subsize' ) ) { foreach ( $new_sizes as $new_size_name => $new_size_data ) { $new_size_meta = $editor->make_subsize( $new_size_data ); if ( is_wp_error( $new_size_meta ) ) { // TODO: Log errors. } else { // Save the size meta value. $image_meta['sizes'][ $new_size_name ] = $new_size_meta; wp_update_attachment_metadata( $attachment_id, $image_meta ); } } } else { // Fall back to `$editor->multi_resize()`. $created_sizes = $editor->multi_resize( $new_sizes ); if ( ! empty( $created_sizes ) ) { $image_meta['sizes'] = array_merge( $image_meta['sizes'], $created_sizes ); wp_update_attachment_metadata( $attachment_id, $image_meta ); } } return $image_meta; } /** * Copy parent attachment properties to newly cropped image. * * @since 6.5.0 * * @param string $cropped Path to the cropped image file. * @param int $parent_attachment_id Parent file Attachment ID. * @param string $context Control calling the function. * @return array Properties of attachment. */ function wp_copy_parent_attachment_properties( $cropped, $parent_attachment_id, $context = '' ) { $parent = get_post( $parent_attachment_id ); $parent_url = wp_get_attachment_url( $parent->ID ); $parent_basename = wp_basename( $parent_url ); $url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url ); $size = wp_getimagesize( $cropped ); $image_type = $size ? $size['mime'] : 'image/jpeg'; $sanitized_post_title = sanitize_file_name( $parent->post_title ); $use_original_title = ( ( '' !== trim( $parent->post_title ) ) && /* * Check if the original image has a title other than the "filename" default, * meaning the image had a title when originally uploaded or its title was edited. */ ( $parent_basename !== $sanitized_post_title ) && ( pathinfo( $parent_basename, PATHINFO_FILENAME ) !== $sanitized_post_title ) ); $use_original_description = ( '' !== trim( $parent->post_content ) ); $attachment = array( 'post_title' => $use_original_title ? $parent->post_title : wp_basename( $cropped ), 'post_content' => $use_original_description ? $parent->post_content : $url, 'post_mime_type' => $image_type, 'guid' => $url, 'context' => $context, ); // Copy the image caption attribute (post_excerpt field) from the original image. if ( '' !== trim( $parent->post_excerpt ) ) { $attachment['post_excerpt'] = $parent->post_excerpt; } // Copy the image alt text attribute from the original image. if ( '' !== trim( $parent->_wp_attachment_image_alt ) ) { $attachment['meta_input'] = array( '_wp_attachment_image_alt' => wp_slash( $parent->_wp_attachment_image_alt ), ); } $attachment['post_parent'] = $parent_attachment_id; return $attachment; } /** * Generates attachment meta data and create image sub-sizes for images. * * @since 2.1.0 * @since 6.0.0 The `$filesize` value was added to the returned array. * @since 6.7.0 The 'image/heic' mime type is supported. * * @param int $attachment_id Attachment ID to process. * @param string $file Filepath of the attached image. * @return array Metadata for attachment. */ function wp_generate_attachment_metadata( $attachment_id, $file ) { $attachment = get_post( $attachment_id ); $metadata = array(); $support = false; $mime_type = get_post_mime_type( $attachment ); if ( 'image/heic' === $mime_type || ( preg_match( '!^image/!', $mime_type ) && file_is_displayable_image( $file ) ) ) { // Make thumbnails and other intermediate sizes. $metadata = wp_create_image_subsizes( $file, $attachment_id ); } elseif ( wp_attachment_is( 'video', $attachment ) ) { $metadata = wp_read_video_metadata( $file ); $support = current_theme_supports( 'post-thumbnails', 'attachment:video' ) || post_type_supports( 'attachment:video', 'thumbnail' ); } elseif ( wp_attachment_is( 'audio', $attachment ) ) { $metadata = wp_read_audio_metadata( $file ); $support = current_theme_supports( 'post-thumbnails', 'attachment:audio' ) || post_type_supports( 'attachment:audio', 'thumbnail' ); } /* * wp_read_video_metadata() and wp_read_audio_metadata() return `false` * if the attachment does not exist in the local filesystem, * so make sure to convert the value to an array. */ if ( ! is_array( $metadata ) ) { $metadata = array(); } if ( $support && ! empty( $metadata['image']['data'] ) ) { // Check for existing cover. $hash = md5( $metadata['image']['data'] ); $posts = get_posts( array( 'fields' => 'ids', 'post_type' => 'attachment', 'post_mime_type' => $metadata['image']['mime'], 'post_status' => 'inherit', 'posts_per_page' => 1, 'meta_key' => '_cover_hash', 'meta_value' => $hash, ) ); $exists = reset( $posts ); if ( ! empty( $exists ) ) { update_post_meta( $attachment_id, '_thumbnail_id', $exists ); } else { $ext = '.jpg'; switch ( $metadata['image']['mime'] ) { case 'image/gif': $ext = '.gif'; break; case 'image/png': $ext = '.png'; break; case 'image/webp': $ext = '.webp'; break; } $basename = str_replace( '.', '-', wp_basename( $file ) ) . '-image' . $ext; $uploaded = wp_upload_bits( $basename, '', $metadata['image']['data'] ); if ( false === $uploaded['error'] ) { $image_attachment = array( 'post_mime_type' => $metadata['image']['mime'], 'post_type' => 'attachment', 'post_content' => '', ); /** * Filters the parameters for the attachment thumbnail creation. * * @since 3.9.0 * * @param array $image_attachment An array of parameters to create the thumbnail. * @param array $metadata Current attachment metadata. * @param array $uploaded { * Information about the newly-uploaded file. * * @type string $file Filename of the newly-uploaded file. * @type string $url URL of the uploaded file. * @type string $type File type. * } */ $image_attachment = apply_filters( 'attachment_thumbnail_args', $image_attachment, $metadata, $uploaded ); $sub_attachment_id = wp_insert_attachment( $image_attachment, $uploaded['file'] ); add_post_meta( $sub_attachment_id, '_cover_hash', $hash ); $attach_data = wp_generate_attachment_metadata( $sub_attachment_id, $uploaded['file'] ); wp_update_attachment_metadata( $sub_attachment_id, $attach_data ); update_post_meta( $attachment_id, '_thumbnail_id', $sub_attachment_id ); } } } elseif ( 'application/pdf' === $mime_type ) { // Try to create image thumbnails for PDFs. $fallback_sizes = array( 'thumbnail', 'medium', 'large', ); /** * Filters the image sizes generated for non-image mime types. * * @since 4.7.0 * * @param string[] $fallback_sizes An array of image size names. * @param array $metadata Current attachment metadata. */ $fallback_sizes = apply_filters( 'fallback_intermediate_image_sizes', $fallback_sizes, $metadata ); $registered_sizes = wp_get_registered_image_subsizes(); $merged_sizes = array_intersect_key( $registered_sizes, array_flip( $fallback_sizes ) ); // Force thumbnails to be soft crops. if ( isset( $merged_sizes['thumbnail'] ) && is_array( $merged_sizes['thumbnail'] ) ) { $merged_sizes['thumbnail']['crop'] = false; } // Only load PDFs in an image editor if we're processing sizes. if ( ! empty( $merged_sizes ) ) { $editor = wp_get_image_editor( $file ); if ( ! is_wp_error( $editor ) ) { // No support for this type of file. /* * PDFs may have the same file filename as JPEGs. * Ensure the PDF preview image does not overwrite any JPEG images that already exist. */ $dirname = dirname( $file ) . '/'; $ext = '.' . pathinfo( $file, PATHINFO_EXTENSION ); $preview_file = $dirname . wp_unique_filename( $dirname, wp_basename( $file, $ext ) . '-pdf.jpg' ); $uploaded = $editor->save( $preview_file, 'image/jpeg' ); unset( $editor ); // Resize based on the full size image, rather than the source. if ( ! is_wp_error( $uploaded ) ) { $image_file = $uploaded['path']; unset( $uploaded['path'] ); $metadata['sizes'] = array( 'full' => $uploaded, ); // Save the meta data before any image post-processing errors could happen. wp_update_attachment_metadata( $attachment_id, $metadata ); // Create sub-sizes saving the image meta after each. $metadata = _wp_make_subsizes( $merged_sizes, $image_file, $metadata, $attachment_id ); } } } } // Remove the blob of binary data from the array. unset( $metadata['image']['data'] ); // Capture file size for cases where it has not been captured yet, such as PDFs. if ( ! isset( $metadata['filesize'] ) && file_exists( $file ) ) { $metadata['filesize'] = wp_filesize( $file ); } /** * Filters the generated attachment meta data. * * @since 2.1.0 * @since 5.3.0 The `$context` parameter was added. * * @param array $metadata An array of attachment meta data. * @param int $attachment_id Current attachment ID. * @param string $context Additional context. Can be 'create' when metadata was initially created for new attachment * or 'update' when the metadata was updated. */ return apply_filters( 'wp_generate_attachment_metadata', $metadata, $attachment_id, 'create' ); } /** * Converts a fraction string to a decimal. * * @since 2.5.0 * * @param string $str Fraction string. * @return int|float Returns calculated fraction or integer 0 on invalid input. */ function wp_exif_frac2dec( $str ) { if ( ! is_scalar( $str ) || is_bool( $str ) ) { return 0; } if ( ! is_string( $str ) ) { return $str; // This can only be an integer or float, so this is fine. } // Fractions passed as a string must contain a single `/`. if ( substr_count( $str, '/' ) !== 1 ) { if ( is_numeric( $str ) ) { return (float) $str; } return 0; } list( $numerator, $denominator ) = explode( '/', $str ); // Both the numerator and the denominator must be numbers. if ( ! is_numeric( $numerator ) || ! is_numeric( $denominator ) ) { return 0; } // The denominator must not be zero. if ( 0 == $denominator ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual -- Deliberate loose comparison. return 0; } return $numerator / $denominator; } /** * Converts the exif date format to a unix timestamp. * * @since 2.5.0 * * @param string $str A date string expected to be in Exif format (Y:m:d H:i:s). * @return int|false The unix timestamp, or false on failure. */ function wp_exif_date2ts( $str ) { list( $date, $time ) = explode( ' ', trim( $str ) ); list( $y, $m, $d ) = explode( ':', $date ); return strtotime( "{$y}-{$m}-{$d} {$time}" ); } /** * Gets extended image metadata, exif or iptc as available. * * Retrieves the EXIF metadata aperture, credit, camera, caption, copyright, iso * created_timestamp, focal_length, shutter_speed, and title. * * The IPTC metadata that is retrieved is APP13, credit, byline, created date * and time, caption, copyright, alt, and title. Also includes FNumber, Model, * DateTimeDigitized, FocalLength, ISOSpeedRatings, and ExposureTime. * * @todo Try other exif libraries if available. * @since 2.5.0 * * @param string $file * @return array|false Image metadata array on success, false on failure. */ function wp_read_image_metadata( $file ) { if ( ! file_exists( $file ) ) { return false; } $image_size = wp_getimagesize( $file ); if ( false === $image_size ) { return false; } list( , , $image_type ) = $image_size; /* * EXIF contains a bunch of data we'll probably never need formatted in ways * that are difficult to use. We'll normalize it and just extract the fields * that are likely to be useful. Fractions and numbers are converted to * floats, dates to unix timestamps, and everything else to strings. */ $meta = array( 'aperture' => 0, 'credit' => '', 'camera' => '', 'caption' => '', 'created_timestamp' => 0, 'copyright' => '', 'focal_length' => 0, 'iso' => 0, 'shutter_speed' => 0, 'title' => '', 'orientation' => 0, 'keywords' => array(), 'alt' => '', ); $iptc = array(); $info = array(); /* * Read IPTC first, since it might contain data not available in exif such * as caption, description etc. */ if ( is_callable( 'iptcparse' ) ) { wp_getimagesize( $file, $info ); if ( ! empty( $info['APP13'] ) ) { // Don't silence errors when in debug mode, unless running unit tests. if ( defined( 'WP_DEBUG' ) && WP_DEBUG && ! defined( 'WP_RUN_CORE_TESTS' ) ) { $iptc = iptcparse( $info['APP13'] ); } else { // Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480 $iptc = @iptcparse( $info['APP13'] ); } if ( ! is_array( $iptc ) ) { $iptc = array(); } // Headline, "A brief synopsis of the caption". if ( ! empty( $iptc['2#105'][0] ) ) { $meta['title'] = trim( $iptc['2#105'][0] ); /* * Title, "Many use the Title field to store the filename of the image, * though the field may be used in many ways". */ } elseif ( ! empty( $iptc['2#005'][0] ) ) { $meta['title'] = trim( $iptc['2#005'][0] ); } if ( ! empty( $iptc['2#120'][0] ) ) { // Description / legacy caption. $caption = trim( $iptc['2#120'][0] ); mbstring_binary_safe_encoding(); $caption_length = strlen( $caption ); reset_mbstring_encoding(); if ( empty( $meta['title'] ) && $caption_length < 80 ) { // Assume the title is stored in 2:120 if it's short. $meta['title'] = $caption; } $meta['caption'] = $caption; } if ( ! empty( $iptc['2#110'][0] ) ) { // Credit. $meta['credit'] = trim( $iptc['2#110'][0] ); } elseif ( ! empty( $iptc['2#080'][0] ) ) { // Creator / legacy byline. $meta['credit'] = trim( $iptc['2#080'][0] ); } if ( ! empty( $iptc['2#055'][0] ) && ! empty( $iptc['2#060'][0] ) ) { // Created date and time. $meta['created_timestamp'] = strtotime( $iptc['2#055'][0] . ' ' . $iptc['2#060'][0] ); } if ( ! empty( $iptc['2#116'][0] ) ) { // Copyright. $meta['copyright'] = trim( $iptc['2#116'][0] ); } if ( ! empty( $iptc['2#025'][0] ) ) { // Keywords array. $meta['keywords'] = array_values( $iptc['2#025'] ); } } } $meta['alt'] = wp_get_image_alttext( $file ); $exif = array(); /** * Filters the image types to check for exif data. * * @since 2.5.0 * * @param int[] $image_types Array of image types to check for exif data. Each value * is usually one of the `IMAGETYPE_*` constants. */ $exif_image_types = apply_filters( 'wp_read_image_metadata_types', array( IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ) ); if ( is_callable( 'exif_read_data' ) && in_array( $image_type, $exif_image_types, true ) ) { // Don't silence errors when in debug mode, unless running unit tests. if ( defined( 'WP_DEBUG' ) && WP_DEBUG && ! defined( 'WP_RUN_CORE_TESTS' ) ) { $exif = exif_read_data( $file ); } else { // Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480 $exif = @exif_read_data( $file ); } if ( ! is_array( $exif ) ) { $exif = array(); } $exif_description = ''; $exif_usercomment = ''; if ( ! empty( $exif['ImageDescription'] ) ) { $exif_description = trim( $exif['ImageDescription'] ); } if ( ! empty( $exif['COMPUTED']['UserComment'] ) ) { $exif_usercomment = trim( $exif['COMPUTED']['UserComment'] ); } if ( $exif_description ) { mbstring_binary_safe_encoding(); $description_length = strlen( $exif_description ); reset_mbstring_encoding(); if ( empty( $meta['title'] ) && $description_length < 80 ) { // Assume the title is stored in ImageDescription. $meta['title'] = $exif_description; } // If both user comments and description are present. if ( empty( $meta['caption'] ) && $exif_usercomment ) { if ( ! empty( $meta['title'] ) && $exif_description === $meta['title'] ) { $caption = $exif_usercomment; } else { if ( $exif_description === $exif_usercomment ) { $caption = $exif_description; } else { $caption = trim( $exif_description . ' ' . $exif_usercomment ); } } $meta['caption'] = $caption; } if ( empty( $meta['caption'] ) && $exif_usercomment ) { $meta['caption'] = $exif_usercomment; } if ( empty( $meta['caption'] ) ) { $meta['caption'] = $exif_description; } } elseif ( empty( $meta['caption'] ) && $exif_usercomment ) { $meta['caption'] = $exif_usercomment; $description_length = strlen( $exif_usercomment ); if ( empty( $meta['title'] ) && $description_length < 80 ) { $meta['title'] = trim( $exif_usercomment ); } } elseif ( empty( $meta['caption'] ) && ! empty( $exif['Comments'] ) ) { $meta['caption'] = trim( $exif['Comments'] ); } if ( empty( $meta['credit'] ) ) { if ( ! empty( $exif['Artist'] ) ) { $meta['credit'] = trim( $exif['Artist'] ); } elseif ( ! empty( $exif['Author'] ) ) { $meta['credit'] = trim( $exif['Author'] ); } } if ( empty( $meta['copyright'] ) && ! empty( $exif['Copyright'] ) ) { $meta['copyright'] = trim( $exif['Copyright'] ); } if ( ! empty( $exif['FNumber'] ) && is_scalar( $exif['FNumber'] ) ) { $meta['aperture'] = round( wp_exif_frac2dec( $exif['FNumber'] ), 2 ); } if ( ! empty( $exif['Model'] ) ) { $meta['camera'] = trim( $exif['Model'] ); } if ( empty( $meta['created_timestamp'] ) && ! empty( $exif['DateTimeDigitized'] ) ) { $meta['created_timestamp'] = wp_exif_date2ts( $exif['DateTimeDigitized'] ); } if ( ! empty( $exif['FocalLength'] ) ) { $meta['focal_length'] = (string) $exif['FocalLength']; if ( is_scalar( $exif['FocalLength'] ) ) { $meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] ); } } if ( ! empty( $exif['ISOSpeedRatings'] ) ) { $meta['iso'] = is_array( $exif['ISOSpeedRatings'] ) ? reset( $exif['ISOSpeedRatings'] ) : $exif['ISOSpeedRatings']; $meta['iso'] = trim( $meta['iso'] ); } if ( ! empty( $exif['ExposureTime'] ) ) { $meta['shutter_speed'] = (string) $exif['ExposureTime']; if ( is_scalar( $exif['ExposureTime'] ) ) { $meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] ); } } if ( ! empty( $exif['Orientation'] ) ) { $meta['orientation'] = $exif['Orientation']; } } foreach ( array( 'title', 'caption', 'credit', 'copyright', 'camera', 'iso' ) as $key ) { if ( $meta[ $key ] && ! wp_is_valid_utf8( $meta[ $key ] ) ) { $meta[ $key ] = utf8_encode( $meta[ $key ] ); } } foreach ( $meta['keywords'] as $key => $keyword ) { if ( ! wp_is_valid_utf8( $keyword ) ) { $meta['keywords'][ $key ] = utf8_encode( $keyword ); } } $meta = wp_kses_post_deep( $meta ); /** * Filters the array of meta data read from an image's exif data. * * @since 2.5.0 * @since 4.4.0 The `$iptc` parameter was added. * @since 5.0.0 The `$exif` parameter was added. * * @param array $meta Image meta data. * @param string $file Path to image file. * @param int $image_type Type of image, one of the `IMAGETYPE_XXX` constants. * @param array $iptc IPTC data. * @param array $exif EXIF data. */ return apply_filters( 'wp_read_image_metadata', $meta, $file, $image_type, $iptc, $exif ); } /** * Gets the alt text from image meta data. * * @since 7.0.0 * * @param string $file File path to the image. * @return string Embedded alternative text. */ function wp_get_image_alttext( $file ) { $alt_text = ''; $img_contents = file_get_contents( $file ); if ( false === $img_contents ) { return $alt_text; } // Find the start and end positions of the XMP metadata. $xmp_start = strpos( $img_contents, '<x:xmpmeta' ); $xmp_end = strpos( $img_contents, '</x:xmpmeta>' ); if ( false === $xmp_start || false === $xmp_end ) { // No XMP metadata found. return $alt_text; } // Extract the XMP metadata from the JPEG contents $xmp_data = substr( $img_contents, $xmp_start, $xmp_end - $xmp_start + 12 ); // Parse the XMP metadata using DOMDocument. $doc = new DOMDocument(); if ( false === $doc->loadXML( $xmp_data ) ) { // Invalid XML in metadata. return $alt_text; } // Instantiate an XPath object, used to extract portions of the XMP. $xpath = new DOMXPath( $doc ); // Register the relevant XML namespaces. $xpath->registerNamespace( 'x', 'adobe:ns:meta/' ); $xpath->registerNamespace( 'rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' ); $xpath->registerNamespace( 'Iptc4xmpCore', 'http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/' ); $node_list = $xpath->query( '/x:xmpmeta/rdf:RDF/rdf:Description/Iptc4xmpCore:AltTextAccessibility' ); if ( $node_list && $node_list->count() ) { $node = $node_list->item( 0 ); // Get the site's locale. $locale = get_locale(); // Get the alt text accessibility alternative most appropriate for the site language. // There are 3 possibilities: // // 1. there is an rdf:li with an exact match on the site locale. // 2. there is an rdf:li with a partial match on the site locale (e.g., site locale is en_US and rdf:li has @xml:lang="en"). // 3. there is an rdf:li with an "x-default" lang. // // Evaluate in that order, stopping when we have a match. $alt_text = $xpath->evaluate( "string( rdf:Alt/rdf:li[ @xml:lang = '{$locale}' ] )", $node ); if ( ! $alt_text ) { $alt_text = $xpath->evaluate( 'string( rdf:Alt/rdf:li[ @xml:lang = "' . substr( $locale, 0, 2 ) . '" ] )', $node ); if ( ! $alt_text ) { $alt_text = $xpath->evaluate( 'string( rdf:Alt/rdf:li[ @xml:lang = "x-default" ] )', $node ); } } } return $alt_text; } /** * Validates that file is an image. * * @since 2.5.0 * * @param string $path File path to test if valid image. * @return bool True if valid image, false if not valid image. */ function file_is_valid_image( $path ) { $size = wp_getimagesize( $path ); return ! empty( $size ); } /** * Validates that file is suitable for displaying within a web page. * * @since 2.5.0 * * @param string $path File path to test. * @return bool True if suitable, false if not suitable. */ function file_is_displayable_image( $path ) { $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP, IMAGETYPE_AVIF ); $info = wp_getimagesize( $path ); if ( empty( $info ) ) { $result = false; } elseif ( ! in_array( $info[2], $displayable_image_types, true ) ) { $result = false; } else { $result = true; } /** * Filters whether the current image is displayable in the browser. * * @since 2.5.0 * * @param bool $result Whether the image can be displayed. Default true. * @param string $path Path to the image. */ return apply_filters( 'file_is_displayable_image', $result, $path ); } /** * Loads an image resource for editing. * * @since 2.9.0 * * @param int $attachment_id Attachment ID. * @param string $mime_type Image mime type. * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array * of width and height values in pixels (in that order). Default 'full'. * @return resource|GdImage|false The resulting image resource or GdImage instance on success, * false on failure. */ function load_image_to_edit( $attachment_id, $mime_type, $size = 'full' ) { $filepath = _load_image_to_edit_path( $attachment_id, $size ); if ( empty( $filepath ) ) { return false; } switch ( $mime_type ) { case 'image/jpeg': $image = imagecreatefromjpeg( $filepath ); break; case 'image/png': $image = imagecreatefrompng( $filepath ); break; case 'image/gif': $image = imagecreatefromgif( $filepath ); break; case 'image/webp': $image = false; if ( function_exists( 'imagecreatefromwebp' ) ) { $image = imagecreatefromwebp( $filepath ); } break; default: $image = false; break; } if ( is_gd_image( $image ) ) { /** * Filters the current image being loaded for editing. * * @since 2.9.0 * * @param resource|GdImage $image Current image. * @param int $attachment_id Attachment ID. * @param string|int[] $size Requested image size. Can be any registered image size name, or * an array of width and height values in pixels (in that order). */ $image = apply_filters( 'load_image_to_edit', $image, $attachment_id, $size ); if ( function_exists( 'imagealphablending' ) && function_exists( 'imagesavealpha' ) ) { imagealphablending( $image, false ); imagesavealpha( $image, true ); } } return $image; } /** * Retrieves the path or URL of an attachment's attached file. * * If the attached file is not present on the local filesystem (usually due to replication plugins), * then the URL of the file is returned if `allow_url_fopen` is supported. * * @since 3.4.0 * @access private * * @param int $attachment_id Attachment ID. * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array * of width and height values in pixels (in that order). Default 'full'. * @return string|false File path or URL on success, false on failure. */ function _load_image_to_edit_path( $attachment_id, $size = 'full' ) { $filepath = get_attached_file( $attachment_id ); if ( $filepath && file_exists( $filepath ) ) { if ( 'full' !== $size ) { $data = image_get_intermediate_size( $attachment_id, $size ); if ( $data ) { $filepath = path_join( dirname( $filepath ), $data['file'] ); /** * Filters the path to an attachment's file when editing the image. * * The filter is evaluated for all image sizes except 'full'. * * @since 3.1.0 * * @param string $path Path to the current image. * @param int $attachment_id Attachment ID. * @param string|int[] $size Requested image size. Can be any registered image size name, or * an array of width and height values in pixels (in that order). */ $filepath = apply_filters( 'load_image_to_edit_filesystempath', $filepath, $attachment_id, $size ); } } } elseif ( function_exists( 'fopen' ) && ini_get( 'allow_url_fopen' ) ) { /** * Filters the path to an attachment's URL when editing the image. * * The filter is only evaluated if the file isn't stored locally and `allow_url_fopen` is enabled on the server. * * @since 3.1.0 * * @param string|false $image_url Current image URL. * @param int $attachment_id Attachment ID. * @param string|int[] $size Requested image size. Can be any registered image size name, or * an array of width and height values in pixels (in that order). */ $filepath = apply_filters( 'load_image_to_edit_attachmenturl', wp_get_attachment_url( $attachment_id ), $attachment_id, $size ); } /** * Filters the returned path or URL of the current image. * * @since 2.9.0 * * @param string|false $filepath File path or URL to current image, or false. * @param int $attachment_id Attachment ID. * @param string|int[] $size Requested image size. Can be any registered image size name, or * an array of width and height values in pixels (in that order). */ return apply_filters( 'load_image_to_edit_path', $filepath, $attachment_id, $size ); } /** * Copies an existing image file. * * @since 3.4.0 * @access private * * @param int $attachment_id Attachment ID. * @return string|false New file path on success, false on failure. */ function _copy_image_file( $attachment_id ) { $dst_file = get_attached_file( $attachment_id ); $src_file = $dst_file; if ( ! file_exists( $src_file ) ) { $src_file = _load_image_to_edit_path( $attachment_id ); } if ( $src_file ) { $dst_file = str_replace( wp_basename( $dst_file ), 'copy-' . wp_basename( $dst_file ), $dst_file ); $dst_file = dirname( $dst_file ) . '/' . wp_unique_filename( dirname( $dst_file ), wp_basename( $dst_file ) ); /* * The directory containing the original file may no longer * exist when using a replication plugin. */ wp_mkdir_p( dirname( $dst_file ) ); if ( ! copy( $src_file, $dst_file ) ) { $dst_file = false; } } else { $dst_file = false; } return $dst_file; } PK $��\�H��2) 2) widgets.phpnu �[��� <?php /** * WordPress Widgets Administration API * * @package WordPress * @subpackage Administration */ /** * Display list of the available widgets. * * @since 2.5.0 * * @global array $wp_registered_widgets * @global array $wp_registered_widget_controls */ function wp_list_widgets() { global $wp_registered_widgets, $wp_registered_widget_controls; $sort = $wp_registered_widgets; usort( $sort, '_sort_name_callback' ); $done = array(); foreach ( $sort as $widget ) { if ( in_array( $widget['callback'], $done, true ) ) { // We already showed this multi-widget. continue; } $sidebar = is_active_widget( $widget['callback'], $widget['id'], false, false ); $done[] = $widget['callback']; if ( ! isset( $widget['params'][0] ) ) { $widget['params'][0] = array(); } $args = array( 'widget_id' => $widget['id'], 'widget_name' => $widget['name'], '_display' => 'template', ); if ( isset( $wp_registered_widget_controls[ $widget['id'] ]['id_base'] ) && isset( $widget['params'][0]['number'] ) ) { $id_base = $wp_registered_widget_controls[ $widget['id'] ]['id_base']; $args['_temp_id'] = "$id_base-__i__"; $args['_multi_num'] = next_widget_id_number( $id_base ); $args['_add'] = 'multi'; } else { $args['_add'] = 'single'; if ( $sidebar ) { $args['_hide'] = '1'; } } $control_args = array( 0 => $args, 1 => $widget['params'][0], ); $sidebar_args = wp_list_widget_controls_dynamic_sidebar( $control_args ); wp_widget_control( ...$sidebar_args ); } } /** * Callback to sort array by a 'name' key. * * @since 3.1.0 * @access private * * @param array $a First array. * @param array $b Second array. * @return int Comparison result. */ function _sort_name_callback( $a, $b ) { return strnatcasecmp( $a['name'], $b['name'] ); } /** * Show the widgets and their settings for a sidebar. * Used in the admin widget config screen. * * @since 2.5.0 * * @param string $sidebar Sidebar ID. * @param string $sidebar_name Optional. Sidebar name. Default empty. */ function wp_list_widget_controls( $sidebar, $sidebar_name = '' ) { add_filter( 'dynamic_sidebar_params', 'wp_list_widget_controls_dynamic_sidebar' ); $description = wp_sidebar_description( $sidebar ); echo '<div id="' . esc_attr( $sidebar ) . '" class="widgets-sortables">'; if ( $sidebar_name ) { $add_to = sprintf( /* translators: %s: Widgets sidebar name. */ __( 'Add to: %s' ), $sidebar_name ); ?> <div class="sidebar-name" data-add-to="<?php echo esc_attr( $add_to ); ?>"> <button type="button" class="handlediv hide-if-no-js" aria-expanded="true"> <span class="screen-reader-text"><?php echo esc_html( $sidebar_name ); ?></span> <span class="toggle-indicator" aria-hidden="true"></span> </button> <h2><?php echo esc_html( $sidebar_name ); ?> <span class="spinner"></span></h2> </div> <?php } if ( ! empty( $description ) ) { ?> <div class="sidebar-description"> <p class="description"><?php echo $description; ?></p> </div> <?php } dynamic_sidebar( $sidebar ); echo '</div>'; } /** * Retrieves the widget control arguments. * * @since 2.5.0 * * @global array $wp_registered_widgets * * @param array $params * @return array Widget control arguments. */ function wp_list_widget_controls_dynamic_sidebar( $params ) { global $wp_registered_widgets; static $i = 0; ++$i; $widget_id = $params[0]['widget_id']; $id = $params[0]['_temp_id'] ?? $widget_id; $hidden = isset( $params[0]['_hide'] ) ? ' style="display:none;"' : ''; $params[0]['before_widget'] = "<div id='widget-{$i}_{$id}' class='widget'$hidden>"; $params[0]['after_widget'] = '</div>'; $params[0]['before_title'] = '%BEG_OF_TITLE%'; // Deprecated. $params[0]['after_title'] = '%END_OF_TITLE%'; // Deprecated. if ( is_callable( $wp_registered_widgets[ $widget_id ]['callback'] ) ) { $wp_registered_widgets[ $widget_id ]['_callback'] = $wp_registered_widgets[ $widget_id ]['callback']; $wp_registered_widgets[ $widget_id ]['callback'] = 'wp_widget_control'; } return $params; } /** * @global array $wp_registered_widgets * * @param string $id_base * @return int Next available widget ID number. */ function next_widget_id_number( $id_base ) { global $wp_registered_widgets; $number = 1; foreach ( $wp_registered_widgets as $widget_id => $widget ) { if ( preg_match( '/' . preg_quote( $id_base, '/' ) . '-([0-9]+)$/', $widget_id, $matches ) ) { $number = max( $number, $matches[1] ); } } ++$number; return $number; } /** * Meta widget used to display the control form for a widget. * * Called from dynamic_sidebar(). * * @since 2.5.0 * * @global array $wp_registered_widgets * @global array $wp_registered_widget_controls * @global array $sidebars_widgets * * @param array $sidebar_args * @return array Passed through value of `$sidebar_args` param. */ function wp_widget_control( $sidebar_args ) { global $wp_registered_widgets, $wp_registered_widget_controls, $sidebars_widgets; $widget_id = $sidebar_args['widget_id']; $sidebar_id = $sidebar_args['id'] ?? false; $key = $sidebar_id ? array_search( $widget_id, $sidebars_widgets[ $sidebar_id ], true ) : '-1'; // Position of widget in sidebar. $control = $wp_registered_widget_controls[ $widget_id ] ?? array(); $widget = $wp_registered_widgets[ $widget_id ]; $id_format = $widget['id']; $widget_number = $control['params'][0]['number'] ?? ''; $id_base = $control['id_base'] ?? $widget_id; $width = $control['width'] ?? ''; $height = $control['height'] ?? ''; $multi_number = $sidebar_args['_multi_num'] ?? ''; $add_new = $sidebar_args['_add'] ?? ''; $before_form = $sidebar_args['before_form'] ?? '<form method="post">'; $after_form = $sidebar_args['after_form'] ?? '</form>'; $before_widget_content = $sidebar_args['before_widget_content'] ?? '<div class="widget-content">'; $after_widget_content = $sidebar_args['after_widget_content'] ?? '</div>'; $query_arg = array( 'editwidget' => $widget['id'] ); if ( $add_new ) { $query_arg['addnew'] = 1; if ( $multi_number ) { $query_arg['num'] = $multi_number; $query_arg['base'] = $id_base; } } else { $query_arg['sidebar'] = $sidebar_id; $query_arg['key'] = $key; } /* * We aren't showing a widget control, we're outputting a template * for a multi-widget control. */ if ( isset( $sidebar_args['_display'] ) && 'template' === $sidebar_args['_display'] && $widget_number ) { // number == -1 implies a template where id numbers are replaced by a generic '__i__'. $control['params'][0]['number'] = -1; // With id_base widget ID's are constructed like {$id_base}-{$id_number}. if ( isset( $control['id_base'] ) ) { $id_format = $control['id_base'] . '-__i__'; } } $wp_registered_widgets[ $widget_id ]['callback'] = $wp_registered_widgets[ $widget_id ]['_callback']; unset( $wp_registered_widgets[ $widget_id ]['_callback'] ); $widget_title = esc_html( strip_tags( $sidebar_args['widget_name'] ) ); $has_form = 'noform'; echo $sidebar_args['before_widget']; ?> <div class="widget-top"> <div class="widget-title-action"> <button type="button" class="widget-action hide-if-no-js" aria-expanded="false"> <span class="screen-reader-text edit"> <?php /* translators: Hidden accessibility text. %s: Widget title. */ printf( __( 'Edit widget: %s' ), $widget_title ); ?> </span> <span class="screen-reader-text add"> <?php /* translators: Hidden accessibility text. %s: Widget title. */ printf( __( 'Add widget: %s' ), $widget_title ); ?> </span> <span class="toggle-indicator" aria-hidden="true"></span> </button> <a class="widget-control-edit hide-if-js" href="<?php echo esc_url( add_query_arg( $query_arg ) ); ?>"> <span class="edit"><?php _ex( 'Edit', 'widget' ); ?></span> <span class="add"><?php _ex( 'Add', 'widget' ); ?></span> <span class="screen-reader-text"><?php echo $widget_title; ?></span> </a> </div> <div class="widget-title"><h3><?php echo $widget_title; ?><span class="in-widget-title"></span></h3></div> </div> <div class="widget-inside"> <?php echo $before_form; ?> <?php echo $before_widget_content; ?> <?php if ( isset( $control['callback'] ) ) { $has_form = call_user_func_array( $control['callback'], $control['params'] ); } else { echo "\t\t<p>" . __( 'There are no options for this widget.' ) . "</p>\n"; } $noform_class = ''; if ( 'noform' === $has_form ) { $noform_class = ' widget-control-noform'; } ?> <?php echo $after_widget_content; ?> <input type="hidden" name="widget-id" class="widget-id" value="<?php echo esc_attr( $id_format ); ?>" /> <input type="hidden" name="id_base" class="id_base" value="<?php echo esc_attr( $id_base ); ?>" /> <input type="hidden" name="widget-width" class="widget-width" value="<?php echo esc_attr( $width ); ?>" /> <input type="hidden" name="widget-height" class="widget-height" value="<?php echo esc_attr( $height ); ?>" /> <input type="hidden" name="widget_number" class="widget_number" value="<?php echo esc_attr( $widget_number ); ?>" /> <input type="hidden" name="multi_number" class="multi_number" value="<?php echo esc_attr( $multi_number ); ?>" /> <input type="hidden" name="add_new" class="add_new" value="<?php echo esc_attr( $add_new ); ?>" /> <div class="widget-control-actions"> <div class="alignleft"> <button type="button" class="button-link button-link-delete widget-control-remove"><?php _e( 'Delete' ); ?></button> <span class="widget-control-close-wrapper"> | <button type="button" class="button-link widget-control-close"><?php _e( 'Done' ); ?></button> </span> </div> <div class="alignright<?php echo $noform_class; ?>"> <?php submit_button( __( 'Save' ), 'primary widget-control-save right', 'savewidget', false, array( 'id' => 'widget-' . esc_attr( $id_format ) . '-savewidget' ) ); ?> <span class="spinner"></span> </div> </div> <?php echo $after_form; ?> </div> <div class="widget-description"> <?php $widget_description = wp_widget_description( $widget_id ); echo ( $widget_description ) ? "$widget_description\n" : "$widget_title\n"; ?> </div> <?php echo $sidebar_args['after_widget']; return $sidebar_args; } /** * @param string $classes * @return string Modified body classes. */ function wp_widgets_access_body_class( $classes ) { return "$classes widgets_access "; } PK $��\�wAf� � class-wp-upgrader-skins.phpnu �[��� <?php /** * The User Interface "Skins" for the WordPress File Upgrader * * @package WordPress * @subpackage Upgrader * @since 2.8.0 * @deprecated 4.7.0 */ _deprecated_file( basename( __FILE__ ), '4.7.0', 'class-wp-upgrader.php' ); /** WP_Upgrader_Skin class */ require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader-skin.php'; /** Plugin_Upgrader_Skin class */ require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader-skin.php'; /** Theme_Upgrader_Skin class */ require_once ABSPATH . 'wp-admin/includes/class-theme-upgrader-skin.php'; /** Bulk_Upgrader_Skin class */ require_once ABSPATH . 'wp-admin/includes/class-bulk-upgrader-skin.php'; /** Bulk_Plugin_Upgrader_Skin class */ require_once ABSPATH . 'wp-admin/includes/class-bulk-plugin-upgrader-skin.php'; /** Bulk_Theme_Upgrader_Skin class */ require_once ABSPATH . 'wp-admin/includes/class-bulk-theme-upgrader-skin.php'; /** Plugin_Installer_Skin class */ require_once ABSPATH . 'wp-admin/includes/class-plugin-installer-skin.php'; /** Theme_Installer_Skin class */ require_once ABSPATH . 'wp-admin/includes/class-theme-installer-skin.php'; /** Language_Pack_Upgrader_Skin class */ require_once ABSPATH . 'wp-admin/includes/class-language-pack-upgrader-skin.php'; /** Automatic_Upgrader_Skin class */ require_once ABSPATH . 'wp-admin/includes/class-automatic-upgrader-skin.php'; /** WP_Ajax_Upgrader_Skin class */ require_once ABSPATH . 'wp-admin/includes/class-wp-ajax-upgrader-skin.php'; PK $��\^�c( c( class-wp-themes-list-table.phpnu �[��� <?php /** * List Table API: WP_Themes_List_Table class * * @package WordPress * @subpackage Administration * @since 3.1.0 */ /** * Core class used to implement displaying installed themes in a list table. * * @since 3.1.0 * * @see WP_List_Table */ class WP_Themes_List_Table extends WP_List_Table { protected $search_terms = array(); public $features = array(); /** * Constructor. * * @since 3.1.0 * * @see WP_List_Table::__construct() for more information on default arguments. * * @param array $args An associative array of arguments. */ public function __construct( $args = array() ) { parent::__construct( array( 'ajax' => true, 'screen' => $args['screen'] ?? null, ) ); } /** * @return bool */ public function ajax_user_can() { // Do not check edit_theme_options here. Ajax calls for available themes require switch_themes. return current_user_can( 'switch_themes' ); } /** */ public function prepare_items() { $themes = wp_get_themes( array( 'allowed' => true ) ); if ( ! empty( $_REQUEST['s'] ) ) { $this->search_terms = array_unique( array_filter( array_map( 'trim', explode( ',', strtolower( wp_unslash( $_REQUEST['s'] ) ) ) ) ) ); } if ( ! empty( $_REQUEST['features'] ) ) { $this->features = $_REQUEST['features']; } if ( $this->search_terms || $this->features ) { foreach ( $themes as $key => $theme ) { if ( ! $this->search_theme( $theme ) ) { unset( $themes[ $key ] ); } } } unset( $themes[ get_option( 'stylesheet' ) ] ); WP_Theme::sort_by_name( $themes ); $per_page = 36; $page = $this->get_pagenum(); $start = ( $page - 1 ) * $per_page; $this->items = array_slice( $themes, $start, $per_page, true ); $this->set_pagination_args( array( 'total_items' => count( $themes ), 'per_page' => $per_page, 'infinite_scroll' => true, ) ); } /** */ public function no_items() { if ( $this->search_terms || $this->features ) { _e( 'No items found.' ); return; } $blog_id = get_current_blog_id(); if ( is_multisite() ) { if ( current_user_can( 'install_themes' ) && current_user_can( 'manage_network_themes' ) ) { printf( /* translators: 1: URL to Themes tab on Edit Site screen, 2: URL to Add Themes screen. */ __( 'You only have one theme enabled for this site right now. Visit the Network Admin to <a href="%1$s">enable</a> or <a href="%2$s">install</a> more themes.' ), network_admin_url( 'site-themes.php?id=' . $blog_id ), network_admin_url( 'theme-install.php' ) ); return; } elseif ( current_user_can( 'manage_network_themes' ) ) { printf( /* translators: %s: URL to Themes tab on Edit Site screen. */ __( 'You only have one theme enabled for this site right now. Visit the Network Admin to <a href="%s">enable</a> more themes.' ), network_admin_url( 'site-themes.php?id=' . $blog_id ) ); return; } // Else, fallthrough. install_themes doesn't help if you can't enable it. } else { if ( current_user_can( 'install_themes' ) ) { printf( /* translators: %s: URL to Add Themes screen. */ __( 'You only have one theme installed right now. Live a little! You can choose from over 1,000 free themes in the WordPress Theme Directory at any time: just click on the <a href="%s">Install Themes</a> tab above.' ), admin_url( 'theme-install.php' ) ); return; } } // Fallthrough. printf( /* translators: %s: Network title. */ __( 'Only the active theme is available to you. Contact the %s administrator for information about accessing additional themes.' ), get_site_option( 'site_name' ) ); } /** * @param string $which */ public function tablenav( $which = 'top' ) { if ( $this->get_pagination_arg( 'total_pages' ) <= 1 ) { return; } ?> <div class="tablenav themes <?php echo $which; ?>"> <?php $this->pagination( $which ); ?> <span class="spinner"></span> <br class="clear" /> </div> <?php } /** * Displays the themes table. * * Overrides the parent display() method to provide a different container. * * @since 3.1.0 */ public function display() { wp_nonce_field( 'fetch-list-' . get_class( $this ), '_ajax_fetch_list_nonce' ); ?> <?php $this->tablenav( 'top' ); ?> <div id="availablethemes"> <?php $this->display_rows_or_placeholder(); ?> </div> <?php $this->tablenav( 'bottom' ); ?> <?php } /** * @return string[] Array of column titles keyed by their column name. */ public function get_columns() { return array(); } /** */ public function display_rows_or_placeholder() { if ( $this->has_items() ) { $this->display_rows(); } else { echo '<div class="no-items">'; $this->no_items(); echo '</div>'; } } /** * Generates the list table rows. * * @since 3.1.0 */ public function display_rows() { $themes = $this->items; foreach ( $themes as $theme ) : ?> <div class="available-theme"> <?php $template = $theme->get_template(); $stylesheet = $theme->get_stylesheet(); $title = $theme->display( 'Name' ); $version = $theme->display( 'Version' ); $author = $theme->display( 'Author' ); $activate_link = wp_nonce_url( 'themes.php?action=activate&template=' . urlencode( $template ) . '&stylesheet=' . urlencode( $stylesheet ), 'switch-theme_' . $stylesheet ); $actions = array(); $actions['activate'] = sprintf( '<a href="%s" class="activatelink" aria-label="%s">%s</a>', $activate_link, /* translators: %s: Theme name. */ esc_attr( sprintf( _x( 'Activate “%s”', 'theme' ), $title ) ), _x( 'Activate', 'theme' ) ); if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { $actions['preview'] .= sprintf( '<a href="%s" class="load-customize hide-if-no-customize">%s</a>', wp_customize_url( $stylesheet ), __( 'Live Preview' ) ); } if ( ! is_multisite() && current_user_can( 'delete_themes' ) ) { $actions['delete'] = sprintf( '<a class="submitdelete deletion" href="%s" onclick="return confirm( \'%s\' );">%s</a>', wp_nonce_url( 'themes.php?action=delete&stylesheet=' . urlencode( $stylesheet ), 'delete-theme_' . $stylesheet ), /* translators: %s: Theme name. */ esc_js( sprintf( __( "You are about to delete this theme '%s'\n 'Cancel' to stop, 'OK' to delete." ), $title ) ), __( 'Delete' ) ); } /** This filter is documented in wp-admin/includes/class-wp-ms-themes-list-table.php */ $actions = apply_filters( 'theme_action_links', $actions, $theme, 'all' ); /** This filter is documented in wp-admin/includes/class-wp-ms-themes-list-table.php */ $actions = apply_filters( "theme_action_links_{$stylesheet}", $actions, $theme, 'all' ); $delete_action = isset( $actions['delete'] ) ? '<div class="delete-theme">' . $actions['delete'] . '</div>' : ''; unset( $actions['delete'] ); $screenshot = $theme->get_screenshot(); ?> <span class="screenshot hide-if-customize"> <?php if ( $screenshot ) : ?> <img src="<?php echo esc_url( $screenshot . '?ver=' . $theme->version ); ?>" alt="" /> <?php endif; ?> </span> <a href="<?php echo wp_customize_url( $stylesheet ); ?>" class="screenshot load-customize hide-if-no-customize"> <?php if ( $screenshot ) : ?> <img src="<?php echo esc_url( $screenshot . '?ver=' . $theme->version ); ?>" alt="" /> <?php endif; ?> </a> <h3><?php echo $title; ?></h3> <div class="theme-author"> <?php /* translators: %s: Theme author. */ printf( __( 'By %s' ), $author ); ?> </div> <div class="action-links"> <ul> <?php foreach ( $actions as $action ) : ?> <li><?php echo $action; ?></li> <?php endforeach; ?> <li class="hide-if-no-js"><a href="#" class="theme-detail"><?php _e( 'Details' ); ?></a></li> </ul> <?php echo $delete_action; ?> <?php theme_update_available( $theme ); ?> </div> <div class="themedetaildiv hide-if-js"> <p><strong><?php _e( 'Version:' ); ?></strong> <?php echo $version; ?></p> <p><?php echo $theme->display( 'Description' ); ?></p> <?php if ( $theme->parent() ) { printf( /* translators: 1: Link to documentation on child themes, 2: Name of parent theme. */ ' <p class="howto">' . __( 'This <a href="%1$s">child theme</a> requires its parent theme, %2$s.' ) . '</p>', __( 'https://developer.wordpress.org/themes/advanced-topics/child-themes/' ), $theme->parent()->display( 'Name' ) ); } ?> </div> </div> <?php endforeach; } /** * @param WP_Theme $theme * @return bool */ public function search_theme( $theme ) { // Search the features. foreach ( $this->features as $word ) { if ( ! in_array( $word, $theme->get( 'Tags' ), true ) ) { return false; } } // Match all phrases. foreach ( $this->search_terms as $word ) { if ( in_array( $word, $theme->get( 'Tags' ), true ) ) { continue; } foreach ( array( 'Name', 'Description', 'Author', 'AuthorURI' ) as $header ) { // Don't mark up; Do translate. if ( false !== stripos( strip_tags( $theme->display( $header, false, true ) ), $word ) ) { continue 2; } } if ( false !== stripos( $theme->get_stylesheet(), $word ) ) { continue; } if ( false !== stripos( $theme->get_template(), $word ) ) { continue; } return false; } return true; } /** * Send required variables to JavaScript land * * @since 3.4.0 * * @param array $extra_args */ public function _js_vars( $extra_args = array() ) { $search_string = isset( $_REQUEST['s'] ) ? esc_attr( wp_unslash( $_REQUEST['s'] ) ) : ''; $args = array( 'search' => $search_string, 'features' => $this->features, 'paged' => $this->get_pagenum(), 'total_pages' => ! empty( $this->_pagination_args['total_pages'] ) ? $this->_pagination_args['total_pages'] : 1, ); if ( is_array( $extra_args ) ) { $args = array_merge( $args, $extra_args ); } printf( "<script>var theme_list_args = %s;</script>\n", wp_json_encode( $args, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ); parent::_js_vars(); } } PK $��\���� � class-wp-importer.phpnu �[��� <?php /** * WP_Importer base class * * @package WordPress * @subpackage Importer * @since 3.0.0 */ #[AllowDynamicProperties] class WP_Importer { /** * Class Constructor */ public function __construct() {} /** * Returns array with imported permalinks from WordPress database. * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $importer_name * @param string $blog_id * @return array */ public function get_imported_posts( $importer_name, $blog_id ) { global $wpdb; $hashtable = array(); $limit = 100; $offset = 0; // Grab all posts in chunks. do { $meta_key = $importer_name . '_' . $blog_id . '_permalink'; $results = $wpdb->get_results( $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = %s LIMIT %d,%d", $meta_key, $offset, $limit ) ); // Increment offset. $offset = ( $limit + $offset ); if ( ! empty( $results ) ) { foreach ( $results as $r ) { // Set permalinks into array. $hashtable[ $r->meta_value ] = (int) $r->post_id; } } } while ( count( $results ) === $limit ); return $hashtable; } /** * Returns count of imported permalinks from WordPress database. * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $importer_name * @param string $blog_id * @return int */ public function count_imported_posts( $importer_name, $blog_id ) { global $wpdb; $count = 0; // Get count of permalinks. $meta_key = $importer_name . '_' . $blog_id . '_permalink'; $result = $wpdb->get_results( $wpdb->prepare( "SELECT COUNT( post_id ) AS cnt FROM $wpdb->postmeta WHERE meta_key = %s", $meta_key ) ); if ( ! empty( $result ) ) { $count = (int) $result[0]->cnt; } return $count; } /** * Sets array with imported comments from WordPress database. * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $blog_id * @return array */ public function get_imported_comments( $blog_id ) { global $wpdb; $hashtable = array(); $limit = 100; $offset = 0; // Grab all comments in chunks. do { $results = $wpdb->get_results( $wpdb->prepare( "SELECT comment_ID, comment_agent FROM $wpdb->comments LIMIT %d,%d", $offset, $limit ) ); // Increment offset. $offset = ( $limit + $offset ); if ( ! empty( $results ) ) { foreach ( $results as $r ) { // Explode comment_agent key. list ( $comment_agent_blog_id, $source_comment_id ) = explode( '-', $r->comment_agent ); $source_comment_id = (int) $source_comment_id; // Check if this comment came from this blog. if ( (int) $blog_id === (int) $comment_agent_blog_id ) { $hashtable[ $source_comment_id ] = (int) $r->comment_ID; } } } } while ( count( $results ) === $limit ); return $hashtable; } /** * @param int $blog_id * @return int|void */ public function set_blog( $blog_id ) { if ( is_numeric( $blog_id ) ) { $blog_id = (int) $blog_id; } else { $blog = 'http://' . preg_replace( '#^https?://#', '', $blog_id ); $parsed = parse_url( $blog ); if ( ! $parsed || empty( $parsed['host'] ) ) { fwrite( STDERR, "Error: can not determine blog_id from $blog_id\n" ); exit; } if ( empty( $parsed['path'] ) ) { $parsed['path'] = '/'; } $blogs = get_sites( array( 'domain' => $parsed['host'], 'number' => 1, 'path' => $parsed['path'], ) ); if ( ! $blogs ) { fwrite( STDERR, "Error: Could not find blog\n" ); exit; } $blog = array_shift( $blogs ); $blog_id = (int) $blog->blog_id; } if ( function_exists( 'is_multisite' ) ) { if ( is_multisite() ) { switch_to_blog( $blog_id ); } } return $blog_id; } /** * @param int $user_id * @return int|void */ public function set_user( $user_id ) { if ( is_numeric( $user_id ) ) { $user_id = (int) $user_id; } else { $user_id = (int) username_exists( $user_id ); } if ( ! $user_id || ! wp_set_current_user( $user_id ) ) { fwrite( STDERR, "Error: can not find user\n" ); exit; } return $user_id; } /** * Sorts by strlen, longest string first. * * @param string $a * @param string $b * @return int */ public function cmpr_strlen( $a, $b ) { return strlen( $b ) - strlen( $a ); } /** * Gets URL. * * @param string $url * @param string $username * @param string $password * @param bool $head * @return array */ public function get_page( $url, $username = '', #[\SensitiveParameter] $password = '', $head = false ) { // Increase the timeout. add_filter( 'http_request_timeout', array( $this, 'bump_request_timeout' ) ); $headers = array(); $args = array(); if ( true === $head ) { $args['method'] = 'HEAD'; } if ( ! empty( $username ) && ! empty( $password ) ) { $headers['Authorization'] = 'Basic ' . base64_encode( "$username:$password" ); } $args['headers'] = $headers; return wp_safe_remote_request( $url, $args ); } /** * Bumps up the request timeout for http requests. * * @param int $val * @return int */ public function bump_request_timeout( $val ) { return 60; } /** * Checks if user has exceeded disk quota. * * @return bool */ public function is_user_over_quota() { if ( function_exists( 'upload_is_user_over_quota' ) ) { if ( upload_is_user_over_quota() ) { return true; } } return false; } /** * Replaces newlines, tabs, and multiple spaces with a single space. * * @param string $text * @return string */ public function min_whitespace( $text ) { return preg_replace( '|[\r\n\t ]+|', ' ', $text ); } /** * Resets global variables that grow out of control during imports. * * @since 3.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * @global int[] $wp_actions Stores the number of times each action was triggered. */ public function stop_the_insanity() { global $wpdb, $wp_actions; // Or define( 'WP_IMPORTING', true ); $wpdb->queries = array(); // Reset $wp_actions to keep it from growing out of control. $wp_actions = array(); } } /** * Returns value of command line params. * Exits when a required param is not set. * * @param string $param The parameter name to retrieve. * @param bool $required Optional. Whether the parameter is required. Default false. * @return string|true|null|never The parameter value or true if found, null otherwise. * The function exits when a required parameter is missing. */ function get_cli_args( $param, $required = false ) { $args = $_SERVER['argv']; if ( ! is_array( $args ) ) { $args = array(); } $out = array(); $last_arg = null; $return = null; $il = count( $args ); for ( $i = 1, $il; $i < $il; $i++ ) { if ( (bool) preg_match( '/^--(.+)/', $args[ $i ], $match ) ) { $parts = explode( '=', $match[1] ); $key = preg_replace( '/[^a-z0-9]+/', '', $parts[0] ); $out[ $key ] = $parts[1] ?? true; $last_arg = $key; } elseif ( (bool) preg_match( '/^-([a-zA-Z0-9]+)/', $args[ $i ], $match ) ) { for ( $j = 0, $jl = strlen( $match[1] ); $j < $jl; $j++ ) { $key = $match[1][ $j ]; $out[ $key ] = true; } $last_arg = $key; } elseif ( null !== $last_arg ) { $out[ $last_arg ] = $args[ $i ]; } } // Check array for specified param. if ( isset( $out[ $param ] ) ) { // Set return value. $return = $out[ $param ]; } // Check for missing required param. if ( ! isset( $out[ $param ] ) && $required ) { // Display message and exit. echo "\"$param\" parameter is required but was not specified\n"; exit; } return $return; } PK $��\�$���T �T ajax-actions.phpnu �[��� <?php /** * Administration API: Core Ajax handlers * * @package WordPress * @subpackage Administration * @since 2.1.0 */ // // No-privilege Ajax handlers. // /** * Handles the Heartbeat API in the no-privilege context via AJAX . * * Runs when the user is not logged in. * * @since 3.6.0 */ function wp_ajax_nopriv_heartbeat() { $response = array(); // 'screen_id' is the same as $current_screen->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. // /** * Handles fetching a list table via AJAX. * * @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 ); } /** * Handles tag search via AJAX. * * @since 3.1.0 */ function wp_ajax_ajax_tag_search() { if ( ! isset( $_GET['tax'] ) ) { wp_die( 0 ); } $taxonomy = sanitize_key( $_GET['tax'] ); $taxonomy_object = get_taxonomy( $taxonomy ); if ( ! $taxonomy_object ) { wp_die( 0 ); } if ( ! current_user_can( $taxonomy_object->cap->assign_terms ) ) { wp_die( -1 ); } $search = wp_unslash( $_GET['q'] ); $comma = _x( ',', 'tag delimiter' ); if ( ',' !== $comma ) { $search = str_replace( $comma, ',', $search ); } if ( str_contains( $search, ',' ) ) { $search = explode( ',', $search ); $search = $search[ count( $search ) - 1 ]; } $search = trim( $search ); /** * 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 $taxonomy_object The taxonomy object. * @param string $search The search term. */ $term_search_min_chars = (int) apply_filters( 'term_search_min_chars', 2, $taxonomy_object, $search ); /* * 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( $search ) < $term_search_min_chars ) ) { wp_die(); } $results = get_terms( array( 'taxonomy' => $taxonomy, 'name__like' => $search, 'fields' => 'names', 'hide_empty' => false, 'number' => isset( $_GET['number'] ) ? (int) $_GET['number'] : 0, ) ); /** * Filters the Ajax term search results. * * @since 6.1.0 * * @param string[] $results Array of term names. * @param WP_Taxonomy $taxonomy_object The taxonomy object. * @param string $search The search term. */ $results = apply_filters( 'ajax_term_search_results', $results, $taxonomy_object, $search ); echo implode( "\n", $results ); wp_die(); } /** * Handles compression testing via AJAX. * * @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' ) ) { // Use `update_option()` on single site to mark the option for autoloading. if ( is_multisite() ) { update_site_option( 'can_compress_scripts', 0 ); } else { update_option( 'can_compress_scripts', 0, true ); } 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' ); $output = gzdeflate( $test_str, 1 ); } elseif ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) && function_exists( 'gzencode' ) ) { header( 'Content-Encoding: gzip' ); $output = gzencode( $test_str, 1 ); } else { wp_die( -1 ); } echo $output; wp_die(); } elseif ( 'no' === $_GET['test'] ) { check_ajax_referer( 'update_can_compress_scripts' ); // Use `update_option()` on single site to mark the option for autoloading. if ( is_multisite() ) { update_site_option( 'can_compress_scripts', 0 ); } else { update_option( 'can_compress_scripts', 0, true ); } } elseif ( 'yes' === $_GET['test'] ) { check_ajax_referer( 'update_can_compress_scripts' ); // Use `update_option()` on single site to mark the option for autoloading. if ( is_multisite() ) { update_site_option( 'can_compress_scripts', 1 ); } else { update_option( 'can_compress_scripts', 1, true ); } } } wp_die( 0 ); } /** * Handles image editor previews via AJAX. * * @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" ); require_once ABSPATH . 'wp-admin/includes/image-edit.php'; if ( ! stream_preview_image( $post_id ) ) { wp_die( -1 ); } wp_die(); } /** * Handles oEmbed caching via AJAX. * * @since 3.1.0 * * @global WP_Embed $wp_embed WordPress Embed object. */ function wp_ajax_oembed_cache() { $GLOBALS['wp_embed']->cache_oembed( $_GET['post'] ); wp_die( 0 ); } /** * Handles user autocomplete via AJAX. * * @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_meta( $user_id, 'community-events-location', $events['location'] ); } wp_send_json_success( $events ); } } /** * Handles dashboard widgets via AJAX. * * @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(); } /** * Handles Customizer preview logged-in status via AJAX. * * @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 Comment ID. * @param int $delta Optional. Change in the number of total comments. Default -1. */ 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'] ) ? sanitize_url( $_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(); $response = 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, ), ) ); $response->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(); $response = 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' => (int) ceil( $total / $per_page ), 'total_pages_i18n' => number_format_i18n( (int) 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 ) ), ), ) ); $response->send(); } // // POST-based Ajax handlers. // /** * Handles adding a hierarchical term via AJAX. * * @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 $category_name ) { $category_name = trim( $category_name ); $category_nicename = sanitize_title( $category_name ); if ( '' === $category_nicename ) { continue; } $category_id = wp_insert_term( $category_name, $taxonomy->name, array( 'parent' => $parent ) ); if ( ! $category_id || is_wp_error( $category_id ) ) { continue; } else { $category_id = $category_id['term_id']; } $checked_categories[] = $category_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' => $category_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids, ) ); $data = ob_get_clean(); $add = array( 'what' => $taxonomy->name, 'id' => $category_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, ); } $parent_dropdown_args = array( 'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new' . $taxonomy->name . '_parent', 'orderby' => 'name', 'hierarchical' => 1, 'show_option_none' => '— ' . $taxonomy->labels->parent_item . ' —', ); /** This filter is documented in wp-admin/includes/meta-boxes.php */ $parent_dropdown_args = apply_filters( 'post_edit_category_parent_dropdown_args', $parent_dropdown_args ); ob_start(); wp_dropdown_categories( $parent_dropdown_args ); $supplemental = ob_get_clean(); $add['supplemental'] = array( 'newcat_parent' => $supplemental ); $response = new WP_Ajax_Response( $add ); $response->send(); } /** * Handles deleting a comment via AJAX. * * @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() ); } $result = wp_trash_comment( $comment ); } elseif ( isset( $_POST['untrash'] ) && '1' === $_POST['untrash'] ) { if ( 'trash' !== $status ) { wp_die( time() ); } $result = 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() ); } $result = wp_spam_comment( $comment ); } elseif ( isset( $_POST['unspam'] ) && '1' === $_POST['unspam'] ) { if ( 'spam' !== $status ) { wp_die( time() ); } $result = 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'] ) { $result = wp_delete_comment( $comment ); } else { wp_die( -1 ); } if ( $result ) { // 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 ); } /** * Handles deleting a tag via AJAX. * * @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 ); } } /** * Handles deleting a link via AJAX. * * @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 ); } } /** * Handles deleting meta via AJAX. * * @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 ); } /** * Handles deleting a post via AJAX. * * @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 ); } } /** * Handles sending a post to the Trash via AJAX. * * @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 ); } /** * Handles restoring a post from the Trash via AJAX. * * @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 ); } /** * Handles deleting a page via AJAX. * * @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 ); } } /** * Handles dimming a comment via AJAX. * * @since 3.1.0 */ function wp_ajax_dim_comment() { $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0; $comment = get_comment( $id ); if ( ! $comment ) { $response = new WP_Ajax_Response( array( 'what' => 'comment', 'id' => new WP_Error( 'invalid_comment', /* translators: %d: Comment ID. */ sprintf( __( 'Comment %d does not exist' ), $id ) ), ) ); $response->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 ) ) { $response = new WP_Ajax_Response( array( 'what' => 'comment', 'id' => $result, ) ); $response->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 ); } /** * Handles adding a link category via AJAX. * * @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 ); $taxonomy_object = get_taxonomy( 'link_category' ); if ( ! current_user_can( $taxonomy_object->cap->manage_terms ) ) { wp_die( -1 ); } $names = explode( ',', wp_unslash( $_POST['newcat'] ) ); $response = new WP_Ajax_Response(); foreach ( $names as $category_name ) { $category_name = trim( $category_name ); $slug = sanitize_title( $category_name ); if ( '' === $slug ) { continue; } $category_id = wp_insert_term( $category_name, 'link_category' ); if ( ! $category_id || is_wp_error( $category_id ) ) { continue; } else { $category_id = $category_id['term_id']; } $category_name = esc_html( $category_name ); $response->add( array( 'what' => 'link-category', 'id' => $category_id, 'data' => "<li id='link-category-$category_id'><label for='in-link-category-$category_id' class='selectit'><input value='" . esc_attr( $category_id ) . "' type='checkbox' checked='checked' name='link_category[]' id='in-link-category-$category_id'/> $category_name</label></li>", 'position' => -1, ) ); } $response->send(); } /** * Handles adding a tag via AJAX. * * @since 3.1.0 */ function wp_ajax_add_tag() { check_ajax_referer( 'add-tag', '_wpnonce_add-tag' ); $taxonomy = ! empty( $_POST['taxonomy'] ) ? $_POST['taxonomy'] : 'post_tag'; $taxonomy_object = get_taxonomy( $taxonomy ); if ( ! current_user_can( $taxonomy_object->cap->edit_terms ) ) { wp_die( -1 ); } $response = new WP_Ajax_Response(); $tag = wp_insert_term( $_POST['tag-name'], $taxonomy, $_POST ); if ( $tag && ! is_wp_error( $tag ) ) { $tag = get_term( $tag['term_id'], $taxonomy ); } if ( ! $tag || is_wp_error( $tag ) ) { $message = __( 'An error has occurred. Please reload the page and try again.' ); $error_code = 'error'; if ( is_wp_error( $tag ) && $tag->get_error_message() ) { $message = $tag->get_error_message(); } if ( is_wp_error( $tag ) && $tag->get_error_code() ) { $error_code = $tag->get_error_code(); } $response->add( array( 'what' => 'taxonomy', 'data' => new WP_Error( $error_code, $message ), ) ); $response->send(); } $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => $_POST['screen'] ) ); $level = 0; $no_parents = ''; if ( is_taxonomy_hierarchical( $taxonomy ) ) { $level = count( get_ancestors( $tag->term_id, $taxonomy, 'taxonomy' ) ); ob_start(); $wp_list_table->single_row( $tag, $level ); $no_parents = ob_get_clean(); } ob_start(); $wp_list_table->single_row( $tag ); $parents = ob_get_clean(); require ABSPATH . 'wp-admin/includes/edit-tag-messages.php'; $message = ''; if ( isset( $messages[ $taxonomy_object->name ][1] ) ) { $message = $messages[ $taxonomy_object->name ][1]; } elseif ( isset( $messages['_item'][1] ) ) { $message = $messages['_item'][1]; } $response->add( array( 'what' => 'taxonomy', 'data' => $message, 'supplemental' => array( 'parents' => $parents, 'noparents' => $no_parents, 'notice' => $message, ), ) ); $response->add( array( 'what' => 'term', 'position' => $level, 'supplemental' => (array) $tag, ) ); $response->send(); } /** * Handles getting a tagcloud via AJAX. * * @since 3.1.0 */ function wp_ajax_get_tagcloud() { if ( ! isset( $_POST['tax'] ) ) { wp_die( 0 ); } $taxonomy = sanitize_key( $_POST['tax'] ); $taxonomy_object = get_taxonomy( $taxonomy ); if ( ! $taxonomy_object ) { wp_die( 0 ); } if ( ! current_user_can( $taxonomy_object->cap->assign_terms ) ) { wp_die( -1 ); } $tags = get_terms( array( 'taxonomy' => $taxonomy, 'number' => 45, 'orderby' => 'count', 'order' => 'DESC', ) ); if ( empty( $tags ) ) { wp_die( $taxonomy_object->labels->not_found ); } if ( is_wp_error( $tags ) ) { wp_die( $tags->get_error_message() ); } foreach ( $tags as $key => $tag ) { $tags[ $key ]->link = '#'; $tags[ $key ]->id = $tag->term_id; } // We need raw tag names here, so don't filter the output. $return = wp_generate_tag_cloud( $tags, array( 'filter' => 0, 'format' => 'list', ) ); if ( empty( $return ) ) { wp_die( 0 ); } echo $return; wp_die(); } /** * Handles getting comments via AJAX. * * @since 3.1.0 * * @global int $post_id Post ID. * * @param string $action Action to perform. */ function wp_ajax_get_comments( $action ) { global $post_id; if ( empty( $action ) ) { $action = 'get-comments'; } check_ajax_referer( $action ); if ( empty( $post_id ) && ! empty( $_REQUEST['p'] ) ) { $id = absint( $_REQUEST['p'] ); if ( ! empty( $id ) ) { $post_id = $id; } } if ( empty( $post_id ) ) { wp_die( -1 ); } $wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) ); if ( ! current_user_can( 'edit_post', $post_id ) ) { wp_die( -1 ); } $wp_list_table->prepare_items(); if ( ! $wp_list_table->has_items() ) { wp_die( 1 ); } $response = new WP_Ajax_Response(); ob_start(); foreach ( $wp_list_table->items as $comment ) { if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && 0 === $comment->comment_approved ) { continue; } get_comment( $comment ); $wp_list_table->single_row( $comment ); } $comment_list_item = ob_get_clean(); $response->add( array( 'what' => 'comments', 'data' => $comment_list_item, ) ); $response->send(); } /** * Handles replying to a comment via AJAX. * * @since 3.1.0 * * @param string $action Action to perform. */ function wp_ajax_replyto_comment( $action ) { if ( empty( $action ) ) { $action = 'replyto-comment'; } check_ajax_referer( $action, '_ajax_nonce-replyto-comment' ); $comment_post_id = (int) $_POST['comment_post_ID']; $post = get_post( $comment_post_id ); if ( ! $post ) { wp_die( -1 ); } if ( ! current_user_can( 'edit_post', $comment_post_id ) ) { wp_die( -1 ); } if ( empty( $post->post_status ) ) { wp_die( 1 ); } elseif ( in_array( $post->post_status, array( 'draft', 'pending', 'trash' ), true ) ) { wp_die( __( 'You cannot reply to a comment on a draft post.' ) ); } $user = wp_get_current_user(); if ( $user->exists() ) { $comment_author = wp_slash( $user->display_name ); $comment_author_email = wp_slash( $user->user_email ); $comment_author_url = wp_slash( $user->user_url ); $user_id = $user->ID; if ( current_user_can( 'unfiltered_html' ) ) { if ( ! isset( $_POST['_wp_unfiltered_html_comment'] ) ) { $_POST['_wp_unfiltered_html_comment'] = ''; } if ( wp_create_nonce( 'unfiltered-html-comment' ) !== $_POST['_wp_unfiltered_html_comment'] ) { kses_remove_filters(); // Start with a clean slate. kses_init_filters(); // Set up the filters. remove_filter( 'pre_comment_content', 'wp_filter_post_kses' ); add_filter( 'pre_comment_content', 'wp_filter_kses' ); } } } else { wp_die( __( 'Sorry, you must be logged in to reply to a comment.' ) ); } $comment_content = trim( $_POST['content'] ); if ( '' === $comment_content ) { wp_die( __( 'Please type your comment text.' ) ); } $comment_type = isset( $_POST['comment_type'] ) ? trim( $_POST['comment_type'] ) : 'comment'; $comment_parent = 0; if ( isset( $_POST['comment_ID'] ) ) { $comment_parent = absint( $_POST['comment_ID'] ); } $comment_auto_approved = false; $commentdata = array( 'comment_post_ID' => $comment_post_id, ); $commentdata += compact( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_id' ); // Automatically approve parent comment. if ( ! empty( $_POST['approve_parent'] ) ) { $parent = get_comment( $comment_parent ); if ( $parent && '0' === $parent->comment_approved && (int) $parent->comment_post_ID === $comment_post_id ) { if ( ! current_user_can( 'edit_comment', $parent->comment_ID ) ) { wp_die( -1 ); } if ( wp_set_comment_status( $parent, 'approve' ) ) { $comment_auto_approved = true; } } } $comment_id = wp_new_comment( $commentdata ); if ( is_wp_error( $comment_id ) ) { wp_die( $comment_id->get_error_message() ); } $comment = get_comment( $comment_id ); if ( ! $comment ) { wp_die( 1 ); } $position = ( isset( $_POST['position'] ) && (int) $_POST['position'] ) ? (int) $_POST['position'] : '-1'; ob_start(); if ( isset( $_REQUEST['mode'] ) && 'dashboard' === $_REQUEST['mode'] ) { require_once ABSPATH . 'wp-admin/includes/dashboard.php'; _wp_dashboard_recent_comments_row( $comment ); } else { if ( isset( $_REQUEST['mode'] ) && 'single' === $_REQUEST['mode'] ) { $wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) ); } else { $wp_list_table = _get_list_table( 'WP_Comments_List_Table', array( 'screen' => 'edit-comments' ) ); } $wp_list_table->single_row( $comment ); } $comment_list_item = ob_get_clean(); $response_data = array( 'what' => 'comment', 'id' => $comment->comment_ID, 'data' => $comment_list_item, 'position' => $position, ); $counts = wp_count_comments(); $response_data['supplemental'] = array( '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 ) ), ); if ( $comment_auto_approved ) { $response_data['supplemental']['parent_approved'] = $parent->comment_ID; $response_data['supplemental']['parent_post_id'] = $parent->comment_post_ID; } $response = new WP_Ajax_Response(); $response->add( $response_data ); $response->send(); } /** * Handles editing a comment via AJAX. * * @since 3.1.0 */ function wp_ajax_edit_comment() { check_ajax_referer( 'replyto-comment', '_ajax_nonce-replyto-comment' ); $comment_id = (int) $_POST['comment_ID']; if ( ! current_user_can( 'edit_comment', $comment_id ) ) { wp_die( -1 ); } if ( '' === $_POST['content'] ) { wp_die( __( 'Please type your comment text.' ) ); } if ( isset( $_POST['status'] ) ) { $_POST['comment_status'] = $_POST['status']; } $updated = edit_comment(); if ( is_wp_error( $updated ) ) { wp_die( $updated->get_error_message() ); } $position = ( isset( $_POST['position'] ) && (int) $_POST['position'] ) ? (int) $_POST['position'] : '-1'; /* * Checkbox is used to differentiate between the Edit Comments screen (1) * and the Comments section on the Edit Post screen (0). */ $checkbox = ( isset( $_POST['checkbox'] ) && '1' === $_POST['checkbox'] ) ? 1 : 0; $wp_list_table = _get_list_table( $checkbox ? 'WP_Comments_List_Table' : 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) ); $comment = get_comment( $comment_id ); if ( empty( $comment->comment_ID ) ) { wp_die( -1 ); } ob_start(); $wp_list_table->single_row( $comment ); $comment_list_item = ob_get_clean(); $response = new WP_Ajax_Response(); $response->add( array( 'what' => 'edit_comment', 'id' => $comment->comment_ID, 'data' => $comment_list_item, 'position' => $position, ) ); $response->send(); } /** * Handles adding a menu item via AJAX. * * @since 3.1.0 */ function wp_ajax_add_menu_item() { check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' ); if ( ! current_user_can( 'edit_theme_options' ) ) { wp_die( -1 ); } require_once ABSPATH . 'wp-admin/includes/nav-menu.php'; /* * For performance reasons, we omit some object properties from the checklist. * The following is a hacky way to restore them when adding non-custom items. */ $menu_items_data = array(); foreach ( (array) $_POST['menu-item'] as $menu_item_data ) { if ( ! empty( $menu_item_data['menu-item-type'] ) && 'custom' !== $menu_item_data['menu-item-type'] && ! empty( $menu_item_data['menu-item-object-id'] ) ) { switch ( $menu_item_data['menu-item-type'] ) { case 'post_type': $_object = get_post( $menu_item_data['menu-item-object-id'] ); break; case 'post_type_archive': $_object = get_post_type_object( $menu_item_data['menu-item-object'] ); break; case 'taxonomy': $_object = get_term( $menu_item_data['menu-item-object-id'], $menu_item_data['menu-item-object'] ); break; } $_menu_items = array_map( 'wp_setup_nav_menu_item', array( $_object ) ); $_menu_item = reset( $_menu_items ); // Restore the missing menu item properties. $menu_item_data['menu-item-description'] = $_menu_item->description; } $menu_items_data[] = $menu_item_data; } $item_ids = wp_save_nav_menu_items( 0, $menu_items_data ); if ( is_wp_error( $item_ids ) ) { wp_die( 0 ); } $menu_items = array(); foreach ( (array) $item_ids as $menu_item_id ) { $menu_object = get_post( $menu_item_id ); if ( ! empty( $menu_object->ID ) ) { $menu_object = wp_setup_nav_menu_item( $menu_object ); $menu_object->title = empty( $menu_object->title ) ? __( 'Menu Item' ) : $menu_object->title; $menu_object->label = $menu_object->title; // Don't show "(pending)" in ajax-added items. $menu_items[] = $menu_object; } } /** This filter is documented in wp-admin/includes/nav-menu.php */ $walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $_POST['menu'] ); if ( ! class_exists( $walker_class_name ) ) { wp_die( 0 ); } if ( ! empty( $menu_items ) ) { $args = array( 'after' => '', 'before' => '', 'link_after' => '', 'link_before' => '', 'walker' => new $walker_class_name(), ); echo walk_nav_menu_tree( $menu_items, 0, (object) $args ); } wp_die(); } /** * Handles adding meta via AJAX. * * @since 3.1.0 */ function wp_ajax_add_meta() { check_ajax_referer( 'add-meta', '_ajax_nonce-add-meta' ); $count = 0; $post_id = (int) $_POST['post_id']; $post = get_post( $post_id ); if ( isset( $_POST['metakeyselect'] ) || isset( $_POST['metakeyinput'] ) ) { if ( ! current_user_can( 'edit_post', $post_id ) ) { wp_die( -1 ); } if ( isset( $_POST['metakeyselect'] ) && '#NONE#' === $_POST['metakeyselect'] && empty( $_POST['metakeyinput'] ) ) { wp_die( 1 ); } // If the post is an autodraft, save the post as a draft and then attempt to save the meta. if ( 'auto-draft' === $post->post_status ) { $post_data = array(); $post_data['action'] = 'draft'; // Warning fix. $post_data['post_ID'] = $post_id; $post_data['post_type'] = $post->post_type; $post_data['post_status'] = 'draft'; $now = time(); $post_data['post_title'] = sprintf( /* translators: 1: Post creation date, 2: Post creation time. */ __( 'Draft created on %1$s at %2$s' ), gmdate( __( 'F j, Y' ), $now ), gmdate( __( 'g:i a' ), $now ) ); $post_id = edit_post( $post_data ); if ( $post_id ) { if ( is_wp_error( $post_id ) ) { $response = new WP_Ajax_Response( array( 'what' => 'meta', 'data' => $post_id, ) ); $response->send(); } $meta_id = add_meta( $post_id ); if ( ! $meta_id ) { wp_die( __( 'Please provide a custom field value.' ) ); } } else { wp_die( 0 ); } } else { $meta_id = add_meta( $post_id ); if ( ! $meta_id ) { wp_die( __( 'Please provide a custom field value.' ) ); } } $meta = get_metadata_by_mid( 'post', $meta_id ); $post_id = (int) $meta->post_id; $meta = get_object_vars( $meta ); $response = new WP_Ajax_Response( array( 'what' => 'meta', 'id' => $meta_id, 'data' => _list_meta_row( $meta, $count ), 'position' => 1, 'supplemental' => array( 'postid' => $post_id ), ) ); } else { // Update? $meta_id = (int) key( $_POST['meta'] ); $key = wp_unslash( $_POST['meta'][ $meta_id ]['key'] ); $value = wp_unslash( $_POST['meta'][ $meta_id ]['value'] ); if ( '' === trim( $key ) ) { wp_die( __( 'Please provide a custom field name.' ) ); } $meta = get_metadata_by_mid( 'post', $meta_id ); if ( ! $meta ) { wp_die( 0 ); // If meta doesn't exist. } if ( is_protected_meta( $meta->meta_key, 'post' ) || is_protected_meta( $key, 'post' ) || ! current_user_can( 'edit_post_meta', $meta->post_id, $meta->meta_key ) || ! current_user_can( 'edit_post_meta', $meta->post_id, $key ) ) { wp_die( -1 ); } if ( $meta->meta_value !== $value || $meta->meta_key !== $key ) { $update_result = update_metadata_by_mid( 'post', $meta_id, $value, $key ); if ( ! $update_result ) { wp_die( 0 ); // We know meta exists; we also know it's unchanged (or DB error, in which case there are bigger problems). } } $response = new WP_Ajax_Response( array( 'what' => 'meta', 'id' => $meta_id, 'old_id' => $meta_id, 'data' => _list_meta_row( array( 'meta_key' => $key, 'meta_value' => $value, 'meta_id' => $meta_id, ), $c ), 'position' => 0, 'supplemental' => array( 'postid' => $meta->post_id ), ) ); } $response->send(); } /** * Handles adding a user via AJAX. * * @since 3.1.0 * * @param string $action Action to perform. */ function wp_ajax_add_user( $action ) { if ( empty( $action ) ) { $action = 'add-user'; } check_ajax_referer( $action ); if ( ! current_user_can( 'create_users' ) ) { wp_die( -1 ); } $user_id = edit_user(); if ( ! $user_id ) { wp_die( 0 ); } elseif ( is_wp_error( $user_id ) ) { $response = new WP_Ajax_Response( array( 'what' => 'user', 'id' => $user_id, ) ); $response->send(); } $user_object = get_userdata( $user_id ); $wp_list_table = _get_list_table( 'WP_Users_List_Table' ); $role = current( $user_object->roles ); $response = new WP_Ajax_Response( array( 'what' => 'user', 'id' => $user_id, 'data' => $wp_list_table->single_row( $user_object, '', $role ), 'supplemental' => array( 'show-link' => sprintf( /* translators: %s: The new user. */ __( 'User %s added' ), '<a href="#user-' . $user_id . '">' . $user_object->user_login . '</a>' ), 'role' => $role, ), ) ); $response->send(); } /** * Handles closed post boxes via AJAX. * * @since 3.1.0 */ function wp_ajax_closed_postboxes() { check_ajax_referer( 'closedpostboxes', 'closedpostboxesnonce' ); $closed = isset( $_POST['closed'] ) ? explode( ',', $_POST['closed'] ) : array(); $closed = array_filter( $closed ); $hidden = isset( $_POST['hidden'] ) ? explode( ',', $_POST['hidden'] ) : array(); $hidden = array_filter( $hidden ); $page = $_POST['page'] ?? ''; if ( sanitize_key( $page ) !== $page ) { wp_die( 0 ); } $user = wp_get_current_user(); if ( ! $user ) { wp_die( -1 ); } if ( is_array( $closed ) ) { update_user_meta( $user->ID, "closedpostboxes_$page", $closed ); } if ( is_array( $hidden ) ) { // Postboxes that are always shown. $hidden = array_diff( $hidden, array( 'submitdiv', 'linksubmitdiv', 'manage-menu', 'create-menu' ) ); update_user_meta( $user->ID, "metaboxhidden_$page", $hidden ); } wp_die( 1 ); } /** * Handles hidden columns via AJAX. * * @since 3.1.0 */ function wp_ajax_hidden_columns() { check_ajax_referer( 'screen-options-nonce', 'screenoptionnonce' ); $page = $_POST['page'] ?? ''; if ( sanitize_key( $page ) !== $page ) { wp_die( 0 ); } $user = wp_get_current_user(); if ( ! $user ) { wp_die( -1 ); } $hidden = ! empty( $_POST['hidden'] ) ? explode( ',', $_POST['hidden'] ) : array(); update_user_meta( $user->ID, "manage{$page}columnshidden", $hidden ); wp_die( 1 ); } /** * Handles updating whether to display the welcome panel via AJAX. * * @since 3.1.0 */ function wp_ajax_update_welcome_panel() { check_ajax_referer( 'welcome-panel-nonce', 'welcomepanelnonce' ); if ( ! current_user_can( 'edit_theme_options' ) ) { wp_die( -1 ); } update_user_meta( get_current_user_id(), 'show_welcome_panel', empty( $_POST['visible'] ) ? 0 : 1 ); wp_die( 1 ); } /** * Handles for retrieving menu meta boxes via AJAX. * * @since 3.1.0 */ function wp_ajax_menu_get_metabox() { if ( ! current_user_can( 'edit_theme_options' ) ) { wp_die( -1 ); } require_once ABSPATH . 'wp-admin/includes/nav-menu.php'; if ( isset( $_POST['item-type'] ) && 'post_type' === $_POST['item-type'] ) { $type = 'posttype'; $callback = 'wp_nav_menu_item_post_type_meta_box'; $items = (array) get_post_types( array( 'show_in_nav_menus' => true ), 'object' ); } elseif ( isset( $_POST['item-type'] ) && 'taxonomy' === $_POST['item-type'] ) { $type = 'taxonomy'; $callback = 'wp_nav_menu_item_taxonomy_meta_box'; $items = (array) get_taxonomies( array( 'show_ui' => true ), 'object' ); } if ( ! empty( $_POST['item-object'] ) && isset( $items[ $_POST['item-object'] ] ) ) { $menus_meta_box_object = $items[ $_POST['item-object'] ]; /** This filter is documented in wp-admin/includes/nav-menu.php */ $item = apply_filters( 'nav_menu_meta_box_object', $menus_meta_box_object ); $box_args = array( 'id' => 'add-' . $item->name, 'title' => $item->labels->name, 'callback' => $callback, 'args' => $item, ); ob_start(); $callback( null, $box_args ); $markup = ob_get_clean(); echo wp_json_encode( array( 'replace-id' => $type . '-' . $item->name, 'markup' => $markup, ) ); } wp_die(); } /** * Handles internal linking via AJAX. * * @since 3.1.0 */ function wp_ajax_wp_link_ajax() { check_ajax_referer( 'internal-linking', '_ajax_linking_nonce' ); $args = array(); if ( isset( $_POST['search'] ) ) { $args['s'] = wp_unslash( $_POST['search'] ); } if ( isset( $_POST['term'] ) ) { $args['s'] = wp_unslash( $_POST['term'] ); } $args['pagenum'] = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1; if ( ! class_exists( '_WP_Editors', false ) ) { require ABSPATH . WPINC . '/class-wp-editor.php'; } $results = _WP_Editors::wp_link_query( $args ); if ( ! isset( $results ) ) { wp_die( 0 ); } echo wp_json_encode( $results ); echo "\n"; wp_die(); } /** * Handles saving menu locations via AJAX. * * @since 3.1.0 */ function wp_ajax_menu_locations_save() { if ( ! current_user_can( 'edit_theme_options' ) ) { wp_die( -1 ); } check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' ); if ( ! isset( $_POST['menu-locations'] ) ) { wp_die( 0 ); } set_theme_mod( 'nav_menu_locations', array_map( 'absint', $_POST['menu-locations'] ) ); wp_die( 1 ); } /** * Handles saving the meta box order via AJAX. * * @since 3.1.0 */ function wp_ajax_meta_box_order() { check_ajax_referer( 'meta-box-order' ); $order = isset( $_POST['order'] ) ? (array) $_POST['order'] : false; $page_columns = $_POST['page_columns'] ?? 'auto'; if ( 'auto' !== $page_columns ) { $page_columns = (int) $page_columns; } $page = $_POST['page'] ?? ''; if ( sanitize_key( $page ) !== $page ) { wp_die( 0 ); } $user = wp_get_current_user(); if ( ! $user ) { wp_die( -1 ); } if ( $order ) { update_user_meta( $user->ID, "meta-box-order_$page", $order ); } if ( $page_columns ) { update_user_meta( $user->ID, "screen_layout_$page", $page_columns ); } wp_send_json_success(); } /** * Handles menu quick searching via AJAX. * * @since 3.1.0 */ function wp_ajax_menu_quick_search() { if ( ! current_user_can( 'edit_theme_options' ) ) { wp_die( -1 ); } require_once ABSPATH . 'wp-admin/includes/nav-menu.php'; _wp_ajax_menu_quick_search( $_POST ); wp_die(); } /** * Handles retrieving a permalink via AJAX. * * @since 3.1.0 */ function wp_ajax_get_permalink() { check_ajax_referer( 'getpermalink', 'getpermalinknonce' ); $post_id = isset( $_POST['post_id'] ) ? (int) $_POST['post_id'] : 0; wp_die( get_preview_post_link( $post_id ) ); } /** * Handles retrieving a sample permalink via AJAX. * * @since 3.1.0 */ function wp_ajax_sample_permalink() { check_ajax_referer( 'samplepermalink', 'samplepermalinknonce' ); $post_id = isset( $_POST['post_id'] ) ? (int) $_POST['post_id'] : 0; $title = $_POST['new_title'] ?? ''; $slug = $_POST['new_slug'] ?? null; wp_die( get_sample_permalink_html( $post_id, $title, $slug ) ); } /** * Handles Quick Edit saving a post from a list table via AJAX. * * @since 3.1.0 * * @global string $mode List table view mode. */ function wp_ajax_inline_save() { global $mode; check_ajax_referer( 'inlineeditnonce', '_inline_edit' ); if ( ! isset( $_POST['post_ID'] ) || ! (int) $_POST['post_ID'] ) { wp_die(); } $post_id = (int) $_POST['post_ID']; if ( 'page' === $_POST['post_type'] ) { if ( ! current_user_can( 'edit_page', $post_id ) ) { wp_die( __( 'Sorry, you are not allowed to edit this page.' ) ); } } else { if ( ! current_user_can( 'edit_post', $post_id ) ) { wp_die( __( 'Sorry, you are not allowed to edit this post.' ) ); } } $last = wp_check_post_lock( $post_id ); if ( $last ) { $last_user = get_userdata( $last ); $last_user_name = $last_user ? $last_user->display_name : __( 'Someone' ); /* translators: %s: User's display name. */ $msg_template = __( 'Saving is disabled: %s is currently editing this post.' ); if ( 'page' === $_POST['post_type'] ) { /* translators: %s: User's display name. */ $msg_template = __( 'Saving is disabled: %s is currently editing this page.' ); } printf( $msg_template, esc_html( $last_user_name ) ); wp_die(); } $data = &$_POST; $post = get_post( $post_id, ARRAY_A ); // Since it's coming from the database. $post = wp_slash( $post ); $data['content'] = $post['post_content']; $data['excerpt'] = $post['post_excerpt']; // Rename. $data['user_ID'] = get_current_user_id(); if ( isset( $data['post_parent'] ) ) { $data['parent_id'] = $data['post_parent']; } // Status. if ( isset( $data['keep_private'] ) && 'private' === $data['keep_private'] ) { $data['visibility'] = 'private'; $data['post_status'] = 'private'; } elseif ( isset( $data['_status'] ) ) { $data['post_status'] = $data['_status']; } if ( empty( $data['comment_status'] ) ) { $data['comment_status'] = 'closed'; } if ( empty( $data['ping_status'] ) ) { $data['ping_status'] = 'closed'; } // Exclude terms from taxonomies that are not supposed to appear in Quick Edit. if ( ! empty( $data['tax_input'] ) ) { foreach ( $data['tax_input'] as $taxonomy => $terms ) { $tax_object = get_taxonomy( $taxonomy ); /** This filter is documented in wp-admin/includes/class-wp-posts-list-table.php */ if ( ! apply_filters( 'quick_edit_show_taxonomy', $tax_object->show_in_quick_edit, $taxonomy, $post['post_type'] ) ) { unset( $data['tax_input'][ $taxonomy ] ); } } } // Hack: wp_unique_post_slug() doesn't work for drafts, so we will fake that our post is published. if ( ! empty( $data['post_name'] ) && in_array( $post['post_status'], array( 'draft', 'pending' ), true ) ) { $post['post_status'] = 'publish'; $data['post_name'] = wp_unique_post_slug( $data['post_name'], $post['ID'], $post['post_status'], $post['post_type'], $post['post_parent'] ); } // Update the post. edit_post(); $wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) ); $mode = 'excerpt' === $_POST['post_view'] ? 'excerpt' : 'list'; $level = 0; if ( is_post_type_hierarchical( $wp_list_table->screen->post_type ) ) { $request_post = array( get_post( $_POST['post_ID'] ) ); $parent = $request_post[0]->post_parent; while ( $parent > 0 ) { $parent_post = get_post( $parent ); $parent = $parent_post->post_parent; ++$level; } } $wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level ); wp_die(); } /** * Handles Quick Edit saving for a term via AJAX. * * @since 3.1.0 */ function wp_ajax_inline_save_tax() { check_ajax_referer( 'taxinlineeditnonce', '_inline_edit' ); $taxonomy = sanitize_key( $_POST['taxonomy'] ); $taxonomy_object = get_taxonomy( $taxonomy ); if ( ! $taxonomy_object ) { wp_die( 0 ); } if ( ! isset( $_POST['tax_ID'] ) || ! (int) $_POST['tax_ID'] ) { wp_die( -1 ); } $id = (int) $_POST['tax_ID']; if ( ! current_user_can( 'edit_term', $id ) ) { wp_die( -1 ); } $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) ); $tag = get_term( $id, $taxonomy ); $_POST['description'] = $tag->description; $updated = wp_update_term( $id, $taxonomy, $_POST ); if ( $updated && ! is_wp_error( $updated ) ) { $tag = get_term( $updated['term_id'], $taxonomy ); if ( ! $tag || is_wp_error( $tag ) ) { if ( is_wp_error( $tag ) && $tag->get_error_message() ) { wp_die( $tag->get_error_message() ); } wp_die( __( 'Item not updated.' ) ); } } else { if ( is_wp_error( $updated ) && $updated->get_error_message() ) { wp_die( $updated->get_error_message() ); } wp_die( __( 'Item not updated.' ) ); } $level = 0; $parent = $tag->parent; while ( $parent > 0 ) { $parent_tag = get_term( $parent, $taxonomy ); $parent = $parent_tag->parent; ++$level; } $wp_list_table->single_row( $tag, $level ); wp_die(); } /** * Handles querying posts for the Find Posts modal via AJAX. * * @see window.findPosts * * @since 3.1.0 */ function wp_ajax_find_posts() { check_ajax_referer( 'find-posts' ); $post_types = get_post_types( array( 'public' => true ), 'objects' ); unset( $post_types['attachment'] ); $args = array( 'post_type' => array_keys( $post_types ), 'post_status' => 'any', 'posts_per_page' => 50, ); $search = wp_unslash( $_POST['ps'] ); if ( '' !== $search ) { $args['s'] = $search; } $posts = get_posts( $args ); if ( ! $posts ) { wp_send_json_error( __( 'No items found.' ) ); } $html = '<table class="widefat"><thead><tr><th class="found-radio"><br /></th><th>' . __( 'Title' ) . '</th><th class="no-break">' . __( 'Type' ) . '</th><th class="no-break">' . __( 'Date' ) . '</th><th class="no-break">' . __( 'Status' ) . '</th></tr></thead><tbody>'; $alternate = ''; foreach ( $posts as $post ) { $title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' ); $alternate = ( 'alternate' === $alternate ) ? '' : 'alternate'; switch ( $post->post_status ) { case 'publish': case 'private': $stat = __( 'Published' ); break; case 'future': $stat = __( 'Scheduled' ); break; case 'pending': $stat = __( 'Pending Review' ); break; case 'draft': $stat = __( 'Draft' ); break; } if ( '0000-00-00 00:00:00' === $post->post_date ) { $time = ''; } else { /* translators: Date format in table columns, see https://www.php.net/manual/datetime.format.php */ $time = mysql2date( __( 'Y/m/d' ), $post->post_date ); } $html .= '<tr class="' . trim( 'found-posts ' . $alternate ) . '"><td class="found-radio"><input type="radio" id="found-' . $post->ID . '" name="found_post_id" value="' . esc_attr( $post->ID ) . '"></td>'; $html .= '<td><label for="found-' . $post->ID . '">' . esc_html( $title ) . '</label></td><td class="no-break">' . esc_html( $post_types[ $post->post_type ]->labels->singular_name ) . '</td><td class="no-break">' . esc_html( $time ) . '</td><td class="no-break">' . esc_html( $stat ) . ' </td></tr>' . "\n\n"; } $html .= '</tbody></table>'; wp_send_json_success( $html ); } /** * Handles saving the widgets order via AJAX. * * @since 3.1.0 */ function wp_ajax_widgets_order() { check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' ); if ( ! current_user_can( 'edit_theme_options' ) ) { wp_die( -1 ); } unset( $_POST['savewidgets'], $_POST['action'] ); // Save widgets order for all sidebars. if ( is_array( $_POST['sidebars'] ) ) { $sidebars = array(); foreach ( wp_unslash( $_POST['sidebars'] ) as $key => $val ) { $sidebar = array(); if ( ! empty( $val ) ) { $val = explode( ',', $val ); foreach ( $val as $k => $v ) { if ( ! str_contains( $v, 'widget-' ) ) { continue; } $sidebar[ $k ] = substr( $v, strpos( $v, '_' ) + 1 ); } } $sidebars[ $key ] = $sidebar; } wp_set_sidebars_widgets( $sidebars ); wp_die( 1 ); } wp_die( -1 ); } /** * Handles saving a widget via AJAX. * * @since 3.1.0 * * @global array $wp_registered_widgets Registered widgets. * @global array $wp_registered_widget_controls Registered widget controls. * @global array $wp_registered_widget_updates Registered widget updates. */ function wp_ajax_save_widget() { global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates; check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' ); if ( ! current_user_can( 'edit_theme_options' ) || ! isset( $_POST['id_base'] ) ) { wp_die( -1 ); } unset( $_POST['savewidgets'], $_POST['action'] ); /** * Fires early when editing the widgets displayed in sidebars. * * @since 2.8.0 */ do_action( 'load-widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores /** * Fires early when editing the widgets displayed in sidebars. * * @since 2.8.0 */ do_action( 'widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores /** This action is documented in wp-admin/widgets-form.php */ do_action( 'sidebar_admin_setup' ); $id_base = wp_unslash( $_POST['id_base'] ); $widget_id = wp_unslash( $_POST['widget-id'] ); $sidebar_id = $_POST['sidebar']; $multi_number = ! empty( $_POST['multi_number'] ) ? (int) $_POST['multi_number'] : 0; $settings = isset( $_POST[ 'widget-' . $id_base ] ) && is_array( $_POST[ 'widget-' . $id_base ] ) ? $_POST[ 'widget-' . $id_base ] : false; $error = '<p>' . __( 'An error has occurred. Please reload the page and try again.' ) . '</p>'; $sidebars = wp_get_sidebars_widgets(); $sidebar = $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-form.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(); } /** * Handles updating a widget via AJAX. * * @since 3.9.0 * * @global WP_Customize_Manager $wp_customize Customizer manager object. */ function wp_ajax_update_widget() { global $wp_customize; $wp_customize->widgets->wp_ajax_update_widget(); } /** * Handles removing inactive widgets via AJAX. * * @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-form.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(); } /** * Handles creating missing image sub-sizes for just uploaded images via AJAX. * * @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 ); } /** * Handles uploading attachments via AJAX. * * @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(); } /** * Handles image editing via AJAX. * * @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" ); require_once ABSPATH . 'wp-admin/includes/image-edit.php'; $message = false; switch ( $_POST['do'] ) { case 'save': $message = wp_save_image( $attachment_id ); if ( ! empty( $message->error ) ) { wp_send_json_error( $message ); } wp_send_json_success( $message ); break; case 'scale': $message = wp_save_image( $attachment_id ); break; case 'restore': $message = wp_restore_image( $attachment_id ); break; } ob_start(); wp_image_editor( $attachment_id, $message ); $html = ob_get_clean(); if ( ! empty( $message->error ) ) { wp_send_json_error( array( 'message' => $message, 'html' => $html, ) ); } wp_send_json_success( array( 'message' => $message, 'html' => $html, ) ); } /** * Handles setting the featured image via AJAX. * * @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 ); } /** * Handles retrieving HTML for the featured image via AJAX. * * @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 ); } /** * Handles setting the featured image for an attachment via AJAX. * * @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(); } /** * Handles formatting a date via AJAX. * * @since 3.1.0 */ function wp_ajax_date_format() { wp_die( date_i18n( sanitize_option( 'date_format', wp_unslash( $_POST['date'] ) ) ) ); } /** * Handles formatting a time via AJAX. * * @since 3.1.0 */ function wp_ajax_time_format() { wp_die( date_i18n( sanitize_option( 'time_format', wp_unslash( $_POST['date'] ) ) ) ); } /** * Handles saving posts from the fullscreen editor via AJAX. * * @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 ) ); } /** * Handles removing a post lock via AJAX. * * @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 ); } /** * Handles dismissing a WordPress pointer via AJAX. * * @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 ); } /** * Handles getting an attachment via AJAX. * * @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 ); } /** * Handles querying attachments via AJAX. * * @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 $taxonomy ) { if ( $taxonomy->query_var && isset( $query[ $taxonomy->query_var ] ) ) { $keys[] = $taxonomy->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 ); $attachments_query = new WP_Query( $query ); update_post_parent_caches( $attachments_query->posts ); $posts = array_map( 'wp_prepare_attachment_for_js', $attachments_query->posts ); $posts = array_filter( $posts ); $total_posts = $attachments_query->found_posts; if ( $total_posts < 1 ) { // Out-of-bounds, run the query again without LIMIT for total count. unset( $query['paged'] ); $count_query = new WP_Query(); $count_query->query( $query ); $total_posts = $count_query->found_posts; } $posts_per_page = (int) $attachments_query->get( 'posts_per_page' ); $max_pages = $posts_per_page ? (int) ceil( $total_posts / $posts_per_page ) : 0; header( 'X-WP-Total: ' . (int) $total_posts ); header( 'X-WP-TotalPages: ' . $max_pages ); wp_send_json_success( $posts ); } /** * Handles updating attachment attributes via AJAX. * * @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; $id3_data = wp_get_attachment_metadata( $post['ID'] ); if ( ! is_array( $id3_data ) ) { $changed = true; $id3_data = array(); } foreach ( wp_get_attachment_id3_keys( (object) $post, 'edit' ) as $key => $label ) { if ( isset( $changes[ $key ] ) ) { $changed = true; $id3_data[ $key ] = sanitize_text_field( wp_unslash( $changes[ $key ] ) ); } } if ( $changed ) { wp_update_attachment_metadata( $id, $id3_data ); } } if ( MEDIA_TRASH && isset( $changes['status'] ) && 'trash' === $changes['status'] ) { wp_delete_post( $id ); } else { wp_update_post( $post ); } wp_send_json_success(); } /** * Handles saving backward compatible attachment attributes via AJAX. * * @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 ); } /** * Handles saving the attachment order via AJAX. * * @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(); } /** * Handles sending an attachment to the editor via AJAX. * * 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 = ( str_contains( $url, 'attachment_id' ) || get_attachment_link( $id ) === $url ); remove_filter( 'media_send_to_editor', 'image_media_send_to_editor' ); if ( str_starts_with( $post->post_mime_type, 'image' ) ) { $align = $attachment['align'] ?? 'none'; $size = $attachment['image-size'] ?? 'medium'; $alt = $attachment['image_alt'] ?? ''; // No whitespace-only captions. $caption = $attachment['post_excerpt'] ?? ''; if ( '' === trim( $caption ) ) { $caption = ''; } $title = ''; // We no longer insert title tags into <img> tags, as they are redundant. $html = get_image_send_to_editor( $id, $caption, $title, $align, $url, $rel, $size, $alt ); } elseif ( wp_attachment_is( 'video', $post ) || wp_attachment_is( 'audio', $post ) ) { $html = stripslashes_deep( $_POST['html'] ); } else { $html = $attachment['post_title'] ?? ''; $rel = $rel ? ' rel="attachment wp-att-' . $id . '"' : ''; // Hard-coded string, $id is already sanitized. if ( ! empty( $url ) ) { $html = '<a href="' . esc_url( $url ) . '"' . $rel . '>' . $html . '</a>'; } } /** This filter is documented in wp-admin/includes/media.php */ $html = apply_filters( 'media_send_to_editor', $html, $id, $attachment ); wp_send_json_success( $html ); } /** * Handles sending a link to the editor via AJAX. * * Generates the HTML to send a non-image embed link to the editor. * * Backward compatible with the following filters: * - file_send_to_editor_url * - audio_send_to_editor_url * - video_send_to_editor_url * * @since 3.5.0 * * @global WP_Post $post Global post object. * @global WP_Embed $wp_embed WordPress Embed object. */ function wp_ajax_send_link_to_editor() { global $post, $wp_embed; check_ajax_referer( 'media-send-to-editor', 'nonce' ); $src = wp_unslash( $_POST['src'] ); if ( ! $src ) { wp_send_json_error(); } if ( ! strpos( $src, '://' ) ) { $src = 'http://' . $src; } $src = sanitize_url( $src ); if ( ! $src ) { wp_send_json_error(); } $link_text = trim( wp_unslash( $_POST['link_text'] ) ); if ( ! $link_text ) { $link_text = wp_basename( $src ); } $post = get_post( $_POST['post_id'] ?? 0 ); // Ping WordPress for an embed. $check_embed = $wp_embed->run_shortcode( '[embed]' . $src . '[/embed]' ); // Fallback that WordPress creates when no oEmbed was found. $fallback = $wp_embed->maybe_make_link( $src ); if ( $check_embed !== $fallback ) { // TinyMCE view for [embed] will parse this. $html = '[embed]' . $src . '[/embed]'; } elseif ( $link_text ) { $html = '<a href="' . esc_url( $src ) . '">' . $link_text . '</a>'; } else { $html = ''; } // Figure out what filter to run: $type = 'file'; $extension = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ); if ( $extension ) { $extension_type = wp_ext2type( $extension ); if ( 'audio' === $extension_type || 'video' === $extension_type ) { $type = $extension_type; } } /** This filter is documented in wp-admin/includes/media.php */ $html = apply_filters( "{$type}_send_to_editor_url", $html, $src, $link_text ); wp_send_json_success( $html ); } /** * Handles the Heartbeat API via AJAX. * * Runs when the user is logged in. * * @since 3.6.0 */ function wp_ajax_heartbeat() { if ( empty( $_POST['_nonce'] ) ) { wp_send_json_error(); } $response = array(); $data = array(); $nonce_state = wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' ); // 'screen_id' is the same as $current_screen->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'] ); } if ( 1 !== $nonce_state ) { /** * Filters the nonces to send to the New/Edit Post screen. * * @since 4.3.0 * * @param array $response The Heartbeat response. * @param array $data The $_POST data sent. * @param string $screen_id The screen ID. */ $response = apply_filters( 'wp_refresh_nonces', $response, $data, $screen_id ); if ( false === $nonce_state ) { // User is logged in but nonces have expired. $response['nonces_expired'] = true; wp_send_json( $response ); } } if ( ! empty( $data ) ) { /** * Filters the Heartbeat response received. * * @since 3.6.0 * * @param array $response The Heartbeat response. * @param array $data The $_POST data sent. * @param string $screen_id The screen ID. */ $response = apply_filters( 'heartbeat_received', $response, $data, $screen_id ); } /** * Filters the Heartbeat response sent. * * @since 3.6.0 * * @param array $response The Heartbeat response. * @param string $screen_id The screen ID. */ $response = apply_filters( 'heartbeat_send', $response, $screen_id ); /** * Fires when Heartbeat ticks in logged-in environments. * * Allows the transport to be easily replaced with long-polling. * * @since 3.6.0 * * @param array $response The Heartbeat response. * @param string $screen_id The screen ID. */ do_action( 'heartbeat_tick', $response, $screen_id ); // Send the current time according to the server. $response['server_time'] = time(); wp_send_json( $response ); } /** * Handles getting revision diffs via AJAX. * * @since 3.6.0 */ function wp_ajax_get_revision_diffs() { require ABSPATH . 'wp-admin/includes/revision.php'; $post = get_post( (int) $_REQUEST['post_id'] ); if ( ! $post ) { wp_send_json_error(); } if ( ! current_user_can( 'edit_post', $post->ID ) ) { wp_send_json_error(); } // Really just pre-loading the cache here. $revisions = wp_get_post_revisions( $post->ID, array( 'check_enabled' => false ) ); if ( ! $revisions ) { wp_send_json_error(); } $return = array(); // Increase the script timeout limit to allow ample time for diff UI setup. if ( function_exists( 'set_time_limit' ) ) { set_time_limit( 5 * MINUTE_IN_SECONDS ); } foreach ( $_REQUEST['compare'] as $compare_key ) { list( $compare_from, $compare_to ) = explode( ':', $compare_key ); // from:to $return[] = array( 'id' => $compare_key, 'fields' => wp_get_revision_ui_diff( $post, $compare_from, $compare_to ), ); } wp_send_json_success( $return ); } /** * Handles auto-saving the selected color scheme for * a user's own profile via AJAX. * * @since 3.8.0 * * @global array $_wp_admin_css_colors Registered admin CSS color schemes. */ function wp_ajax_save_user_color_scheme() { global $_wp_admin_css_colors; check_ajax_referer( 'save-color-scheme', 'nonce' ); $color_scheme = sanitize_key( $_POST['color_scheme'] ); if ( ! isset( $_wp_admin_css_colors[ $color_scheme ] ) ) { wp_send_json_error(); } $previous_color_scheme = get_user_meta( get_current_user_id(), 'admin_color', true ); update_user_meta( get_current_user_id(), 'admin_color', $color_scheme ); wp_send_json_success( array( 'previousScheme' => 'admin-color-' . $previous_color_scheme, 'currentScheme' => 'admin-color-' . $color_scheme, ) ); } /** * Handles getting themes from themes_api() via AJAX. * * @since 3.9.0 * * @global array $themes_allowedtags Allowed HTML tags for theme descriptions. * @global array $theme_field_defaults Default theme fields. */ function wp_ajax_query_themes() { global $themes_allowedtags, $theme_field_defaults; if ( ! current_user_can( 'install_themes' ) ) { wp_send_json_error(); } $args = wp_parse_args( wp_unslash( $_REQUEST['request'] ), array( 'per_page' => 20, 'fields' => array_merge( (array) $theme_field_defaults, array( 'reviews_url' => true, // Explicitly request the reviews URL to be linked from the Add Themes screen. ) ), ) ); if ( isset( $args['browse'] ) && 'favorites' === $args['browse'] && ! isset( $args['user'] ) ) { $user = get_user_option( 'wporg_favorites' ); if ( $user ) { $args['user'] = $user; } } $old_filter = $args['browse'] ?? 'search'; /** This filter is documented in wp-admin/includes/class-wp-theme-install-list-table.php */ $args = apply_filters( 'install_themes_table_api_args_' . $old_filter, $args ); $api = themes_api( 'query_themes', $args ); if ( is_wp_error( $api ) ) { wp_send_json_error(); } $update_php = network_admin_url( 'update.php?action=install-theme' ); $installed_themes = search_theme_directories(); if ( false === $installed_themes ) { $installed_themes = array(); } foreach ( $installed_themes as $theme_slug => $theme_data ) { // Ignore child themes. if ( str_contains( $theme_slug, '/' ) ) { unset( $installed_themes[ $theme_slug ] ); } } foreach ( $api->themes as &$theme ) { $theme->install_url = add_query_arg( array( 'theme' => $theme->slug, '_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug ), ), $update_php ); if ( current_user_can( 'switch_themes' ) ) { if ( is_multisite() ) { $theme->activate_url = add_query_arg( array( 'action' => 'enable', '_wpnonce' => wp_create_nonce( 'enable-theme_' . $theme->slug ), 'theme' => $theme->slug, ), network_admin_url( 'themes.php' ) ); } else { $theme->activate_url = add_query_arg( array( 'action' => 'activate', '_wpnonce' => wp_create_nonce( 'switch-theme_' . $theme->slug ), 'stylesheet' => $theme->slug, ), admin_url( 'themes.php' ) ); } } $is_theme_installed = array_key_exists( $theme->slug, $installed_themes ); // We only care about installed themes. $theme->block_theme = $is_theme_installed && wp_get_theme( $theme->slug )->is_block_theme(); if ( ! is_multisite() && current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { $customize_url = $theme->block_theme ? admin_url( 'site-editor.php' ) : wp_customize_url( $theme->slug ); $theme->customize_url = add_query_arg( array( 'return' => urlencode( network_admin_url( 'theme-install.php', 'relative' ) ), ), $customize_url ); } $theme->name = wp_kses( $theme->name, $themes_allowedtags ); $theme->author = wp_kses( $theme->author['display_name'], $themes_allowedtags ); $theme->version = wp_kses( $theme->version, $themes_allowedtags ); $theme->description = wp_kses( $theme->description, $themes_allowedtags ); $theme->stars = wp_star_rating( array( 'rating' => $theme->rating, 'type' => 'percent', 'number' => $theme->num_ratings, 'echo' => false, ) ); $theme->num_ratings = number_format_i18n( $theme->num_ratings ); $theme->preview_url = set_url_scheme( $theme->preview_url ); $theme->compatible_wp = is_wp_version_compatible( $theme->requires ); $theme->compatible_php = is_php_version_compatible( $theme->requires_php ); } wp_send_json_success( $api ); } /** * Applies [embed] Ajax handlers to a string. * * @since 4.0.0 * * @global WP_Post $post Global post object. * @global WP_Embed $wp_embed WordPress Embed object. * @global WP_Scripts $wp_scripts Script dependencies object. * @global int $content_width Shared post content width. */ function wp_ajax_parse_embed() { global $post, $wp_embed, $content_width; if ( empty( $_POST['shortcode'] ) ) { wp_send_json_error(); } $post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0; if ( $post_id > 0 ) { $post = get_post( $post_id ); if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) { wp_send_json_error(); } setup_postdata( $post ); } elseif ( ! current_user_can( 'edit_posts' ) ) { // See WP_oEmbed_Controller::get_proxy_item_permissions_check(). wp_send_json_error(); } $shortcode = wp_unslash( $_POST['shortcode'] ); preg_match( '/' . get_shortcode_regex() . '/s', $shortcode, $matches ); $atts = shortcode_parse_atts( $matches[3] ); if ( ! empty( $matches[5] ) ) { $url = $matches[5]; } elseif ( ! empty( $atts['src'] ) ) { $url = $atts['src']; } else { $url = ''; } $parsed = false; $wp_embed->return_false_on_fail = true; if ( 0 === $post_id ) { /* * Refresh oEmbeds cached outside of posts that are past their TTL. * Posts are excluded because they have separate logic for refreshing * their post meta caches. See WP_Embed::cache_oembed(). */ $wp_embed->usecache = false; } if ( is_ssl() && str_starts_with( $url, 'http://' ) ) { /* * Admin is ssl and the user pasted non-ssl URL. * Check if the provider supports ssl embeds and use that for the preview. */ $ssl_shortcode = preg_replace( '%^(\\[embed[^\\]]*\\])http://%i', '$1https://', $shortcode ); $parsed = $wp_embed->run_shortcode( $ssl_shortcode ); if ( ! $parsed ) { $no_ssl_support = true; } } // Set $content_width so any embeds fit in the destination iframe. if ( isset( $_POST['maxwidth'] ) && is_numeric( $_POST['maxwidth'] ) && $_POST['maxwidth'] > 0 ) { if ( ! isset( $content_width ) ) { $content_width = (int) $_POST['maxwidth']; } else { $content_width = min( $content_width, (int) $_POST['maxwidth'] ); } } if ( $url && ! $parsed ) { $parsed = $wp_embed->run_shortcode( $shortcode ); } if ( ! $parsed ) { wp_send_json_error( array( 'type' => 'not-embeddable', /* translators: %s: URL that could not be embedded. */ 'message' => sprintf( __( '%s failed to embed.' ), '<code>' . esc_html( $url ) . '</code>' ), ) ); } if ( has_shortcode( $parsed, 'audio' ) || has_shortcode( $parsed, 'video' ) ) { $styles = ''; $mce_styles = wpview_media_sandbox_styles(); foreach ( $mce_styles as $style ) { $styles .= sprintf( '<link rel="stylesheet" href="%s" />', $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( '%<link [^>]*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 ( str_contains( $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'] = '<script src="' . $script_src . '"></script>'; $return['sandbox'] = true; } wp_send_json_success( $return ); } /** * @since 4.0.0 * * @global WP_Post $post Global post object. * @global WP_Scripts $wp_scripts Script dependencies object. */ 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 .= '<link rel="stylesheet" href="' . $style . '">'; } 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(), ) ); } /** * Handles destroying multiple open sessions for a user via AJAX. * * @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 ) ); } /** * Handles cropping an image via AJAX. * * @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. // Copy attachment properties. $attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, $context ); // Update the attachment. add_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) ); $attachment_id = $wp_site_icon->insert_attachment( $attachment, $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. // Copy attachment properties. $attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, $context ); $attachment_id = wp_insert_attachment( $attachment, $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 ) ); } /** * Handles generating a password via AJAX. * * @since 4.4.0 */ function wp_ajax_generate_password() { wp_send_json_success( wp_generate_password( 24 ) ); } /** * Handles generating a password in the no-privilege context via AJAX. * * @since 5.7.0 */ function wp_ajax_nopriv_generate_password() { wp_send_json_success( wp_generate_password( 24 ) ); } /** * Handles saving the user's WordPress.org username via AJAX. * * @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 ) ); } /** * Handles installing a theme via AJAX. * * @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'; require_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' ) ); } } $theme = wp_get_theme( $slug ); $status['blockTheme'] = $theme->is_block_theme(); 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 ); } /** * Handles updating a theme via AJAX. * * @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 ); } /** * Handles deleting a theme via AJAX. * * @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 ); } require_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 ); } /** * Handles installing a plugin via AJAX. * * @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'; require_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 ); } /** * Handles activating a plugin via AJAX. * * @since 6.5.0 */ function wp_ajax_activate_plugin() { check_ajax_referer( 'updates' ); if ( empty( $_POST['name'] ) || empty( $_POST['slug'] ) || empty( $_POST['plugin'] ) ) { wp_send_json_error( array( 'slug' => '', 'pluginName' => '', 'plugin' => '', 'errorCode' => 'no_plugin_specified', 'errorMessage' => __( 'No plugin specified.' ), ) ); } $status = array( 'activate' => 'plugin', 'slug' => wp_unslash( $_POST['slug'] ), 'pluginName' => wp_unslash( $_POST['name'] ), 'plugin' => wp_unslash( $_POST['plugin'] ), ); if ( ! current_user_can( 'activate_plugin', $status['plugin'] ) ) { $status['errorMessage'] = __( 'Sorry, you are not allowed to activate plugins on this site.' ); wp_send_json_error( $status ); } if ( is_plugin_active( $status['plugin'] ) ) { $status['errorMessage'] = sprintf( /* translators: %s: Plugin name. */ __( '%s is already active.' ), $status['pluginName'] ); } $activated = activate_plugin( $status['plugin'] ); if ( is_wp_error( $activated ) ) { $status['errorMessage'] = $activated->get_error_message(); wp_send_json_error( $status ); } wp_send_json_success( $status ); } /** * Handles updating a plugin via AJAX. * * @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 ); } /** * Handles deleting a plugin via AJAX. * * @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 ); } /** * Handles searching plugins via AJAX. * * @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(); WP_Plugin_Dependencies::initialize(); $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 ); } /** * Handles searching plugins to install via AJAX. * * @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 ); } /** * Handles editing a theme or plugin file via AJAX. * * @since 4.9.0 * * @see wp_edit_theme_plugin_file() */ function wp_ajax_edit_theme_plugin_file() { $edit_result = wp_edit_theme_plugin_file( wp_unslash( $_POST ) ); // Validation of args is done in wp_edit_theme_plugin_file(). if ( is_wp_error( $edit_result ) ) { wp_send_json_error( array_merge( array( 'code' => $edit_result->get_error_code(), 'message' => $edit_result->get_error_message(), ), (array) $edit_result->get_error_data() ) ); } else { wp_send_json_success( array( 'message' => __( 'File edited successfully.' ), ) ); } } /** * Handles exporting a user's personal data via AJAX. * * @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 number 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 number. * @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 number 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 ); } /** * Handles erasing personal data via AJAX. * * @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 * number, 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 number. * * @type bool $items_removed Whether items were actually removed or not. * @type bool $items_retained Whether items were retained or not. * @type string[] $messages An array of messages to add to the personal data export file. * @type bool $done Whether the eraser is finished or not. * } * @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 number 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 ); } /** * Handles site health checks on server communication via AJAX. * * @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() ); } /** * Handles site health checks on background updates via AJAX. * * @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() ); } /** * Handles site health checks on loopback requests via AJAX. * * @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() ); } /** * Handles site health check to update the result status via AJAX. * * @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(); } /** * Handles site health check to get directories and database sizes via AJAX. * * @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 ); } /** * Handles renewing the REST API nonce via AJAX. * * @since 5.3.0 */ function wp_ajax_rest_nonce() { exit( wp_create_nonce( 'wp_rest' ) ); } /** * Handles enabling or disable plugin and theme auto-updates via AJAX. * * @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(); } /** * Handles sending a password reset link via AJAX. * * @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 $��\������ �� upgrade.phpnu �[��� <?php /** * WordPress Upgrade API * * Most of the functions are pluggable and can be overwritten. * * @package WordPress * @subpackage Administration */ /** Include user installation customization script. */ if ( file_exists( WP_CONTENT_DIR . '/install.php' ) ) { require WP_CONTENT_DIR . '/install.php'; } /** WordPress Administration API */ require_once ABSPATH . 'wp-admin/includes/admin.php'; /** WordPress Schema API */ require_once ABSPATH . 'wp-admin/includes/schema.php'; if ( ! function_exists( 'wp_install' ) ) : /** * Installs the site. * * Runs the required functions to set up and populate the database, * including primary admin user and initial options. * * @since 2.1.0 * * @param string $blog_title Site title. * @param string $user_name User's username. * @param string $user_email User's email. * @param bool $is_public Whether the site is public. * @param string $deprecated Optional. Not used. * @param string $user_password Optional. User's chosen password. Default empty (random password). * @param string $language Optional. Language chosen. Default empty. * @return array { * Data for the newly installed site. * * @type string $url The URL of the site. * @type int $user_id The ID of the site owner. * @type string $password The password of the site owner, if their user account didn't already exist. * @type string $password_message The explanatory message regarding the password. * } */ function wp_install( $blog_title, $user_name, $user_email, $is_public, $deprecated = '', #[\SensitiveParameter] $user_password = '', $language = '' ) { if ( ! empty( $deprecated ) ) { _deprecated_argument( __FUNCTION__, '2.6.0' ); } wp_check_mysql_version(); wp_cache_flush(); make_db_current_silent(); /* * Ensure update checks are delayed after installation. * * This prevents users being presented with a maintenance mode screen * immediately after installation. */ wp_unschedule_hook( 'wp_version_check' ); wp_unschedule_hook( 'wp_update_plugins' ); wp_unschedule_hook( 'wp_update_themes' ); wp_schedule_event( time() + HOUR_IN_SECONDS, 'twicedaily', 'wp_version_check' ); wp_schedule_event( time() + ( 1.5 * HOUR_IN_SECONDS ), 'twicedaily', 'wp_update_plugins' ); wp_schedule_event( time() + ( 2 * HOUR_IN_SECONDS ), 'twicedaily', 'wp_update_themes' ); populate_options(); populate_roles(); update_option( 'blogname', $blog_title ); update_option( 'admin_email', $user_email ); update_option( 'blog_public', $is_public ); // Freshness of site - in the future, this could get more specific about actions taken, perhaps. update_option( 'fresh_site', 1, false ); if ( $language ) { update_option( 'WPLANG', $language ); } $guessurl = wp_guess_url(); update_option( 'siteurl', $guessurl ); // If not a public site, don't ping. if ( ! $is_public ) { update_option( 'default_pingback_flag', 0 ); } /* * Create default user. If the user already exists, the user tables are * being shared among sites. Just set the role in that case. */ $user_id = username_exists( $user_name ); $user_password = trim( $user_password ); $email_password = false; $user_created = false; if ( ! $user_id && empty( $user_password ) ) { $user_password = wp_generate_password( 12, false ); $message = __( '<strong><em>Note that password</em></strong> carefully! It is a <em>random</em> password that was generated just for you.' ); $user_id = wp_create_user( $user_name, $user_password, $user_email ); update_user_meta( $user_id, 'default_password_nag', true ); $email_password = true; $user_created = true; } elseif ( ! $user_id ) { // Password has been provided. $message = '<em>' . __( 'Your chosen password.' ) . '</em>'; $user_id = wp_create_user( $user_name, $user_password, $user_email ); $user_created = true; } else { $message = __( 'User already exists. Password inherited.' ); } $user = new WP_User( $user_id ); $user->set_role( 'administrator' ); if ( $user_created ) { $user->user_url = $guessurl; wp_update_user( $user ); } wp_install_defaults( $user_id ); wp_install_maybe_enable_pretty_permalinks(); flush_rewrite_rules(); wp_new_blog_notification( $blog_title, $guessurl, $user_id, ( $email_password ? $user_password : __( 'The password you chose during installation.' ) ) ); wp_cache_flush(); /** * Fires after a site is fully installed. * * @since 3.9.0 * * @param WP_User $user The site owner. */ do_action( 'wp_install', $user ); return array( 'url' => $guessurl, 'user_id' => $user_id, 'password' => $user_password, 'password_message' => $message, ); } endif; if ( ! function_exists( 'wp_install_defaults' ) ) : /** * Creates the initial content for a newly-installed site. * * Adds the default "Uncategorized" category, the first post (with comment), * first page, and default widgets for default theme for the current version. * * @since 2.1.0 * * @global wpdb $wpdb WordPress database abstraction object. * @global WP_Rewrite $wp_rewrite WordPress rewrite component. * @global string $table_prefix The database table prefix. * * @param int $user_id User ID. */ function wp_install_defaults( $user_id ) { global $wpdb, $wp_rewrite, $table_prefix; // Default category. $cat_name = __( 'Uncategorized' ); /* translators: Default category slug. */ $cat_slug = sanitize_title( _x( 'Uncategorized', 'Default category slug' ) ); $cat_id = 1; $wpdb->insert( $wpdb->terms, array( 'term_id' => $cat_id, 'name' => $cat_name, 'slug' => $cat_slug, 'term_group' => 0, ) ); $wpdb->insert( $wpdb->term_taxonomy, array( 'term_id' => $cat_id, 'taxonomy' => 'category', 'description' => '', 'parent' => 0, 'count' => 1, ) ); $cat_tt_id = $wpdb->insert_id; // First post. $now = current_time( 'mysql' ); $now_gmt = current_time( 'mysql', true ); $first_post_guid = get_option( 'home' ) . '/?p=1'; if ( is_multisite() ) { $first_post = get_site_option( 'first_post' ); if ( ! $first_post ) { $first_post = "<!-- wp:paragraph -->\n<p>" . /* translators: First post content. %s: Site link. */ __( 'Welcome to %s. This is your first post. Edit or delete it, then start writing!' ) . "</p>\n<!-- /wp:paragraph -->"; } $first_post = sprintf( $first_post, sprintf( '<a href="%s">%s</a>', esc_url( network_home_url() ), get_network()->site_name ) ); // Back-compat for pre-4.4. $first_post = str_replace( 'SITE_URL', esc_url( network_home_url() ), $first_post ); $first_post = str_replace( 'SITE_NAME', get_network()->site_name, $first_post ); } else { $first_post = "<!-- wp:paragraph -->\n<p>" . /* translators: First post content. %s: Site link. */ __( 'Welcome to WordPress. This is your first post. Edit or delete it, then start writing!' ) . "</p>\n<!-- /wp:paragraph -->"; } $wpdb->insert( $wpdb->posts, array( 'post_author' => $user_id, 'post_date' => $now, 'post_date_gmt' => $now_gmt, 'post_content' => $first_post, 'post_excerpt' => '', 'post_title' => __( 'Hello world!' ), /* translators: Default post slug. */ 'post_name' => sanitize_title( _x( 'hello-world', 'Default post slug' ) ), 'post_modified' => $now, 'post_modified_gmt' => $now_gmt, 'guid' => $first_post_guid, 'comment_count' => 1, 'to_ping' => '', 'pinged' => '', 'post_content_filtered' => '', ) ); if ( is_multisite() ) { update_posts_count(); } $wpdb->insert( $wpdb->term_relationships, array( 'term_taxonomy_id' => $cat_tt_id, 'object_id' => 1, ) ); // Default comment. if ( is_multisite() ) { $first_comment_author = get_site_option( 'first_comment_author' ); $first_comment_email = get_site_option( 'first_comment_email' ); $first_comment_url = get_site_option( 'first_comment_url', network_home_url() ); $first_comment = get_site_option( 'first_comment' ); } $first_comment_author = ! empty( $first_comment_author ) ? $first_comment_author : __( 'A WordPress Commenter' ); $first_comment_email = ! empty( $first_comment_email ) ? $first_comment_email : 'wapuu@wordpress.example'; $first_comment_url = ! empty( $first_comment_url ) ? $first_comment_url : esc_url( __( 'https://wordpress.org/' ) ); $first_comment = ! empty( $first_comment ) ? $first_comment : sprintf( /* translators: %s: Gravatar URL. */ __( 'Hi, this is a comment. To get started with moderating, editing, and deleting comments, please visit the Comments screen in the dashboard. Commenter avatars come from <a href="%s">Gravatar</a>.' ), /* translators: The localized Gravatar URL. */ esc_url( __( 'https://gravatar.com/' ) ) ); $wpdb->insert( $wpdb->comments, array( 'comment_post_ID' => 1, 'comment_author' => $first_comment_author, 'comment_author_email' => $first_comment_email, 'comment_author_url' => $first_comment_url, 'comment_date' => $now, 'comment_date_gmt' => $now_gmt, 'comment_content' => $first_comment, 'comment_type' => 'comment', ) ); // First page. if ( is_multisite() ) { $first_page = get_site_option( 'first_page' ); } if ( empty( $first_page ) ) { $first_page = "<!-- wp:paragraph -->\n<p>"; /* translators: First page content. */ $first_page .= __( "This is an example page. It's different from a blog post because it will stay in one place and will show up in your site navigation (in most themes). Most people start with an About page that introduces them to potential site visitors. It might say something like this:" ); $first_page .= "</p>\n<!-- /wp:paragraph -->\n\n"; $first_page .= "<!-- wp:quote -->\n<blockquote class=\"wp-block-quote\">\n<!-- wp:paragraph -->\n<p>"; /* translators: First page content. */ $first_page .= __( "Hi there! I'm a bike messenger by day, aspiring actor by night, and this is my website. I live in Los Angeles, have a great dog named Jack, and I like piña coladas. (And gettin' caught in the rain.)" ); $first_page .= "</p>\n<!-- /wp:paragraph -->\n</blockquote>\n<!-- /wp:quote -->\n\n"; $first_page .= "<!-- wp:paragraph -->\n<p>"; /* translators: First page content. */ $first_page .= __( '...or something like this:' ); $first_page .= "</p>\n<!-- /wp:paragraph -->\n\n"; $first_page .= "<!-- wp:quote -->\n<blockquote class=\"wp-block-quote\">\n<!-- wp:paragraph -->\n<p>"; /* translators: First page content. */ $first_page .= __( 'The XYZ Doohickey Company was founded in 1971, and has been providing quality doohickeys to the public ever since. Located in Gotham City, XYZ employs over 2,000 people and does all kinds of awesome things for the Gotham community.' ); $first_page .= "</p>\n<!-- /wp:paragraph -->\n</blockquote>\n<!-- /wp:quote -->\n\n"; $first_page .= "<!-- wp:paragraph -->\n<p>"; $first_page .= sprintf( /* translators: First page content. %s: Site admin URL. */ __( 'As a new WordPress user, you should go to <a href="%s">your dashboard</a> to delete this page and create new pages for your content. Have fun!' ), admin_url() ); $first_page .= "</p>\n<!-- /wp:paragraph -->"; } $first_post_guid = get_option( 'home' ) . '/?page_id=2'; $wpdb->insert( $wpdb->posts, array( 'post_author' => $user_id, 'post_date' => $now, 'post_date_gmt' => $now_gmt, 'post_content' => $first_page, 'post_excerpt' => '', 'comment_status' => 'closed', 'post_title' => __( 'Sample Page' ), /* translators: Default page slug. */ 'post_name' => __( 'sample-page' ), 'post_modified' => $now, 'post_modified_gmt' => $now_gmt, 'guid' => $first_post_guid, 'post_type' => 'page', 'to_ping' => '', 'pinged' => '', 'post_content_filtered' => '', ) ); $wpdb->insert( $wpdb->postmeta, array( 'post_id' => 2, 'meta_key' => '_wp_page_template', 'meta_value' => 'default', ) ); // Privacy Policy page. if ( is_multisite() ) { // Disable by default unless the suggested content is provided. $privacy_policy_content = get_site_option( 'default_privacy_policy_content' ); } else { if ( ! class_exists( 'WP_Privacy_Policy_Content' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-policy-content.php'; } $privacy_policy_content = WP_Privacy_Policy_Content::get_default_content(); } if ( ! empty( $privacy_policy_content ) ) { $privacy_policy_guid = get_option( 'home' ) . '/?page_id=3'; $wpdb->insert( $wpdb->posts, array( 'post_author' => $user_id, 'post_date' => $now, 'post_date_gmt' => $now_gmt, 'post_content' => $privacy_policy_content, 'post_excerpt' => '', 'comment_status' => 'closed', 'post_title' => __( 'Privacy Policy' ), /* translators: Privacy Policy page slug. */ 'post_name' => __( 'privacy-policy' ), 'post_modified' => $now, 'post_modified_gmt' => $now_gmt, 'guid' => $privacy_policy_guid, 'post_type' => 'page', 'post_status' => 'draft', 'to_ping' => '', 'pinged' => '', 'post_content_filtered' => '', ) ); $wpdb->insert( $wpdb->postmeta, array( 'post_id' => 3, 'meta_key' => '_wp_page_template', 'meta_value' => 'default', ) ); update_option( 'wp_page_for_privacy_policy', 3 ); } // Set up default widgets for default theme. update_option( 'widget_block', array( 2 => array( 'content' => '<!-- wp:search /-->' ), 3 => array( 'content' => '<!-- wp:group --><div class="wp-block-group"><!-- wp:heading --><h2>' . __( 'Recent Posts' ) . '</h2><!-- /wp:heading --><!-- wp:latest-posts /--></div><!-- /wp:group -->' ), 4 => array( 'content' => '<!-- wp:group --><div class="wp-block-group"><!-- wp:heading --><h2>' . __( 'Recent Comments' ) . '</h2><!-- /wp:heading --><!-- wp:latest-comments {"displayAvatar":false,"displayDate":false,"displayExcerpt":false} /--></div><!-- /wp:group -->' ), 5 => array( 'content' => '<!-- wp:group --><div class="wp-block-group"><!-- wp:heading --><h2>' . __( 'Archives' ) . '</h2><!-- /wp:heading --><!-- wp:archives /--></div><!-- /wp:group -->' ), 6 => array( 'content' => '<!-- wp:group --><div class="wp-block-group"><!-- wp:heading --><h2>' . __( 'Categories' ) . '</h2><!-- /wp:heading --><!-- wp:categories /--></div><!-- /wp:group -->' ), '_multiwidget' => 1, ) ); update_option( 'sidebars_widgets', array( 'wp_inactive_widgets' => array(), 'sidebar-1' => array( 0 => 'block-2', 1 => 'block-3', 2 => 'block-4', ), 'sidebar-2' => array( 0 => 'block-5', 1 => 'block-6', ), 'array_version' => 3, ) ); if ( ! is_multisite() ) { update_user_meta( $user_id, 'show_welcome_panel', 1 ); } elseif ( ! is_super_admin( $user_id ) && ! metadata_exists( 'user', $user_id, 'show_welcome_panel' ) ) { update_user_meta( $user_id, 'show_welcome_panel', 2 ); } if ( is_multisite() ) { // Flush rules to pick up the new page. $wp_rewrite->init(); $wp_rewrite->flush_rules(); $user = new WP_User( $user_id ); $wpdb->update( $wpdb->options, array( 'option_value' => $user->user_email ), array( 'option_name' => 'admin_email' ) ); // Remove all perms except for the login user. $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->usermeta WHERE user_id != %d AND meta_key = %s", $user_id, $table_prefix . 'user_level' ) ); $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->usermeta WHERE user_id != %d AND meta_key = %s", $user_id, $table_prefix . 'capabilities' ) ); /* * Delete any caps that snuck into the previously active blog. (Hardcoded to blog 1 for now.) * TODO: Get previous_blog_id. */ if ( ! is_super_admin( $user_id ) && 1 !== $user_id ) { $wpdb->delete( $wpdb->usermeta, array( 'user_id' => $user_id, 'meta_key' => $wpdb->base_prefix . '1_capabilities', ) ); } } } endif; /** * Maybe enable pretty permalinks on installation. * * If after enabling pretty permalinks don't work, fallback to query-string permalinks. * * @since 4.2.0 * * @global WP_Rewrite $wp_rewrite WordPress rewrite component. * * @return bool Whether pretty permalinks are enabled. False otherwise. */ function wp_install_maybe_enable_pretty_permalinks() { global $wp_rewrite; // Bail if a permalink structure is already enabled. if ( get_option( 'permalink_structure' ) ) { return true; } /* * The Permalink structures to attempt. * * The first is designed for mod_rewrite or nginx rewriting. * * The second is PATHINFO-based permalinks for web server configurations * without a true rewrite module enabled. */ $permalink_structures = array( '/%year%/%monthnum%/%day%/%postname%/', '/index.php/%year%/%monthnum%/%day%/%postname%/', ); foreach ( (array) $permalink_structures as $permalink_structure ) { $wp_rewrite->set_permalink_structure( $permalink_structure ); /* * Flush rules with the hard option to force refresh of the web-server's * rewrite config file (e.g. .htaccess or web.config). */ $wp_rewrite->flush_rules( true ); $test_url = ''; // Test against a real WordPress post. $first_post = get_page_by_path( sanitize_title( _x( 'hello-world', 'Default post slug' ) ), OBJECT, 'post' ); if ( $first_post ) { $test_url = get_permalink( $first_post->ID ); } /* * Send a request to the site, and check whether * the 'X-Pingback' header is returned as expected. * * Uses wp_remote_get() instead of wp_remote_head() because web servers * can block head requests. */ $response = wp_remote_get( $test_url, array( 'timeout' => 5 ) ); $x_pingback_header = wp_remote_retrieve_header( $response, 'X-Pingback' ); $pretty_permalinks = $x_pingback_header && get_bloginfo( 'pingback_url' ) === $x_pingback_header; if ( $pretty_permalinks ) { return true; } } /* * If it makes it this far, pretty permalinks failed. * Fallback to query-string permalinks. */ $wp_rewrite->set_permalink_structure( '' ); $wp_rewrite->flush_rules( true ); return false; } if ( ! function_exists( 'wp_new_blog_notification' ) ) : /** * Notifies the site admin that the installation of WordPress is complete. * * Sends an email to the new administrator that the installation is complete * and provides them with a record of their login credentials. * * @since 2.1.0 * * @param string $blog_title Site title. * @param string $blog_url Site URL. * @param int $user_id Administrator's user ID. * @param string $password Administrator's password. Note that a placeholder message is * usually passed instead of the actual password. */ function wp_new_blog_notification( $blog_title, $blog_url, $user_id, #[\SensitiveParameter] $password ) { $user = new WP_User( $user_id ); $email = $user->user_email; $name = $user->user_login; $login_url = wp_login_url(); $message = sprintf( /* translators: New site notification email. 1: New site URL, 2: User login, 3: User password or password reset link, 4: Login URL. */ __( 'Your new WordPress site has been successfully set up at: %1$s You can log in to the administrator account with the following information: Username: %2$s Password: %3$s Log in here: %4$s We hope you enjoy your new site. Thanks! --The WordPress Team https://wordpress.org/ ' ), $blog_url, $name, $password, $login_url ); $installed_email = array( 'to' => $email, 'subject' => __( 'New WordPress Site' ), 'message' => $message, 'headers' => '', ); /** * Filters the contents of the email sent to the site administrator when WordPress is installed. * * @since 5.6.0 * * @param array $installed_email { * Used to build wp_mail(). * * @type string $to The email address of the recipient. * @type string $subject The subject of the email. * @type string $message The content of the email. * @type string $headers Headers. * } * @param WP_User $user The site administrator user object. * @param string $blog_title The site title. * @param string $blog_url The site URL. * @param string $password The site administrator's password. Note that a placeholder message * is usually passed instead of the user's actual password. */ $installed_email = apply_filters( 'wp_installed_email', $installed_email, $user, $blog_title, $blog_url, $password ); wp_mail( $installed_email['to'], $installed_email['subject'], $installed_email['message'], $installed_email['headers'] ); } endif; if ( ! function_exists( 'wp_upgrade' ) ) : /** * Runs WordPress Upgrade functions. * * Upgrades the database if needed during a site update. * * @since 2.1.0 * * @global int $wp_current_db_version The old (current) database version. * @global int $wp_db_version The new database version. */ function wp_upgrade() { global $wp_current_db_version, $wp_db_version; $wp_current_db_version = (int) __get_option( 'db_version' ); // We are up to date. Nothing to do. if ( $wp_db_version === $wp_current_db_version ) { return; } if ( ! is_blog_installed() ) { return; } wp_check_mysql_version(); wp_cache_flush(); pre_schema_upgrade(); make_db_current_silent(); upgrade_all(); if ( is_multisite() && is_main_site() ) { upgrade_network(); } wp_cache_flush(); if ( is_multisite() ) { update_site_meta( get_current_blog_id(), 'db_version', $wp_db_version ); update_site_meta( get_current_blog_id(), 'db_last_updated', microtime() ); } delete_transient( 'wp_core_block_css_files' ); /** * Fires after a site is fully upgraded. * * @since 3.9.0 * * @param int $wp_db_version The new $wp_db_version. * @param int $wp_current_db_version The old (current) $wp_db_version. */ do_action( 'wp_upgrade', $wp_db_version, $wp_current_db_version ); } endif; /** * Functions to be called in installation and upgrade scripts. * * Contains conditional checks to determine which upgrade scripts to run, * based on database version and WP version being updated-to. * * @ignore * @since 1.0.1 * * @global int $wp_current_db_version The old (current) database version. * @global int $wp_db_version The new database version. */ function upgrade_all() { global $wp_current_db_version, $wp_db_version; $wp_current_db_version = (int) __get_option( 'db_version' ); // We are up to date. Nothing to do. if ( $wp_db_version === $wp_current_db_version ) { return; } // If the version is not set in the DB, try to guess the version. if ( empty( $wp_current_db_version ) ) { $wp_current_db_version = 0; // If the template option exists, we have 1.5. $template = __get_option( 'template' ); if ( ! empty( $template ) ) { $wp_current_db_version = 2541; } } if ( $wp_current_db_version < 6039 ) { upgrade_230_options_table(); } populate_options(); if ( $wp_current_db_version < 2541 ) { upgrade_100(); upgrade_101(); upgrade_110(); upgrade_130(); } if ( $wp_current_db_version < 3308 ) { upgrade_160(); } if ( $wp_current_db_version < 4772 ) { upgrade_210(); } if ( $wp_current_db_version < 4351 ) { upgrade_old_slugs(); } if ( $wp_current_db_version < 5539 ) { upgrade_230(); } if ( $wp_current_db_version < 6124 ) { upgrade_230_old_tables(); } if ( $wp_current_db_version < 7499 ) { upgrade_250(); } if ( $wp_current_db_version < 7935 ) { upgrade_252(); } if ( $wp_current_db_version < 8201 ) { upgrade_260(); } if ( $wp_current_db_version < 8989 ) { upgrade_270(); } if ( $wp_current_db_version < 10360 ) { upgrade_280(); } if ( $wp_current_db_version < 11958 ) { upgrade_290(); } if ( $wp_current_db_version < 15260 ) { upgrade_300(); } if ( $wp_current_db_version < 19389 ) { upgrade_330(); } if ( $wp_current_db_version < 20080 ) { upgrade_340(); } if ( $wp_current_db_version < 22422 ) { upgrade_350(); } if ( $wp_current_db_version < 25824 ) { upgrade_370(); } if ( $wp_current_db_version < 26148 ) { upgrade_372(); } if ( $wp_current_db_version < 26691 ) { upgrade_380(); } if ( $wp_current_db_version < 29630 ) { upgrade_400(); } if ( $wp_current_db_version < 33055 ) { upgrade_430(); } if ( $wp_current_db_version < 33056 ) { upgrade_431(); } if ( $wp_current_db_version < 35700 ) { upgrade_440(); } if ( $wp_current_db_version < 36686 ) { upgrade_450(); } if ( $wp_current_db_version < 37965 ) { upgrade_460(); } if ( $wp_current_db_version < 44719 ) { upgrade_510(); } if ( $wp_current_db_version < 45744 ) { upgrade_530(); } if ( $wp_current_db_version < 48575 ) { upgrade_550(); } if ( $wp_current_db_version < 49752 ) { upgrade_560(); } if ( $wp_current_db_version < 51917 ) { upgrade_590(); } if ( $wp_current_db_version < 53011 ) { upgrade_600(); } if ( $wp_current_db_version < 55853 ) { upgrade_630(); } if ( $wp_current_db_version < 56657 ) { upgrade_640(); } if ( $wp_current_db_version < 57155 ) { upgrade_650(); } if ( $wp_current_db_version < 58975 ) { upgrade_670(); } if ( $wp_current_db_version < 60421 ) { upgrade_682(); } if ( $wp_current_db_version < 61644 ) { upgrade_700(); } maybe_disable_link_manager(); maybe_disable_automattic_widgets(); update_option( 'db_version', $wp_db_version ); update_option( 'db_upgraded', true ); } /** * Execute changes made in WordPress 1.0. * * @ignore * @since 1.0.0 * * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_100() { global $wpdb; // Get the title and ID of every post, post_name to check if it already has a value. $posts = $wpdb->get_results( "SELECT ID, post_title, post_name FROM $wpdb->posts WHERE post_name = ''" ); if ( $posts ) { foreach ( $posts as $post ) { if ( '' === $post->post_name ) { $newtitle = sanitize_title( $post->post_title ); $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_name = %s WHERE ID = %d", $newtitle, $post->ID ) ); } } } $categories = $wpdb->get_results( "SELECT cat_ID, cat_name, category_nicename FROM $wpdb->categories" ); foreach ( $categories as $category ) { if ( '' === $category->category_nicename ) { $newtitle = sanitize_title( $category->cat_name ); $wpdb->update( $wpdb->categories, array( 'category_nicename' => $newtitle ), array( 'cat_ID' => $category->cat_ID ) ); } } $sql = "UPDATE $wpdb->options SET option_value = REPLACE(option_value, 'wp-links/links-images/', 'wp-images/links/') WHERE option_name LIKE %s AND option_value LIKE %s"; $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( 'links_rating_image' ) . '%', $wpdb->esc_like( 'wp-links/links-images/' ) . '%' ) ); $done_ids = $wpdb->get_results( "SELECT DISTINCT post_id FROM $wpdb->post2cat" ); if ( $done_ids ) : $done_posts = array(); foreach ( $done_ids as $done_id ) : $done_posts[] = $done_id->post_id; endforeach; $catwhere = ' AND ID NOT IN (' . implode( ',', $done_posts ) . ')'; else : $catwhere = ''; endif; $allposts = $wpdb->get_results( "SELECT ID, post_category FROM $wpdb->posts WHERE post_category != '0' $catwhere" ); if ( $allposts ) : foreach ( $allposts as $post ) { // Check to see if it's already been imported. $cat = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->post2cat WHERE post_id = %d AND category_id = %d", $post->ID, $post->post_category ) ); if ( ! $cat && 0 !== (int) $post->post_category ) { // If there's no result. $wpdb->insert( $wpdb->post2cat, array( 'post_id' => $post->ID, 'category_id' => $post->post_category, ) ); } } endif; } /** * Execute changes made in WordPress 1.0.1. * * @ignore * @since 1.0.1 * * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_101() { global $wpdb; // Clean up indices, add a few. add_clean_index( $wpdb->posts, 'post_name' ); add_clean_index( $wpdb->posts, 'post_status' ); add_clean_index( $wpdb->categories, 'category_nicename' ); add_clean_index( $wpdb->comments, 'comment_approved' ); add_clean_index( $wpdb->comments, 'comment_post_ID' ); add_clean_index( $wpdb->links, 'link_category' ); add_clean_index( $wpdb->links, 'link_visible' ); } /** * Execute changes made in WordPress 1.2. * * @ignore * @since 1.2.0 * @since 6.8.0 User passwords are no longer hashed with md5. * * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_110() { global $wpdb; // Set user_nicename. $users = $wpdb->get_results( "SELECT ID, user_nickname, user_nicename FROM $wpdb->users" ); foreach ( $users as $user ) { if ( '' === $user->user_nicename ) { $newname = sanitize_title( $user->user_nickname ); $wpdb->update( $wpdb->users, array( 'user_nicename' => $newname ), array( 'ID' => $user->ID ) ); } } // Get the GMT offset, we'll use that later on. $all_options = get_alloptions_110(); $time_difference = $all_options->time_difference; $server_time = time() + (int) gmdate( 'Z' ); $weblogger_time = $server_time + $time_difference * HOUR_IN_SECONDS; $gmt_time = time(); $diff_gmt_server = ( $gmt_time - $server_time ) / HOUR_IN_SECONDS; $diff_weblogger_server = ( $weblogger_time - $server_time ) / HOUR_IN_SECONDS; $diff_gmt_weblogger = $diff_gmt_server - $diff_weblogger_server; $gmt_offset = -$diff_gmt_weblogger; // Add a gmt_offset option, with value $gmt_offset. add_option( 'gmt_offset', $gmt_offset ); /* * Check if we already set the GMT fields. If we did, then * MAX(post_date_gmt) can't be '0000-00-00 00:00:00'. * <michel_v> I just slapped myself silly for not thinking about it earlier. */ $got_gmt_fields = ( '0000-00-00 00:00:00' !== $wpdb->get_var( "SELECT MAX(post_date_gmt) FROM $wpdb->posts" ) ); if ( ! $got_gmt_fields ) { // Add or subtract time to all dates, to get GMT dates. $add_hours = (int) $diff_gmt_weblogger; $add_minutes = (int) ( 60 * ( $diff_gmt_weblogger - $add_hours ) ); $wpdb->query( "UPDATE $wpdb->posts SET post_date_gmt = DATE_ADD(post_date, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE)" ); $wpdb->query( "UPDATE $wpdb->posts SET post_modified = post_date" ); $wpdb->query( "UPDATE $wpdb->posts SET post_modified_gmt = DATE_ADD(post_modified, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE) WHERE post_modified != '0000-00-00 00:00:00'" ); $wpdb->query( "UPDATE $wpdb->comments SET comment_date_gmt = DATE_ADD(comment_date, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE)" ); $wpdb->query( "UPDATE $wpdb->users SET user_registered = DATE_ADD(user_registered, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE)" ); } } /** * Execute changes made in WordPress 1.5. * * @ignore * @since 1.5.0 * * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_130() { global $wpdb; // Remove extraneous backslashes. $posts = $wpdb->get_results( "SELECT ID, post_title, post_content, post_excerpt, guid, post_date, post_name, post_status, post_author FROM $wpdb->posts" ); if ( $posts ) { foreach ( $posts as $post ) { $post_content = addslashes( deslash( $post->post_content ) ); $post_title = addslashes( deslash( $post->post_title ) ); $post_excerpt = addslashes( deslash( $post->post_excerpt ) ); if ( empty( $post->guid ) ) { $guid = get_permalink( $post->ID ); } else { $guid = $post->guid; } $wpdb->update( $wpdb->posts, compact( 'post_title', 'post_content', 'post_excerpt', 'guid' ), array( 'ID' => $post->ID ) ); } } // Remove extraneous backslashes. $comments = $wpdb->get_results( "SELECT comment_ID, comment_author, comment_content FROM $wpdb->comments" ); if ( $comments ) { foreach ( $comments as $comment ) { $comment_content = deslash( $comment->comment_content ); $comment_author = deslash( $comment->comment_author ); $wpdb->update( $wpdb->comments, compact( 'comment_content', 'comment_author' ), array( 'comment_ID' => $comment->comment_ID ) ); } } // Remove extraneous backslashes. $links = $wpdb->get_results( "SELECT link_id, link_name, link_description FROM $wpdb->links" ); if ( $links ) { foreach ( $links as $link ) { $link_name = deslash( $link->link_name ); $link_description = deslash( $link->link_description ); $wpdb->update( $wpdb->links, compact( 'link_name', 'link_description' ), array( 'link_id' => $link->link_id ) ); } } $active_plugins = __get_option( 'active_plugins' ); /* * If plugins are not stored in an array, they're stored in the old * newline separated format. Convert to new format. */ if ( ! is_array( $active_plugins ) ) { $active_plugins = explode( "\n", trim( $active_plugins ) ); update_option( 'active_plugins', $active_plugins ); } // Obsolete tables. $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optionvalues' ); $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optiontypes' ); $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optiongroups' ); $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optiongroup_options' ); // Update comments table to use comment_type. $wpdb->query( "UPDATE $wpdb->comments SET comment_type='trackback', comment_content = REPLACE(comment_content, '<trackback />', '') WHERE comment_content LIKE '<trackback />%'" ); $wpdb->query( "UPDATE $wpdb->comments SET comment_type='pingback', comment_content = REPLACE(comment_content, '<pingback />', '') WHERE comment_content LIKE '<pingback />%'" ); // Some versions have multiple duplicate option_name rows with the same values. $options = $wpdb->get_results( "SELECT option_name, COUNT(option_name) AS dupes FROM `$wpdb->options` GROUP BY option_name" ); foreach ( $options as $option ) { if ( $option->dupes > 1 ) { // Could this be done in the query? $limit = $option->dupes - 1; $dupe_ids = $wpdb->get_col( $wpdb->prepare( "SELECT option_id FROM $wpdb->options WHERE option_name = %s LIMIT %d", $option->option_name, $limit ) ); if ( $dupe_ids ) { $dupe_ids = implode( ',', $dupe_ids ); $wpdb->query( "DELETE FROM $wpdb->options WHERE option_id IN ($dupe_ids)" ); } } } make_site_theme(); } /** * Execute changes made in WordPress 2.0. * * @ignore * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * @global int $wp_current_db_version The old (current) database version. */ function upgrade_160() { global $wpdb, $wp_current_db_version; populate_roles_160(); $users = $wpdb->get_results( "SELECT * FROM $wpdb->users" ); foreach ( $users as $user ) : if ( ! empty( $user->user_firstname ) ) { update_user_meta( $user->ID, 'first_name', wp_slash( $user->user_firstname ) ); } if ( ! empty( $user->user_lastname ) ) { update_user_meta( $user->ID, 'last_name', wp_slash( $user->user_lastname ) ); } if ( ! empty( $user->user_nickname ) ) { update_user_meta( $user->ID, 'nickname', wp_slash( $user->user_nickname ) ); } if ( ! empty( $user->user_level ) ) { update_user_meta( $user->ID, $wpdb->prefix . 'user_level', $user->user_level ); } if ( ! empty( $user->user_icq ) ) { update_user_meta( $user->ID, 'icq', wp_slash( $user->user_icq ) ); } if ( ! empty( $user->user_aim ) ) { update_user_meta( $user->ID, 'aim', wp_slash( $user->user_aim ) ); } if ( ! empty( $user->user_msn ) ) { update_user_meta( $user->ID, 'msn', wp_slash( $user->user_msn ) ); } if ( ! empty( $user->user_yim ) ) { update_user_meta( $user->ID, 'yim', wp_slash( $user->user_icq ) ); } if ( ! empty( $user->user_description ) ) { update_user_meta( $user->ID, 'description', wp_slash( $user->user_description ) ); } if ( isset( $user->user_idmode ) ) : $idmode = $user->user_idmode; if ( 'nickname' === $idmode ) { $id = $user->user_nickname; } if ( 'login' === $idmode ) { $id = $user->user_login; } if ( 'firstname' === $idmode ) { $id = $user->user_firstname; } if ( 'lastname' === $idmode ) { $id = $user->user_lastname; } if ( 'namefl' === $idmode ) { $id = $user->user_firstname . ' ' . $user->user_lastname; } if ( 'namelf' === $idmode ) { $id = $user->user_lastname . ' ' . $user->user_firstname; } if ( ! $idmode ) { $id = $user->user_nickname; } $wpdb->update( $wpdb->users, array( 'display_name' => $id ), array( 'ID' => $user->ID ) ); endif; // FIXME: RESET_CAPS is temporary code to reset roles and caps if flag is set. $caps = get_user_meta( $user->ID, $wpdb->prefix . 'capabilities' ); if ( empty( $caps ) || defined( 'RESET_CAPS' ) ) { $level = get_user_meta( $user->ID, $wpdb->prefix . 'user_level', true ); $role = translate_level_to_role( $level ); update_user_meta( $user->ID, $wpdb->prefix . 'capabilities', array( $role => true ) ); } endforeach; $old_user_fields = array( 'user_firstname', 'user_lastname', 'user_icq', 'user_aim', 'user_msn', 'user_yim', 'user_idmode', 'user_ip', 'user_domain', 'user_browser', 'user_description', 'user_nickname', 'user_level' ); $wpdb->hide_errors(); foreach ( $old_user_fields as $old ) { $wpdb->query( "ALTER TABLE $wpdb->users DROP $old" ); } $wpdb->show_errors(); // Populate comment_count field of posts table. $comments = $wpdb->get_results( "SELECT comment_post_ID, COUNT(*) as c FROM $wpdb->comments WHERE comment_approved = '1' GROUP BY comment_post_ID" ); if ( is_array( $comments ) ) { foreach ( $comments as $comment ) { $wpdb->update( $wpdb->posts, array( 'comment_count' => $comment->c ), array( 'ID' => $comment->comment_post_ID ) ); } } /* * Some alpha versions used a post status of object instead of attachment * and put the mime type in post_type instead of post_mime_type. */ if ( $wp_current_db_version > 2541 && $wp_current_db_version <= 3091 ) { $objects = $wpdb->get_results( "SELECT ID, post_type FROM $wpdb->posts WHERE post_status = 'object'" ); foreach ( $objects as $object ) { $wpdb->update( $wpdb->posts, array( 'post_status' => 'attachment', 'post_mime_type' => $object->post_type, 'post_type' => '', ), array( 'ID' => $object->ID ) ); $meta = get_post_meta( $object->ID, 'imagedata', true ); if ( ! empty( $meta['file'] ) ) { update_attached_file( $object->ID, $meta['file'] ); } } } } /** * Execute changes made in WordPress 2.1. * * @ignore * @since 2.1.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_210() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 3506 ) { // Update status and type. $posts = $wpdb->get_results( "SELECT ID, post_status FROM $wpdb->posts" ); if ( ! empty( $posts ) ) { foreach ( $posts as $post ) { $status = $post->post_status; $type = 'post'; if ( 'static' === $status ) { $status = 'publish'; $type = 'page'; } elseif ( 'attachment' === $status ) { $status = 'inherit'; $type = 'attachment'; } $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_status = %s, post_type = %s WHERE ID = %d", $status, $type, $post->ID ) ); } } } if ( $wp_current_db_version < 3845 ) { populate_roles_210(); } if ( $wp_current_db_version < 3531 ) { // Give future posts a post_status of future. $now = gmdate( 'Y-m-d H:i:59' ); $wpdb->query( "UPDATE $wpdb->posts SET post_status = 'future' WHERE post_status = 'publish' AND post_date_gmt > '$now'" ); $posts = $wpdb->get_results( "SELECT ID, post_date FROM $wpdb->posts WHERE post_status ='future'" ); if ( ! empty( $posts ) ) { foreach ( $posts as $post ) { wp_schedule_single_event( mysql2date( 'U', $post->post_date, false ), 'publish_future_post', array( $post->ID ) ); } } } } /** * Execute changes made in WordPress 2.3. * * @ignore * @since 2.3.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_230() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 5200 ) { populate_roles_230(); } // Convert categories to terms. $tt_ids = array(); $have_tags = false; $categories = $wpdb->get_results( "SELECT * FROM $wpdb->categories ORDER BY cat_ID" ); foreach ( $categories as $category ) { $term_id = (int) $category->cat_ID; $name = $category->cat_name; $description = $category->category_description; $slug = $category->category_nicename; $parent = $category->category_parent; $term_group = 0; // Associate terms with the same slug in a term group and make slugs unique. $exists = $wpdb->get_results( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $slug ) ); if ( $exists ) { $term_group = $exists[0]->term_group; $id = $exists[0]->term_id; $num = 2; do { $alt_slug = $slug . "-$num"; ++$num; $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) ); } while ( $slug_check ); $slug = $alt_slug; if ( empty( $term_group ) ) { $term_group = $wpdb->get_var( "SELECT MAX(term_group) FROM $wpdb->terms GROUP BY term_group" ) + 1; $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->terms SET term_group = %d WHERE term_id = %d", $term_group, $id ) ); } } $wpdb->query( $wpdb->prepare( "INSERT INTO $wpdb->terms (term_id, name, slug, term_group) VALUES (%d, %s, %s, %d)", $term_id, $name, $slug, $term_group ) ); $count = 0; if ( ! empty( $category->category_count ) ) { $count = (int) $category->category_count; $taxonomy = 'category'; $wpdb->query( $wpdb->prepare( "INSERT INTO $wpdb->term_taxonomy (term_id, taxonomy, description, parent, count) VALUES ( %d, %s, %s, %d, %d)", $term_id, $taxonomy, $description, $parent, $count ) ); $tt_ids[ $term_id ][ $taxonomy ] = (int) $wpdb->insert_id; } if ( ! empty( $category->link_count ) ) { $count = (int) $category->link_count; $taxonomy = 'link_category'; $wpdb->query( $wpdb->prepare( "INSERT INTO $wpdb->term_taxonomy (term_id, taxonomy, description, parent, count) VALUES ( %d, %s, %s, %d, %d)", $term_id, $taxonomy, $description, $parent, $count ) ); $tt_ids[ $term_id ][ $taxonomy ] = (int) $wpdb->insert_id; } if ( ! empty( $category->tag_count ) ) { $have_tags = true; $count = (int) $category->tag_count; $taxonomy = 'post_tag'; $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent', 'count' ) ); $tt_ids[ $term_id ][ $taxonomy ] = (int) $wpdb->insert_id; } if ( empty( $count ) ) { $count = 0; $taxonomy = 'category'; $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent', 'count' ) ); $tt_ids[ $term_id ][ $taxonomy ] = (int) $wpdb->insert_id; } } $select = 'post_id, category_id'; if ( $have_tags ) { $select .= ', rel_type'; } $posts = $wpdb->get_results( "SELECT $select FROM $wpdb->post2cat GROUP BY post_id, category_id" ); foreach ( $posts as $post ) { $post_id = (int) $post->post_id; $term_id = (int) $post->category_id; $taxonomy = 'category'; if ( ! empty( $post->rel_type ) && 'tag' === $post->rel_type ) { $taxonomy = 'tag'; } $tt_id = $tt_ids[ $term_id ][ $taxonomy ]; if ( empty( $tt_id ) ) { continue; } $wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $post_id, 'term_taxonomy_id' => $tt_id, ) ); } // < 3570 we used linkcategories. >= 3570 we used categories and link2cat. if ( $wp_current_db_version < 3570 ) { /* * Create link_category terms for link categories. Create a map of link * category IDs to link_category terms. */ $link_cat_id_map = array(); $default_link_cat = 0; $tt_ids = array(); $link_cats = $wpdb->get_results( 'SELECT cat_id, cat_name FROM ' . $wpdb->prefix . 'linkcategories' ); foreach ( $link_cats as $category ) { $cat_id = (int) $category->cat_id; $term_id = 0; $name = wp_slash( $category->cat_name ); $slug = sanitize_title( $name ); $term_group = 0; // Associate terms with the same slug in a term group and make slugs unique. $exists = $wpdb->get_results( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $slug ) ); if ( $exists ) { $term_group = $exists[0]->term_group; $term_id = $exists[0]->term_id; } if ( empty( $term_id ) ) { $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ); $term_id = (int) $wpdb->insert_id; } $link_cat_id_map[ $cat_id ] = $term_id; $default_link_cat = $term_id; $wpdb->insert( $wpdb->term_taxonomy, array( 'term_id' => $term_id, 'taxonomy' => 'link_category', 'description' => '', 'parent' => 0, 'count' => 0, ) ); $tt_ids[ $term_id ] = (int) $wpdb->insert_id; } // Associate links to categories. $links = $wpdb->get_results( "SELECT link_id, link_category FROM $wpdb->links" ); if ( ! empty( $links ) ) { foreach ( $links as $link ) { if ( 0 === (int) $link->link_category ) { continue; } if ( ! isset( $link_cat_id_map[ $link->link_category ] ) ) { continue; } $term_id = $link_cat_id_map[ $link->link_category ]; $tt_id = $tt_ids[ $term_id ]; if ( empty( $tt_id ) ) { continue; } $wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $link->link_id, 'term_taxonomy_id' => $tt_id, ) ); } } // Set default to the last category we grabbed during the upgrade loop. update_option( 'default_link_category', $default_link_cat ); } else { $links = $wpdb->get_results( "SELECT link_id, category_id FROM $wpdb->link2cat GROUP BY link_id, category_id" ); foreach ( $links as $link ) { $link_id = (int) $link->link_id; $term_id = (int) $link->category_id; $taxonomy = 'link_category'; $tt_id = $tt_ids[ $term_id ][ $taxonomy ]; if ( empty( $tt_id ) ) { continue; } $wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $link_id, 'term_taxonomy_id' => $tt_id, ) ); } } if ( $wp_current_db_version < 4772 ) { // Obsolete linkcategories table. $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'linkcategories' ); } // Recalculate all counts. $terms = $wpdb->get_results( "SELECT term_taxonomy_id, taxonomy FROM $wpdb->term_taxonomy" ); foreach ( (array) $terms as $term ) { if ( 'post_tag' === $term->taxonomy || 'category' === $term->taxonomy ) { $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type = 'post' AND term_taxonomy_id = %d", $term->term_taxonomy_id ) ); } else { $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term->term_taxonomy_id ) ); } $wpdb->update( $wpdb->term_taxonomy, array( 'count' => $count ), array( 'term_taxonomy_id' => $term->term_taxonomy_id ) ); } } /** * Remove old options from the database. * * @ignore * @since 2.3.0 * * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_230_options_table() { global $wpdb; $old_options_fields = array( 'option_can_override', 'option_type', 'option_width', 'option_height', 'option_description', 'option_admin_level' ); $wpdb->hide_errors(); foreach ( $old_options_fields as $old ) { $wpdb->query( "ALTER TABLE $wpdb->options DROP $old" ); } $wpdb->show_errors(); } /** * Remove old categories, link2cat, and post2cat database tables. * * @ignore * @since 2.3.0 * * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_230_old_tables() { global $wpdb; $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'categories' ); $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'link2cat' ); $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'post2cat' ); } /** * Upgrade old slugs made in version 2.2. * * @ignore * @since 2.2.0 * * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_old_slugs() { // Upgrade people who were using the Redirect Old Slugs plugin. global $wpdb; $wpdb->query( "UPDATE $wpdb->postmeta SET meta_key = '_wp_old_slug' WHERE meta_key = 'old_slug'" ); } /** * Execute changes made in WordPress 2.5.0. * * @ignore * @since 2.5.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_250() { global $wp_current_db_version; if ( $wp_current_db_version < 6689 ) { populate_roles_250(); } } /** * Execute changes made in WordPress 2.5.2. * * @ignore * @since 2.5.2 * * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_252() { global $wpdb; $wpdb->query( "UPDATE $wpdb->users SET user_activation_key = ''" ); } /** * Execute changes made in WordPress 2.6. * * @ignore * @since 2.6.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_260() { global $wp_current_db_version; if ( $wp_current_db_version < 8000 ) { populate_roles_260(); } } /** * Execute changes made in WordPress 2.7. * * @ignore * @since 2.7.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_270() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 8980 ) { populate_roles_270(); } // Update post_date for unpublished posts with empty timestamp. if ( $wp_current_db_version < 8921 ) { $wpdb->query( "UPDATE $wpdb->posts SET post_date = post_modified WHERE post_date = '0000-00-00 00:00:00'" ); } } /** * Execute changes made in WordPress 2.8. * * @ignore * @since 2.8.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_280() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 10360 ) { populate_roles_280(); } if ( is_multisite() ) { $start = 0; while ( $rows = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options ORDER BY option_id LIMIT $start, 20" ) ) { foreach ( $rows as $row ) { $value = maybe_unserialize( $row->option_value ); if ( $value === $row->option_value ) { $value = stripslashes( $value ); } if ( $value !== $row->option_value ) { update_option( $row->option_name, $value ); } } $start += 20; } clean_blog_cache( get_current_blog_id() ); } } /** * Execute changes made in WordPress 2.9. * * @ignore * @since 2.9.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_290() { global $wp_current_db_version; if ( $wp_current_db_version < 11958 ) { /* * Previously, setting depth to 1 would redundantly disable threading, * but now 2 is the minimum depth to avoid confusion. */ if ( 1 === (int) get_option( 'thread_comments_depth' ) ) { update_option( 'thread_comments_depth', 2 ); update_option( 'thread_comments', 0 ); } } } /** * Execute changes made in WordPress 3.0. * * @ignore * @since 3.0.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_300() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 15093 ) { populate_roles_300(); } if ( $wp_current_db_version < 14139 && is_multisite() && is_main_site() && ! defined( 'MULTISITE' ) && get_site_option( 'siteurl' ) === false ) { add_site_option( 'siteurl', '' ); } // 3.0 screen options key name changes. if ( wp_should_upgrade_global_tables() ) { $sql = "DELETE FROM $wpdb->usermeta WHERE meta_key LIKE %s OR meta_key LIKE %s OR meta_key LIKE %s OR meta_key LIKE %s OR meta_key LIKE %s OR meta_key LIKE %s OR meta_key = 'manageedittagscolumnshidden' OR meta_key = 'managecategoriescolumnshidden' OR meta_key = 'manageedit-tagscolumnshidden' OR meta_key = 'manageeditcolumnshidden' OR meta_key = 'categories_per_page' OR meta_key = 'edit_tags_per_page'"; $prefix = $wpdb->esc_like( $wpdb->base_prefix ); $wpdb->query( $wpdb->prepare( $sql, $prefix . '%' . $wpdb->esc_like( 'meta-box-hidden' ) . '%', $prefix . '%' . $wpdb->esc_like( 'closedpostboxes' ) . '%', $prefix . '%' . $wpdb->esc_like( 'manage-' ) . '%' . $wpdb->esc_like( '-columns-hidden' ) . '%', $prefix . '%' . $wpdb->esc_like( 'meta-box-order' ) . '%', $prefix . '%' . $wpdb->esc_like( 'metaboxorder' ) . '%', $prefix . '%' . $wpdb->esc_like( 'screen_layout' ) . '%' ) ); } } /** * Execute changes made in WordPress 3.3. * * @ignore * @since 3.3.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. * @global array $wp_registered_widgets * @global array $sidebars_widgets */ function upgrade_330() { global $wp_current_db_version, $wpdb, $wp_registered_widgets, $sidebars_widgets; if ( $wp_current_db_version < 19061 && wp_should_upgrade_global_tables() ) { $wpdb->query( "DELETE FROM $wpdb->usermeta WHERE meta_key IN ('show_admin_bar_admin', 'plugins_last_view')" ); } if ( $wp_current_db_version >= 11548 ) { return; } $sidebars_widgets = get_option( 'sidebars_widgets', array() ); $_sidebars_widgets = array(); if ( isset( $sidebars_widgets['wp_inactive_widgets'] ) || empty( $sidebars_widgets ) ) { $sidebars_widgets['array_version'] = 3; } elseif ( ! isset( $sidebars_widgets['array_version'] ) ) { $sidebars_widgets['array_version'] = 1; } switch ( $sidebars_widgets['array_version'] ) { case 1: foreach ( (array) $sidebars_widgets as $index => $sidebar ) { if ( is_array( $sidebar ) ) { foreach ( (array) $sidebar as $i => $name ) { $id = strtolower( $name ); if ( isset( $wp_registered_widgets[ $id ] ) ) { $_sidebars_widgets[ $index ][ $i ] = $id; continue; } $id = sanitize_title( $name ); if ( isset( $wp_registered_widgets[ $id ] ) ) { $_sidebars_widgets[ $index ][ $i ] = $id; continue; } $found = false; foreach ( $wp_registered_widgets as $widget_id => $widget ) { if ( strtolower( $widget['name'] ) === strtolower( $name ) ) { $_sidebars_widgets[ $index ][ $i ] = $widget['id']; $found = true; break; } elseif ( sanitize_title( $widget['name'] ) === sanitize_title( $name ) ) { $_sidebars_widgets[ $index ][ $i ] = $widget['id']; $found = true; break; } } if ( $found ) { continue; } unset( $_sidebars_widgets[ $index ][ $i ] ); } } } $_sidebars_widgets['array_version'] = 2; $sidebars_widgets = $_sidebars_widgets; unset( $_sidebars_widgets ); // Intentional fall-through to upgrade to the next version. case 2: $sidebars_widgets = retrieve_widgets(); $sidebars_widgets['array_version'] = 3; update_option( 'sidebars_widgets', $sidebars_widgets ); } } /** * Execute changes made in WordPress 3.4. * * @ignore * @since 3.4.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_340() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 19798 ) { $wpdb->hide_errors(); $wpdb->query( "ALTER TABLE $wpdb->options DROP COLUMN blog_id" ); $wpdb->show_errors(); } if ( $wp_current_db_version < 19799 ) { $wpdb->hide_errors(); $wpdb->query( "ALTER TABLE $wpdb->comments DROP INDEX comment_approved" ); $wpdb->show_errors(); } if ( $wp_current_db_version < 20022 && wp_should_upgrade_global_tables() ) { $wpdb->query( "DELETE FROM $wpdb->usermeta WHERE meta_key = 'themes_last_view'" ); } if ( $wp_current_db_version < 20080 ) { if ( 'yes' === $wpdb->get_var( "SELECT autoload FROM $wpdb->options WHERE option_name = 'uninstall_plugins'" ) ) { $uninstall_plugins = get_option( 'uninstall_plugins' ); delete_option( 'uninstall_plugins' ); add_option( 'uninstall_plugins', $uninstall_plugins, null, false ); } } } /** * Execute changes made in WordPress 3.5. * * @ignore * @since 3.5.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_350() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 22006 && $wpdb->get_var( "SELECT link_id FROM $wpdb->links LIMIT 1" ) ) { update_option( 'link_manager_enabled', 1 ); // Previously set to 0 by populate_options(). } if ( $wp_current_db_version < 21811 && wp_should_upgrade_global_tables() ) { $meta_keys = array(); foreach ( array_merge( get_post_types(), get_taxonomies() ) as $name ) { if ( str_contains( $name, '-' ) ) { $meta_keys[] = 'edit_' . str_replace( '-', '_', $name ) . '_per_page'; } } if ( $meta_keys ) { $meta_keys = implode( "', '", $meta_keys ); $wpdb->query( "DELETE FROM $wpdb->usermeta WHERE meta_key IN ('$meta_keys')" ); } } if ( $wp_current_db_version < 22422 ) { $term = get_term_by( 'slug', 'post-format-standard', 'post_format' ); if ( $term ) { wp_delete_term( $term->term_id, 'post_format' ); } } } /** * Execute changes made in WordPress 3.7. * * @ignore * @since 3.7.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_370() { global $wp_current_db_version; if ( $wp_current_db_version < 25824 ) { wp_clear_scheduled_hook( 'wp_auto_updates_maybe_update' ); } } /** * Execute changes made in WordPress 3.7.2. * * @ignore * @since 3.7.2 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_372() { global $wp_current_db_version; if ( $wp_current_db_version < 26148 ) { wp_clear_scheduled_hook( 'wp_maybe_auto_update' ); } } /** * Execute changes made in WordPress 3.8.0. * * @ignore * @since 3.8.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_380() { global $wp_current_db_version; if ( $wp_current_db_version < 26691 ) { deactivate_plugins( array( 'mp6/mp6.php' ), true ); } } /** * Execute changes made in WordPress 4.0.0. * * @ignore * @since 4.0.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_400() { global $wp_current_db_version; if ( $wp_current_db_version < 29630 ) { if ( ! is_multisite() && false === get_option( 'WPLANG' ) ) { if ( defined( 'WPLANG' ) && ( '' !== WPLANG ) && in_array( WPLANG, get_available_languages(), true ) ) { update_option( 'WPLANG', WPLANG ); } else { update_option( 'WPLANG', '' ); } } } } /** * Execute changes made in WordPress 4.2.0. * * @ignore * @since 4.2.0 */ function upgrade_420() {} /** * Executes changes made in WordPress 4.3.0. * * @ignore * @since 4.3.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_430() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 32364 ) { upgrade_430_fix_comments(); } // Shared terms are split in a separate process. if ( $wp_current_db_version < 32814 ) { update_option( 'finished_splitting_shared_terms', 0 ); wp_schedule_single_event( time() + ( 1 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' ); } if ( $wp_current_db_version < 33055 && 'utf8mb4' === $wpdb->charset ) { if ( is_multisite() ) { $tables = $wpdb->tables( 'blog' ); } else { $tables = $wpdb->tables( 'all' ); if ( ! wp_should_upgrade_global_tables() ) { $global_tables = $wpdb->tables( 'global' ); $tables = array_diff_assoc( $tables, $global_tables ); } } foreach ( $tables as $table ) { maybe_convert_table_to_utf8mb4( $table ); } } } /** * Executes comments changes made in WordPress 4.3.0. * * @ignore * @since 4.3.0 * * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_430_fix_comments() { global $wpdb; $content_length = $wpdb->get_col_length( $wpdb->comments, 'comment_content' ); if ( is_wp_error( $content_length ) ) { return; } if ( false === $content_length ) { $content_length = array( 'type' => 'byte', 'length' => 65535, ); } elseif ( ! is_array( $content_length ) ) { $length = (int) $content_length > 0 ? (int) $content_length : 65535; $content_length = array( 'type' => 'byte', 'length' => $length, ); } if ( 'byte' !== $content_length['type'] || 0 === $content_length['length'] ) { // Sites with malformed DB schemas are on their own. return; } $allowed_length = (int) $content_length['length'] - 10; $comments = $wpdb->get_results( "SELECT `comment_ID` FROM `{$wpdb->comments}` WHERE `comment_date_gmt` > '2015-04-26' AND LENGTH( `comment_content` ) >= {$allowed_length} AND ( `comment_content` LIKE '%<%' OR `comment_content` LIKE '%>%' )" ); foreach ( $comments as $comment ) { wp_delete_comment( $comment->comment_ID, true ); } } /** * Executes changes made in WordPress 4.3.1. * * @ignore * @since 4.3.1 */ function upgrade_431() { // Fix incorrect cron entries for term splitting. $cron_array = _get_cron_array(); if ( isset( $cron_array['wp_batch_split_terms'] ) ) { unset( $cron_array['wp_batch_split_terms'] ); _set_cron_array( $cron_array ); } } /** * Executes changes made in WordPress 4.4.0. * * @ignore * @since 4.4.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_440() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 34030 ) { $wpdb->query( "ALTER TABLE {$wpdb->options} MODIFY option_name VARCHAR(191)" ); } // Remove the unused 'add_users' role. $roles = wp_roles(); foreach ( $roles->role_objects as $role ) { if ( $role->has_cap( 'add_users' ) ) { $role->remove_cap( 'add_users' ); } } } /** * Executes changes made in WordPress 4.5.0. * * @ignore * @since 4.5.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_450() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 36180 ) { wp_clear_scheduled_hook( 'wp_maybe_auto_update' ); } // Remove unused email confirmation options, moved to usermeta. if ( $wp_current_db_version < 36679 && is_multisite() ) { $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name REGEXP '^[0-9]+_new_email$'" ); } // Remove unused user setting for wpLink. delete_user_setting( 'wplink' ); } /** * Executes changes made in WordPress 4.6.0. * * @ignore * @since 4.6.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_460() { global $wp_current_db_version; // Remove unused post meta. if ( $wp_current_db_version < 37854 ) { delete_post_meta_by_key( '_post_restored_from' ); } // Remove plugins with callback as an array object/method as the uninstall hook, see #13786. if ( $wp_current_db_version < 37965 ) { $uninstall_plugins = get_option( 'uninstall_plugins', array() ); if ( ! empty( $uninstall_plugins ) ) { foreach ( $uninstall_plugins as $basename => $callback ) { if ( is_array( $callback ) && is_object( $callback[0] ) ) { unset( $uninstall_plugins[ $basename ] ); } } update_option( 'uninstall_plugins', $uninstall_plugins ); } } } /** * Executes changes made in WordPress 5.0.0. * * @ignore * @since 5.0.0 * @deprecated 5.1.0 */ function upgrade_500() { } /** * Executes changes made in WordPress 5.1.0. * * @ignore * @since 5.1.0 */ function upgrade_510() { delete_site_option( 'upgrade_500_was_gutenberg_active' ); } /** * Executes changes made in WordPress 5.3.0. * * @ignore * @since 5.3.0 */ function upgrade_530() { /* * The `admin_email_lifespan` option may have been set by an admin that just logged in, * saw the verification screen, clicked on a button there, and is now upgrading the db, * or by populate_options() that is called earlier in upgrade_all(). * In the second case `admin_email_lifespan` should be reset so the verification screen * is shown next time an admin logs in. */ if ( function_exists( 'current_user_can' ) && ! current_user_can( 'manage_options' ) ) { update_option( 'admin_email_lifespan', 0 ); } } /** * Executes changes made in WordPress 5.5.0. * * @ignore * @since 5.5.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_550() { global $wp_current_db_version; if ( $wp_current_db_version < 48121 ) { $comment_previously_approved = get_option( 'comment_whitelist', '' ); update_option( 'comment_previously_approved', $comment_previously_approved ); delete_option( 'comment_whitelist' ); } if ( $wp_current_db_version < 48575 ) { // Use more clear and inclusive language. $disallowed_list = get_option( 'blacklist_keys' ); /* * This option key was briefly renamed `blocklist_keys`. * Account for sites that have this key present when the original key does not exist. */ if ( false === $disallowed_list ) { $disallowed_list = get_option( 'blocklist_keys' ); } update_option( 'disallowed_keys', $disallowed_list ); delete_option( 'blacklist_keys' ); delete_option( 'blocklist_keys' ); } if ( $wp_current_db_version < 48748 ) { update_option( 'finished_updating_comment_type', 0 ); wp_schedule_single_event( time() + ( 1 * MINUTE_IN_SECONDS ), 'wp_update_comment_type_batch' ); } } /** * Executes changes made in WordPress 5.6.0. * * @ignore * @since 5.6.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_560() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 49572 ) { /* * Clean up the `post_category` column removed from schema in version 2.8.0. * Its presence may conflict with `WP_Post::__get()`. */ $post_category_exists = $wpdb->get_var( "SHOW COLUMNS FROM $wpdb->posts LIKE 'post_category'" ); if ( ! is_null( $post_category_exists ) ) { $wpdb->query( "ALTER TABLE $wpdb->posts DROP COLUMN `post_category`" ); } /* * When upgrading from WP < 5.6.0 set the core major auto-updates option to `unset` by default. * This overrides the same option from populate_options() that is intended for new installs. * See https://core.trac.wordpress.org/ticket/51742. */ update_option( 'auto_update_core_major', 'unset' ); } if ( $wp_current_db_version < 49632 ) { /* * Regenerate the .htaccess file to add the `HTTP_AUTHORIZATION` rewrite rule. * See https://core.trac.wordpress.org/ticket/51723. */ save_mod_rewrite_rules(); } if ( $wp_current_db_version < 49735 ) { delete_transient( 'dirsize_cache' ); } if ( $wp_current_db_version < 49752 ) { $results = $wpdb->get_results( $wpdb->prepare( "SELECT 1 FROM {$wpdb->usermeta} WHERE meta_key = %s LIMIT 1", WP_Application_Passwords::USERMETA_KEY_APPLICATION_PASSWORDS ) ); if ( ! empty( $results ) ) { $network_id = get_main_network_id(); update_network_option( $network_id, WP_Application_Passwords::OPTION_KEY_IN_USE, 1 ); } } } /** * Executes changes made in WordPress 5.9.0. * * @ignore * @since 5.9.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_590() { global $wp_current_db_version; if ( $wp_current_db_version < 51917 ) { $crons = _get_cron_array(); if ( $crons && is_array( $crons ) ) { // Remove errant `false` values, see #53950, #54906. $crons = array_filter( $crons ); _set_cron_array( $crons ); } } } /** * Executes changes made in WordPress 6.0.0. * * @ignore * @since 6.0.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_600() { global $wp_current_db_version; if ( $wp_current_db_version < 53011 ) { wp_update_user_counts(); } } /** * Executes changes made in WordPress 6.3.0. * * @ignore * @since 6.3.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_630() { global $wp_current_db_version; if ( $wp_current_db_version < 55853 ) { if ( ! is_multisite() ) { // Replace non-autoload option can_compress_scripts with autoload option, see #55270 $can_compress_scripts = get_option( 'can_compress_scripts', false ); if ( false !== $can_compress_scripts ) { delete_option( 'can_compress_scripts' ); add_option( 'can_compress_scripts', $can_compress_scripts, '', true ); } } } } /** * Executes changes made in WordPress 6.4.0. * * @ignore * @since 6.4.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_640() { global $wp_current_db_version; if ( $wp_current_db_version < 56657 ) { // Enable attachment pages. update_option( 'wp_attachment_pages_enabled', 1 ); // Remove the wp_https_detection cron. Https status is checked directly in an async Site Health check. $scheduled = wp_get_scheduled_event( 'wp_https_detection' ); if ( $scheduled ) { wp_clear_scheduled_hook( 'wp_https_detection' ); } } } /** * Executes changes made in WordPress 6.5.0. * * @ignore * @since 6.5.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_650() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version < 57155 ) { $stylesheet = get_stylesheet(); // Set autoload=no for all themes except the current one. $theme_mods_options = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE autoload = 'yes' AND option_name != %s AND option_name LIKE %s", "theme_mods_$stylesheet", $wpdb->esc_like( 'theme_mods_' ) . '%' ) ); $autoload = array_fill_keys( $theme_mods_options, false ); wp_set_option_autoload_values( $autoload ); } } /** * Executes changes made in WordPress 6.7.0. * * @ignore * @since 6.7.0 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_670() { global $wp_current_db_version; if ( $wp_current_db_version < 58975 ) { $options = array( 'recently_activated', '_wp_suggested_policy_text_has_changed', 'dashboard_widget_options', 'ftp_credentials', 'adminhash', 'nav_menu_options', 'wp_force_deactivated_plugins', 'delete_blog_hash', 'allowedthemes', 'recovery_keys', 'https_detection_errors', 'fresh_site', ); wp_set_options_autoload( $options, false ); } } /** * Executes changes made in WordPress 6.8.2. * * @ignore * @since 6.8.2 * * @global int $wp_current_db_version The old (current) database version. */ function upgrade_682() { global $wp_current_db_version; if ( $wp_current_db_version < 60421 ) { // Upgrade Ping-O-Matic and Twingly to use HTTPS. $ping_sites_value = get_option( 'ping_sites' ); $ping_sites_value = explode( "\n", $ping_sites_value ); $ping_sites_value = array_map( function ( $url ) { $url = trim( $url ); $url = sanitize_url( $url ); if ( str_ends_with( trailingslashit( $url ), '://rpc.pingomatic.com/' ) || str_ends_with( trailingslashit( $url ), '://rpc.twingly.com/' ) ) { $url = set_url_scheme( $url, 'https' ); } return $url; }, $ping_sites_value ); $ping_sites_value = array_filter( $ping_sites_value ); $ping_sites_value = implode( "\n", $ping_sites_value ); update_option( 'ping_sites', $ping_sites_value ); } } /** * Executes changes made in WordPress 7.0. * * @ignore * @since 7.0.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_700() { global $wp_current_db_version, $wpdb; // Migrate users with 'fresh' admin color to 'modern'. if ( $wp_current_db_version < 61644 ) { $wpdb->update( $wpdb->usermeta, array( 'meta_value' => 'modern' ), array( 'meta_key' => 'admin_color', 'meta_value' => 'fresh', ) ); } } /** * Executes network-level upgrade routines. * * @since 3.0.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function upgrade_network() { global $wp_current_db_version, $wpdb; // Always clear expired transients. delete_expired_transients( true ); // 2.8.0 if ( $wp_current_db_version < 11549 ) { $wpmu_sitewide_plugins = get_site_option( 'wpmu_sitewide_plugins' ); $active_sitewide_plugins = get_site_option( 'active_sitewide_plugins' ); if ( $wpmu_sitewide_plugins ) { if ( ! $active_sitewide_plugins ) { $sitewide_plugins = (array) $wpmu_sitewide_plugins; } else { $sitewide_plugins = array_merge( (array) $active_sitewide_plugins, (array) $wpmu_sitewide_plugins ); } update_site_option( 'active_sitewide_plugins', $sitewide_plugins ); } delete_site_option( 'wpmu_sitewide_plugins' ); delete_site_option( 'deactivated_sitewide_plugins' ); $start = 0; while ( $rows = $wpdb->get_results( "SELECT meta_key, meta_value FROM {$wpdb->sitemeta} ORDER BY meta_id LIMIT $start, 20" ) ) { foreach ( $rows as $row ) { $value = $row->meta_value; if ( ! @unserialize( $value ) ) { $value = stripslashes( $value ); } if ( $value !== $row->meta_value ) { update_site_option( $row->meta_key, $value ); } } $start += 20; } } // 3.0.0 if ( $wp_current_db_version < 13576 ) { update_site_option( 'global_terms_enabled', '1' ); } // 3.3.0 if ( $wp_current_db_version < 19390 ) { update_site_option( 'initial_db_version', $wp_current_db_version ); } if ( $wp_current_db_version < 19470 ) { if ( false === get_site_option( 'active_sitewide_plugins' ) ) { update_site_option( 'active_sitewide_plugins', array() ); } } // 3.4.0 if ( $wp_current_db_version < 20148 ) { // 'allowedthemes' keys things by stylesheet. 'allowed_themes' keyed things by name. $allowedthemes = get_site_option( 'allowedthemes' ); $allowed_themes = get_site_option( 'allowed_themes' ); if ( false === $allowedthemes && is_array( $allowed_themes ) && $allowed_themes ) { $converted = array(); $themes = wp_get_themes(); foreach ( $themes as $stylesheet => $theme_data ) { if ( isset( $allowed_themes[ $theme_data->get( 'Name' ) ] ) ) { $converted[ $stylesheet ] = true; } } update_site_option( 'allowedthemes', $converted ); delete_site_option( 'allowed_themes' ); } } // 3.5.0 if ( $wp_current_db_version < 21823 ) { update_site_option( 'ms_files_rewriting', '1' ); } // 3.5.2 if ( $wp_current_db_version < 24448 ) { $illegal_names = get_site_option( 'illegal_names' ); if ( is_array( $illegal_names ) && count( $illegal_names ) === 1 ) { $illegal_name = reset( $illegal_names ); $illegal_names = explode( ' ', $illegal_name ); update_site_option( 'illegal_names', $illegal_names ); } } // 4.2.0 if ( $wp_current_db_version < 31351 && 'utf8mb4' === $wpdb->charset ) { if ( wp_should_upgrade_global_tables() ) { $wpdb->query( "ALTER TABLE $wpdb->usermeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); $wpdb->query( "ALTER TABLE $wpdb->site DROP INDEX domain, ADD INDEX domain(domain(140),path(51))" ); $wpdb->query( "ALTER TABLE $wpdb->sitemeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); $wpdb->query( "ALTER TABLE $wpdb->signups DROP INDEX domain_path, ADD INDEX domain_path(domain(140),path(51))" ); $tables = $wpdb->tables( 'global' ); // sitecategories may not exist. if ( ! $wpdb->get_var( "SHOW TABLES LIKE '{$tables['sitecategories']}'" ) ) { unset( $tables['sitecategories'] ); } foreach ( $tables as $table ) { maybe_convert_table_to_utf8mb4( $table ); } } } // 4.3.0 if ( $wp_current_db_version < 33055 && 'utf8mb4' === $wpdb->charset ) { if ( wp_should_upgrade_global_tables() ) { $upgrade = false; $indexes = $wpdb->get_results( "SHOW INDEXES FROM $wpdb->signups" ); foreach ( $indexes as $index ) { if ( 'domain_path' === $index->Key_name && 'domain' === $index->Column_name && '140' !== $index->Sub_part ) { $upgrade = true; break; } } if ( $upgrade ) { $wpdb->query( "ALTER TABLE $wpdb->signups DROP INDEX domain_path, ADD INDEX domain_path(domain(140),path(51))" ); } $tables = $wpdb->tables( 'global' ); // sitecategories may not exist. if ( ! $wpdb->get_var( "SHOW TABLES LIKE '{$tables['sitecategories']}'" ) ) { unset( $tables['sitecategories'] ); } foreach ( $tables as $table ) { maybe_convert_table_to_utf8mb4( $table ); } } } // 5.1.0 if ( $wp_current_db_version < 44467 ) { $network_id = get_main_network_id(); delete_network_option( $network_id, 'site_meta_supported' ); is_site_meta_supported(); } } // // General functions we use to actually do stuff. // /** * Creates a table in the database, if it doesn't already exist. * * This method checks for an existing database table and creates a new one if it's not * already present. It doesn't rely on MySQL's "IF NOT EXISTS" statement, but chooses * to query all tables first and then run the SQL statement creating the table. * * @since 1.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $table_name Database table name. * @param string $create_ddl SQL statement to create table. * @return bool True on success or if the table already exists. False on failure. */ function maybe_create_table( $table_name, $create_ddl ) { global $wpdb; $query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table_name ) ); if ( $wpdb->get_var( $query ) === $table_name ) { return true; } // Didn't find it, so try to create it. $wpdb->query( $create_ddl ); // We cannot directly tell that whether this succeeded! if ( $wpdb->get_var( $query ) === $table_name ) { return true; } return false; } /** * Drops a specified index from a table. * * @since 1.0.1 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $table Database table name. * @param string $index Index name to drop. * @return true True, when finished. */ function drop_index( $table, $index ) { global $wpdb; $wpdb->hide_errors(); $wpdb->query( "ALTER TABLE `$table` DROP INDEX `$index`" ); // Now we need to take out all the extra ones we may have created. for ( $i = 0; $i < 25; $i++ ) { $wpdb->query( "ALTER TABLE `$table` DROP INDEX `{$index}_$i`" ); } $wpdb->show_errors(); return true; } /** * Adds an index to a specified table. * * @since 1.0.1 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $table Database table name. * @param string $index Database table index column. * @return true True, when done with execution. */ function add_clean_index( $table, $index ) { global $wpdb; drop_index( $table, $index ); $wpdb->query( "ALTER TABLE `$table` ADD INDEX ( `$index` )" ); return true; } /** * Adds column to a database table, if it doesn't already exist. * * @since 1.3.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $table_name Database table name. * @param string $column_name Table column name. * @param string $create_ddl SQL statement to add column. * @return bool True on success or if the column already exists. False on failure. */ function maybe_add_column( $table_name, $column_name, $create_ddl ) { global $wpdb; foreach ( $wpdb->get_col( "DESC $table_name", 0 ) as $column ) { if ( $column === $column_name ) { return true; } } // Didn't find it, so try to create it. $wpdb->query( $create_ddl ); // We cannot directly tell that whether this succeeded! foreach ( $wpdb->get_col( "DESC $table_name", 0 ) as $column ) { if ( $column === $column_name ) { return true; } } return false; } /** * If a table only contains utf8 or utf8mb4 columns, convert it to utf8mb4. * * @since 4.2.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $table The table to convert. * @return bool True if the table was converted, false if it wasn't. */ function maybe_convert_table_to_utf8mb4( $table ) { global $wpdb; $results = $wpdb->get_results( "SHOW FULL COLUMNS FROM `$table`" ); if ( ! $results ) { return false; } foreach ( $results as $column ) { if ( $column->Collation ) { list( $charset ) = explode( '_', $column->Collation ); $charset = strtolower( $charset ); if ( 'utf8' !== $charset && 'utf8mb4' !== $charset ) { // Don't upgrade tables that have non-utf8 columns. return false; } } } $table_details = $wpdb->get_row( "SHOW TABLE STATUS LIKE '$table'" ); if ( ! $table_details ) { return false; } list( $table_charset ) = explode( '_', $table_details->Collation ); $table_charset = strtolower( $table_charset ); if ( 'utf8mb4' === $table_charset ) { return true; } return $wpdb->query( "ALTER TABLE $table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" ); } /** * Retrieve all options as it was for 1.2. * * @since 1.2.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @return stdClass List of options. */ function get_alloptions_110() { global $wpdb; $all_options = new stdClass(); $options = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" ); if ( $options ) { foreach ( $options as $option ) { if ( 'siteurl' === $option->option_name || 'home' === $option->option_name || 'category_base' === $option->option_name ) { $option->option_value = untrailingslashit( $option->option_value ); } $all_options->{$option->option_name} = stripslashes( $option->option_value ); } } return $all_options; } /** * Utility version of get_option that is private to installation/upgrade. * * @ignore * @since 1.5.1 * @access private * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $setting Option name. * @return mixed Option value. */ function __get_option( $setting ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore global $wpdb; if ( 'home' === $setting && defined( 'WP_HOME' ) ) { return untrailingslashit( WP_HOME ); } if ( 'siteurl' === $setting && defined( 'WP_SITEURL' ) ) { return untrailingslashit( WP_SITEURL ); } $option = $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s", $setting ) ); if ( 'home' === $setting && ! $option ) { return __get_option( 'siteurl' ); } if ( in_array( $setting, array( 'siteurl', 'home', 'category_base', 'tag_base' ), true ) ) { $option = untrailingslashit( $option ); } return maybe_unserialize( $option ); } /** * Filters for content to remove unnecessary slashes. * * @since 1.5.0 * * @param string $content The content to modify. * @return string The de-slashed content. */ function deslash( $content ) { // Note: \\\ inside a regex denotes a single backslash. /* * Replace one or more backslashes followed by a single quote with * a single quote. */ $content = preg_replace( "/\\\+'/", "'", $content ); /* * Replace one or more backslashes followed by a double quote with * a double quote. */ $content = preg_replace( '/\\\+"/', '"', $content ); // Replace one or more backslashes with one backslash. $content = preg_replace( '/\\\+/', '\\', $content ); return $content; } /** * Modifies the database based on specified SQL statements. * * Useful for creating new tables and updating existing tables to a new structure. * * @since 1.5.0 * @since 6.1.0 Ignores display width for integer data types on MySQL 8.0.17 or later, * to match MySQL behavior. Note: This does not affect MariaDB. * * @global wpdb $wpdb WordPress database abstraction object. * * @param string[]|string $queries Optional. The query to run. Can be multiple queries * in an array, or a string of queries separated by * semicolons. Default empty string. * @param bool $execute Optional. Whether or not to execute the query right away. * Default true. * @return string[] Strings containing the results of the various update queries. */ function dbDelta( $queries = '', $execute = true ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid global $wpdb; if ( in_array( $queries, array( '', 'all', 'blog', 'global', 'ms_global' ), true ) ) { $queries = wp_get_db_schema( $queries ); } // Separate individual queries into an array. if ( ! is_array( $queries ) ) { $queries = explode( ';', $queries ); $queries = array_filter( $queries ); } /** * Filters the dbDelta SQL queries. * * @since 3.3.0 * * @param string[] $queries An array of dbDelta SQL queries. */ $queries = apply_filters( 'dbdelta_queries', $queries ); $cqueries = array(); // Creation queries. $iqueries = array(); // Insertion queries. $for_update = array(); // Create a tablename index for an array ($cqueries) of recognized query types. foreach ( $queries as $qry ) { if ( preg_match( '|CREATE TABLE ([^ ]*)|', $qry, $matches ) ) { $table_name = trim( $matches[1], '`' ); $cqueries[ $table_name ] = $qry; $for_update[ $table_name ] = 'Created table ' . $matches[1]; continue; } if ( preg_match( '|CREATE DATABASE ([^ ]*)|', $qry, $matches ) ) { array_unshift( $cqueries, $qry ); continue; } if ( preg_match( '|INSERT INTO ([^ ]*)|', $qry, $matches ) ) { $iqueries[] = $qry; continue; } if ( preg_match( '|UPDATE ([^ ]*)|', $qry, $matches ) ) { $iqueries[] = $qry; continue; } } /** * Filters the dbDelta SQL queries for creating tables and/or databases. * * Queries filterable via this hook contain "CREATE TABLE" or "CREATE DATABASE". * * @since 3.3.0 * * @param string[] $cqueries An array of dbDelta create SQL queries. */ $cqueries = apply_filters( 'dbdelta_create_queries', $cqueries ); /** * Filters the dbDelta SQL queries for inserting or updating. * * Queries filterable via this hook contain "INSERT INTO" or "UPDATE". * * @since 3.3.0 * * @param string[] $iqueries An array of dbDelta insert or update SQL queries. */ $iqueries = apply_filters( 'dbdelta_insert_queries', $iqueries ); $text_fields = array( 'tinytext', 'text', 'mediumtext', 'longtext' ); $blob_fields = array( 'tinyblob', 'blob', 'mediumblob', 'longblob' ); $int_fields = array( 'tinyint', 'smallint', 'mediumint', 'int', 'integer', 'bigint' ); $global_tables = $wpdb->tables( 'global' ); $db_version = $wpdb->db_version(); $db_server_info = $wpdb->db_server_info(); foreach ( $cqueries as $table => $qry ) { // Upgrade global tables only for the main site. Don't upgrade at all if conditions are not optimal. if ( in_array( $table, $global_tables, true ) && ! wp_should_upgrade_global_tables() ) { unset( $cqueries[ $table ], $for_update[ $table ] ); continue; } // Fetch the table column structure from the database. $suppress = $wpdb->suppress_errors(); $tablefields = $wpdb->get_results( "DESCRIBE {$table};" ); $wpdb->suppress_errors( $suppress ); if ( ! $tablefields ) { continue; } // Clear the field and index arrays. $cfields = array(); $indices = array(); $indices_without_subparts = array(); // Get all of the field names in the query from between the parentheses. preg_match( '|\((.*)\)|ms', $qry, $match2 ); $qryline = trim( $match2[1] ); // Separate field lines into an array. $flds = explode( "\n", $qryline ); // For every field line specified in the query. foreach ( $flds as $fld ) { $fld = trim( $fld, " \t\n\r\0\x0B," ); // Default trim characters, plus ','. // Extract the field name. preg_match( '|^([^ ]*)|', $fld, $fvals ); $fieldname = trim( $fvals[1], '`' ); $fieldname_lowercased = strtolower( $fieldname ); // Verify the found field name. $validfield = true; switch ( $fieldname_lowercased ) { case '': case 'primary': case 'index': case 'fulltext': case 'unique': case 'key': case 'spatial': $validfield = false; /* * Normalize the index definition. * * This is done so the definition can be compared against the result of a * `SHOW INDEX FROM $table_name` query which returns the current table * index information. */ // Extract type, name and columns from the definition. preg_match( '/^ (?P<index_type> # 1) Type of the index. PRIMARY\s+KEY|(?:UNIQUE|FULLTEXT|SPATIAL)\s+(?:KEY|INDEX)|KEY|INDEX ) \s+ # Followed by at least one white space character. (?: # Name of the index. Optional if type is PRIMARY KEY. `? # Name can be escaped with a backtick. (?P<index_name> # 2) Name of the index. (?:[0-9a-zA-Z$_-]|[\xC2-\xDF][\x80-\xBF])+ ) `? # Name can be escaped with a backtick. \s+ # Followed by at least one white space character. )* \( # Opening bracket for the columns. (?P<index_columns> .+? # 3) Column names, index prefixes, and orders. ) \) # Closing bracket for the columns. $/imx', $fld, $index_matches ); // Uppercase the index type and normalize space characters. $index_type = strtoupper( preg_replace( '/\s+/', ' ', trim( $index_matches['index_type'] ) ) ); // 'INDEX' is a synonym for 'KEY', standardize on 'KEY'. $index_type = str_replace( 'INDEX', 'KEY', $index_type ); // Escape the index name with backticks. An index for a primary key has no name. $index_name = ( 'PRIMARY KEY' === $index_type ) ? '' : '`' . strtolower( $index_matches['index_name'] ) . '`'; // Parse the columns. Multiple columns are separated by a comma. $index_columns = array_map( 'trim', explode( ',', $index_matches['index_columns'] ) ); $index_columns_without_subparts = $index_columns; // Normalize columns. foreach ( $index_columns as $id => &$index_column ) { // Extract column name and number of indexed characters (sub_part). preg_match( '/ `? # Name can be escaped with a backtick. (?P<column_name> # 1) Name of the column. (?:[0-9a-zA-Z$_-]|[\xC2-\xDF][\x80-\xBF])+ ) `? # Name can be escaped with a backtick. (?: # Optional sub part. \s* # Optional white space character between name and opening bracket. \( # Opening bracket for the sub part. \s* # Optional white space character after opening bracket. (?P<sub_part> \d+ # 2) Number of indexed characters. ) \s* # Optional white space character before closing bracket. \) # Closing bracket for the sub part. )? /x', $index_column, $index_column_matches ); // Escape the column name with backticks. $index_column = '`' . $index_column_matches['column_name'] . '`'; // We don't need to add the subpart to $index_columns_without_subparts $index_columns_without_subparts[ $id ] = $index_column; // Append the optional sup part with the number of indexed characters. if ( isset( $index_column_matches['sub_part'] ) ) { $index_column .= '(' . $index_column_matches['sub_part'] . ')'; } } // Build the normalized index definition and add it to the list of indices. $indices[] = "{$index_type} {$index_name} (" . implode( ',', $index_columns ) . ')'; $indices_without_subparts[] = "{$index_type} {$index_name} (" . implode( ',', $index_columns_without_subparts ) . ')'; // Destroy no longer needed variables. unset( $index_column, $index_column_matches, $index_matches, $index_type, $index_name, $index_columns, $index_columns_without_subparts ); break; } // If it's a valid field, add it to the field array. if ( $validfield ) { $cfields[ $fieldname_lowercased ] = $fld; } } // For every field in the table. foreach ( $tablefields as $tablefield ) { $tablefield_field_lowercased = strtolower( $tablefield->Field ); $tablefield_type_lowercased = strtolower( $tablefield->Type ); $tablefield_type_without_parentheses = preg_replace( '/' . '(.+)' // Field type, e.g. `int`. . '\(\d*\)' // Display width. . '(.*)' // Optional attributes, e.g. `unsigned`. . '/', '$1$2', $tablefield_type_lowercased ); // Get the type without attributes, e.g. `int`. $tablefield_type_base = strtok( $tablefield_type_without_parentheses, ' ' ); // If the table field exists in the field array... if ( array_key_exists( $tablefield_field_lowercased, $cfields ) ) { // Get the field type from the query. preg_match( '|`?' . $tablefield->Field . '`? ([^ ]*( unsigned)?)|i', $cfields[ $tablefield_field_lowercased ], $matches ); $fieldtype = $matches[1]; $fieldtype_lowercased = strtolower( $fieldtype ); $fieldtype_without_parentheses = preg_replace( '/' . '(.+)' // Field type, e.g. `int`. . '\(\d*\)' // Display width. . '(.*)' // Optional attributes, e.g. `unsigned`. . '/', '$1$2', $fieldtype_lowercased ); // Get the type without attributes, e.g. `int`. $fieldtype_base = strtok( $fieldtype_without_parentheses, ' ' ); // Is actual field type different from the field type in query? if ( $tablefield->Type !== $fieldtype_lowercased ) { $do_change = true; if ( in_array( $fieldtype_lowercased, $text_fields, true ) && in_array( $tablefield_type_lowercased, $text_fields, true ) ) { if ( array_search( $fieldtype_lowercased, $text_fields, true ) < array_search( $tablefield_type_lowercased, $text_fields, true ) ) { $do_change = false; } } if ( in_array( $fieldtype_lowercased, $blob_fields, true ) && in_array( $tablefield_type_lowercased, $blob_fields, true ) ) { if ( array_search( $fieldtype_lowercased, $blob_fields, true ) < array_search( $tablefield_type_lowercased, $blob_fields, true ) ) { $do_change = false; } } if ( in_array( $fieldtype_base, $int_fields, true ) && in_array( $tablefield_type_base, $int_fields, true ) && $fieldtype_without_parentheses === $tablefield_type_without_parentheses ) { /* * MySQL 8.0.17 or later does not support display width for integer data types, * so if display width is the only difference, it can be safely ignored. * Note: This is specific to MySQL and does not affect MariaDB. */ if ( version_compare( $db_version, '8.0.17', '>=' ) && ! str_contains( $db_server_info, 'MariaDB' ) ) { $do_change = false; } } if ( $do_change ) { // Add a query to change the column type. $cqueries[] = "ALTER TABLE {$table} CHANGE COLUMN `{$tablefield->Field}` " . $cfields[ $tablefield_field_lowercased ]; $for_update[ $table . '.' . $tablefield->Field ] = "Changed type of {$table}.{$tablefield->Field} from {$tablefield->Type} to {$fieldtype}"; } } // Get the default value from the array. if ( preg_match( "| DEFAULT '(.*?)'|i", $cfields[ $tablefield_field_lowercased ], $matches ) ) { $default_value = $matches[1]; if ( $tablefield->Default !== $default_value ) { // Add a query to change the column's default value $cqueries[] = "ALTER TABLE {$table} ALTER COLUMN `{$tablefield->Field}` SET DEFAULT '{$default_value}'"; $for_update[ $table . '.' . $tablefield->Field ] = "Changed default value of {$table}.{$tablefield->Field} from {$tablefield->Default} to {$default_value}"; } } // Remove the field from the array (so it's not added). unset( $cfields[ $tablefield_field_lowercased ] ); } else { // This field exists in the table, but not in the creation queries? } } // For every remaining field specified for the table. foreach ( $cfields as $fieldname => $fielddef ) { // Push a query line into $cqueries that adds the field to that table. $cqueries[] = "ALTER TABLE {$table} ADD COLUMN $fielddef"; $for_update[ $table . '.' . $fieldname ] = 'Added column ' . $table . '.' . $fieldname; } // Index stuff goes here. Fetch the table index structure from the database. $tableindices = $wpdb->get_results( "SHOW INDEX FROM {$table};" ); if ( $tableindices ) { // Clear the index array. $index_ary = array(); // For every index in the table. foreach ( $tableindices as $tableindex ) { $keyname = strtolower( $tableindex->Key_name ); // Add the index to the index data array. $index_ary[ $keyname ]['columns'][] = array( 'fieldname' => $tableindex->Column_name, 'subpart' => $tableindex->Sub_part, ); $index_ary[ $keyname ]['unique'] = ( '0' === (string) $tableindex->Non_unique ) ? true : false; $index_ary[ $keyname ]['index_type'] = $tableindex->Index_type; } // For each actual index in the index array. foreach ( $index_ary as $index_name => $index_data ) { // Build a create string to compare to the query. $index_string = ''; if ( 'primary' === $index_name ) { $index_string .= 'PRIMARY '; } elseif ( $index_data['unique'] ) { $index_string .= 'UNIQUE '; } if ( 'FULLTEXT' === strtoupper( $index_data['index_type'] ) ) { $index_string .= 'FULLTEXT '; } if ( 'SPATIAL' === strtoupper( $index_data['index_type'] ) ) { $index_string .= 'SPATIAL '; } $index_string .= 'KEY '; if ( 'primary' !== $index_name ) { $index_string .= '`' . $index_name . '`'; } $index_columns = ''; // For each column in the index. foreach ( $index_data['columns'] as $column_data ) { if ( '' !== $index_columns ) { $index_columns .= ','; } // Add the field to the column list string. $index_columns .= '`' . $column_data['fieldname'] . '`'; } // Add the column list to the index create string. $index_string .= " ($index_columns)"; // Check if the index definition exists, ignoring subparts. $aindex = array_search( $index_string, $indices_without_subparts, true ); if ( false !== $aindex ) { // If the index already exists (even with different subparts), we don't need to create it. unset( $indices_without_subparts[ $aindex ] ); unset( $indices[ $aindex ] ); } } } // For every remaining index specified for the table. foreach ( (array) $indices as $index ) { // Push a query line into $cqueries that adds the index to that table. $cqueries[] = "ALTER TABLE {$table} ADD $index"; $for_update[] = 'Added index ' . $table . ' ' . $index; } // Remove the original table creation query from processing. unset( $cqueries[ $table ], $for_update[ $table ] ); } $allqueries = array_merge( $cqueries, $iqueries ); if ( $execute ) { foreach ( $allqueries as $query ) { $wpdb->query( $query ); } } return $for_update; } /** * Updates the database tables to a new schema. * * By default, updates all the tables to use the latest defined schema, but can also * be used to update a specific set of tables in wp_get_db_schema(). * * @since 1.5.0 * * @uses dbDelta * * @param string $tables Optional. Which set of tables to update. Default is 'all'. */ function make_db_current( $tables = 'all' ) { $alterations = dbDelta( $tables ); echo "<ol>\n"; foreach ( $alterations as $alteration ) { echo "<li>$alteration</li>\n"; } echo "</ol>\n"; } /** * Updates the database tables to a new schema, but without displaying results. * * By default, updates all the tables to use the latest defined schema, but can * also be used to update a specific set of tables in wp_get_db_schema(). * * @since 1.5.0 * * @see make_db_current() * * @param string $tables Optional. Which set of tables to update. Default is 'all'. */ function make_db_current_silent( $tables = 'all' ) { dbDelta( $tables ); } /** * Creates a site theme from an existing theme. * * {@internal Missing Long Description}} * * @since 1.5.0 * * @param string $theme_name The name of the theme. * @param string $template The directory name of the theme. * @return bool True on success, false on failure. */ function make_site_theme_from_oldschool( $theme_name, $template ) { $home_path = get_home_path(); $site_dir = WP_CONTENT_DIR . "/themes/$template"; $default_dir = WP_CONTENT_DIR . '/themes/' . WP_DEFAULT_THEME; if ( ! file_exists( "$home_path/index.php" ) ) { return false; } /* * Copy files from the old locations to the site theme. * TODO: This does not copy arbitrary include dependencies. Only the standard WP files are copied. */ $files = array( 'index.php' => 'index.php', 'wp-layout.css' => 'style.css', 'wp-comments.php' => 'comments.php', 'wp-comments-popup.php' => 'comments-popup.php', ); foreach ( $files as $oldfile => $newfile ) { if ( 'index.php' === $oldfile ) { $oldpath = $home_path; } else { $oldpath = ABSPATH; } // Check to make sure it's not a new index. if ( 'index.php' === $oldfile ) { $index = implode( '', file( "$oldpath/$oldfile" ) ); if ( str_contains( $index, 'WP_USE_THEMES' ) ) { if ( ! copy( "$default_dir/$oldfile", "$site_dir/$newfile" ) ) { return false; } // Don't copy anything. continue; } } if ( ! copy( "$oldpath/$oldfile", "$site_dir/$newfile" ) ) { return false; } chmod( "$site_dir/$newfile", 0777 ); // Update the blog header include in each file. $lines = explode( "\n", implode( '', file( "$site_dir/$newfile" ) ) ); if ( $lines ) { $f = fopen( "$site_dir/$newfile", 'w' ); foreach ( $lines as $line ) { if ( preg_match( '/require.*wp-blog-header/', $line ) ) { $line = '//' . $line; } // Update stylesheet references. $line = str_replace( "<?php echo __get_option('siteurl'); ?>/wp-layout.css", "<?php bloginfo('stylesheet_url'); ?>", $line ); // Update comments template inclusion. $line = str_replace( "<?php include(ABSPATH . 'wp-comments.php'); ?>", '<?php comments_template(); ?>', $line ); fwrite( $f, "{$line}\n" ); } fclose( $f ); } } // Add a theme header. $header = "/*\n" . "Theme Name: $theme_name\n" . 'Theme URI: ' . __get_option( 'siteurl' ) . "\n" . "Description: A theme automatically created by the update.\n" . "Version: 1.0\n" . "Author: Moi\n" . "*/\n"; $stylelines = file_get_contents( "$site_dir/style.css" ); if ( $stylelines ) { $f = fopen( "$site_dir/style.css", 'w' ); fwrite( $f, $header ); fwrite( $f, $stylelines ); fclose( $f ); } return true; } /** * Creates a site theme from the default theme. * * {@internal Missing Long Description}} * * @since 1.5.0 * * @param string $theme_name The name of the theme. * @param string $template The directory name of the theme. * @return void|false */ function make_site_theme_from_default( $theme_name, $template ) { $site_dir = WP_CONTENT_DIR . "/themes/$template"; $default_dir = WP_CONTENT_DIR . '/themes/' . WP_DEFAULT_THEME; /* * Copy files from the default theme to the site theme. * $files = array( 'index.php', 'comments.php', 'comments-popup.php', 'footer.php', 'header.php', 'sidebar.php', 'style.css' ); */ $theme_dir = @opendir( $default_dir ); if ( $theme_dir ) { while ( ( $theme_file = readdir( $theme_dir ) ) !== false ) { if ( is_dir( "$default_dir/$theme_file" ) ) { continue; } if ( ! copy( "$default_dir/$theme_file", "$site_dir/$theme_file" ) ) { return; } chmod( "$site_dir/$theme_file", 0777 ); } closedir( $theme_dir ); } // Rewrite the theme header. $stylelines = explode( "\n", implode( '', file( "$site_dir/style.css" ) ) ); if ( $stylelines ) { $f = fopen( "$site_dir/style.css", 'w' ); $headers = array( 'Theme Name:' => $theme_name, 'Theme URI:' => __get_option( 'url' ), 'Description:' => 'Your theme.', 'Version:' => '1', 'Author:' => 'You', ); foreach ( $stylelines as $line ) { foreach ( $headers as $header => $value ) { if ( str_contains( $line, $header ) ) { $line = $header . ' ' . $value; break; } } fwrite( $f, $line . "\n" ); } fclose( $f ); } // Copy the images. umask( 0 ); if ( ! mkdir( "$site_dir/images", 0777 ) ) { return false; } $images_dir = @opendir( "$default_dir/images" ); if ( $images_dir ) { while ( ( $image = readdir( $images_dir ) ) !== false ) { if ( is_dir( "$default_dir/images/$image" ) ) { continue; } if ( ! copy( "$default_dir/images/$image", "$site_dir/images/$image" ) ) { return; } chmod( "$site_dir/images/$image", 0777 ); } closedir( $images_dir ); } } /** * Creates a site theme. * * {@internal Missing Long Description}} * * @since 1.5.0 * * @return string|false */ function make_site_theme() { // Name the theme after the blog. $theme_name = __get_option( 'blogname' ); $template = sanitize_title( $theme_name ); $site_dir = WP_CONTENT_DIR . "/themes/$template"; // If the theme already exists, nothing to do. if ( is_dir( $site_dir ) ) { return false; } // We must be able to write to the themes dir. if ( ! is_writable( WP_CONTENT_DIR . '/themes' ) ) { return false; } umask( 0 ); if ( ! mkdir( $site_dir, 0777 ) ) { return false; } if ( file_exists( ABSPATH . 'wp-layout.css' ) ) { if ( ! make_site_theme_from_oldschool( $theme_name, $template ) ) { // TODO: rm -rf the site theme directory. return false; } } else { if ( ! make_site_theme_from_default( $theme_name, $template ) ) { // TODO: rm -rf the site theme directory. return false; } } // Make the new site theme active. $current_template = __get_option( 'template' ); if ( WP_DEFAULT_THEME === $current_template ) { update_option( 'template', $template ); update_option( 'stylesheet', $template ); } return $template; } /** * Translate user level to user role name. * * @since 2.0.0 * * @param int $level User level. * @return string User role name. */ function translate_level_to_role( $level ) { switch ( $level ) { case 10: case 9: case 8: return 'administrator'; case 7: case 6: case 5: return 'editor'; case 4: case 3: case 2: return 'author'; case 1: return 'contributor'; case 0: default: return 'subscriber'; } } /** * Checks the version of the installed MySQL binary. * * @since 2.1.0 * * @global wpdb $wpdb WordPress database abstraction object. */ function wp_check_mysql_version() { global $wpdb; $result = $wpdb->check_database_version(); if ( is_wp_error( $result ) ) { wp_die( $result ); } } /** * Disables the Automattic widgets plugin, which was merged into core. * * @since 2.2.0 */ function maybe_disable_automattic_widgets() { $plugins = __get_option( 'active_plugins' ); foreach ( (array) $plugins as $plugin ) { if ( 'widgets.php' === basename( $plugin ) ) { array_splice( $plugins, array_search( $plugin, $plugins, true ), 1 ); update_option( 'active_plugins', $plugins ); break; } } } /** * Disables the Link Manager on upgrade if, at the time of upgrade, no links exist in the DB. * * @since 3.5.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function maybe_disable_link_manager() { global $wp_current_db_version, $wpdb; if ( $wp_current_db_version >= 22006 && get_option( 'link_manager_enabled' ) && ! $wpdb->get_var( "SELECT link_id FROM $wpdb->links LIMIT 1" ) ) { update_option( 'link_manager_enabled', 0 ); } } /** * Runs before the schema is upgraded. * * @since 2.9.0 * * @global int $wp_current_db_version The old (current) database version. * @global wpdb $wpdb WordPress database abstraction object. */ function pre_schema_upgrade() { global $wp_current_db_version, $wpdb; // Upgrade versions prior to 2.9. if ( $wp_current_db_version < 11557 ) { // Delete duplicate options. Keep the option with the highest option_id. $wpdb->query( "DELETE o1 FROM $wpdb->options AS o1 JOIN $wpdb->options AS o2 USING (`option_name`) WHERE o2.option_id > o1.option_id" ); // Drop the old primary key and add the new. $wpdb->query( "ALTER TABLE $wpdb->options DROP PRIMARY KEY, ADD PRIMARY KEY(option_id)" ); // Drop the old option_name index. dbDelta() doesn't do the drop. $wpdb->query( "ALTER TABLE $wpdb->options DROP INDEX option_name" ); } // Multisite schema upgrades. if ( $wp_current_db_version < 60497 && is_multisite() && wp_should_upgrade_global_tables() ) { // Upgrade versions prior to 3.7. if ( $wp_current_db_version < 25179 ) { // New primary key for signups. $wpdb->query( "ALTER TABLE $wpdb->signups ADD signup_id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST" ); $wpdb->query( "ALTER TABLE $wpdb->signups DROP INDEX domain" ); } if ( $wp_current_db_version < 25448 ) { // Convert archived from enum to tinyint. $wpdb->query( "ALTER TABLE $wpdb->blogs CHANGE COLUMN archived archived varchar(1) NOT NULL default '0'" ); $wpdb->query( "ALTER TABLE $wpdb->blogs CHANGE COLUMN archived archived tinyint(2) NOT NULL default 0" ); } // Upgrade versions prior to 6.9 if ( $wp_current_db_version < 60497 ) { // Convert ID columns from signed to unsigned $wpdb->query( "ALTER TABLE $wpdb->blogs MODIFY blog_id bigint(20) unsigned NOT NULL auto_increment" ); $wpdb->query( "ALTER TABLE $wpdb->blogs MODIFY site_id bigint(20) unsigned NOT NULL default 0" ); $wpdb->query( "ALTER TABLE $wpdb->blogmeta MODIFY blog_id bigint(20) unsigned NOT NULL default 0" ); $wpdb->query( "ALTER TABLE $wpdb->registration_log MODIFY ID bigint(20) unsigned NOT NULL auto_increment" ); $wpdb->query( "ALTER TABLE $wpdb->registration_log MODIFY blog_id bigint(20) unsigned NOT NULL default 0" ); $wpdb->query( "ALTER TABLE $wpdb->site MODIFY id bigint(20) unsigned NOT NULL auto_increment" ); $wpdb->query( "ALTER TABLE $wpdb->sitemeta MODIFY meta_id bigint(20) unsigned NOT NULL auto_increment" ); $wpdb->query( "ALTER TABLE $wpdb->sitemeta MODIFY site_id bigint(20) unsigned NOT NULL default 0" ); $wpdb->query( "ALTER TABLE $wpdb->signups MODIFY signup_id bigint(20) unsigned NOT NULL auto_increment" ); } } // Upgrade versions prior to 4.2. if ( $wp_current_db_version < 31351 ) { if ( ! is_multisite() && wp_should_upgrade_global_tables() ) { $wpdb->query( "ALTER TABLE $wpdb->usermeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); } $wpdb->query( "ALTER TABLE $wpdb->terms DROP INDEX slug, ADD INDEX slug(slug(191))" ); $wpdb->query( "ALTER TABLE $wpdb->terms DROP INDEX name, ADD INDEX name(name(191))" ); $wpdb->query( "ALTER TABLE $wpdb->commentmeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); $wpdb->query( "ALTER TABLE $wpdb->postmeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); $wpdb->query( "ALTER TABLE $wpdb->posts DROP INDEX post_name, ADD INDEX post_name(post_name(191))" ); } // Upgrade versions prior to 4.4. if ( $wp_current_db_version < 34978 ) { // If compatible termmeta table is found, use it, but enforce a proper index and update collation. if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->termmeta}'" ) && $wpdb->get_results( "SHOW INDEX FROM {$wpdb->termmeta} WHERE Column_name = 'meta_key'" ) ) { $wpdb->query( "ALTER TABLE $wpdb->termmeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); maybe_convert_table_to_utf8mb4( $wpdb->termmeta ); } } } /** * Determine if global tables should be upgraded. * * This function performs a series of checks to ensure the environment allows * for the safe upgrading of global WordPress database tables. It is necessary * because global tables will commonly grow to millions of rows on large * installations, and the ability to control their upgrade routines can be * critical to the operation of large networks. * * In a future iteration, this function may use `wp_is_large_network()` to more- * intelligently prevent global table upgrades. Until then, we make sure * WordPress is on the main site of the main network, to avoid running queries * more than once in multi-site or multi-network environments. * * @since 4.3.0 * * @return bool Whether to run the upgrade routines on global tables. */ function wp_should_upgrade_global_tables() { // Return false early if explicitly not upgrading. if ( defined( 'DO_NOT_UPGRADE_GLOBAL_TABLES' ) ) { return false; } // Assume global tables should be upgraded. $should_upgrade = true; // Set to false if not on main network (does not matter if not multi-network). if ( ! is_main_network() ) { $should_upgrade = false; } // Set to false if not on main site of current network (does not matter if not multi-site). if ( ! is_main_site() ) { $should_upgrade = false; } /** * Filters if upgrade routines should be run on global tables. * * @since 4.3.0 * * @param bool $should_upgrade Whether to run the upgrade routines on global tables. */ return apply_filters( 'wp_should_upgrade_global_tables', $should_upgrade ); } PK $��\���8% 8% class-wp-links-list-table.phpnu �[��� <?php /** * List Table API: WP_Links_List_Table class * * @package WordPress * @subpackage Administration * @since 3.1.0 */ /** * Core class used to implement displaying links in a list table. * * @since 3.1.0 * * @see WP_List_Table */ class WP_Links_List_Table extends WP_List_Table { /** * Constructor. * * @since 3.1.0 * * @see WP_List_Table::__construct() for more information on default arguments. * * @param array $args An associative array of arguments. */ public function __construct( $args = array() ) { parent::__construct( array( 'plural' => 'bookmarks', 'screen' => $args['screen'] ?? null, ) ); } /** * @return bool */ public function ajax_user_can() { return current_user_can( 'manage_links' ); } /** * @global int $cat_id Link category ID. * @global string $s Search string. * @global string $orderby The field to order the links by. * @global string $order The direction to order the links. */ public function prepare_items() { global $cat_id, $s, $orderby, $order; $cat_id = ! empty( $_REQUEST['cat_id'] ) ? absint( $_REQUEST['cat_id'] ) : 0; $orderby = ! empty( $_REQUEST['orderby'] ) ? sanitize_text_field( $_REQUEST['orderby'] ) : ''; $order = ! empty( $_REQUEST['order'] ) ? sanitize_text_field( $_REQUEST['order'] ) : ''; $s = ! empty( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : ''; $args = array( 'hide_invisible' => 0, 'hide_empty' => 0, ); if ( 'all' !== $cat_id ) { $args['category'] = $cat_id; } if ( ! empty( $s ) ) { $args['search'] = $s; } if ( ! empty( $orderby ) ) { $args['orderby'] = $orderby; } if ( ! empty( $order ) ) { $args['order'] = $order; } $this->items = get_bookmarks( $args ); } /** * Displays the message for no items. */ public function no_items() { _e( 'No links found.' ); } /** * Gets the list of bulk actions. * * @return array */ protected function get_bulk_actions() { $actions = array(); $actions['delete'] = __( 'Delete' ); return $actions; } /** * @global int $cat_id Link category ID. * @param string $which The location: 'top' or 'bottom'. */ protected function extra_tablenav( $which ) { global $cat_id; if ( 'top' !== $which ) { return; } ?> <div class="alignleft actions"> <?php $dropdown_options = array( 'selected' => $cat_id, 'name' => 'cat_id', 'taxonomy' => 'link_category', 'show_option_all' => get_taxonomy( 'link_category' )->labels->all_items, 'hide_empty' => true, 'hierarchical' => 1, 'show_count' => 0, 'orderby' => 'name', ); echo '<label class="screen-reader-text" for="cat_id">' . get_taxonomy( 'link_category' )->labels->filter_by_item . '</label>'; wp_dropdown_categories( $dropdown_options ); submit_button( __( 'Filter' ), 'button-compact', 'filter_action', false, array( 'id' => 'post-query-submit' ) ); ?> </div> <?php } /** * @return string[] Array of column titles keyed by their column name. */ public function get_columns() { return array( 'cb' => '<input type="checkbox" />', 'name' => _x( 'Name', 'link name' ), 'url' => __( 'URL' ), 'categories' => __( 'Categories' ), 'rel' => __( 'Relationship' ), 'visible' => __( 'Visible' ), 'rating' => __( 'Rating' ), ); } /** * Gets the list of sortable columns. * * @return array */ protected function get_sortable_columns() { return array( 'name' => array( 'name', false, _x( 'Name', 'link name' ), __( 'Table ordered by Name.' ), 'asc' ), 'url' => array( 'url', false, __( 'URL' ), __( 'Table ordered by URL.' ) ), 'visible' => array( 'visible', false, __( 'Visible' ), __( 'Table ordered by Visibility.' ) ), 'rating' => array( 'rating', false, __( 'Rating' ), __( 'Table ordered by Rating.' ) ), ); } /** * Gets the name of the default primary column. * * @since 4.3.0 * * @return string Name of the default primary column, in this case, 'name'. */ protected function get_default_primary_column_name() { return 'name'; } /** * Handles the checkbox column output. * * @since 4.3.0 * @since 5.9.0 Renamed `$link` to `$item` to match parent class for PHP 8 named parameter support. * * @param object $item The current link object. */ public function column_cb( $item ) { // Restores the more descriptive, specific name for use within this method. $link = $item; ?> <input type="checkbox" name="linkcheck[]" id="cb-select-<?php echo $link->link_id; ?>" value="<?php echo esc_attr( $link->link_id ); ?>" /> <label for="cb-select-<?php echo $link->link_id; ?>"> <span class="screen-reader-text"> <?php /* translators: Hidden accessibility text. %s: Link name. */ printf( __( 'Select %s' ), $link->link_name ); ?> </span> </label> <?php } /** * Handles the link name column output. * * @since 4.3.0 * * @param object $link The current link object. */ public function column_name( $link ) { $edit_link = get_edit_bookmark_link( $link ); printf( '<strong><a class="row-title" href="%s" aria-label="%s">%s</a></strong>', $edit_link, /* translators: %s: Link name. */ esc_attr( sprintf( __( 'Edit “%s”' ), $link->link_name ) ), $link->link_name ); } /** * Handles the link URL column output. * * @since 4.3.0 * * @param object $link The current link object. */ public function column_url( $link ) { $short_url = url_shorten( $link->link_url ); echo "<a href='$link->link_url'>$short_url</a>"; } /** * Handles the link categories column output. * * @since 4.3.0 * * @global int $cat_id Link category ID. * * @param object $link The current link object. */ public function column_categories( $link ) { global $cat_id; $cat_names = array(); foreach ( $link->link_category as $category ) { $cat = get_term( $category, 'link_category', OBJECT, 'display' ); if ( is_wp_error( $cat ) ) { echo $cat->get_error_message(); } $cat_name = $cat->name; if ( (int) $cat_id !== $category ) { $cat_name = "<a href='link-manager.php?cat_id=$category'>$cat_name</a>"; } $cat_names[] = $cat_name; } echo implode( ', ', $cat_names ); } /** * Handles the link relation column output. * * @since 4.3.0 * * @param object $link The current link object. */ public function column_rel( $link ) { echo empty( $link->link_rel ) ? '<br />' : $link->link_rel; } /** * Handles the link visibility column output. * * @since 4.3.0 * * @param object $link The current link object. */ public function column_visible( $link ) { if ( 'Y' === $link->link_visible ) { _e( 'Yes' ); } else { _e( 'No' ); } } /** * Handles the link rating column output. * * @since 4.3.0 * * @param object $link The current link object. */ public function column_rating( $link ) { echo $link->link_rating; } /** * Handles the default column output. * * @since 4.3.0 * @since 5.9.0 Renamed `$link` to `$item` to match parent class for PHP 8 named parameter support. * * @param object $item Link object. * @param string $column_name Current column name. */ public function column_default( $item, $column_name ) { // Restores the more descriptive, specific name for use within this method. $link = $item; /** * Fires for each registered custom link column. * * @since 2.1.0 * * @param string $column_name Name of the custom column. * @param int $link_id Link ID. */ do_action( 'manage_link_custom_column', $column_name, $link->link_id ); } /** * Generates the list table rows. * * @since 3.1.0 */ public function display_rows() { foreach ( $this->items as $link ) { $link = sanitize_bookmark( $link ); $link->link_name = esc_attr( $link->link_name ); $link->link_category = wp_get_link_cats( $link->link_id ); ?> <tr id="link-<?php echo $link->link_id; ?>"> <?php $this->single_row_columns( $link ); ?> </tr> <?php } } /** * Generates and displays row action links. * * @since 4.3.0 * @since 5.9.0 Renamed `$link` to `$item` to match parent class for PHP 8 named parameter support. * * @param object $item Link being acted upon. * @param string $column_name Current column name. * @param string $primary Primary column name. * @return string Row actions output for links, or an empty string * if the current column is not the primary column. */ protected function handle_row_actions( $item, $column_name, $primary ) { if ( $primary !== $column_name ) { return ''; } // Restores the more descriptive, specific name for use within this method. $link = $item; $edit_link = get_edit_bookmark_link( $link ); $actions = array(); $actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>'; $actions['delete'] = sprintf( '<a class="submitdelete" href="%s" onclick="return confirm( \'%s\' );">%s</a>', wp_nonce_url( "link.php?action=delete&link_id=$link->link_id", 'delete-bookmark_' . $link->link_id ), /* translators: %s: Link name. */ esc_js( sprintf( __( "You are about to delete this link '%s'\n 'Cancel' to stop, 'OK' to delete." ), $link->link_name ) ), __( 'Delete' ) ); return $this->row_actions( $actions ); } } PK $��\ � �] �] user.phpnu �[��� <?php /** * WordPress user administration API. * * @package WordPress * @subpackage Administration */ /** * Creates a new user from the "Users" form using $_POST information. * * @since 2.0.0 * * @return int|WP_Error WP_Error or User ID. */ function add_user() { return edit_user(); } /** * Edit user settings based on contents of $_POST * * Used on user-edit.php and profile.php to manage and process user options, passwords etc. * * @since 2.0.0 * * @param int $user_id Optional. User ID. * @return int|WP_Error User ID of the updated user or WP_Error on failure. */ function edit_user( $user_id = 0 ) { $wp_roles = wp_roles(); $user = new stdClass(); $user_id = (int) $user_id; if ( $user_id ) { $update = true; $user->ID = $user_id; $userdata = get_userdata( $user_id ); $user->user_login = wp_slash( $userdata->user_login ); } else { $update = false; } if ( ! $update && isset( $_POST['user_login'] ) ) { $user->user_login = sanitize_user( wp_unslash( $_POST['user_login'] ), true ); } $pass1 = ''; $pass2 = ''; if ( isset( $_POST['pass1'] ) ) { $pass1 = trim( $_POST['pass1'] ); } if ( isset( $_POST['pass2'] ) ) { $pass2 = trim( $_POST['pass2'] ); } if ( isset( $_POST['role'] ) && current_user_can( 'promote_users' ) && ( ! $user_id || current_user_can( 'promote_user', $user_id ) ) ) { $new_role = sanitize_text_field( $_POST['role'] ); // If the new role isn't editable by the logged-in user die with error. $editable_roles = get_editable_roles(); if ( ! empty( $new_role ) && empty( $editable_roles[ $new_role ] ) ) { wp_die( __( 'Sorry, you are not allowed to give users that role.' ), 403 ); } $potential_role = $wp_roles->role_objects[ $new_role ] ?? false; /* * Don't let anyone with 'promote_users' edit their own role to something without it. * Multisite super admins can freely edit their roles, they possess all caps. */ if ( ( is_multisite() && current_user_can( 'manage_network_users' ) ) || get_current_user_id() !== $user_id || ( $potential_role && $potential_role->has_cap( 'promote_users' ) ) ) { $user->role = $new_role; } } if ( isset( $_POST['email'] ) ) { $user->user_email = sanitize_text_field( wp_unslash( $_POST['email'] ) ); } if ( isset( $_POST['url'] ) ) { if ( empty( $_POST['url'] ) || 'http://' === $_POST['url'] ) { $user->user_url = ''; } else { $user->user_url = sanitize_url( $_POST['url'] ); $protocols = implode( '|', array_map( 'preg_quote', wp_allowed_protocols() ) ); $user->user_url = preg_match( '/^(' . $protocols . '):/is', $user->user_url ) ? $user->user_url : 'http://' . $user->user_url; } } if ( isset( $_POST['first_name'] ) ) { $user->first_name = sanitize_text_field( $_POST['first_name'] ); } if ( isset( $_POST['last_name'] ) ) { $user->last_name = sanitize_text_field( $_POST['last_name'] ); } if ( isset( $_POST['nickname'] ) ) { $user->nickname = sanitize_text_field( $_POST['nickname'] ); } if ( isset( $_POST['display_name'] ) ) { $user->display_name = sanitize_text_field( $_POST['display_name'] ); } if ( isset( $_POST['description'] ) ) { $user->description = trim( $_POST['description'] ); } foreach ( wp_get_user_contact_methods( $user ) as $method => $name ) { if ( isset( $_POST[ $method ] ) ) { $user->$method = sanitize_text_field( $_POST[ $method ] ); } } if ( isset( $_POST['locale'] ) ) { $locale = sanitize_text_field( $_POST['locale'] ); if ( 'site-default' === $locale ) { $locale = ''; } elseif ( '' === $locale ) { $locale = 'en_US'; } elseif ( ! in_array( $locale, get_available_languages(), true ) ) { if ( current_user_can( 'install_languages' ) && wp_can_install_language_pack() ) { if ( ! wp_download_language_pack( $locale ) ) { $locale = ''; } } else { $locale = ''; } } $user->locale = $locale; } if ( $update ) { $user->rich_editing = isset( $_POST['rich_editing'] ) && 'false' === $_POST['rich_editing'] ? 'false' : 'true'; $user->syntax_highlighting = isset( $_POST['syntax_highlighting'] ) && 'false' === $_POST['syntax_highlighting'] ? 'false' : 'true'; $user->admin_color = isset( $_POST['admin_color'] ) ? sanitize_text_field( $_POST['admin_color'] ) : 'modern'; $user->show_admin_bar_front = isset( $_POST['admin_bar_front'] ) ? 'true' : 'false'; } $user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' === $_POST['comment_shortcuts'] ? 'true' : ''; $user->use_ssl = 0; if ( ! empty( $_POST['use_ssl'] ) ) { $user->use_ssl = 1; } $errors = new WP_Error(); /* checking that username has been typed */ if ( '' === $user->user_login ) { $errors->add( 'user_login', __( '<strong>Error:</strong> Please enter a username.' ) ); } /* checking that nickname has been typed */ if ( $update && empty( $user->nickname ) ) { $errors->add( 'nickname', __( '<strong>Error:</strong> Please enter a nickname.' ) ); } /** * Fires before the password and confirm password fields are checked for congruity. * * @since 1.5.1 * * @param string $user_login The username. * @param string $pass1 The password (passed by reference). * @param string $pass2 The confirmed password (passed by reference). */ do_action_ref_array( 'check_passwords', array( $user->user_login, &$pass1, &$pass2 ) ); // Check for blank password when adding a user. if ( ! $update && empty( $pass1 ) ) { $errors->add( 'pass', __( '<strong>Error:</strong> Please enter a password.' ), array( 'form-field' => 'pass1' ) ); } // Check for "\" in password. if ( str_contains( wp_unslash( $pass1 ), '\\' ) ) { $errors->add( 'pass', __( '<strong>Error:</strong> Passwords may not contain the character "\\".' ), array( 'form-field' => 'pass1' ) ); } // Checking the password has been typed twice the same. if ( ( $update || ! empty( $pass1 ) ) && $pass1 !== $pass2 ) { $errors->add( 'pass', __( '<strong>Error:</strong> Passwords do not match. Please enter the same password in both password fields.' ), array( 'form-field' => 'pass1' ) ); } if ( ! empty( $pass1 ) ) { $user->user_pass = $pass1; } if ( ! $update && isset( $_POST['user_login'] ) && ! validate_username( $_POST['user_login'] ) ) { $errors->add( 'user_login', __( '<strong>Error:</strong> This username is invalid because it uses illegal characters. Please enter a valid username.' ) ); } if ( ! $update && username_exists( $user->user_login ) ) { $errors->add( 'user_login', __( '<strong>Error:</strong> This username is already registered. Please choose another one.' ) ); } /** This filter is documented in wp-includes/user.php */ $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() ); if ( in_array( strtolower( $user->user_login ), array_map( 'strtolower', $illegal_logins ), true ) ) { $errors->add( 'invalid_username', __( '<strong>Error:</strong> Sorry, that username is not allowed.' ) ); } // Checking email address. if ( empty( $user->user_email ) ) { $errors->add( 'empty_email', __( '<strong>Error:</strong> Please enter an email address.' ), array( 'form-field' => 'email' ) ); } elseif ( ! is_email( $user->user_email ) ) { $errors->add( 'invalid_email', __( '<strong>Error:</strong> The email address is not correct.' ), array( 'form-field' => 'email' ) ); } else { $owner_id = email_exists( $user->user_email ); if ( $owner_id && ( ! $update || ( $owner_id !== $user->ID ) ) ) { $errors->add( 'email_exists', __( '<strong>Error:</strong> This email is already registered. Please choose another one.' ), array( 'form-field' => 'email' ) ); } } /** * Fires before user profile update errors are returned. * * @since 2.8.0 * * @param WP_Error $errors WP_Error object (passed by reference). * @param bool $update Whether this is a user update. * @param stdClass $user User object (passed by reference). */ do_action_ref_array( 'user_profile_update_errors', array( &$errors, $update, &$user ) ); if ( $errors->has_errors() ) { return $errors; } if ( $update ) { $user_id = wp_update_user( $user ); } else { $user_id = wp_insert_user( $user ); $notify = isset( $_POST['send_user_notification'] ) ? 'both' : 'admin'; /** * Fires after a new user has been created. * * @since 4.4.0 * * @param int|WP_Error $user_id ID of the newly created user or WP_Error on failure. * @param string $notify Type of notification that should happen. See * wp_send_new_user_notifications() for more information. */ do_action( 'edit_user_created_user', $user_id, $notify ); } return $user_id; } /** * Fetch a filtered list of user roles that the current user is * allowed to edit. * * Simple function whose main purpose is to allow filtering of the * list of roles in the $wp_roles object so that plugins can remove * inappropriate ones depending on the situation or user making edits. * Specifically because without filtering anyone with the edit_users * capability can edit others to be administrators, even if they are * only editors or authors. This filter allows admins to delegate * user management. * * @since 2.8.0 * * @return array[] Array of arrays containing role information. */ function get_editable_roles() { $all_roles = wp_roles()->roles; /** * Filters the list of editable roles. * * @since 2.8.0 * * @param array[] $all_roles Array of arrays containing role information. */ $editable_roles = apply_filters( 'editable_roles', $all_roles ); return $editable_roles; } /** * Retrieve user data and filter it. * * @since 2.0.5 * * @param int $user_id User ID. * @return WP_User|false WP_User object on success, false on failure. */ function get_user_to_edit( $user_id ) { $user = get_userdata( $user_id ); if ( $user ) { $user->filter = 'edit'; } return $user; } /** * Retrieve the user's drafts. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $user_id User ID. * @return object[] The user's draft posts, with 'ID' and 'post_title' keys. */ function get_users_drafts( $user_id ) { global $wpdb; $query = $wpdb->prepare( "SELECT ID, post_title FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'draft' AND post_author = %d ORDER BY post_modified DESC", $user_id ); /** * Filters the SQL query string for the user's drafts query. * * @since 2.0.0 * * @param string $query The user's drafts query string. */ $query = apply_filters( 'get_users_drafts', $query ); return $wpdb->get_results( $query ); } /** * Delete user and optionally reassign posts and links to another user. * * Note that on a Multisite installation the user only gets removed from the site * and does not get deleted from the database. * * If the `$reassign` parameter is not assigned to a user ID, then all posts will * be deleted of that user. The action {@see 'delete_user'} that is passed the user ID * being deleted will be run after the posts are either reassigned or deleted. * The user meta will also be deleted that are for that user ID. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $id User ID. * @param int $reassign Optional. Reassign posts and links to new User ID. * @return bool True when finished. */ function wp_delete_user( $id, $reassign = null ) { global $wpdb; if ( ! is_numeric( $id ) ) { return false; } $id = (int) $id; $user = new WP_User( $id ); if ( ! $user->exists() ) { return false; } // Normalize $reassign to null or a user ID. 'novalue' was an older default. if ( 'novalue' === $reassign ) { $reassign = null; } elseif ( null !== $reassign ) { $reassign = (int) $reassign; } /** * Fires immediately before a user is deleted from the site. * * Note that on a Multisite installation the user only gets removed from the site * and does not get deleted from the database. * * @since 2.0.0 * @since 5.5.0 Added the `$user` parameter. * * @param int $id ID of the user to delete. * @param int|null $reassign ID of the user to reassign posts and links to. * Default null, for no reassignment. * @param WP_User $user WP_User object of the user to delete. */ do_action( 'delete_user', $id, $reassign, $user ); if ( null === $reassign ) { $post_types_to_delete = array(); foreach ( get_post_types( array(), 'objects' ) as $post_type ) { if ( $post_type->delete_with_user ) { $post_types_to_delete[] = $post_type->name; } elseif ( null === $post_type->delete_with_user && post_type_supports( $post_type->name, 'author' ) ) { $post_types_to_delete[] = $post_type->name; } } /** * Filters the list of post types to delete with a user. * * @since 3.4.0 * * @param string[] $post_types_to_delete Array of post types to delete. * @param int $id User ID. */ $post_types_to_delete = apply_filters( 'post_types_to_delete_with_user', $post_types_to_delete, $id ); $post_types_to_delete = implode( "', '", $post_types_to_delete ); $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d AND post_type IN ('$post_types_to_delete')", $id ) ); if ( $post_ids ) { foreach ( $post_ids as $post_id ) { wp_delete_post( $post_id ); } } // Clean links. $link_ids = $wpdb->get_col( $wpdb->prepare( "SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id ) ); if ( $link_ids ) { foreach ( $link_ids as $link_id ) { wp_delete_link( $link_id ); } } } else { $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $id ) ); $wpdb->update( $wpdb->posts, array( 'post_author' => $reassign ), array( 'post_author' => $id ) ); if ( ! empty( $post_ids ) ) { foreach ( $post_ids as $post_id ) { clean_post_cache( $post_id ); } } $link_ids = $wpdb->get_col( $wpdb->prepare( "SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id ) ); $wpdb->update( $wpdb->links, array( 'link_owner' => $reassign ), array( 'link_owner' => $id ) ); if ( ! empty( $link_ids ) ) { foreach ( $link_ids as $link_id ) { clean_bookmark_cache( $link_id ); } } } // FINALLY, delete user. if ( is_multisite() ) { remove_user_from_blog( $id, get_current_blog_id() ); } else { $meta = $wpdb->get_col( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d", $id ) ); foreach ( $meta as $mid ) { delete_metadata_by_mid( 'user', $mid ); } $wpdb->delete( $wpdb->users, array( 'ID' => $id ) ); } clean_user_cache( $user ); /** * Fires immediately after a user is deleted from the site. * * Note that on a Multisite installation the user may not have been deleted from * the database depending on whether `wp_delete_user()` or `wpmu_delete_user()` * was called. * * @since 2.9.0 * @since 5.5.0 Added the `$user` parameter. * * @param int $id ID of the deleted user. * @param int|null $reassign ID of the user to reassign posts and links to. * Default null, for no reassignment. * @param WP_User $user WP_User object of the deleted user. */ do_action( 'deleted_user', $id, $reassign, $user ); return true; } /** * Remove all capabilities from user. * * @since 2.1.0 * * @param int $id User ID. */ function wp_revoke_user( $id ) { $id = (int) $id; $user = new WP_User( $id ); $user->remove_all_caps(); } /** * @since 2.8.0 * * @global int $user_ID Current user ID. * * @param false $errors Deprecated. */ function default_password_nag_handler( $errors = false ) { global $user_ID; // Short-circuit it. if ( ! get_user_option( 'default_password_nag' ) ) { return; } // get_user_setting() = JS-saved UI setting. Else no-js-fallback code. if ( 'hide' === get_user_setting( 'default_password_nag' ) || isset( $_GET['default_password_nag'] ) && '0' === $_GET['default_password_nag'] ) { delete_user_setting( 'default_password_nag' ); update_user_meta( $user_ID, 'default_password_nag', false ); } } /** * @since 2.8.0 * * @param int $user_ID User ID. * @param WP_User $old_data The user object before the update. */ function default_password_nag_edit_user( $user_ID, $old_data ) { // Short-circuit it. if ( ! get_user_option( 'default_password_nag', $user_ID ) ) { return; } $new_data = get_userdata( $user_ID ); // Remove the nag if the password has been changed. if ( $new_data->user_pass !== $old_data->user_pass ) { delete_user_setting( 'default_password_nag' ); update_user_meta( $user_ID, 'default_password_nag', false ); } } /** * @since 2.8.0 * * @global string $pagenow The filename of the current screen. */ function default_password_nag() { global $pagenow; // Short-circuit it. if ( 'profile.php' === $pagenow || ! get_user_option( 'default_password_nag' ) ) { return; } $default_password_nag_message = sprintf( '<p><strong>%1$s</strong> %2$s</p>', __( 'Notice:' ), __( 'You are using the auto-generated password for your account. Would you like to change it?' ) ); $default_password_nag_message .= sprintf( '<p><a href="%1$s">%2$s</a> | ', esc_url( get_edit_profile_url() . '#password' ), __( 'Yes, take me to my profile page' ) ); $default_password_nag_message .= sprintf( '<a href="%1$s" id="default-password-nag-no">%2$s</a></p>', '?default_password_nag=0', __( 'No thanks, do not remind me again' ) ); wp_admin_notice( $default_password_nag_message, array( 'additional_classes' => array( 'error', 'default-password-nag' ), 'paragraph_wrap' => false, ) ); } /** * @since 3.5.0 * @access private */ function delete_users_add_js() { ?> <script> jQuery( function($) { var submit = $('#submit').prop('disabled', true); $('input[name="delete_option"]').one('change', function() { submit.prop('disabled', false); }); $('#reassign_user').focus( function() { $('#delete_option1').prop('checked', true).trigger('change'); }); } ); </script> <?php } /** * Optional SSL preference that can be turned on by hooking to the 'personal_options' action. * * See the {@see 'personal_options'} action. * * @since 2.7.0 * * @param WP_User $user User data object. */ function use_ssl_preference( $user ) { ?> <tr class="user-use-ssl-wrap"> <th scope="row"><?php _e( 'Use https' ); ?></th> <td><label for="use_ssl"><input name="use_ssl" type="checkbox" id="use_ssl" value="1" <?php checked( '1', $user->use_ssl ); ?> /> <?php _e( 'Always use https when visiting the admin' ); ?></label></td> </tr> <?php } /** * @since MU (3.0.0) * * @param string $text The email body text. * @return string User site invitation email message. */ function admin_created_user_email( $text ) { $roles = get_editable_roles(); $role = $roles[ $_REQUEST['role'] ]; if ( '' !== get_bloginfo( 'name' ) ) { $site_title = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); } else { $site_title = parse_url( home_url(), PHP_URL_HOST ); } return sprintf( /* translators: 1: Site title, 2: Site URL, 3: User role. */ __( 'Hi, You\'ve been invited to join \'%1$s\' at %2$s with the role of %3$s. If you do not want to join this site please ignore this email. This invitation will expire in a few days. Please click the following link to activate your user account: %%s' ), $site_title, home_url(), wp_specialchars_decode( translate_user_role( $role['name'] ) ) ); } /** * Checks if the Authorize Application Password request is valid. * * @since 5.6.0 * @since 6.2.0 Allow insecure HTTP connections for the local environment. * @since 6.3.2 Validates the success and reject URLs to prevent `javascript` pseudo protocol from being executed. * * @param array $request { * The array of request data. All arguments are optional and may be empty. * * @type string $app_name The suggested name of the application. * @type string $app_id A UUID provided by the application to uniquely identify it. * @type string $success_url The URL the user will be redirected to after approving the application. * @type string $reject_url The URL the user will be redirected to after rejecting the application. * } * @param WP_User $user The user authorizing the application. * @return true|WP_Error True if the request is valid, a WP_Error object contains errors if not. */ function wp_is_authorize_application_password_request_valid( $request, $user ) { $error = new WP_Error(); if ( isset( $request['success_url'] ) ) { $validated_success_url = wp_is_authorize_application_redirect_url_valid( $request['success_url'] ); if ( is_wp_error( $validated_success_url ) ) { $error->add( $validated_success_url->get_error_code(), $validated_success_url->get_error_message() ); } } if ( isset( $request['reject_url'] ) ) { $validated_reject_url = wp_is_authorize_application_redirect_url_valid( $request['reject_url'] ); if ( is_wp_error( $validated_reject_url ) ) { $error->add( $validated_reject_url->get_error_code(), $validated_reject_url->get_error_message() ); } } if ( ! empty( $request['app_id'] ) && ! wp_is_uuid( $request['app_id'] ) ) { $error->add( 'invalid_app_id', __( 'The application ID must be a UUID.' ) ); } /** * Fires before application password errors are returned. * * @since 5.6.0 * * @param WP_Error $error The error object. * @param array $request The array of request data. * @param WP_User $user The user authorizing the application. */ do_action( 'wp_authorize_application_password_request_errors', $error, $request, $user ); if ( $error->has_errors() ) { return $error; } return true; } /** * Validates the redirect URL protocol scheme. * * The `http` scheme is allowed for loopback IP addresses (127.0.0.1, [::1]) * and local environments. The `javascript` and `data` protocols are always rejected. * * @since 6.3.2 * * @param string $url The redirect URL to be validated. * @return true|WP_Error True if the redirect URL is valid, a WP_Error object otherwise. */ function wp_is_authorize_application_redirect_url_valid( $url ) { $bad_protocols = array( 'javascript', 'data' ); if ( empty( $url ) ) { return true; } // Based on https://www.rfc-editor.org/rfc/rfc2396#section-3.1 $valid_scheme_regex = '/^[a-zA-Z][a-zA-Z0-9+.-]*:/'; if ( ! preg_match( $valid_scheme_regex, $url ) ) { return new WP_Error( 'invalid_redirect_url_format', __( 'Invalid URL format.' ) ); } /** * Filters the list of invalid protocols used in applications redirect URLs. * * @since 6.3.2 * * @param string[] $bad_protocols Array of invalid protocols. * @param string $url The redirect URL to be validated. */ $invalid_protocols = apply_filters( 'wp_authorize_application_redirect_url_invalid_protocols', $bad_protocols, $url ); $invalid_protocols = array_map( 'strtolower', $invalid_protocols ); $scheme = wp_parse_url( $url, PHP_URL_SCHEME ); $host = wp_parse_url( $url, PHP_URL_HOST ); $is_local = 'local' === wp_get_environment_type(); // Validates if the proper URI format is applied to the URL. if ( empty( $host ) || empty( $scheme ) || in_array( strtolower( $scheme ), $invalid_protocols, true ) ) { return new WP_Error( 'invalid_redirect_url_format', __( 'Invalid URL format.' ) ); } // Allow insecure HTTP connections to locally hosted applications. $is_loopback = in_array( strtolower( $host ), array( '127.0.0.1', '[::1]' ), true ); if ( 'http' === $scheme && ! $is_local && ! $is_loopback ) { return new WP_Error( 'invalid_redirect_scheme', __( 'The URL must be served over a secure connection.' ) ); } return true; } PK $��\���^; ^; class-core-upgrader.phpnu �[��� <?php /** * Upgrade API: Core_Upgrader class * * @package WordPress * @subpackage Upgrader * @since 4.6.0 */ /** * Core class used for updating core. * * It allows for WordPress to upgrade itself in combination with * the wp-admin/includes/update-core.php file. * * Note: Newly introduced functions and methods cannot be used here. * All functions must be present in the previous version being upgraded from * as this file is used there too. * * @since 2.8.0 * @since 4.6.0 Moved to its own file from wp-admin/includes/class-wp-upgrader.php. * * @see WP_Upgrader */ class Core_Upgrader extends WP_Upgrader { /** * Initializes the upgrade strings. * * @since 2.8.0 */ public function upgrade_strings() { $this->strings['up_to_date'] = __( 'WordPress is at the latest version.' ); $this->strings['locked'] = __( 'Another update is currently in progress.' ); $this->strings['no_package'] = __( 'Update package not available.' ); /* translators: %s: Package URL. */ $this->strings['downloading_package'] = sprintf( __( 'Downloading update from %s…' ), '<span class="code pre">%s</span>' ); $this->strings['unpack_package'] = __( 'Unpacking the update…' ); $this->strings['copy_failed'] = __( 'Could not copy files.' ); $this->strings['copy_failed_space'] = __( 'Could not copy files. You may have run out of disk space.' ); $this->strings['start_rollback'] = __( 'Attempting to restore the previous version.' ); $this->strings['rollback_was_required'] = __( 'Due to an error during updating, WordPress has been restored to your previous version.' ); } /** * Upgrades WordPress core. * * @since 2.8.0 * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * @global callable $_wp_filesystem_direct_method Filesystem direct method callback. * * @param object $current Response object for whether WordPress is current. * @param array $args { * Optional. Arguments for upgrading WordPress core. Default empty array. * * @type bool $pre_check_md5 Whether to check the file checksums before * attempting the upgrade. Default true. * @type bool $attempt_rollback Whether to attempt to rollback the chances if * there is a problem. Default false. * @type bool $do_rollback Whether to perform this "upgrade" as a rollback. * Default false. * } * @return string|false|WP_Error New WordPress version on success, false or WP_Error on failure. */ public function upgrade( $current, $args = array() ) { global $wp_filesystem; require ABSPATH . WPINC . '/version.php'; // $wp_version; $start_time = time(); $defaults = array( 'pre_check_md5' => true, 'attempt_rollback' => false, 'do_rollback' => false, 'allow_relaxed_file_ownership' => false, ); $parsed_args = wp_parse_args( $args, $defaults ); $this->init(); $this->upgrade_strings(); // Is an update available? if ( ! isset( $current->response ) || 'latest' === $current->response ) { return new WP_Error( 'up_to_date', $this->strings['up_to_date'] ); } $res = $this->fs_connect( array( ABSPATH, WP_CONTENT_DIR ), $parsed_args['allow_relaxed_file_ownership'] ); if ( ! $res || is_wp_error( $res ) ) { return $res; } $wp_dir = trailingslashit( $wp_filesystem->abspath() ); $partial = true; if ( $parsed_args['do_rollback'] ) { $partial = false; } elseif ( $parsed_args['pre_check_md5'] && ! $this->check_files() ) { $partial = false; } /* * If partial update is returned from the API, use that, unless we're doing * a reinstallation. If we cross the new_bundled version number, then use * the new_bundled zip. Don't though if the constant is set to skip bundled items. * If the API returns a no_content zip, go with it. Finally, default to the full zip. */ if ( $parsed_args['do_rollback'] && $current->packages->rollback ) { $to_download = 'rollback'; } elseif ( $current->packages->partial && 'reinstall' !== $current->response && $wp_version === $current->partial_version && $partial ) { $to_download = 'partial'; } elseif ( $current->packages->new_bundled && version_compare( $wp_version, $current->new_bundled, '<' ) && ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) ) { $to_download = 'new_bundled'; } elseif ( $current->packages->no_content ) { $to_download = 'no_content'; } else { $to_download = 'full'; } // Lock to prevent multiple Core Updates occurring. $lock = WP_Upgrader::create_lock( 'core_updater', 15 * MINUTE_IN_SECONDS ); if ( ! $lock ) { return new WP_Error( 'locked', $this->strings['locked'] ); } $download = $this->download_package( $current->packages->$to_download, false ); /* * Allow for signature soft-fail. * WARNING: This may be removed in the future. */ if ( is_wp_error( $download ) && $download->get_error_data( 'softfail-filename' ) ) { // Output the failure error as a normal feedback, and not as an error: /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', $download->get_error_message() ); // Report this failure back to WordPress.org for debugging purposes. wp_version_check( array( 'signature_failure_code' => $download->get_error_code(), 'signature_failure_data' => $download->get_error_data(), ) ); // Pretend this error didn't happen. $download = $download->get_error_data( 'softfail-filename' ); } if ( is_wp_error( $download ) ) { WP_Upgrader::release_lock( 'core_updater' ); return $download; } $working_dir = $this->unpack_package( $download ); if ( is_wp_error( $working_dir ) ) { WP_Upgrader::release_lock( 'core_updater' ); return $working_dir; } // Copy update-core.php from the new version into place. if ( ! $wp_filesystem->copy( $working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true ) ) { $wp_filesystem->delete( $working_dir, true ); WP_Upgrader::release_lock( 'core_updater' ); return new WP_Error( 'copy_failed_for_update_core_file', __( 'The update cannot be installed because some files could not be copied. This is usually due to inconsistent file permissions.' ), 'wp-admin/includes/update-core.php' ); } $wp_filesystem->chmod( $wp_dir . 'wp-admin/includes/update-core.php', FS_CHMOD_FILE ); wp_opcache_invalidate( ABSPATH . 'wp-admin/includes/update-core.php' ); require_once ABSPATH . 'wp-admin/includes/update-core.php'; if ( ! function_exists( 'update_core' ) ) { WP_Upgrader::release_lock( 'core_updater' ); return new WP_Error( 'copy_failed_space', $this->strings['copy_failed_space'] ); } $result = update_core( $working_dir, $wp_dir ); // In the event of an issue, we may be able to roll back. if ( $parsed_args['attempt_rollback'] && $current->packages->rollback && ! $parsed_args['do_rollback'] ) { $try_rollback = false; if ( is_wp_error( $result ) ) { $error_code = $result->get_error_code(); /* * Not all errors are equal. These codes are critical: copy_failed__copy_dir, * mkdir_failed__copy_dir, copy_failed__copy_dir_retry, and disk_full. * do_rollback allows for update_core() to trigger a rollback if needed. */ if ( str_contains( $error_code, 'do_rollback' ) ) { $try_rollback = true; } elseif ( str_contains( $error_code, '__copy_dir' ) ) { $try_rollback = true; } elseif ( 'disk_full' === $error_code ) { $try_rollback = true; } } if ( $try_rollback ) { /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', $result ); /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters( 'update_feedback', $this->strings['start_rollback'] ); $rollback_result = $this->upgrade( $current, array_merge( $parsed_args, array( 'do_rollback' => true ) ) ); $original_result = $result; $result = new WP_Error( 'rollback_was_required', $this->strings['rollback_was_required'], (object) array( 'update' => $original_result, 'rollback' => $rollback_result, ) ); } } /** This action is documented in wp-admin/includes/class-wp-upgrader.php */ do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'core', ) ); // Clear the current updates. delete_site_transient( 'update_core' ); if ( ! $parsed_args['do_rollback'] ) { $stats = array( 'update_type' => $current->response, 'success' => true, 'fs_method' => $wp_filesystem->method, 'fs_method_forced' => defined( 'FS_METHOD' ) || has_filter( 'filesystem_method' ), 'fs_method_direct' => ! empty( $GLOBALS['_wp_filesystem_direct_method'] ) ? $GLOBALS['_wp_filesystem_direct_method'] : '', 'time_taken' => time() - $start_time, 'reported' => $wp_version, 'attempted' => $current->version, ); if ( is_wp_error( $result ) ) { $stats['success'] = false; // Did a rollback occur? if ( ! empty( $try_rollback ) ) { $stats['error_code'] = $original_result->get_error_code(); $stats['error_data'] = $original_result->get_error_data(); // Was the rollback successful? If not, collect its error too. $stats['rollback'] = ! is_wp_error( $rollback_result ); if ( is_wp_error( $rollback_result ) ) { $stats['rollback_code'] = $rollback_result->get_error_code(); $stats['rollback_data'] = $rollback_result->get_error_data(); } } else { $stats['error_code'] = $result->get_error_code(); $stats['error_data'] = $result->get_error_data(); } } wp_version_check( $stats ); } WP_Upgrader::release_lock( 'core_updater' ); return $result; } /** * Determines if this WordPress Core version should update to an offered version or not. * * @since 3.7.0 * * @param string $offered_ver The offered version, of the format x.y.z. * @return bool True if we should update to the offered version, otherwise false. */ public static function should_update_to_version( $offered_ver ) { require ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z $current_branch = implode( '.', array_slice( preg_split( '/[.-]/', $wp_version ), 0, 2 ) ); // x.y $new_branch = implode( '.', array_slice( preg_split( '/[.-]/', $offered_ver ), 0, 2 ) ); // x.y $current_is_development_version = (bool) strpos( $wp_version, '-' ); // Defaults: $upgrade_dev = get_site_option( 'auto_update_core_dev', 'enabled' ) === 'enabled'; $upgrade_minor = get_site_option( 'auto_update_core_minor', 'enabled' ) === 'enabled'; $upgrade_major = get_site_option( 'auto_update_core_major', 'unset' ) === 'enabled'; // WP_AUTO_UPDATE_CORE = true (all), 'beta', 'rc', 'development', 'branch-development', 'minor', false. if ( defined( 'WP_AUTO_UPDATE_CORE' ) ) { if ( false === WP_AUTO_UPDATE_CORE ) { // Defaults to turned off, unless a filter allows it. $upgrade_dev = false; $upgrade_minor = false; $upgrade_major = false; } elseif ( true === WP_AUTO_UPDATE_CORE || in_array( WP_AUTO_UPDATE_CORE, array( 'beta', 'rc', 'development', 'branch-development' ), true ) ) { // ALL updates for core. $upgrade_dev = true; $upgrade_minor = true; $upgrade_major = true; } elseif ( 'minor' === WP_AUTO_UPDATE_CORE ) { // Only minor updates for core. $upgrade_dev = false; $upgrade_minor = true; $upgrade_major = false; } } // 1: If we're already on that version, not much point in updating? if ( $offered_ver === $wp_version ) { return false; } // 2: If we're running a newer version, that's a nope. if ( version_compare( $wp_version, $offered_ver, '>' ) ) { return false; } $failure_data = get_site_option( 'auto_core_update_failed' ); if ( $failure_data ) { // If this was a critical update failure, cannot update. if ( ! empty( $failure_data['critical'] ) ) { return false; } // Don't claim we can update on update-core.php if we have a non-critical failure logged. if ( $wp_version === $failure_data['current'] && str_contains( $offered_ver, '.1.next.minor' ) ) { return false; } /* * Cannot update if we're retrying the same A to B update that caused a non-critical failure. * Some non-critical failures do allow retries, like download_failed. * 3.7.1 => 3.7.2 resulted in files_not_writable, if we are still on 3.7.1 and still trying to update to 3.7.2. */ if ( empty( $failure_data['retry'] ) && $wp_version === $failure_data['current'] && $offered_ver === $failure_data['attempted'] ) { return false; } } // 3: 3.7-alpha-25000 -> 3.7-alpha-25678 -> 3.7-beta1 -> 3.7-beta2. if ( $current_is_development_version ) { /** * Filters whether to enable automatic core updates for development versions. * * @since 3.7.0 * * @param bool $upgrade_dev Whether to enable automatic updates for * development versions. */ if ( ! apply_filters( 'allow_dev_auto_core_updates', $upgrade_dev ) ) { return false; } // Else fall through to minor + major branches below. } // 4: Minor in-branch updates (3.7.0 -> 3.7.1 -> 3.7.2 -> 3.7.4). if ( $current_branch === $new_branch ) { /** * Filters whether to enable minor automatic core updates. * * @since 3.7.0 * * @param bool $upgrade_minor Whether to enable minor automatic core updates. */ return apply_filters( 'allow_minor_auto_core_updates', $upgrade_minor ); } // 5: Major version updates (3.7.0 -> 3.8.0 -> 3.9.1). if ( version_compare( $new_branch, $current_branch, '>' ) ) { /** * Filters whether to enable major automatic core updates. * * @since 3.7.0 * * @param bool $upgrade_major Whether to enable major automatic core updates. */ return apply_filters( 'allow_major_auto_core_updates', $upgrade_major ); } // If we're not sure, we don't want it. return false; } /** * Compares the disk file checksums against the expected checksums. * * @since 3.7.0 * * @global string $wp_version The WordPress version string. * @global string $wp_local_package Locale code of the package. * * @return bool True if the checksums match, otherwise false. */ public function check_files() { global $wp_version, $wp_local_package; $checksums = get_core_checksums( $wp_version, $wp_local_package ?? 'en_US' ); if ( ! is_array( $checksums ) ) { return false; } foreach ( $checksums as $file => $checksum ) { // Skip files which get updated. if ( str_starts_with( $file, 'wp-content' ) ) { continue; } if ( ! file_exists( ABSPATH . $file ) || md5_file( ABSPATH . $file ) !== $checksum ) { return false; } } return true; } } PK $��\�$��% % - class-wp-application-passwords-list-table.phpnu �[��� <?php /** * List Table API: WP_Application_Passwords_List_Table class * * @package WordPress * @subpackage Administration * @since 5.6.0 */ /** * Class for displaying the list of application password items. * * @since 5.6.0 * * @see WP_List_Table */ class WP_Application_Passwords_List_Table extends WP_List_Table { /** * Gets the list of columns. * * @since 5.6.0 * * @return string[] Array of column titles keyed by their column name. */ public function get_columns() { return array( 'name' => __( 'Name' ), 'created' => __( 'Created' ), 'last_used' => __( 'Last Used' ), 'last_ip' => __( 'Last IP' ), 'revoke' => __( 'Revoke' ), ); } /** * Prepares the list of items for displaying. * * @since 5.6.0 * * @global int $user_id User ID. */ public function prepare_items() { global $user_id; $this->items = array_reverse( WP_Application_Passwords::get_user_application_passwords( $user_id ) ); } /** * Handles the name column output. * * @since 5.6.0 * * @param array $item The current application password item. */ public function column_name( $item ) { echo esc_html( $item['name'] ); } /** * Handles the created column output. * * @since 5.6.0 * * @param array $item The current application password item. */ public function column_created( $item ) { if ( empty( $item['created'] ) ) { echo '—'; } else { echo date_i18n( __( 'F j, Y' ), $item['created'] ); } } /** * Handles the last used column output. * * @since 5.6.0 * * @param array $item The current application password item. */ public function column_last_used( $item ) { if ( empty( $item['last_used'] ) ) { echo '—'; } else { echo date_i18n( __( 'F j, Y' ), $item['last_used'] ); } } /** * Handles the last ip column output. * * @since 5.6.0 * * @param array $item The current application password item. */ public function column_last_ip( $item ) { if ( empty( $item['last_ip'] ) ) { echo '—'; } else { echo $item['last_ip']; } } /** * Handles the revoke column output. * * @since 5.6.0 * * @param array $item The current application password item. */ public function column_revoke( $item ) { $name = 'revoke-application-password-' . $item['uuid']; printf( '<button type="button" name="%1$s" id="%1$s" class="button delete" aria-label="%2$s">%3$s</button>', esc_attr( $name ), /* translators: %s: the application password's given name. */ esc_attr( sprintf( __( 'Revoke "%s"' ), $item['name'] ) ), __( 'Revoke' ) ); } /** * Generates content for a single row of the table * * @since 5.6.0 * * @param array $item The current item. * @param string $column_name The current column name. */ protected function column_default( $item, $column_name ) { /** * Fires for each custom column in the Application Passwords list table. * * Custom columns are registered using the {@see 'manage_application-passwords-user_columns'} filter. * * @since 5.6.0 * * @param string $column_name Name of the custom column. * @param array $item The application password item. */ do_action( "manage_{$this->screen->id}_custom_column", $column_name, $item ); } /** * Generates custom table navigation to prevent conflicting nonces. * * @since 5.6.0 * * @param string $which The location of the bulk actions: Either 'top' or 'bottom'. */ protected function display_tablenav( $which ) { ?> <div class="tablenav <?php echo esc_attr( $which ); ?>"> <?php if ( 'bottom' === $which ) : ?> <div class="alignright"> <button type="button" name="revoke-all-application-passwords" id="revoke-all-application-passwords" class="button delete"><?php _e( 'Revoke all application passwords' ); ?></button> </div> <?php endif; ?> <div class="alignleft actions bulkactions"> <?php $this->bulk_actions( $which ); ?> </div> <?php $this->extra_tablenav( $which ); $this->pagination( $which ); ?> <br class="clear" /> </div> <?php } /** * Generates content for a single row of the table. * * @since 5.6.0 * * @param array $item The current item. */ public function single_row( $item ) { echo '<tr data-uuid="' . esc_attr( $item['uuid'] ) . '">'; $this->single_row_columns( $item ); echo '</tr>'; } /** * Gets the name of the default primary column. * * @since 5.6.0 * * @return string Name of the default primary column, in this case, 'name'. */ protected function get_default_primary_column_name() { return 'name'; } /** * Prints the JavaScript template for the new row item. * * @since 5.6.0 */ public function print_js_template_row() { list( $columns, $hidden, , $primary ) = $this->get_column_info(); echo '<tr data-uuid="{{ data.uuid }}">'; foreach ( $columns as $column_name => $display_name ) { $is_primary = $primary === $column_name; $classes = "{$column_name} column-{$column_name}"; if ( $is_primary ) { $classes .= ' has-row-actions column-primary'; } if ( in_array( $column_name, $hidden, true ) ) { $classes .= ' hidden'; } printf( '<td class="%s" data-colname="%s">', esc_attr( $classes ), esc_attr( wp_strip_all_tags( $display_name ) ) ); switch ( $column_name ) { case 'name': echo '{{ data.name }}'; break; case 'created': // JSON encoding automatically doubles backslashes to ensure they don't get lost when printing the inline JS. echo '<# print( wp.date.dateI18n( ' . wp_json_encode( __( 'F j, Y' ) ) . ', data.created ) ) #>'; break; case 'last_used': echo '<# print( data.last_used !== null ? wp.date.dateI18n( ' . wp_json_encode( __( 'F j, Y' ) ) . ", data.last_used ) : '—' ) #>"; break; case 'last_ip': echo "{{ data.last_ip || '—' }}"; break; case 'revoke': printf( '<button type="button" class="button delete" aria-label="%1$s">%2$s</button>', /* translators: %s: the application password's given name. */ esc_attr( sprintf( __( 'Revoke "%s"' ), '{{ data.name }}' ) ), esc_html__( 'Revoke' ) ); break; default: /** * Fires in the JavaScript row template for each custom column in the Application Passwords list table. * * Custom columns are registered using the {@see 'manage_application-passwords-user_columns'} filter. * * @since 5.6.0 * * @param string $column_name Name of the custom column. */ do_action( "manage_{$this->screen->id}_custom_column_js_template", $column_name ); break; } if ( $is_primary ) { echo '<button type="button" class="toggle-row"><span class="screen-reader-text">' . /* translators: Hidden accessibility text. */ __( 'Show more details' ) . '</span></button>'; } echo '</td>'; } echo '</tr>'; } } PK $��\�\@cAH AH "