WordPress 4.3
[autoinstalls/wordpress.git] / wp-admin / includes / ajax-actions.php
index 40f8f5d195792e9cadabee569961bc163106646d..77c32b05ed6d1701d2145a112fbcdd32d007143e 100644 (file)
@@ -78,6 +78,8 @@ function wp_ajax_nopriv_heartbeat() {
  * Ajax handler for fetching a list table.
  *
  * @since 3.1.0
+ *
+ * @global WP_List_Table $wp_list_table
  */
 function wp_ajax_fetch_list() {
        global $wp_list_table;
@@ -226,6 +228,8 @@ function wp_ajax_imgedit_preview() {
  * Ajax handler for oEmbed caching.
  *
  * @since 3.1.0
+ *
+ * @global WP_Embed $wp_embed
  */
 function wp_ajax_oembed_cache() {
        $GLOBALS['wp_embed']->cache_oembed( $_GET['post'] );
@@ -334,7 +338,7 @@ function wp_ajax_logged_in() {
  * @since 2.7.0
  *
  * @param int $comment_id
- * @return die
+ * @param int $delta
  */
 function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) {
        $total    = isset( $_POST['_total'] )    ? (int) $_POST['_total']    : 0;
@@ -430,10 +434,13 @@ function _wp_ajax_add_hierarchical_term() {
                $checked_categories[] = $cat_id;
                if ( $parent ) // Do these all at once in a second
                        continue;
+
                ob_start();
-                       wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name, 'descendants_and_self' => $cat_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids ));
-               $data = ob_get_contents();
-               ob_end_clean();
+
+               wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name, 'descendants_and_self' => $cat_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids ));
+
+               $data = ob_get_clean();
+
                $add = array(
                        'what' => $taxonomy->name,
                        'id' => $cat_id,
@@ -454,9 +461,11 @@ function _wp_ajax_add_hierarchical_term() {
                }
 
                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_contents();
-               ob_end_clean();
+
+               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,
@@ -466,12 +475,14 @@ function _wp_ajax_add_hierarchical_term() {
        }
 
        ob_start();
-               wp_dropdown_categories( array(
-                       'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
-                       'hierarchical' => 1, 'show_option_none' => '— '.$taxonomy->labels->parent_item.' —'
-               ) );
-       $sup = ob_get_contents();
-       ob_end_clean();
+
+       wp_dropdown_categories( array(
+               'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
+               'hierarchical' => 1, 'show_option_none' => '— '.$taxonomy->labels->parent_item.' —'
+       ) );
+
+       $sup = ob_get_clean();
+
        $add['supplemental'] = array( 'newcat_parent' => $sup );
 
        $x = new WP_Ajax_Response( $add );
@@ -660,6 +671,11 @@ function wp_ajax_untrash_post( $action ) {
        wp_ajax_trash_post( $action );
 }
 
+/**
+ * @since 3.1.0
+ *
+ * @param string $action
+ */
 function wp_ajax_delete_page( $action ) {
        if ( empty( $action ) )
                $action = 'delete-page';
@@ -762,6 +778,8 @@ function wp_ajax_add_link_category( $action ) {
  * Ajax handler to add a tag.
  *
  * @since 3.1.0
+ *
+ * @global WP_List_Table $wp_list_table
  */
 function wp_ajax_add_tag() {
        global $wp_list_table;
@@ -806,12 +824,12 @@ function wp_ajax_add_tag() {
        $x->add( array(
                'what' => 'taxonomy',
                'supplemental' => compact('parents', 'noparents')
-               ) );
+       ) );
        $x->add( array(
                'what' => 'term',
                'position' => $level,
                'supplemental' => (array) $tag
-               ) );
+       ) );
        $x->send();
 }
 
@@ -864,6 +882,9 @@ function wp_ajax_get_tagcloud() {
  *
  * @since 3.1.0
  *
+ * @global WP_List_Table $wp_list_table
+ * @global int           $post_id
+ *
  * @param string $action Action to perform.
  */
 function wp_ajax_get_comments( $action ) {
@@ -900,8 +921,7 @@ function wp_ajax_get_comments( $action ) {
                get_comment( $comment );
                $wp_list_table->single_row( $comment );
        }
-       $comment_list_item = ob_get_contents();
-       ob_end_clean();
+       $comment_list_item = ob_get_clean();
 
        $x->add( array(
                'what' => 'comments',
@@ -915,6 +935,8 @@ function wp_ajax_get_comments( $action ) {
  *
  * @since 3.1.0
  *
+ * @global WP_List_Table $wp_list_table
+ *
  * @param string $action Action to perform.
  */
 function wp_ajax_replyto_comment( $action ) {
@@ -1016,6 +1038,8 @@ function wp_ajax_replyto_comment( $action ) {
  * Ajax handler for editing a comment.
  *
  * @since 3.1.0
+ *
+ * @global WP_List_Table $wp_list_table
  */
 function wp_ajax_edit_comment() {
        global $wp_list_table;
@@ -1229,6 +1253,8 @@ function wp_ajax_add_meta() {
  *
  * @since 3.1.0
  *
+ * @global WP_List_Table $wp_list_table
+ *
  * @param string $action Action to perform.
  */
 function wp_ajax_add_user( $action ) {
@@ -1305,7 +1331,6 @@ function wp_ajax_closed_postboxes() {
  */
 function wp_ajax_hidden_columns() {
        check_ajax_referer( 'screen-options-nonce', 'screenoptionnonce' );
-       $hidden = explode( ',', isset( $_POST['hidden'] ) ? $_POST['hidden'] : '' );
        $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
 
        if ( $page != sanitize_key( $page ) )
@@ -1314,8 +1339,8 @@ function wp_ajax_hidden_columns() {
        if ( ! $user = wp_get_current_user() )
                wp_die( -1 );
 
-       if ( is_array($hidden) )
-               update_user_option($user->ID, "manage{$page}columnshidden", $hidden, true);
+       $hidden = ! empty( $_POST['hidden'] ) ? explode( ',', $_POST['hidden'] ) : array();
+       update_user_option( $user->ID, "manage{$page}columnshidden", $hidden, true );
 
        wp_die( 1 );
 }
@@ -1499,6 +1524,8 @@ function wp_ajax_sample_permalink() {
  * Ajax handler for Quick Edit saving a post from a list table.
  *
  * @since 3.1.0
+ *
+ * @global WP_List_Table $wp_list_table
  */
 function wp_ajax_inline_save() {
        global $wp_list_table;
@@ -1540,10 +1567,12 @@ function wp_ajax_inline_save() {
                $data['parent_id'] = $data['post_parent'];
 
        // Status.
-       if ( isset($data['keep_private']) && 'private' == $data['keep_private'] )
+       if ( isset( $data['keep_private'] ) && 'private' == $data['keep_private'] ) {
+               $data['visibility']  = 'private';
                $data['post_status'] = 'private';
-       else
+       } else {
                $data['post_status'] = $data['_status'];
+       }
 
        if ( empty($data['comment_status']) )
                $data['comment_status'] = 'closed';
@@ -1591,6 +1620,8 @@ function wp_ajax_inline_save() {
  * Ajax handler for quick edit saving for a term.
  *
  * @since 3.1.0
+ *
+ * @global WP_List_Table $wp_list_table
  */
 function wp_ajax_inline_save_tax() {
        global $wp_list_table;
@@ -1743,6 +1774,10 @@ function wp_ajax_widgets_order() {
  * Ajax handler for saving a widget.
  *
  * @since 3.1.0
+ *
+ * @global array $wp_registered_widgets
+ * @global array $wp_registered_widget_controls
+ * @global array $wp_registered_widget_updates
  */
 function wp_ajax_save_widget() {
        global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
@@ -1832,6 +1867,8 @@ function wp_ajax_save_widget() {
  * Ajax handler for saving a widget.
  *
  * @since 3.9.0
+ *
+ * @global WP_Customize_Manager $wp_customize
  */
 function wp_ajax_update_widget() {
        global $wp_customize;
@@ -2072,6 +2109,7 @@ function wp_ajax_time_format() {
  * Ajax handler for saving posts from the fullscreen editor.
  *
  * @since 3.1.0
+ * @deprecated 4.3.0
  */
 function wp_ajax_wp_fullscreen_save_post() {
        $post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
@@ -2475,6 +2513,9 @@ function wp_ajax_send_attachment_to_editor() {
  * - video_send_to_editor_url
  *
  * @since 3.5.0
+ *
+ * @global WP_Post  $post
+ * @global WP_Embed $wp_embed
  */
 function wp_ajax_send_link_to_editor() {
        global $post, $wp_embed;
@@ -2530,26 +2571,35 @@ function wp_ajax_send_link_to_editor() {
  * @since 3.6.0
  */
 function wp_ajax_heartbeat() {
-       if ( empty( $_POST['_nonce'] ) )
+       if ( empty( $_POST['_nonce'] ) ) {
                wp_send_json_error();
-
-       $response = array();
-
-       if ( false === wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' ) ) {
-               // User is logged in but nonces have expired.
-               $response['nonces_expired'] = true;
-               wp_send_json($response);
        }
 
+       $response = $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']) )
+       if ( ! empty( $_POST['screen_id'] ) ) {
                $screen_id = sanitize_key($_POST['screen_id']);
-       else
+       } else {
                $screen_id = 'front';
+       }
 
-       if ( ! empty($_POST['data']) ) {
+       if ( ! empty( $_POST['data'] ) ) {
                $data = wp_unslash( (array) $_POST['data'] );
+       }
 
+       if ( 1 !== $nonce_state ) {
+               $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 ) ) {
                /**
                 * Filter the Heartbeat response received.
                 *
@@ -2587,7 +2637,7 @@ function wp_ajax_heartbeat() {
        // Send the current time according to the server
        $response['server_time'] = time();
 
-       wp_send_json($response);
+       wp_send_json( $response );
 }
 
 /**
@@ -2627,6 +2677,8 @@ function wp_ajax_get_revision_diffs() {
  * a user's own profile.
  *
  * @since 3.8.0
+ *
+ * @global array $_wp_admin_css_colors
  */
 function wp_ajax_save_user_color_scheme() {
        global $_wp_admin_css_colors;
@@ -2652,6 +2704,9 @@ function wp_ajax_save_user_color_scheme() {
  * Ajax handler for getting themes from themes_api().
  *
  * @since 3.9.0
+ *
+ * @global array $themes_allowedtags
+ * @global array $theme_field_defaults
  */
 function wp_ajax_query_themes() {
        global $themes_allowedtags, $theme_field_defaults;
@@ -2699,8 +2754,9 @@ function wp_ajax_query_themes() {
  *
  * @since 4.0.0
  *
- * @global WP_Post  $post     Global $post.
- * @global WP_Embed $wp_embed Embed API instance.
+ * @global WP_Post    $post       Global $post.
+ * @global WP_Embed   $wp_embed   Embed API instance.
+ * @global WP_Scripts $wp_scripts
  */
 function wp_ajax_parse_embed() {
        global $post, $wp_embed;
@@ -2714,14 +2770,23 @@ function wp_ajax_parse_embed() {
        }
 
        $shortcode = wp_unslash( $_POST['shortcode'] );
-       $url = str_replace( '[embed]', '', str_replace( '[/embed]', '', $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;
        setup_postdata( $post );
 
        $wp_embed->return_false_on_fail = true;
 
-       if ( is_ssl() && preg_match( '%^\\[embed[^\\]]*\\]http://%i', $shortcode ) ) {
+       if ( is_ssl() && 0 === strpos( $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 );
@@ -2732,7 +2797,7 @@ function wp_ajax_parse_embed() {
                }
        }
 
-       if ( ! $parsed ) {
+       if ( $url && ! $parsed ) {
                $parsed = $wp_embed->run_shortcode( $shortcode );
        }
 
@@ -2774,10 +2839,17 @@ function wp_ajax_parse_embed() {
        }
 
        wp_send_json_success( array(
-               'body' => $parsed
+               'body' => $parsed,
+               'attr' => $wp_embed->last_attr
        ) );
 }
 
+/**
+ * @since 4.0.0
+ *
+ * @global WP_Post    $post
+ * @global WP_Scripts $wp_scripts
+ */
 function wp_ajax_parse_media_shortcode() {
        global $post, $wp_scripts;
 
@@ -2844,7 +2916,6 @@ function wp_ajax_parse_media_shortcode() {
  * @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 ) ) {
@@ -2883,6 +2954,8 @@ function wp_ajax_destroy_sessions() {
  * @see Plugin_Upgrader
  */
 function wp_ajax_update_plugin() {
+       global $wp_filesystem;
+
        $plugin = urldecode( $_POST['plugin'] );
 
        $status = array(
@@ -2892,13 +2965,14 @@ function wp_ajax_update_plugin() {
                'oldVersion' => '',
                'newVersion' => '',
        );
+
        $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
        if ( $plugin_data['Version'] ) {
                $status['oldVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
        }
 
        if ( ! current_user_can( 'update_plugins' ) ) {
-               $status['error'] = __( 'You do not have sufficient permissions to update plugins on this site.' );
+               $status['error'] = __( 'You do not have sufficient permissions to update plugins for this site.' );
                wp_send_json_error( $status );
        }
 
@@ -2906,15 +2980,17 @@ function wp_ajax_update_plugin() {
 
        include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
 
-       $current = get_site_transient( 'update_plugins' );
-       if ( empty( $current ) ) {
-               wp_update_plugins();
-       }
+       wp_update_plugins();
 
-       $upgrader = new Plugin_Upgrader( new Automatic_Upgrader_Skin() );
+       $skin = new Automatic_Upgrader_Skin();
+       $upgrader = new Plugin_Upgrader( $skin );
        $result = $upgrader->bulk_upgrade( array( $plugin ) );
 
-       if ( is_array( $result ) ) {
+       if ( is_array( $result ) && empty( $result[$plugin] ) && is_wp_error( $skin->result ) ) {
+               $result = $skin->result;
+       }
+
+       if ( is_array( $result ) && !empty( $result[ $plugin ] ) ) {
                $plugin_update_data = current( $result );
 
                /*
@@ -2929,7 +3005,8 @@ function wp_ajax_update_plugin() {
                        wp_send_json_error( $status );
                }
 
-               $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
+               $plugin_data = get_plugins( '/' . $result[ $plugin ]['destination_name'] );
+               $plugin_data = reset( $plugin_data );
 
                if ( $plugin_data['Version'] ) {
                        $status['newVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
@@ -2939,10 +3016,18 @@ function wp_ajax_update_plugin() {
        } else if ( is_wp_error( $result ) ) {
                $status['error'] = $result->get_error_message();
                wp_send_json_error( $status );
-       } else if ( is_bool( $result ) && ! $result ) {
+
+       } else if ( is_bool( $result ) && ! $result ) {
                $status['errorCode'] = 'unable_to_connect_to_filesystem';
                $status['error'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
+
+               // Pass through the error from WP_Filesystem if one was raised
+               if ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
+                       $status['error'] = $wp_filesystem->errors->get_error_message();
+               }
+
                wp_send_json_error( $status );
+
        }
 }
 
@@ -2950,6 +3035,8 @@ function wp_ajax_update_plugin() {
  * AJAX handler for saving a post from Press This.
  *
  * @since 4.2.0
+ *
+ * @global WP_Press_This $wp_press_this
  */
 function wp_ajax_press_this_save_post() {
        if ( empty( $GLOBALS['wp_press_this'] ) ) {
@@ -2963,6 +3050,8 @@ function wp_ajax_press_this_save_post() {
  * AJAX handler for creating new category from Press This.
  *
  * @since 4.2.0
+ *
+ * @global WP_Press_This $wp_press_this
  */
 function wp_ajax_press_this_add_category() {
        if ( empty( $GLOBALS['wp_press_this'] ) ) {
@@ -2971,3 +3060,117 @@ function wp_ajax_press_this_add_category() {
 
        $GLOBALS['wp_press_this']->add_category();
 }
+
+/**
+ * AJAX handler for cropping an image.
+ *
+ * @since 4.3.0
+ *
+ * @global WP_Site_Icon $wp_site_icon
+ */
+function wp_ajax_crop_image() {
+       $attachment_id = absint( $_POST['id'] );
+
+       check_ajax_referer( 'image_editor-' . $attachment_id, 'nonce' );
+       if ( ! current_user_can( 'customize' ) ) {
+               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';
+                       global $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/custom-header.php */
+                       $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
+                       $object  = $wp_site_icon->create_attachment_object( $cropped, $attachment_id );
+                       unset( $object['ID'] );
+
+                       // Update the attachment.
+                       add_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) );
+                       $attachment_id = $wp_site_icon->insert_attachment( $object, $cropped );
+                       remove_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) );
+
+                       // Additional sizes in wp_prepare_attachment_for_js().
+                       add_filter( 'image_size_names_choose', array( $wp_site_icon, 'additional_sizes' ) );
+                       break;
+
+               default:
+
+                       /**
+                        * Fires before a cropped image is saved.
+                        *
+                        * Allows to add filters to modify the way a cropped image is saved.
+                        *
+                        * @since 4.3.0
+                        *
+                        * @param string $context       The Customizer control requesting the cropped image.
+                        * @param int    $attachment_id The attachment ID of the original image.
+                        * @param string $cropped       Path to the cropped image file.
+                        */
+                       do_action( 'wp_ajax_crop_image_pre_save', $context, $attachment_id, $cropped );
+
+                       /** This filter is documented in wp-admin/custom-header.php */
+                       $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
+
+                       $parent_url = get_post( $attachment_id )->guid;
+                       $url        = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
+
+                       $size       = @getimagesize( $cropped );
+                       $image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
+
+                       $object = array(
+                               'post_title'     => basename( $cropped ),
+                               'post_content'   => $url,
+                               'post_mime_type' => $image_type,
+                               'guid'           => $url,
+                               'context'        => $context,
+                       );
+
+                       $attachment_id = wp_insert_attachment( $object, $cropped );
+                       $metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );
+
+                       /**
+                        * Filter 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 );
+
+                       /**
+                        * Filter 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 ) );
+}