Update: After debugging why the uploads were so slow, I found out the culript was the plugin WP Smush It. The question and answer bellow is the process of finding that out.

I’m processing thousands of image uploads through a custom Import function I’ve written. It takes a JSON, create a post out of it, then process the images URLs that are stored as JSON keys and uploads them to WordPress. It works fine, however, it’s taking around 5 seconds to upload each image.

The images are stored locally, so WordPress only have to move the file, not download it.

Here’s the timings for the upload image function:

  'uploadtimedebug_start' => 0 seconds
  'uploadtimedebug_after_requires' => 0.006 seconds
  'uploadtimedebug_after_tmp_filled' => 0.597 seconds
  'uploadtimedebug_before_media_handle_sideload' => 0.597 seconds
  'uploadtimedebug_after_media_handle_sideload' => 5.370 seconds // Guilty
  'uploadtimedebug_finish' => 5.370 seconds

Here’s what media_handle_sideload looks like, and their parameters:

// Actually uploads the image
$id = media_handle_sideload( $file_array, $post_id, $desc);

Here is the parameters for media_handle_sideload:

[
    'file_array' => [
        'name' => 'logo.png',
        'tmp_name' => 'C:\\Users\\Lucas\\AppData\\Local\\Temp/logo-Rg0xrY.tmp'
    ],
    'post_id' => 881,
    'desc' => 'Logo',
];

Going inside media_handle_sideload and debugging it’s timings, there’s this:

  'timedebug_start' => 0 seconds
  'timedebug_before_wp_handle_sideload' => 0.001 seconds
  'timedebug_after_wp_handle_sideload' => 0.006 seconds
  'timedebug_before_wp_read_image_metadata' => 0.006 seconds
  'timedebug_after_wp_read_image_metadata' => 0.006 seconds
  'timedebug_before_wp_insert_attachment' => 0.006 seconds
  'timedebug_after_wp_insert_attachment' => 0.058 seconds
  'timedebug_before_wp_update_attachment_metadata' => 0.058 seconds
  'timedebug_after_wp_update_attachment_metadata' => 2.635 seconds // Guilty
  'timedebug_finish' => 2.635 seconds

So the slowliness is coming from wp_update_attachment_metadata. Digging into it, there’s this:

  'timedebug_start' => 0 seconds
  'timedebug_after_get_post' => 0 seconds
  'timedebug_before_apply_filters_wp_update_attachment_metadata' => 0 seconds
  'timedebug_after_apply_filters_wp_update_attachment_metadata' => 3.082 seconds // Guilty
  'timedebug_before_update_post_meta' => 3.082 seconds
  'timedebug_after_update_post_meta' => 3.104 seconds

So, the great slowliness is coming from this:

/**
 * Filters the updated attachment meta data.
 *
 * @since 2.1.0
 *
 * @param array $data          Array of updated attachment meta data.
 * @param int   $attachment_id Attachment post ID.
 */
if ( $data = apply_filters( 'wp_update_attachment_metadata', $data, $post->ID ) )
    return update_post_meta( $post->ID, '_wp_attachment_metadata', $data );
else
    return delete_post_meta( $post->ID, '_wp_attachment_metadata' );

I couldn’t find what add_filter('wp_update_attachment_metadata', $data, $post->ID) calls to debug it further.

Anyways.

Does anyone have any ideas on how to upload thousands of images to WordPress, while getting their attachment IDs in real time as a return?

PS: I’ve seen Add from Server plugin, but it doesn’t meet what I need, because I have to assign the images by ID to specific custom fields, etc, so I need to process those and have their IDs in real time.

1 Answer
1

I’ve modified method wp_update_attachment_metadata from wp-includes/post.php (line 5070) to this, just during the Import:

/**
 * Update metadata for an attachment.
 *
 * @since 2.1.0
 *
 * @param int   $attachment_id Attachment post ID.
 * @param array $data          Attachment meta data.
 * @return int|bool False if $post is invalid.
 */
function wp_update_attachment_metadata( $attachment_id, $data ) {
    $attachment_id = (int) $attachment_id;
    if ( ! $post = get_post( $attachment_id ) ) {
        return false;
    }

    /**
     * Filters the updated attachment meta data.
     *
     * @since 2.1.0
     *
     * @param array $data          Array of updated attachment meta data.
     * @param int   $attachment_id Attachment post ID.
     */
     return update_post_meta( $post->ID, '_wp_attachment_metadata', $data );
}

Media Upload Before:

  'uploadtimedebug_start' => 0 seconds
  'uploadtimedebug_after_requires' => 0.006 seconds
  'uploadtimedebug_after_tmp_filled' => 0.597 seconds
  'uploadtimedebug_before_media_handle_sideload' => 0.597 seconds
  'uploadtimedebug_after_media_handle_sideload' => 5.370 seconds
  'uploadtimedebug_finish' => 5.370 seconds

Media Upload After:

  'uploadtimedebug_inicio' => 0 seconds
  'uploadtimedebug_after_requires' => 0.007 seconds
  'uploadtimedebug_after_tmp_filled' => 0.620 seconds
  'uploadtimedebug_before_media_handle_sideload' => 0.620 seconds
  'uploadtimedebug_after_media_handle_sideload' => 0.723 seconds
  'uploadtimedebug_finish' => 0.723 seconds

No side effects, everything works just fine. Keep in mind though, that this should be a temporary hack, when you’re done uploading your thousand images, revert wp_update_attachment_metadata to it’s original code.

Edit – Please ignore everything I said.

The culript was the plugin “Smush It”, hooked into the wp_update_attachment_metadata filter. Upon disabling Smush It, the filter took zero seconds.

Leave a Reply

Your email address will not be published. Required fields are marked *