Cum pot adăuga un câmp de încărcare imagini direct în panoul personalizat de editare?
Am adăugat o nouă pagină în secțiunea "Pagini" din admin-ul WordPress și am adăugat mai multe câmpuri personalizate. Aș dori de asemenea să pot adăuga un câmp de încărcare imagine în editorul de pagină - există vreo modalitate de a face acest lucru prin intermediul câmpurilor personalizate?
Sau trebuie să abordez diferit această necesitate?
Pentru oricine dorește să afle mai multe despre încărcarea fișierelor, iată un ghid rapid care acoperă subiectele și punctele principale problematice. Acest ghid este scris având în vedere WordPress 3.0 pe un sistem Linux, iar codul reprezintă doar o prezentare generală pentru a explica conceptele. Sunt sigur că unii dintre voi ar putea oferi sfaturi pentru îmbunătățirea implementării.
Schițează Abordarea de Bază
Există cel puțin trei modalități de a asocia imagini cu postările: folosind un câmp post_meta pentru a stoca calea imaginii, folosind un câmp post_meta pentru a stoca ID-ul imaginii din biblioteca media (mai multe despre asta mai târziu), sau atribuind imaginea postării ca atașament. Acest exemplu va folosi un câmp post_meta pentru a stoca ID-ul imaginii din biblioteca media. Rezultatele pot varia.
Codificarea Multipart
În mod implicit, formularele de creare și editare din WordPress nu au enctype. Dacă vrei să încarci un fișier, va trebui să adaugi un "enctype='multipart/form-data'" la tag-ul formularului - altfel colecția $_FILES nu va fi transmisă deloc. În WordPress 3.0, există un hook pentru asta. În unele versiuni anterioare (nu sunt sigur de specificații) trebuie să înlocuiești tag-ul formularului.
function xxxx_add_edit_form_multipart_encoding() {
echo ' enctype="multipart/form-data"';
}
add_action('post_edit_form_tag', 'xxxx_add_edit_form_multipart_encoding');
Creează Meta Box-ul și Câmpul de Upload
Nu voi intra prea mult în crearea meta box-urilor deoarece probabil majoritatea dintre voi știți deja cum să faceți asta, dar voi spune doar că aveți nevoie de un meta box simplu cu un câmp pentru fișier. În exemplul de mai jos am inclus cod pentru a căuta o imagine existentă și pentru a o afișa dacă există. Am inclus de asemenea o funcționalitate simplă de eroare/feedback care transmite erorile folosind un câmp post_meta. Va trebui să modificați asta pentru a folosi clasa WP_Error... este doar pentru demonstrație.
function xxxx_render_image_attachment_box($post) {
// Verifică dacă există o imagine. (Asociem imaginile cu postările salvând 'id-ul atașamentului' imaginii ca valoare post meta)
// În mod similar, așa ai găsi orice fișiere încărcate pentru afișare în frontend.
$existing_image_id = get_post_meta($post->ID,'_xxxx_attached_image', true);
if(is_numeric($existing_image_id)) {
echo '<div>';
$arr_existing_image = wp_get_attachment_image_src($existing_image_id, 'large');
$existing_image_url = $arr_existing_image[0];
echo '<img src="' . $existing_image_url . '" />';
echo '</div>';
}
// Dacă există o imagine, o afișează
if($existing_image_id) {
echo '<div>ID-ul Imaginii Atașate: ' . $existing_image_id . '</div>';
}
echo 'Încarcă o imagine: <input type="file" name="xxxx_image" id="xxxx_image" />';
// Verifică dacă există un mesaj de status de afișat (folosim asta pentru a arăta erori în timpul procesului de upload, deși ar trebui probabil să folosim clasa WP_error)
$status_message = get_post_meta($post->ID,'_xxxx_attached_image_upload_feedback', true);
// Arată un mesaj de eroare dacă există unul
if($status_message) {
echo '<div class="upload_status_message">';
echo $status_message;
echo '</div>';
}
// Pune un flag ascuns. Acesta ajută la diferențierea între salvările manuale și auto-salvări (în auto-salvări, fișierul nu ar fi transmis).
echo '<input type="hidden" name="xxxx_manual_save_flag" value="true" />';
}
function xxxx_setup_meta_boxes() {
// Adaugă box-ul la o pagină de conținut personalizat specific
add_meta_box('xxxx_image_box', 'Încarcă Imagine', 'xxxx_render_image_attachment_box', 'post', 'normal', 'high');
}
add_action('admin_init','xxxx_setup_meta_boxes');
Gestionarea Încărcării Fișierului
Aceasta este partea principală - gestionarea efectivă a încărcării fișierului prin conectarea la acțiunea save_post. Am inclus o funcție puternic comentată mai jos, dar aș dori să menționez cele două funcții cheie WordPress pe care le folosește:
wp_handle_upload() face toată magia gestionării încărcării. Trebuie doar să îi transmiți o referință către câmpul tău din array-ul $_FILES și un array de opțiuni (nu vă faceți prea multe griji despre acestea - singura importantă pe care trebuie să o setați este test_form=false. Aveți încredere). Această funcție nu adaugă însă fișierul încărcat în biblioteca media. Ea doar realizează încărcarea și returnează calea noului fișier (și, util, URL-ul complet de asemenea). Dacă există o problemă, returnează o eroare.
wp_insert_attachment() adaugă imaginea în biblioteca media și generează toate miniaturile corespunzătoare. Trebuie doar să îi transmiți un array de opțiuni (titlu, status postare etc) și calea LOCALĂ (nu URL) către fișierul pe care tocmai l-ai încărcat. Partea grozavă despre punerea imaginilor în biblioteca media este că poți șterge ușor toate fișierele mai târziu apelând wp_delete_attachment și transmițându-i ID-ul elementului din biblioteca media (ceea ce fac în funcția de mai jos). Cu această funcție, va trebui să folosești de asemenea wp_generate_attachment_metadata() și wp_update_attachment_metadata(), care fac exact ce te-ai aștepta să facă - generează metadata pentru elementul media.
function xxxx_update_post($post_id, $post) {
// Obține tipul postării. Deoarece această funcție va rula pentru TOATE salvările postărilor (indiferent de tipul postării), trebuie să știm asta.
// Este de asemenea important de notat că acțiunea save_post poate rula de mai multe ori la fiecare salvare a postării, așa că trebuie să verifici și să te asiguri că
// tipul postării în obiectul transmis nu este "revision"
$post_type = $post->post_type;
// Asigură-te că flag-ul nostru este acolo, altfel este o auto-salvare și ar trebui să ieșim.
if($post_id && isset($_POST['xxxx_manual_save_flag'])) {
// Logică pentru gestionarea tipurilor specifice de postări
switch($post_type) {
// Dacă aceasta este o postare. Poți schimba acest caz pentru a reflecta slug-ul postării tale personalizate
case 'post':
// GESTIONEAZĂ ÎNCĂRCAREA FIȘIERULUI
// Dacă câmpul de upload are un fișier în el
if(isset($_FILES['xxxx_image']) && ($_FILES['xxxx_image']['size'] > 0)) {
// Obține tipul fișierului încărcat. Acesta este returnat ca "tip/extensie"
$arr_file_type = wp_check_filetype(basename($_FILES['xxxx_image']['name']));
$uploaded_file_type = $arr_file_type['type'];
// Setează un array care conține o listă de formate acceptabile
$allowed_file_types = array('image/jpg','image/jpeg','image/gif','image/png');
// Dacă fișierul încărcat este în formatul corect
if(in_array($uploaded_file_type, $allowed_file_types)) {
// Array de opțiuni pentru funcția wp_handle_upload. 'test_upload' => false
$upload_overrides = array( 'test_form' => false );
// Gestionează încărcarea folosind funcția wp_handle_upload a WP. Primește fișierul postat și un array de opțiuni
$uploaded_file = wp_handle_upload($_FILES['xxxx_image'], $upload_overrides);
// Dacă apelul wp_handle_upload a returnat o cale locală pentru imagine
if(isset($uploaded_file['file'])) {
// Funcția wp_insert_attachment are nevoie de calea literală a sistemului, care a fost returnată de wp_handle_upload
$file_name_and_location = $uploaded_file['file'];
// Generează un titlu pentru imagine care va fi folosit în biblioteca media
$file_title_for_media_library = 'titlul tău aici';
// Setează array-ul de opțiuni pentru a adăuga acest fișier ca atașament
$attachment = array(
'post_mime_type' => $uploaded_file_type,
'post_title' => 'Imagine încărcată ' . addslashes($file_title_for_media_library),
'post_content' => '',
'post_status' => 'inherit'
);
// Rulează funcția wp_insert_attachment. Aceasta adaugă fișierul în biblioteca media și generează miniaturile. Dacă ai vrea să atașezi această imagine unei postări, ai putea transmite id-ul postării ca al treilea parametru și s-ar întâmpla magic.
$attach_id = wp_insert_attachment( $attachment, $file_name_and_location );
require_once(ABSPATH . "wp-admin" . '/includes/image.php');
$attach_data = wp_generate_attachment_metadata( $attach_id, $file_name_and_location );
wp_update_attachment_metadata($attach_id, $attach_data);
// Înainte de a actualiza meta postării, șterge orice imagine încărcată anterior pentru această postare.
// S-ar putea să nu vrei acest comportament, în funcție de cum folosești imaginile încărcate.
$existing_uploaded_image = (int) get_post_meta($post_id,'_xxxx_attached_image', true);
if(is_numeric($existing_uploaded_image)) {
wp_delete_attachment($existing_uploaded_image);
}
// Acum, actualizează meta postării pentru a asocia noua imagine cu postarea
update_post_meta($post_id,'_xxxx_attached_image',$attach_id);
// Setează flag-ul de feedback la false, deoarece încărcarea a avut succes
$upload_feedback = false;
} else { // wp_handle_upload a returnat un fel de eroare. returnarea conține detalii despre eroare, așa că le poți folosi aici dacă vrei.
$upload_feedback = 'A apărut o problemă cu încărcarea ta.';
update_post_meta($post_id,'_xxxx_attached_image',$attach_id);
}
} else { // tip de fișier greșit
$upload_feedback = 'Te rugăm să încarci doar fișiere imagine (jpg, gif sau png).';
update_post_meta($post_id,'_xxxx_attached_image',$attach_id);
}
} else { // Nu a fost transmis niciun fișier
$upload_feedback = false;
}
// Actualizează meta postării cu orice feedback
update_post_meta($post_id,'_xxxx_attached_image_upload_feedback',$upload_feedback);
break;
default:
} // Sfârșit switch
return;
} // Sfârșit if manual save flag
return;
}
add_action('save_post','xxxx_update_post',1,2);
Permisiuni, Proprietate și Securitate
Dacă ai probleme cu încărcarea, ar putea fi din cauza permisiunilor. Nu sunt expert în configurarea serverului, așa că vă rog să mă corectați dacă această parte este confuză.
Mai întâi, asigură-te că folderul wp-content/uploads există și este deținut de apache:apache. Dacă da, ar trebui să poți seta permisiunile la 744 și totul ar trebui să funcționeze. Proprietatea este importantă - chiar și setarea permisiunilor la 777 uneori nu va ajuta dacă directorul nu este deținut corespunzător.
Ar trebui de asemenea să iei în considerare limitarea tipurilor de fișiere încărcate și executate folosind un fișier htaccess. Acest lucru împiedică oamenii să încarce fișiere care nu sunt imagini și să execute scripturi deghizate ca imagini. Ar trebui probabil să cauți pe Google mai multe informații autoritare despre asta, dar poți face o limitare simplă a tipului de fișier astfel:
<Files ^(*.jpeg|*.jpg|*.png|*.gif)>
order deny,allow
deny from all
</Files>

