web-dev-qa-db-fra.com

Remplacer toutes les URL d'image de la publication par des URL de répertoire de téléchargement

Sur un site Web WordPress destiné à un client, il va publier des articles contenant de nombreuses images. Lorsque le message est enregistré/publié, nous devons pouvoir télécharger/enregistrer ces images sur le serveur, puis au lieu de les URL d'origine, affichent les URL de l'image comme dans le répertoire de téléchargement.

J'ai choisi de le faire en écrivant une fonction dans functions.php puis en l'ajoutant en tant que filtre. Voici le code que j'ai écrit jusqu'à présent:

function getpostimgs() {
  global $post; 
  $postContent = $post->post_content;

  preg_match_all( '/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', $postContent, $matches );
  // match all images in post, add to array and then
  // get first array (the one with the image URLs in)
  $imgURLs = $matches[1];

  $upload_dir = wp_upload_dir(); // Set upload folder

  foreach ( $imgURLs as $imgURL ) {
    $image_data = file_get_contents( $imgURL ); // Get image data
    $filename = basename( $imgURL ); // Create image file name
    // check upload file exists and the permissions on it are correct
    if( wp_mkdir_p( $upload_dir['path'] ) ) {
      $file = $upload_dir['path'] . '/' . $filename . "-" . $post->ID . ".jpg";
    } else {
      $file = $upload_dir['basedir'] . '/' . $filename . "-" . $post->ID . ".jpg";
    }
    // save file to server, with the filename of the image and then the post ID.
    file_put_contents( $file, $image_data ); // save the file to the server
    // find the occurence of each URL (within the post content)
    // that was in the array and replace them with the file link        
    preg_replace( "*" . $imgURL . "*", $file, $post->post_content );
  }
}

add_action('content_save_pre', 'getpostimgs');

J'ai écrit quelques commentaires alors j'espère que les lignes sont suffisamment expliquées pour que vous compreniez ce qui se passe.

Le problème est que, quand il est enregistré (en utilisant content_save_pre, afin qu'il soit filtré avant d'être enregistré dans la base de données), il efface simplement tout le contenu. Les fichiers sont en cours d’enregistrement et je sais que la valeur de $matches[1] est correcte (c’est-à-dire que les bons liens d’image sont présents), comme je l’ai vérifiée avec var_dump().

Il y a donc quelque chose qui ne va pas avec le preg_replace. Même si vous supprimez tout le contenu du fichier et laissez simplement le preg_replace avec une simple chaîne de remplacement (par exemple, "Hello world"), cela ne fonctionne toujours pas (effacez simplement tout le contenu du message). Quelqu'un sait-il pourquoi?

Merci de m'avoir aidé, j'espère que j'ai été assez clair, heureux de fournir plus d'informations ou de le préciser. :)

3
Tom Oakley

J'ai un plugin qui le fait manuellement dans les traitements par lots via ajax et je reçois beaucoup de demandes pour un moyen de le rendre automatisé.

C'est la fonction qui charge le message, télécharge les images dans le répertoire de téléchargement et les joint au message. Ensuite, il effectue une recherche et remplace les anciennes URL img et les remplace par les nouvelles. Joignez ceci à toutes les actions de publication et vous devriez être prêt à partir.

/**
 * Extracts all images in content adds to media library
 * if external and updates content with new url
 *
 * @param object $post The post object
 *
 */
function prefix_extract_external_images( $post ) {
  if ( ! is_object( $post ) ) {
    $post = get_post( $post );
  }
  $html = $post->post_content;
  $path = wp_upload_dir();
  $path = $path['baseurl'];

  if ( stripos( $html, '<img' ) !== false ) {

    $regex = '#<\s*img [^\>]*src\s*=\s*(["\'])(.*?)\1#im';
    preg_match_all( $regex, $html, $matches );

    if ( is_array( $matches ) && ! empty( $matches ) ) {
      $new = array();
      $old = array();
      foreach ( $matches[2] as $img ) {

        // Compare image source against upload directory
        // to prevent adding same attachment multiple times
        if ( stripos( $img, $path ) !== false ) {
          continue;
        }

        $tmp = download_url( $img );

        preg_match(
          '/[^\?]+\.(jpg|JPG|jpe|JPE|jpeg|JPEG|gif|GIF|png|PNG)/', $img, $matches
        );
        $file_array['name'] = basename( $matches[0] );
        $file_array['tmp_name'] = $tmp;
        // If error storing temporarily, unlink
        if ( is_wp_error( $tmp ) ) {
          @unlink( $file_array['tmp_name'] );
          $file_array['tmp_name'] = '';
          continue;
        }

        $id = media_handle_sideload( $file_array, $post->ID );

        if ( ! is_wp_error( $id ) ) {
          $url = wp_get_attachment_url( $id );
          array_Push( $new, $url );
          array_Push( $old, $img );
        }
      } // end foreach
      if ( ! empty( $new ) ) {
        $content = str_ireplace( $old, $new, $html );
        $post_args = array( 'ID' => $post->ID, 'post_content' => $content, );
        if ( ! empty( $content ) ) {
          $post_id = wp_update_post( $post_args );
        }       
      }
    } // end if ( is_array( $matches ) && ! empty( $matches ) )
  } // end if ( stripos( $html, '<img' ) !== false )
  return $post;
} // end function

$action_arrays = array( 'new_to_publish', 'pending_to_publish', 'draft_to_publish' );

foreach ( $action_array as $action ) {
  add_action( $action, 'prefix_extract_external_images' );
}

Bonus: Définissez la première image trouvée comme image sélectionnée.

Ajoutez ceci juste avant le return $post dans la fonction ci-dessus.

$atts = get_first_attachment( $post->ID );

foreach ( $atts as $a ) {
  $img = set_post_thumbnail( $post->ID, $a['ID'] );
}

Cette fonction sera également requise par le code ci-dessus.

/**
 * Queries for attached images
 * @param int $post_id The post id to check if attachments exist
 * @return array|bool The 1st attached on success false if no attachments
 */
 function get_first_attachment( $post_id ) {
   return get_children( array (
     'post_parent'    => $post_id,
     'post_type'      => 'attachment',
     'post_mime_type' => 'image',
     'posts_per_page'  => (int)1
   ), ARRAY_A );
 }
4
Chris_O