Convertire un URL in un ID Allegato/Post nel Database WordPress
Esiste un modo per prendere l'URL di un'immagine e trovare l'ID dell'allegato o del post di quell'immagine nel database?
Ecco la situazione:
Sto ciclando tutti i tag 'img' circondati da tag 'a' nel contenuto del mio post. Se l'attributo src del tag 'img' non corrisponde all'attributo href del tag 'a' esterno, allora voglio sostituire il tag 'img'. In questo processo, se l'immagine da rimuovere è nella galleria, voglio eliminare quel post e poi inserire la mia immagine sostitutiva al suo posto. Ho provato a usare una funzione come questa:
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;
}
Questo apparentemente non funziona perché il guid ironicamente non è globalmente univoco. Avevo (precedentemente nello stesso script) caricato un file con lo stesso nome (perché? perché era a risoluzione più alta e sto cercando di sostituire versioni a bassa risoluzione della stessa immagine) e sebbene WordPress salvi l'immagine con un nome diverso nella directory, i guid erano impostati per essere uguali. (possibilmente un bug).
C'è un'altra tecnica che posso usare?
Funzione notevolmente migliorata sviluppata per plugin con molte immagini:
if ( ! function_exists( 'get_attachment_id' ) ) {
/**
* Ottiene l'ID dell'allegato per un dato URL dell'immagine.
*
* @link http://wordpress.stackexchange.com/a/7094
*
* @param string $url
*
* @return boolean|integer
*/
function get_attachment_id( $url ) {
$dir = wp_upload_dir();
// baseurl non ha mai uno slash finale
if ( false === strpos( $url, $dir['baseurl'] . '/' ) ) {
// L'URL punta a una posizione esterna alla directory di upload
return false;
}
$file = basename( $url );
$query = array(
'post_type' => 'attachment',
'fields' => 'ids',
'meta_query' => array(
array(
'key' => '_wp_attached_file',
'value' => $file,
'compare' => 'LIKE',
),
)
);
// interroga gli allegati
$ids = get_posts( $query );
if ( ! empty( $ids ) ) {
foreach ( $ids as $id ) {
// il primo elemento dell'array restituito è l'URL
if ( $url === array_shift( wp_get_attachment_image_src( $id, 'full' ) ) )
return $id;
}
}
$query['meta_query'][0]['key'] = '_wp_attachment_metadata';
// interroga nuovamente gli allegati
$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;
}
}

Puoi spiegare perché interroghi sia _wp_attached_file
che _wp_attachment_metadata
?

@StephenHarris perché l'URL può puntare a qualsiasi dimensione dell'immagine, che hanno tutte nomi di file diversi

Funziona benissimo, ma vale la pena notare che, da WordPress 4, esiste una funzione integrata per farlo come menzionato da Gabriel in un'altra risposta. Funziona esattamente nello stesso modo di questa.

@ChrisRae se guardi il sorgente, la funzione principale non funzionerà sulle dimensioni delle immagini, solo sull'immagine principale.

Penso che la funzione integrata di WordPress funzioni meglio. Questo non ha funzionato nella mia produzione ma ha funzionato in Staging (che non ha un certificato SSL). La funzione integrata (come sottolineato da Ego Ipse sotto) funziona in entrambi gli ambienti.

@SyedPriom se l'URL che stai cercando è incoerente con i tuoi dati memorizzati, allora non funzionerà infatti, non era qualcosa che ho considerato quando ho scritto questo, ma probabilmente può essere migliorato per i protocolli. Come sopra, il problema principale con la funzione nativa è che non funzionerà sulle dimensioni delle immagini.

È una funzione molto utile, ma a volte genera un avviso "Notice: Only variables should be passed by reference" Per risolverlo basta assegnare il risultato di array_keys a una variabile e passare quella variabile
$image_src = wp_get_attachment_image_src( $id, $size ); if ( $values['file'] === $file && $url === array_shift( $image_src ) ) return $id;

Tutte quelle funzioni complesse possono essere ridotte a una semplice funzione:
Hai solo bisogno di analizzare l'URL dell'immagine per recuperare l'ID dell'allegato:
$attachment_id = attachment_url_to_postid( $image_url );
echo $attachment_id;
È tutto ciò di cui hai bisogno.

Nota che questo non funzionerà sulle dimensioni delle immagini, la versione core cerca solo il file allegato "principale".

Ho modificato il codice di Rarst per permetterti di confrontare solo il nome del file invece del percorso completo. Questo è utile se stai per importare lateralmente l'immagine se non esiste. Attualmente funziona solo se i nomi dei file sono unici, ma aggiungerò successivamente un controllo hash per gestire immagini con lo stesso nome file.
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;
}

Ho finalmente trovato la risposta che nessuno ha in rete, ho cercato per giorni. Tieni presente che questo funziona solo se il tuo tema o plugin utilizza WP_Customize_Image_Control()
. Se stai usando WP_Customize_Media_Control()
, la funzione get_theme_mod()
restituirà l'ID e non l'URL.
Per la mia soluzione, stavo utilizzando la versione più recente WP_Customize_Image_Control()
.
Molti post sui forum menzionano get_attachment_id()
, che però non funziona più. Ho usato attachment_url_to_postid()
.
Ecco come sono riuscito a farlo. Spero che questo aiuti qualcuno là fuori.
// Questo ottiene l'immagine / URL
$feature1 = get_theme_mod('feature_image_1');
// Questo ottiene l'ID del post
$feature1_id = attachment_url_to_postid($feature1);
// Questo ottiene il testo alternativo dall'immagine impostato nell'area media
$image1_alt = get_post_meta( $feature1_id, '_wp_attachment_image_alt', true );
Markup
<a href="<?php echo $feature1_url; ?>"><img class="img-responsive center-block" src="<?php echo $feature1; ?>" alt="<?php echo $image1_alt; ?>"></a>

Dalla versione 4.0 di WordPress esiste una funzione core attachment_url_to_postid che "Prova a convertire un URL di un allegato in un ID post." Ma questa funzione ha un grosso difetto perché non può convertire URL di immagini con dimensioni personalizzate.
Quasi tutte le risposte principali prima cercano di risolvere questo problema, ma tutte hanno una query al database molto pesante che tenta di ottenere tutti gli allegati esistenti e poi li scorre tutti cercando di ottenere i metadati dell'allegato e trovare le dimensioni personalizzate al loro interno. Funziona bene solo se hai una piccola quantità di allegati nel tuo progetto WordPress. Ma avrai sicuramente problemi di prestazioni se hai un progetto grande con più di 10000 allegati.
Ma puoi estendere la funzione core attachment_url_to_postid attraverso il filtro esistente attachment_url_to_postid cercando di forzare la funzione attachment_url_to_postid a cercare anche tra le dimensioni personalizzate delle immagini. Basta aggiungere il codice qui sotto al file functions.php del tuo tema WordPress attivo. e poi usare la funzione attachment_url_to_postid come la usavi prima ma con la funzionalità aggiuntiva delle dimensioni personalizzate.
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;
}

Ecco una soluzione alternativa:
$image_url = get_field('main_image'); // nel caso di utilizzo di un campo personalizzato
$image_id = attachment_url_to_postid($image_url);
// recupera la dimensione thumbnail della nostra immagine
$image_thumb = wp_get_attachment_image_src($image_id, 'thumbnail');
Dalla versione 4.0 di WP è stata introdotta la funzione attachment_url_to_postid()
che si comporta in modo simile alla tua find_image_post_id()
Per tua referenza, controlla questo url.
