web-dev-qa-db-fra.com

Remplacement par lien sur la pièce jointe par les liens vers les fichiers

J’ai essayé de le faire moi-même mais j’ai vraiment beaucoup de mal à utiliser Regex (regex c’est un enfer. Je ne comprends tout simplement pas).

Quoi qu'il en soit, je pense que cela serait utile à certaines personnes. Le contexte est que nous utilisons un plugin pour afficher des images en post dans une lightbox. Cela ne fonctionne que si nous créons le lien vers le fichier (l'image) et PAS la page de pièce jointe.

La plupart du temps, les auteurs ont oublié de vérifier, la visionneuse ne s'affiche pas et tout le monde est déçu.

Mauvais HTML (notez la pièce jointe Word dans la href et que la href ne se termine pas par .jpg):

 <p>
   <a href="http://domain.ru/uncategorized/208/e-poha-restavratsii/attachment/cyril_gassiline_photo" rel="attachment wp-att-209"><img class="alignnone size-large wp-image-209" title="cyril_gassiline_photo" src="http://domain.ru/wp-content/uploads/2012/07/cyril_gassiline_photo-615x409.jpg" alt="" width="615" height="409" /></a>
 </p>

Donc je suppose que nous pourrions faire quelque chose comme (dans la logique):

function remove_bad_img_links($content) {
$matches = array();
$check_for_attachment_Word = preg_match('/<a[\s]+[^>]*href\s*=\s*(attachment)([\"\']+)([^>]+?)(\1|>)/i', $content, $matches);
if ( $check_for_attachment ) {

       $image_url = preg_match('/<img[\s]+[^>]*src\s*=\s*([\"\']+)([^>]+?)(\1|>)/i', $content, $matches);

       preg_replace('/<a[\s]+[^>]*href\s*=\s*(attachment)([\"\']+)([^>]+?)(\1|>)/i', $content, $image_url);
     }
return $content;
}
add_filter( 'the_content', 'remove_bad_img_links' );

