Transforme um URL em um anexo / ID de postagem

32

Existe alguma maneira de eu pegar um URL de uma imagem e encontrar o anexo ou o ID da postagem no banco de dados?

Aqui está a situação:

Estou repetindo todas as tags 'img' que estão cercadas por 'a' no meu conteúdo da postagem. se o atributo src da tag 'img' não corresponder ao atributo href da tag 'a' externa, então desejo substituir a tag 'img'. Ao fazer isso, se o 'img' a ser removido estiver na galeria, desejo excluir esse post e, em seguida, colocar o meu 'img' substituto em seu lugar. Eu tentei usar uma função 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;
}

Aparentemente, isso não está certo, porque o guia não é ironicamente único em todo o mundo. Eu tinha (anteriormente no mesmo script) enviado um arquivo com o mesmo nome (por quê? Porque era de maior resolução e estou tentando substituir as versões de baixa resolução da mesma imagem) e, embora o wordpress salve a imagem com um nome diferente em No diretório, os guias foram definidos como iguais. (possivelmente um bug).

Existe outra técnica que eu possa usar?

Ankur
fonte
Você pode definir variáveis ​​de solicitação de acordo com o seu URL, instanciar WP_Query e obter as informações a partir dele.
hakre
Ajudaria se você pudesse atualizar sua pergunta e postar alguns exemplos de seu HTML que incluem URLs que você deseja substituir para que possamos discuti-los.
MikeSchinkel
Mike está aí. As imagens maiores às quais você está vinculando estão em sites externos? Caso contrário, basta escolher o tamanho completo ao adicionar a imagem à sua postagem e ter a opção de não vinculá-la a nenhum lugar, caso não faça mais sentido.
sanchothefat

Respostas:

30

Função altamente aprimorada desenvolvida para plugins pesados ​​em imagens:

if ( ! function_exists( 'get_attachment_id' ) ) {
    /**
     * Get the Attachment ID for a given image URL.
     *
     * @link   http://wordpress.stackexchange.com/a/7094
     *
     * @param  string $url
     *
     * @return boolean|integer
     */
    function get_attachment_id( $url ) {

        $dir = wp_upload_dir();

        // baseurl never has a trailing slash
        if ( false === strpos( $url, $dir['baseurl'] . '/' ) ) {
            // URL points to a place outside of upload directory
            return false;
        }

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

        // query attachments
        $ids = get_posts( $query );

        if ( ! empty( $ids ) ) {

            foreach ( $ids as $id ) {

                // first entry of returned array is the URL
                if ( $url === array_shift( wp_get_attachment_image_src( $id, 'full' ) ) )
                    return $id;
            }
        }

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

        // query attachments again
        $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;
    }
}
Rarst
fonte
1
Você pode explicar por que você consulta ambos _wp_attached_filee _wp_attachment_metadata?
Stephen Harris
3
@StephenHarris porque o URL pode apontar para qualquer tamanho de imagem, todos com nomes de arquivos diferentes
#
1
Isso funciona muito bem, mas vale a pena notar aqui que, desde o WordPress 4, existe uma função integrada para fazer isso, conforme mencionado por Gabriel em outra resposta. Funciona exatamente da mesma maneira que este.
Chris Rae
2
@ ChrisRae Se você olhar para a fonte, a função principal não funcionará nos tamanhos das imagens, apenas na imagem principal.
Rarst
Eu acho que a função interna do WordPress funciona melhor. Isso não funcionou na minha produção, mas funcionou no armazenamento temporário (que não possui um certificado SSL). A função incorporada (conforme apontado por Ego Ipse abaixo) funciona nos dois ambientes.
Syed Priom
15

Todas essas funções complexas podem ser reduzidas a uma função simples:

attachment_url_to_postid ()

Você só precisa analisar o URL da imagem para recuperar o ID do anexo:

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

É tudo o que você precisa.

Ego Ipse
fonte
6
Notavelmente, isso não funcionará no tamanho da imagem, a versão principal somente pesquisa no arquivo anexado "principal".
Rarst
3

Modifiquei o código da Rarst para permitir que você correspondesse apenas o nome do arquivo em vez do caminho completo. Isso é útil se você estiver prestes a carregar a imagem se ela não existir. Atualmente, isso só funciona se os nomes de arquivo forem únicos, mas adicionarei uma verificação de hash posteriormente para ajudar com imagens com o mesmo nome de arquivo.

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;
}
Luke Gedeon
fonte
3

Ok, eu encontrei a resposta que ninguém tem na rede que eu estava procurando há dias. Lembre-se de que isso só funciona se o seu tema ou plugin estiver usando o WP_Customize_Image_Control()se você estiver usando WP_Customize_Media_Control()o get_theme_mod()retornará o ID e não o URL.

Para minha solução, eu estava usando a versão mais recente WP_Customize_Image_Control()

Muitas postagens nos fóruns têm o get_attachment_id()que não funciona mais. eu useiattachment_url_to_postid()

Aqui está como eu fui capaz de fazê-lo. Espero que isto seja útil a alguém

// This is getting the image / url
$feature1 = get_theme_mod('feature_image_1');

// This is getting the post id
$feature1_id = attachment_url_to_postid($feature1);

// This is getting the alt text from the image that is set in the media area
$image1_alt = get_post_meta( $feature1_id, '_wp_attachment_image_alt', true );

Marcação

<a href="<?php echo $feature1_url; ?>"><img class="img-responsive center-block" src="<?php echo $feature1; ?>" alt="<?php echo $image1_alt; ?>"></a>
DevTurtle
fonte
0

Aqui está uma solução alternativa:

$image_url = get_field('main_image'); // in case of custom field usage
$image_id = attachment_url_to_postid($image_url);

// retrieve the thumbnail size of our image
$image_thumb = wp_get_attachment_image_src($image_id, 'thumbnail');

Desde o WP 4.0, eles introduziram uma função attachment_url_to_postid()que se comporta de maneira semelhante à suafind_image_post_id()

Por favor, verifique este URL para sua referência.

Lefan
fonte