Cum să actualizezi valoarea update_post_meta ca array
Am creat un câmp personalizat nou în elementele meniului meu de navigare ca opțiuni de selecție multiplă și am folosit update_post_meta()
astfel:
function YPE_update_custom_fields($menu_id, $menu_item_db_id, $menu_item_data) {
if (is_array($_REQUEST['menu-item-content-multiple'])) {
update_post_meta($menu_item_db_id, '_menu_item_content_multiple', $_REQUEST['menu-item-content-multiple'][$menu_item_db_id]);
}
}
add_action('wp_update_nav_menu_item', 'YPE_update_custom_fields', 10, 3);
function YPE_setup_custom_fields($item) {
$item->content_multiple = get_post_meta($item->ID, '_menu_item_content_multiple', true);
return $item;
}
add_filter('wp_setup_nav_menu_item', 'YPE_setup_custom_fields');
Apoi am adăugat un câmp nou în fișierul Walker_Nav_Menu_Edit
astfel:
EDITAT
<?php
$select_options = array (
'key_1' => 'optiune1',
'key_2' => 'optiune2',
'key_3' => 'optiune3'
);
?>
<p class="field-content-multiple description description-thin">
<label for="edit-menu-item-content-multiple-<?php echo $item_id; ?>">
<?php _e( 'Conținut Multiplu' ); ?><br />
<select name="menu-item-content-multiple[<?php echo $item_id; ?>][]" id="edit-menu-item-content-multiple-<?php echo $item_id; ?>" class="widefat code edit-menu-item-content-multiple" multiple="multiple">
<?php foreach ($select_options as $key => $value): ?>
<option value="<?php echo $key; ?>" <?php echo selected(in_array($key, $item->content_multiple)); ?>><?php echo $value;?></option>
<?php endforeach ?>
</select>
</label>
</p>
Codul meu funcționează fără probleme cu caseta de selectare unică, dar când folosesc in_array()
în cazul selecției multiple, returnează această eroare:
Warning: in_array() expects parameter 2 to be array, null given

Tu faci asta:
$item->content_multiple = get_post_meta($item->ID, '_menu_item_content_multiple', true);
Observă cum ai setat al treilea parametru al funcției get_post_meta()
la true
, ceea ce înseamnă că va fi returnată o singură valoare. Dacă citești documentația, vei vedea că, dacă al treilea parametru este false
, vei obține un array cu toate valorile pentru acel câmp meta.
Ține minte că câmpurile meta pot fi unice sau multiple. Sau pot fi unice cu un șir de date serializat.
În stadiul actual, codul tău pare să stocheze toate valorile din select multiple într-un singur câmp meta. Deci, primești un array în cerere și îl trimiți ca valoare unică a câmpului meta. Când valoarea unui câmp meta este un array, WordPress îl convertește într-un șir serializat înainte de a fi stocat în baza de date; acest lucru se face intern cu funcția maybe_serialize()
. Apoi, când încerci să obții valoarea câmpului meta, dacă este un șir serializat, WordPress îl trece prin maybe_unserialize()
, astfel încât șirul serializat se convertește înapoi la array:
Să explicăm cu un exemplu generic.
Acesta va fi array-ul de valori care va fi stocat în baza de date:
$values = [ 'red', 'yellow', 'blue', 'pink' ];
Dacă cheia ta meta este "color", atunci ai două opțiuni:
Multiple intrări pentru aceeași cheie meta
$values = [ 'red', 'yellow', 'blue', 'pink' ];
foreach( $values as $value ) {
// Această metodă folosește `add_post_meta()` în loc de `update_post_meta()`
add_post_meta( $item_id, 'color', $value );
}
Acum, elementul identificat cu $item_id
va avea mai multe intrări pentru cheia meta color
. Apoi, poți folosi get_post_meta()
cu al treilea parametru setat la false
și vei obține un array cu toate valorile:
// Nu este nevoie să setezi al treilea parametru
// deoarece este false implicit
$colors = get_post_meta( $item_id, 'color' );
// $colors ar trebui să fie un array cu toate valorile meta pentru cheia color
var_dump( $colors );
Stochează array-ul într-o singură intrare meta
În acest caz, array-ul de valori este serializat înainte de a fi stocat în baza de date:
$values = [ 'red', 'yellow', 'blue', 'pink' ];
// WordPress face asta automat când un array este trimis ca valoare meta
// $values = maybe_serialize( $values );
update_post_meta( $item_id, 'color', $values );
Acum, elementul identificat cu $item_id
va avea o singură intrare pentru cheia meta color
; valoarea este un șir serializat reprezentând array-ul original. Apoi, poți folosi get_post_meta()
, cu al treilea parametru setat la true, deoarece ai o singură intrare, și apoi deserializați șirul pentru a obține înapoi array-ul:
$colors = get_post_meta( $item_id, 'color', true );
// WordPress face asta automat când valoarea meta este un array serializat
// $colors = maybe_unserialize( $colors );
// $colors ar trebui să fie un array
var_dump( $colors );
Poți urma aceeași abordare cu select multiple din formularul tău.
Cu o singură intrare pentru cheia meta:
if( ! empty( $_REQUEST['menu-item-content-multiple'][$menu_item_db_id] ) ) {
$meta_field_value = $_REQUEST['menu-item-content-multiple'][$menu_item_db_id];
// $meta_field_value va fi serializat automat de WordPress
update_post_meta( $menu_item_db_id, '_menu_item_content_multiple', $meta_field_value );
}
Apoi, poți folosi valoarea ca array:
// Valoarea returnată de get_post_meta() este deserializată automat de WordPress
$item->content_multiple = get_post_meta( $item->ID, '_menu_item_content_multiple', true );
Cu mai multe intrări:
Conceptul aici este puțin diferit; vei avea mai multe intrări în baza de date cu aceeași cheie meta, deci trebuie să folosești add_post_meta()
în loc de update_post_meta()
pentru a adăuga o nouă intrare pentru fiecare valoare.
if( ! empty( $_REQUEST['menu-item-content-multiple'][$menu_item_db_id] ) ) {
$values = $_REQUEST[ 'menu-item-content-multiple' . $menu_item_db_id ];
foreach( $values as $value ) {
add_post_meta( $menu_item_db_id, '_menu_item_content_multiple', $value );
}
}
Acum, poți folosi get_post_meta()
cu al treilea parametru setat la false
(este valoarea implicită, deci poți să-l omiti):
$item->content_multiple = get_post_meta( $item->ID, '_menu_item_content_multiple', false );
Ambele opțiuni sunt OK, trebuie să decizi care este mai bună pentru organizarea datelor în cadrul proiectului tău.
Notă suplimentară: ar trebui să faci o anumită sanitizare înainte de a folosi datele introduse, dar nu cunosc cerințele tale, iată un exemplu:
array_map( 'sanitize_text_field', wp_unslash( $_REQUEST['menu-item-content-multiple'][$menu_item_db_id] ) );

