Transformă un URL într-un ID de Atașament/Postare
Există vreo metodă prin care pot lua URL-ul unei imagini și să găsesc ID-ul atașamentului sau postării acelei imagini în baza de date?
Iată situația:
Sunt într-o buclă care parcurge toate tag-urile 'img' înconjurate de tag-uri 'a' din conținutul postării mele. Dacă atributul src al tag-ului 'img' nu se potrivește cu atributul href al tag-ului 'a' exterior, atunci vreau să înlocuiesc tag-ul 'img'. În acest proces, dacă 'img'-ul care urmează să fie eliminat face parte din galerie, vreau să șterg acea postare și apoi să pun imaginea mea de înlocuire în locul ei. Am încercat să folosesc o funcție ca aceasta:
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;
}
Această abordare pare să nu funcționeze corect, deoarece guid-ul, ironic, nu este global unic. Am încărcat mai devreme (în același script) un fișier cu același nume (de ce? pentru că avea o rezoluție mai mare și încerc să înlocuiesc versiunile cu rezoluție mai mică ale aceleiași imagini) și, deși WordPress salvează imaginea cu un nume diferit în director, guid-urile au fost setate la aceeași valoare. (posibil un bug).
Există vreo altă tehnică pe care o pot folosi?

Funcție îmbunătățită masiv dezvoltată pentru plugin-uri cu multe imagini:
if ( ! function_exists( 'get_attachment_id' ) ) {
/**
* Obține ID-ul atașamentului pentru o anumită URL a imaginii.
*
* @link http://wordpress.stackexchange.com/a/7094
*
* @param string $url
*
* @return boolean|integer
*/
function get_attachment_id( $url ) {
$dir = wp_upload_dir();
// baseurl nu are niciodată o bară oblică la final
if ( false === strpos( $url, $dir['baseurl'] . '/' ) ) {
// URL-ul indică o locație în afara directorului de încărcare
return false;
}
$file = basename( $url );
$query = array(
'post_type' => 'attachment',
'fields' => 'ids',
'meta_query' => array(
array(
'key' => '_wp_attached_file',
'value' => $file,
'compare' => 'LIKE',
),
)
);
// interoghează atașamentele
$ids = get_posts( $query );
if ( ! empty( $ids ) ) {
foreach ( $ids as $id ) {
// primul element din array-ul returnat este URL-ul
if ( $url === array_shift( wp_get_attachment_image_src( $id, 'full' ) ) )
return $id;
}
}
$query['meta_query'][0]['key'] = '_wp_attachment_metadata';
// interoghează din nou atașamentele
$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;
}
}

Poți explica de ce interoghezi atât _wp_attached_file
cât și _wp_attachment_metadata
?

@StephenHarris deoarece URL-ul poate indica oricare dintre dimensiunile imaginii, care au toate nume de fișiere diferite

Această soluție funcționează excelent, dar merită menționat aici că, începând cu WordPress 4, există o funcție integrată pentru a face acest lucru, așa cum a menționat Gabriel într-un alt răspuns. Funcționează exact la fel ca aceasta.

@ChrisRae dacă te uiți la sursă, funcția de bază nu va funcționa pe dimensiunile imaginilor, doar pe imaginea principală.

Cred că funcția încorporată din WordPress funcționează mai bine. Aceasta nu a funcționat în mediul meu de producție, dar a funcționat pe Staging (care nu are un certificat SSL). Funcția încorporată (așa cum a menționat Ego Ipse mai jos) funcționează în ambele medii.

@SyedPriom dacă URL-ul pe care îl cauți este inconsistent cu datele tale stocate, atunci într-adevăr nu va funcționa, nu era ceva la care m-am gândit când am scris asta, dar probabil poate fi îmbunătățit pentru protocoale. După cum am menționat mai sus, principala problemă cu funcția nativă este că nu va funcționa pe dimensiunile imaginilor.

