5, 'post_formats' => $post_formats, /** * Filter whether or not Press This should redirect the user in the parent window upon save. * * @since 4.2.0 * * @param bool $redir_in_parent Whether to redirect in parent window or not. Default false. */ 'redir_in_parent' => apply_filters( 'press_this_redirect_in_parent', __return_false() ), ); } /** * Get the sources images and save them locally, fr posterity, unless we can't. * * @since 4.2.0 * @access public * * @param int $post_id Post ID. * @param string $content Optional. Current expected markup for Press This. Default empty. * @return string New markup with old image URLs replaced with the local attachment ones if swapped. */ public function side_load_images( $post_id, $content = '' ) { $new_content = $content; preg_match_all( '/]+>/', $content, $matches ); if ( ! empty( $matches ) && current_user_can( 'upload_files' ) ) { foreach ( (array) $matches[0] as $key => $image ) { preg_match( '/src=["\']{1}([^"\']+)["\']{1}/', stripslashes( $image ), $url_matches ); if ( empty( $url_matches[1] ) ) { continue; } $image_url = $url_matches[1]; // Don't try to sideload a file without a file extension, leads to WP upload error. if ( ! preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $image_url ) ) continue; // See if files exist in content - we don't want to upload non-used selected files. if ( false !== strpos( $new_content, htmlspecialchars( $image_url ) ) ) { // Sideload image, which ives us a new image tag, strip the empty alt that comes with it. $upload = str_replace( ' alt=""', '', media_sideload_image( $image_url, $post_id ) ); // Preserve assigned class, id, width, height and alt attributes. if ( preg_match_all( '/(class|width|height|id|alt)=\\\?(\"|\')[^"\']+\\\?(\2)/', $image, $attr_matches ) && is_array( $attr_matches[0] ) ) { foreach ( $attr_matches[0] as $attr ) { $upload = str_replace( ' with correct uploaded ones. * Regex contains fix for Magic Quotes. */ if ( ! is_wp_error( $upload ) ) { $new_content = str_replace( $image, $upload, $new_content ); } } } } // Error handling for media_sideload, send original content back. if ( is_wp_error( $new_content ) ) { return $content; } return $new_content; } /** * AJAX handler for saving the post as draft or published. * * @since 4.2.0 * @access public */ public function save_post() { if ( empty( $_POST['pressthis-nonce'] ) || ! wp_verify_nonce( $_POST['pressthis-nonce'], 'press-this' ) ) { wp_send_json_error( array( 'errorMessage' => __( 'Cheatin’ uh?' ) ) ); } if ( empty( $_POST['post_ID'] ) || ! $post_id = (int) $_POST['post_ID'] ) { wp_send_json_error( array( 'errorMessage' => __( 'Missing post ID.' ) ) ); } if ( ! current_user_can( 'edit_post', $post_id ) ) { wp_send_json_error( array( 'errorMessage' => __( 'Cheatin’ uh?' ) ) ); } $post = array( 'ID' => $post_id, 'post_title' => ( ! empty( $_POST['title'] ) ) ? sanitize_text_field( trim( $_POST['title'] ) ) : '', 'post_content' => ( ! empty( $_POST['pressthis'] ) ) ? trim( $_POST['pressthis'] ) : '', 'post_type' => 'post', 'post_status' => 'draft', 'post_format' => ( ! empty( $_POST['post_format'] ) ) ? sanitize_text_field( $_POST['post_format'] ) : '', 'tax_input' => ( ! empty( $_POST['tax_input'] ) ) ? $_POST['tax_input'] : array(), 'post_category' => ( ! empty( $_POST['post_category'] ) ) ? $_POST['post_category'] : array(), ); if ( ! empty( $_POST['post_status'] ) && 'publish' === $_POST['post_status'] ) { if ( current_user_can( 'publish_posts' ) ) { $post['post_status'] = 'publish'; } else { $post['post_status'] = 'pending'; } } $new_content = $this->side_load_images( $post_id, $post['post_content'] ); if ( ! is_wp_error( $new_content ) ) { $post['post_content'] = $new_content; } $updated = wp_update_post( $post, true ); if ( is_wp_error( $updated ) || intval( $updated ) < 1 ) { wp_send_json_error( array( 'errorMessage' => __( 'Error while saving the post. Please try again later.' ) ) ); } else { if ( isset( $post['post_format'] ) ) { if ( current_theme_supports( 'post-formats', $post['post_format'] ) ) { set_post_format( $post_id, $post['post_format'] ); } elseif ( $post['post_format'] ) { set_post_format( $post_id, false ); } } if ( 'publish' === get_post_status( $post_id ) ) { /** * Filter the URL to redirect to when Press This saves. * * @since 4.2.0 * * @param string $url Redirect URL. If `$status` is 'publish', this will be the post permalink. * Otherwise, the post edit URL will be used. * @param int $post_id Post ID. * @param string $status Post status. */ $redirect = apply_filters( 'press_this_save_redirect', get_post_permalink( $post_id ), $post_id, $post['post_status'] ); } else { /** This filter is documented in wp-admin/includes/class-wp-press-this.php */ $redirect = apply_filters( 'press_this_save_redirect', get_edit_post_link( $post_id, 'raw' ), $post_id, $post['post_status'] ); } wp_send_json_success( array( 'redirect' => $redirect ) ); } } /** * AJAX handler for adding a new category. * * @since 4.2.0 * @access public */ public function add_category() { if ( false === wp_verify_nonce( $_POST['new_cat_nonce'], 'add-category' ) ) { wp_send_json_error(); } $taxonomy = get_taxonomy( 'category' ); if ( ! current_user_can( $taxonomy->cap->edit_terms ) || empty( $_POST['name'] ) ) { wp_send_json_error(); } $parent = isset( $_POST['parent'] ) && (int) $_POST['parent'] > 0 ? (int) $_POST['parent'] : 0; $names = explode( ',', $_POST['name'] ); $added = $data = array(); foreach ( $names as $cat_name ) { $cat_name = trim( $cat_name ); $cat_nicename = sanitize_title( $cat_name ); if ( empty( $cat_nicename ) ) { continue; } // @todo Find a more performant to check existence, maybe get_term() with a separate parent check. if ( ! $cat_id = term_exists( $cat_name, $taxonomy->name, $parent ) ) { $cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) ); } if ( is_wp_error( $cat_id ) ) { continue; } elseif ( is_array( $cat_id ) ) { $cat_id = $cat_id['term_id']; } $added[] = $cat_id; } if ( empty( $added ) ) { wp_send_json_error( array( 'errorMessage' => __( 'This category cannot be added. Please change the name and try again.' ) ) ); } foreach ( $added as $new_cat_id ) { $new_cat = get_category( $new_cat_id ); if ( is_wp_error( $new_cat ) ) { wp_send_json_error( array( 'errorMessage' => __( 'Error while adding the category. Please try again later.' ) ) ); } $data[] = array( 'term_id' => $new_cat->term_id, 'name' => $new_cat->name, 'parent' => $new_cat->parent, ); } wp_send_json_success( $data ); } /** * Downloads the source's HTML via server-side call for the given URL. * * @since 4.2.0 * @access public * * @param string $url URL to scan. * @return string Source's HTML sanitized markup */ public function fetch_source_html( $url ) { // Download source page to tmp file. $source_tmp_file = ( ! empty( $url ) ) ? download_url( $url ) : ''; $source_content = ''; if ( ! is_wp_error( $source_tmp_file ) && file_exists( $source_tmp_file ) ) { // Get the content of the source page from the tmp file.. $source_content = wp_kses( file_get_contents( $source_tmp_file ), array( 'img' => array( 'src' => array(), ), 'iframe' => array( 'src' => array(), ), 'link' => array( 'rel' => array(), 'itemprop' => array(), 'href' => array(), ), 'meta' => array( 'property' => array(), 'name' => array(), 'content' => array(), ) ) ); // All done with backward compatibility. Let's do some cleanup, for good measure :) unlink( $source_tmp_file ); } else if ( is_wp_error( $source_tmp_file ) ) { $source_content = new WP_Error( 'upload-error', sprintf( __( 'Error: %s' ), sprintf( __( 'Could not download the source URL (native error: %s).' ), $source_tmp_file->get_error_message() ) ) ); } else if ( ! file_exists( $source_tmp_file ) ) { $source_content = new WP_Error( 'no-local-file', sprintf( __( 'Error: %s' ), __( 'Could not save or locate the temporary download file for the source URL.' ) ) ); } return $source_content; } /** * Fetches and parses _meta, _img, and _links data from the source. * * @since 4.2.0 * @access public * * @param string $url URL to scan. * @param array $data Optional. Existing data array if you have one. Default empty array. * @return array New data array. */ public function source_data_fetch_fallback( $url, $data = array() ) { if ( empty( $url ) ) { return array(); } // Download source page to tmp file. $source_content = $this->fetch_source_html( $url ); if ( is_wp_error( $source_content ) ) { return array( 'errors' => $source_content->get_error_messages() ); } // Fetch and gather data. if ( empty( $data['_img'] ) ) { $data['_img'] = array(); } if ( preg_match_all( '//', $source_content, $matches ) ) { if ( ! empty( $matches[0] ) ) { foreach ( $matches[0] as $value ) { if ( preg_match( '/]+src="([^"]+)"[^>]+\/>/', $value, $new_matches ) ) { if ( ! in_array( $new_matches[1], $data['_img'] ) ) { $data['_img'][] = $new_matches[1]; } } } } } // Fetch and gather