Convertir una URL en un ID de Adjunto o Entrada

10 ene 2011, 07:43:54
Vistas: 16.6K
Votos: 33

¿Existe alguna forma de tomar la URL de una imagen y encontrar el ID de adjunto o entrada de esa imagen en la base de datos?

Esta es la situación:

Estoy en un bucle recorriendo todas las etiquetas 'img' que están rodeadas por etiquetas 'a' en el contenido de mi entrada. Si el atributo src de la etiqueta 'img' no coincide con el atributo href de la etiqueta 'a' exterior, entonces quiero reemplazar la etiqueta 'img'. Al hacer esto, si la 'img' que se va a eliminar está en la galería, quiero borrar esa entrada y luego poner mi imagen de reemplazo en su lugar. Intenté usar una función como esta:

function find_image_post_id($url) {
  global $wpdb;
  $postid = $wpdb->get_var($wpdb->prepare("SELECT DISTINCT ID FROM $wpdb->posts WHERE guid='$url'"));
  if ($postid) {
    return $postid;
  }
  return false;
}

Esto aparentemente no funciona correctamente porque el GUID (Global Unique Identifier) irónicamente no es globalmente único. Había (antes en el mismo script) subido un archivo con el mismo nombre (¿por qué? porque era de mayor resolución y estoy intentando reemplazar versiones de baja resolución de la misma imagen) y aunque WordPress guarda la imagen con un nombre diferente en el directorio, los GUIDs se establecieron iguales (posiblemente un error).

¿Existe otra técnica que pueda usar?

3
Comentarios

Probablemente puedes configurar variables de solicitud según tu URL, instanciar WP_Query y obtener la información a partir de ella.

hakre hakre
10 ene 2011 14:38:51

Sería útil si pudieras actualizar tu pregunta y publicar algunos ejemplos de tu HTML que incluyan las URLs que deseas reemplazar para que podamos analizarlas.

MikeSchinkel MikeSchinkel
10 ene 2011 18:46:21

Mike tiene razón allí. ¿Las imágenes más grandes a las que enlazas están en sitios externos? Si no es así, solo necesitas elegir el tamaño completo cuando añades la imagen a tu publicación y tienes la opción de no enlazarla a ningún lado si ya no tiene sentido hacerlo.

sanchothefat sanchothefat
10 ene 2011 20:46:36
Todas las respuestas a la pregunta 6
7
31

Función mejorada masivamente desarrollada para plugins con gran cantidad de imágenes:

if ( ! function_exists( 'get_attachment_id' ) ) {
    /**
     * Obtiene el ID de adjunto para una URL de imagen dada.
     *
     * @link   http://wordpress.stackexchange.com/a/7094
     *
     * @param  string $url
     *
     * @return boolean|integer
     */
    function get_attachment_id( $url ) {

        $dir = wp_upload_dir();

        // baseurl nunca tiene una barra diagonal al final
        if ( false === strpos( $url, $dir['baseurl'] . '/' ) ) {
            // La URL apunta a un lugar fuera del directorio de subida
            return false;
        }

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

        // consultar adjuntos
        $ids = get_posts( $query );

        if ( ! empty( $ids ) ) {

            foreach ( $ids as $id ) {

                // la primera entrada del array devuelto es la URL
                if ( $url === array_shift( wp_get_attachment_image_src( $id, 'full' ) ) )
                    return $id;
            }
        }

        $query['meta_query'][0]['key'] = '_wp_attachment_metadata';

        // consultar adjuntos nuevamente
        $ids = get_posts( $query );

        if ( empty( $ids) )
            return false;

        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;
    }
}
17 ene 2011 09:13:18
Comentarios

¿Puedes explicar por qué consultas tanto _wp_attached_file como _wp_attachment_metadata?

Stephen Harris Stephen Harris
2 jul 2014 01:11:12

@StephenHarris porque la URL puede apuntar a cualquiera de los tamaños de la imagen, los cuales tienen nombres de archivo diferentes

Rarst Rarst
2 jul 2014 01:14:08

Esto funciona muy bien, pero vale la pena mencionar aquí que, desde WordPress 4, existe una función integrada para hacerlo como mencionó Gabriel en otra respuesta. Funciona exactamente de la misma manera que esta.

Chris Rae Chris Rae
28 sept 2016 02:21:37

@ChrisRae si miras el código fuente, la función principal no funcionará en tamaños de imagen, solo en la imagen principal.

Rarst Rarst
28 sept 2016 11:48:12

Creo que la función integrada de WordPress funciona mejor. Esto no funcionó en mi entorno de producción pero sí funcionó en Staging (que no tiene un certificado SSL). La función incorporada (como señaló Ego Ipse abajo) funciona en ambos entornos.

Syed Priom Syed Priom
18 ene 2017 23:17:36

@SyedPriom si la URL que estás buscando es inconsistente con tus datos almacenados, entonces no funcionará efectivamente, no era algo que tuve en cuenta al escribir esto, pero probablemente se pueda mejorar para protocolos. Como se mencionó arriba, el principal problema con la función nativa es que no funcionará en tamaños de imagen.

Rarst Rarst
19 ene 2017 10:25:44

Es una gran función, pero a veces arroja un aviso "Notice: Only variables should be passed by reference" Para solucionarlo, simplemente asigna el resultado de array_keys a una variable y pasa esa variable

$image_src = wp_get_attachment_image_src( $id, $size ); if ( $values['file'] === $file && $url === array_shift( $image_src ) ) return $id;

Oleg Apanovich Oleg Apanovich
24 oct 2019 18:41:39
Mostrar los 2 comentarios restantes
2
15