Mulțumesc mult MathSmath! Exact de ce aveam nevoie. Aș dori să pot oferi mai multe voturi pozitive acestui răspuns!

Explicație excelentă! SINGURUL lucru pe care l-aș aprecia foarte mult să dezvolți este cum să faci anumite fișiere încărcate inaccesibile publicului. Cu alte cuvinte, dacă ai vrea să creezi un tip specific de postare unde toate fișierele încărcate sunt accesibile doar de utilizatorii cu o anumită capabilitate. Poți, te rog, să elaborezi pe această temă?

Pentru cei care doresc să încarce fișiere în interfața publică, va trebui să includeți următorul cod pentru a avea acces la funcția wp_handle_upload(): if ( ! function_exists( 'wp_handle_upload' ) ) require_once( ABSPATH . 'wp-admin/includes/file.php' );

Codul furnizat de @MathSmath este corect. Cu toate acestea, dacă ai de gestionat mai multe câmpuri de încărcare sau dorești să încarci mai multe fișiere, atunci va trebui să-l modifici semnificativ.
În plus, acesta nu utilizează biblioteca media WordPress pentru încărcarea fișierelor (care se ocupă de toate procesele complexe în spatele scenei).
Aș sugera să arunci o privire la un plugin precum Meta Box. Acest plugin suportă ambele metode de încărcare a fișierelor:
- Prin HTML5
input[type="file"]
, care utilizează un cod similar cu cel de mai sus (vezi documentația) și - Prin Biblioteca Media WordPress (vezi documentația).
Te poate ajuta să reduci efortul de scriere și întreținere a codului, mai ales atunci când dorești să creezi încărcări multiple.
Declarație: Sunt autorul Meta Box.