Mulțumesc, trebuie să folosesc false în loc de true. Dar ai folosit true în get_post_meta!!!

În forma actuală a codului tău, nu, trebuie să folosești metoda serialize și unserialize. Pentru a putea folosi false
în get_post_meta()
, ar trebui să stochezi fiecare valoare din select
ca o intrare separată în baza de date, cu aceeași cheie dar de mai multe ori, adică să folosești update_post_meta()
pentru fiecare valoare dar folosind mereu aceeași cheie; atunci poți folosi false
în get_post_meta()
pentru a le obține pe toate. Sper că înțelegi ce vreau să spun.

Mulțumesc, postarea ta a rezolvat mesajul de eroare. Am editat postarea mea și am adăugat un câmp personalizat cu casetă de selectare ca în fișierul meu. Dar problema este că atunci când selectez mai multe opțiuni, după salvarea setărilor, se salvează doar ultima opțiune și nu toate opțiunile selectate. De ce? Este vreo eroare în utilizarea funcției WordPress selected();? <?php echo selected(in_array($key, $item->content_multiple)); ?> (am folosit codul din a doua opțiune a ta)

Reține că pentru a folosi mai multe intrări pentru aceeași cheie meta, trebuie să execuți update_post_meta()
pentru fiecare valoare, dar folosind aceeași cheie de fiecare dată, așa cum am făcut în răspuns.

Da, vreau mai multe intrări pentru aceeași cheie meta, dar nu știu cum să folosesc această metodă. Te rog ajută-mă și explică-mi asta prin cod.

Să continuăm această discuție în chat.

Scuze cybmeta, dar am o altă problemă cu deselectarea opțiunilor. Când încerc să deselectez o opțiune selectată, după salvarea setărilor rămâne selectată și nu pot deselecta nicio opțiune după selecție.

Pur și simplu folosește delete_post_meta()
când ai nevoie. Am adăugat un exemplu simplu.

Mulțumesc, funcționează dar nu pot elimina toate opțiunile selectate și prima opțiune selectată rămâne. delete_post_meta
nu elimină prima opțiune selectată.

WordPress serializează/deserializează automat datele de tip array într-un singur câmp meta (la fel ca și funcțiile de opțiuni), nu ar trebui să serializezi/deserializezi manual.

@Milo de ce delete_post_meta
în acest răspuns nu deselectează sau elimină prima opțiune selectată.

@Milo, bună observație, am fost confuz cu explicația din codex și din portalul pentru dezvoltatori, dar văzând codul sursă, pot confirma că WordPress face automat serialize/unserialize pentru noi; răspuns actualizat.

Nu folosești funcția selected()
corect. selected()
necesită 1 parametru obligatoriu și 2 opționali. În cazul tău, este mai bine să folosești $selected și $current.
Îți lipsește underscore-ul înaintea numelui meta-câmpului în numele select-ului.
Pentru selected():
selected( $selected, $current, $echo);
poți citi mai multe despre aceasta din codex referința funcției selected()
Select-ul tău trebuie să arate astfel:
<select name="_menu-item-content-multiple[]" multiple>
<?php
foreach ($select_options as $key => $value) {
echo '<option value="'.$key.'" '.selected(in_array($key, $item->content_multiple), $key).'>'.$value.'</option>';
}
?>
</select>

Am folosit codul tău, dar tot primesc eroare, cred că problema este în $item->content_multiple care trebuie salvat ca array, deoarece $item->content_multiple salvează doar o singură valoare și nu salvează mai multe valori ca array.

Ok, verifică dacă numele meta-câmpului tău este mereu același, momentan nu este. Dacă vrei să folosești prefixul underscore, folosește-l mereu, și numește select-ul tău fie cu underscore fie cu liniuță. update_post_meta funcționează dar nu se salvează nicio valoare.

Am adăugat mai mult de 10 câmpuri ca cel de mai sus și toate funcționează fără probleme. Spun că eroarea este în $item->content_multiple deoarece acest câmp salvează doar o singură valoare și nu salvează mai multe valori simultan, pentru că nu este actualizat ca array. Înainte de bucla foreach când am pus $item->content_multiple = array(); a funcționat și nu mi-a mai arătat eroare, dar nu au fost salvate valorile.

Nu sunt complet sigur, dar verifică tipul $item, este un obiect sau un array? Ok, conținutul din el este un array, dar încearcă să-l convertești într-un array pentru funcția in_array, înainte de bucla foreach (array)$item și în selected() folosește-l ca array astfel: $item['content_multiple']