Todas esas funciones complejas se pueden reducir a una simple función:

attachment_url_to_postid()

Solo necesitas analizar la URL de la imagen para obtener el ID del adjunto:

$attachment_id = attachment_url_to_postid( $image_url );
echo $attachment_id;

Eso es todo lo que necesitas.

1 nov 2015 08:58:45
Comentarios

Cabe destacar que esto no funcionará en los tamaños de imagen, la versión principal solo busca el archivo adjunto "principal".

Rarst Rarst
28 sept 2016 11:48:54

Esta solución no funcionó con las variaciones de tamaño de imagen. Solo funciona con la imagen principal en tamaño "completo".

Azamat Azamat
9 nov 2021 09:18:22
0

Modifiqué el código de Rarst para permitir coincidir solo con el nombre del archivo en lugar de la ruta completa. Esto es útil si estás a punto de cargar una imagen lateralmente si no existe. Actualmente esto solo funciona si los nombres de archivo son únicos, pero agregaré una verificación de hash más adelante para ayudar con imágenes que tengan el mismo nombre de archivo.

function get_attachment_id( $url, $ignore_path = false ) {

if ( ! $ignore_path ) {

    $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(
            'key'     => '_wp_attached_file',
            'value'   => $file,
            'compare' => 'LIKE',
        )
    )
);

$ids = get_posts( $query );

foreach( $ids as $id ) {
    $match = array_shift( wp_get_attachment_image_src($id, 'full') );
    if( $url == $match || ( $ignore_path && strstr( $match, $file ) ) )
        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 && ( $ignore_path || $url == array_shift( wp_get_attachment_image_src($id, $size) ) ) )
            return $id;
    }
}

return false;
}
25 abr 2012 19:59:13
0

Ok encontré la respuesta que nadie tiene en la red, he estado buscando durante días. Ten en cuenta que esto solo funciona si tu tema o plugin está usando WP_Customize_Image_Control(). Si estás usando WP_Customize_Media_Control(), el get_theme_mod() devolverá el ID y no la URL.

Para mi solución, estaba usando la versión más nueva WP_Customize_Image_Control()

Muchos posts en los foros tienen el get_attachment_id() que ya no funciona. Yo usé attachment_url_to_postid()

Aquí está cómo pude hacerlo. Espero que esto ayude a alguien por ahí.

// Esto obtiene la imagen / URL
$feature1 = get_theme_mod('feature_image_1');

// Esto obtiene el ID del post
$feature1_id = attachment_url_to_postid($feature1);

// Esto obtiene el texto alternativo de la imagen que se establece en el área de medios
$image1_alt = get_post_meta( $feature1_id, '_wp_attachment_image_alt', true );

Marcado

<a href="<?php echo $feature1_url; ?>"><img class="img-responsive center-block" src="<?php echo $feature1; ?>" alt="<?php echo $image1_alt; ?>"></a>
29 abr 2017 05:26:18
1

Desde la versión 4.0 de WordPress, existe una función principal llamada attachment_url_to_postid que "Intenta convertir una URL de un archivo adjunto en un ID de publicación". Pero esta función tiene un gran defecto porque no puede convertir URLs de imágenes con tamaños personalizados.

Casi todas las respuestas principales intentan resolver este problema, pero todas tienen una consulta a la base de datos muy pesada que intenta obtener todos los archivos adjuntos existentes y luego los recorre para obtener los metadatos del adjunto y buscar los tamaños personalizados en ellos. Esto funciona bien solo si tienes una pequeña cantidad de archivos adjuntos en tu proyecto de WordPress. Pero definitivamente tendrás problemas de rendimiento si tienes un proyecto grande con 10,000+ archivos adjuntos.

Sin embargo, puedes extender la función principal attachment_url_to_postid mediante el filtro existente attachment_url_to_postid para forzar a la función a buscar también entre los tamaños personalizados de imágenes. Simplemente añade el siguiente código al archivo functions.php de tu tema activo de WordPress. y luego usa la función attachment_url_to_postid como lo hacías antes, pero con la funcionalidad adicional de tamaños personalizados.

    add_filter( 'attachment_url_to_postid', 'change_attachment_url_to_postid', 10, 2 );
    function change_attachment_url_to_postid( $post_id, $url ) {
        if ( ! $post_id ) {
            $file  = basename( $url );
            $query = array(
                'post_type'  => 'attachment',
                'fields'     => 'ids',
                'meta_query' => array(
                    array(
                        'key'     => '_wp_attachment_metadata',
                        'value'   => $file,
                        'compare' => 'LIKE',
                    ),
                )
            );

            $ids = get_posts( $query );

            if ( ! empty( $ids ) ) {

                foreach ( $ids as $id ) {
                    $meta = wp_get_attachment_metadata( $id );

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

        return $post_id;
    }
4 ene 2020 19:27:52
Comentarios

¡Esto debería tener más votos a favor! O mejor aún, debería funcionar así en el núcleo de WP...

Sarah Groß Sarah Groß
21 abr 2022 11:47:26
0

Aquí hay una solución alternativa:

$image_url = get_field('main_image'); // en caso de uso de campos personalizados
$image_id = attachment_url_to_postid($image_url);

// recuperar el tamaño miniatura de nuestra imagen
$image_thumb = wp_get_attachment_image_src($image_id, 'thumbnail');

Desde WP 4.0 introdujeron una función attachment_url_to_postid() que se comporta de manera similar a tu find_image_post_id()

Por favor revisa esta url como referencia.

21 mar 2018 12:46:43