Cum să actualizezi valoarea update_post_meta ca array

19 oct. 2016, 12:00:56
Vizualizări: 59.1K
Voturi: 9

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
3
Comentarii

Mesajul de eroare este destul de descriptiv. Ce nu înțelegi? Te rog, explică. in_array() necesită ca al doilea parametru să fie un array, verifică documentația PHP. Deci, trebuie doar să te asiguri că al doilea parametru pe care îl transmiți la in_array() este un array. Asta e tot în legătură cu mesajul de eroare. De asemenea, reține că această întrebare, așa cum este, este despre o eroare generică PHP, care este în afara domeniului acestui site.

cybmeta cybmeta
19 oct. 2016 12:50:28

@cybmeta după ce am folosit codul din răspunsul tău și am pus false în get_post_meta, acum al doilea parametru $item->content_multiple este un array, dar când selectez mai multe opțiuni, se salvează doar ultima opțiune și nu toate opțiunile selectate

Shwan Namiq Shwan Namiq
19 oct. 2016 15:13:05

Te rog, lasă comentarii despre răspuns în secțiunea de răspunsuri, altfel poate deruta alți utilizatori.

cybmeta cybmeta
19 oct. 2016 15:19:29
Toate răspunsurile la întrebare 2
14
22

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] ) );
19 oct. 2016 13:01:35
Comentarii

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

Shwan Namiq Shwan Namiq
19 oct. 2016 13:28:37

Î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.

cybmeta cybmeta
19 oct. 2016 13:50:05

Am actualizat răspunsul cu, sper, o explicație mai bună.

cybmeta cybmeta
19 oct. 2016 13:59:53

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)

Shwan Namiq Shwan Namiq
19 oct. 2016 14:57:49

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.

cybmeta cybmeta
19 oct. 2016 15:21:03

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.

Shwan Namiq Shwan Namiq
19 oct. 2016 15:30:35

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

Shwan Namiq Shwan Namiq
19 oct. 2016 15:43:38

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.

Shwan Namiq Shwan Namiq
20 oct. 2016 02:00:14

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

cybmeta cybmeta
20 oct. 2016 10:39:08

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ă.

Shwan Namiq Shwan Namiq
20 oct. 2016 14:06:26

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 Milo
20 oct. 2016 18:10:16

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

Shwan Namiq Shwan Namiq
20 oct. 2016 22:29:21

@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.

cybmeta cybmeta
21 oct. 2016 09:59:41

@ShwanNamiq cred că e mai bine să postezi o întrebare nouă pentru problema ta nouă.

cybmeta cybmeta
21 oct. 2016 10:10:47
Arată celelalte 9 comentarii
6

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>
19 oct. 2016 12:12:38
Comentarii

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.

Shwan Namiq Shwan Namiq
19 oct. 2016 12:20:18

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.

Benoti Benoti
19 oct. 2016 12:26:45

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.

Shwan Namiq Shwan Namiq
19 oct. 2016 12:38:26

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']

Benoti Benoti
19 oct. 2016 12:50:11

$item este un obiect, nu un array()

Shwan Namiq Shwan Namiq
19 oct. 2016 15:01:34

in_array() acceptă doar un array ca al doilea parametru. Trebuie să convertești obiectul în array astfel: (array)$item, dar lasă al treilea argument din get_post_meta ca true (pentru a obține obiectul și apoi vei putea să-l convertești)

Benoti Benoti
19 oct. 2016 15:16:32
Arată celelalte 1 comentarii