(Je sais que le code est faux, ^^, je n'ai pas du tout la regex)

Pour produire du code HTML corrigé (la valeur dans le img src a remplacé la valeur initiale du a href qui a été détectée comme étant incorrecte, car elle contient la pièce jointe Word (à faire simplement tout le temps):

 <p>
   <a href="http://domain.ru/wp-content/uploads/2012/07/cyril_gassiline_photo-615x409.jpg" rel="attachment wp-att-209"><img class="alignnone size-large wp-image-209" title="cyril_gassiline_photo" src="http://domain.ru/wp-content/uploads/2012/07/cyril_gassiline_photo-615x409.jpg" alt="" width="615" height="409" /></a>
 </p>

Mais en l'écrivant, je me demande si c'est vraiment possible, étant donné qu'un message pourrait avoir plusieurs occurrences de ces liens ...

Il suffit de demander une référence: est-ce possible, est-ce une bonne idée, à quoi ressemblerait la regex?

Je pourrais le faire dans JS mais il serait préférable de faire du référencement dans le code généré.

MODIFIER :

Plus de recherches me disent que "vous n'utiliserez pas d'expressions régulières pour analyser HTML". Une meilleure approche consiste à utiliser DOM: https://stackoverflow.com/questions/3820666/grabbing-the-href-attribute-of-an-a-element

En définitive, je pensais que c'était faux, c'est très mauvais d'analyser HTML: http://www.codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way. html . Je vais essayer d'utiliser DOM et je reviendrai avec update.

2
Simon

J'ai donc complété un moyen de remplacer les liens vers les pages de pièces jointes pour les images et de les remplacer non seulement par l'URL de la balise img, mais également par la version longue du fichier image.

Je n'utilise pas regex parce que c'est diabolique et que je ne veux pas faire mourir de chaton.

Cela fonctionne pour moi, alors je partage comme source de départ pour quelqu'un qui veut faire la même chose (et pour d'éventuelles améliorations ou corrections de la part de personnes plus talentueuses):

D'abord j'utilise une fonction pour obtenir l'identifiant d'un fichier à partir de son URL (je l'ai pris ici: Transforme une URL en pièce jointe/Post ID )

// TOOL
// GET ATTACHMENT ID FROM GUID
function get_attachment_id( $url ) {

    $dir = wp_upload_dir();
    $dir = trailingslashit($dir['baseurl']);

    if( false === strpos( $url, $dir ) )
        return false;

    $file = basename($url);

    $query = array(
        'post_type' => 'attachment',
        'fields' => 'ids',
        'meta_query' => array(
            array(
                'value' => $file,
                'compare' => 'LIKE',
            )
        )
    );

    $query['meta_query'][0]['key'] = '_wp_attached_file';
    $ids = get_posts( $query );

    foreach( $ids as $id )
        if( $url == array_shift( wp_get_attachment_image_src($id, 'full') ) )
            return $id;

    $query['meta_query'][0]['key'] = '_wp_attachment_metadata';
    $ids = get_posts( $query );

    foreach( $ids as $id ) {

        $meta = wp_get_attachment_metadata($id);

        foreach( $meta['sizes'] as $size => $values )
            if( $values['file'] == $file && $url == array_shift( wp_get_attachment_image_src($id, $size) ) ) {

                return $id;
            }
    }

    return false;
}

Ensuite, j'utilise cette fonction pour renvoyer le code innerHTML du noeud <a> que je trouverai (trouvé ici https://stackoverflow.com/questions/2087103/innerhtml-in-phps-domdocument ):

// GET INNER HTML OF A NODE
function DOMinnerHTML($element) 
{ 
    $innerHTML = ""; 
    $children = $element->childNodes; 
    foreach ($children as $child) 
    { 
        $tmp_dom = new DOMDocument(); 
        $tmp_dom->appendChild($tmp_dom->importNode($child, true)); 
        $innerHTML.=trim($tmp_dom->saveHTML()); 
    } 
    return $innerHTML; 
} 

Maintenant, la fonction qui sera ajoutée en tant que filtre à the_content:

function remove_bad_img_links($content) {   
    $dom = new DOMDocument();
    // THIS IS HACK TO LOAD STRING WITH CORRECT ENCODING
    // JUST OUTPUT <--?xml encoding="UTF-8"--> IN HTML SO NO HARM
    $dom->loadHTML( '<?xml encoding="UTF-8">' .  $content );

    // GET ALL <a> NODE
    foreach ( $dom->getElementsByTagName('a') as $node ) {
            // GET HREF 
        $link_href = $node->getAttribute( 'href' );
            // USE INNER OF THIS <a> NODE AS NEW DOC TO EXTRACT IMG
        $dom_node = new DOMDocument();
        $inner = DOMinnerHTML($node);
        $dom_node->loadHTML($inner);
            // EXTRACT IMG AND GET SRC OF IT
            // ASSUMING THERE IS ONLY ONE IMAGE ...
        foreach ( $dom_node->getElementsByTagName('img') as $img_node ) {
            $img_node_link = $img_node->getAttribute( 'src' );
        }
            // CHECK IF THE Word attachment IS IN HREF
        preg_match('/attachment/', $link_href, $matches);
            // IF SO...
        if ( $matches ) {
                    // GET ID OF THE IMAGE VIA CUSTOM FUNCTION
            $img_id = get_attachment_id( $img_node_link );
                    // GET ARRAY OF THE IMAGE VIA BUILTIN FUNCTION
            $img_array = wp_get_attachment_image_src( $img_id, 'large' );
                    // REPLACE HREF WITH NEW SOURCE
                    if ( ! empty ( $img_id ) ) {
            $node->setAttribute('href', $img_array[0] );
                    } else {
                    // FALLBACK IF CUSTOM FUNCTION DONT RETURN URL
            $node->setAttribute('href', $img_node_link );
                    }
        }
    // RETURN MODIFIED DOM
    if ( $matches ) $content = $dom->saveHTML();
    }
    // RETURN CONTENT
    return $content;
}
// APPLY FILTER
add_filter( 'the_content', 'remove_bad_img_links' );

J'ai testé sur des publications sans images, sur plusieurs images, sans aucun problème pour l'instant. Toutes les images ont une destination href correcte et, lorsque cela est possible, cette href est dirigée vers la version de grande taille du fichier.

1
Simon