Este o funcție excelentă, dar uneori aruncă o notificare "Notice: Only variables should be passed by reference" Pentru a o rezolva, atribuiți rezultatul array_keys unei variabile și transmiteți acea variabilă
$image_src = wp_get_attachment_image_src( $id, $size ); if ( $values['file'] === $file && $url === array_shift( $image_src ) ) return $id;

Toate acele funcții complexe pot fi reduse la o singură funcție simplă:
Trebuie doar să analizezi URL-ul imaginii pentru a obține ID-ul atașamentului:
$attachment_id = attachment_url_to_postid( $image_url );
echo $attachment_id;
Este tot ce ai nevoie.

Este important de menționat că acest lucru nu va funcționa pentru dimensiunile imaginilor, versiunea de bază caută doar fișierul atașat "principal".

Am modificat codul lui Rarst pentru a permite potrivirea doar a numelui fișierului în loc de calea completă. Acest lucru este util dacă intenționați să încărcați manual imaginea în cazul în care aceasta nu există. În prezent, acest lucru funcționează doar dacă numele fișierelor sunt unice, dar voi adăuga ulterior o verificare prin hash pentru a ajuta cu imaginile care au același nume de fișier.
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;
}

Bun, am găsit răspunsul pe care nimeni nu îl are pe internet. Am căutat zile întregi. Rețineți că acest lucru funcționează doar dacă tema sau pluginul tău utilizează WP_Customize_Image_Control()
. Dacă folosești WP_Customize_Media_Control()
, funcția get_theme_mod()
va returna ID-ul și nu URL-ul.
Pentru soluția mea, am folosit versiunea mai nouă WP_Customize_Image_Control()
.
Multe postări pe forumuri menționează get_attachment_id()
, care nu mai funcționează. Eu am folosit attachment_url_to_postid()
.
Iată cum am reușit să o fac. Sper că acest lucru va ajuta pe cineva.
// Aceasta obține imaginea / URL-ul
$feature1 = get_theme_mod('feature_image_1');
// Aceasta obține ID-ul postului
$feature1_id = attachment_url_to_postid($feature1);
// Aceasta obține textul alternativ al imaginii setat în zona 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>

Începând cu versiunea 4.0 a WordPress, există o funcție de bază attachment_url_to_postid care "Încearcă să convertească un URL de atașament într-un ID de post." Dar această funcție are un mare dezavantaj pentru că nu poate converti URL-uri de imagini cu dimensiuni personalizate.
Majoritatea răspunsurilor populare înainte încercau să rezolve această problemă, dar toate implicau o interogare grea la baza de date, încercând să obțină toate atașamentele existente și apoi să parcurgă fiecare dintre ele pentru a obține metadatele atașamentului și a găsi dimensiunile personalizate. Acest lucru funcționează bine doar dacă ai un număr mic de atașamente în proiectul tău WordPress. Dar cu siguranță vei avea probleme de performanță dacă ai un proiect mare cu peste 10.000 de atașamente.
Totuși, poți extinde funcția attachment_url_to_postid prin filtrul existent attachment_url_to_postid, forțând funcția să caute și între dimensiunile personalizate ale imaginilor. Doar adaugă codul de mai jos în fișierul functions.php al temei active WordPress. și apoi folosește funcția attachment_url_to_postid ca înainte, dar cu funcționalitatea suplimentară pentru dimensiuni personalizate.
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;
}

Iată o soluție alternativă:
$image_url = get_field('main_image'); // în cazul utilizării unui câmp personalizat
$image_id = attachment_url_to_postid($image_url);
// preluăm dimensiunea thumbnail a imaginii noastre
$image_thumb = wp_get_attachment_image_src($image_id, 'thumbnail');
Începând cu WP 4.0 au introdus o funcție attachment_url_to_postid()
care se comportă similar cu funcția ta find_image_post_id()
Te rugăm să verifici acest link pentru referință.
