Come aggiornare il valore update_post_meta come array
Ho creato un nuovo campo personalizzato all'interno dei miei elementi del menu di navigazione come opzioni di selezione multipla usando update_post_meta()
come segue
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');
Poi ho aggiunto un nuovo campo nel file Walker_Nav_Menu_Edit
come segue
MODIFICATO
<?php
$select_options = array (
'key_1' => 'option1',
'key_2' => 'option2',
'key_3' => 'option3'
);
?>
<p class="field-content-multiple description description-thin">
<label for="edit-menu-item-content-multiple-<?php echo $item_id; ?>">
<?php _e( 'Contenuto Multiplo' ); ?><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>
Il mio codice funziona con il select box singolo senza alcun problema ma quando uso in_array()
nei casi di selezione multipla restituisce questo errore
Warning: in_array() expects parameter 2 to be array, null given

Fai così:
$item->content_multiple = get_post_meta($item->ID, '_menu_item_content_multiple', true);
Nota come imposti il terzo parametro di get_post_meta()
a true
, il che significa che verrà restituito un solo valore. Se leggi la documentazione, vedrai che, se il terzo parametro è false
, otterrai un array con tutti i valori per quel campo meta.
Ricorda che i campi meta possono essere unici o multipli. Oppure possono essere unici con una stringa di dati serializzata.
Così com'è, il tuo codice sembra memorizzare tutti i valori del select multiple in un unico campo meta. Quindi, ottieni un array nella richiesta e lo passi come valore singolo del campo meta. Quando il valore di un campo meta è un array, WordPress lo converte in una stringa serializzata prima di memorizzarlo nel database; questo viene fatto internamente con la funzione maybe_serialize()
. Poi, quando provi a ottenere il valore del campo meta, se è una stringa serializzata, WordPress la passa attraverso maybe_unserialize()
, così la stringa serializzata viene riconvertita nell'array:
Spieghiamo con un esempio generico.
Questo sarà l'array di valori da memorizzare nel database:
$values = [ 'red', 'yellow', 'blue', 'pink' ];
Se la tua chiave meta è "color", allora hai due opzioni:
Multiple voci per la stessa chiave meta
$values = [ 'red', 'yellow', 'blue', 'pink' ];
foreach( $values as $value ) {
// Questo metodo usa `add_post_meta()` invece di `update_post_meta()`
add_post_meta( $item_id, 'color', $value );
}
Ora, l'elemento identificato con $item_id
avrà diverse voci per la chiave meta color
. Poi, puoi usare get_post_meta()
con il terzo parametro impostato a false
e otterrai un array con tutti i valori:
// Non hai davvero bisogno di impostare il terzo parametro
// perché è false di default
$colors = get_post_meta( $item_id, 'color' );
// $colors dovrebbe essere un array con tutti i valori meta per la chiave color
var_dump( $colors );
Memorizzare l'array in una singola voce meta
In questo caso, l'array di valori viene serializzato prima di essere memorizzato nel database:
$values = [ 'red', 'yellow', 'blue', 'pink' ];
// WordPress fa questo automaticamente quando un array viene passato come valore meta
// $values = maybe_serialize( $values );
update_post_meta( $item_id, 'color', $values );
Ora, l'elemento identificato con $item_id
avrà solo una voce per la chiave meta color
; il valore è una stringa serializzata che rappresenta l'array originale. Poi, puoi usare get_post_meta()
, con il terzo parametro impostato a true, poiché hai solo una voce, e poi deserializzare la stringa per ottenere nuovamente l'array:
$colors = get_post_meta( $item_id, 'color', true );
// WordPress fa questo automaticamente quando il valore meta è un array serializzato
// $colors = maybe_unserialize( $colors );
// $colors dovrebbe essere un array
var_dump( $colors );
Puoi seguire lo stesso approccio con il select multiple del tuo form.
Con una sola voce per la chiave 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 verrà serializzata automaticamente da WordPress
update_post_meta( $menu_item_db_id, '_menu_item_content_multiple', $meta_field_value );
}
Poi, puoi usare il valore come array:
// Il valore restituito da get_post_meta() viene deserializzato automaticamente da WordPress
$item->content_multiple = get_post_meta( $item->ID, '_menu_item_content_multiple', true );
Con multiple voci:
Il concetto qui è leggermente diverso; avrai diverse voci nel database con la stessa chiave meta, quindi devi usare add_post_meta()
invece di update_post_meta()
per aggiungere una nuova voce per ogni valore.
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 );
}
}
Ora, puoi usare get_post_meta()
con il terzo parametro impostato a false
(è il valore predefinito, quindi puoi ometterlo):
$item->content_multiple = get_post_meta( $item->ID, '_menu_item_content_multiple', false );
Entrambe le opzioni vanno bene, devi decidere quale sia migliore per organizzare i dati nel tuo progetto.
Nota a margine: dovresti fare un po' di sanificazione prima di usare i dati in input, ma non conosco i requisiti per te, ecco un esempio:
array_map( 'sanitize_text_field', wp_unslash( $_REQUEST['menu-item-content-multiple'][$menu_item_db_id] ) );

Grazie, devo usare false invece di true. Ma hai usato true anche in get_post_meta !!!

Come è scritto il tuo codice, no, devi usare il metodo serialize e unserialize. Per poter usare false
in get_post_meta()
dovresti memorizzare ogni valore del tuo select
in una voce separata nel database, con la stessa chiave ma più volte, cioè usare update_post_meta()
per ogni valore ma utilizzando sempre la stessa chiave; poi puoi usare false
in get_post_meta()
per ottenerli tutti. Spero di essermi spiegato.

Grazie, il tuo post ha risolto il messaggio di errore, ho modificato il mio post aggiungendo un campo personalizzato a selezione come nel mio file. Ma il problema è che quando seleziono più opzioni dopo il salvataggio delle impostazioni viene salvata solo l'ultima opzione e non tutte le opzioni selezionate, perché? C'è qualche errore nell'uso della funzione WordPress selected(); ? <?php echo selected(in_array($key, $item->content_multiple)); ?> (ho usato il tuo secondo codice dell'opzione)

Nota che per utilizzare più voci per la stessa meta chiave, devi eseguire update_post_meta()
per ogni valore, ma utilizzando la stessa chiave ogni volta, come ho fatto nella risposta.

Sì, voglio più voci per la stessa meta chiave, ma non so come usare questo metodo, per favore aiutami e spiegamelo con del codice

Continuiamo questa discussione nella chat.

Scusa cybmeta ma ho un altro problema con la deselezione delle opzioni. Quando voglio deselezionare un'opzione già selezionata, dopo aver salvato le impostazioni rimane selezionata e non riesco più a deselezionare nessuna opzione dopo la selezione

Usa semplicemente delete_post_meta()
quando ne hai bisogno. Ho aggiunto un esempio base.

Grazie, funziona ma non riesco a rimuovere tutte le opzioni selezionate, inoltre rimane la prima opzione selezionata. Il delete_post_meta
non rimuove la prima opzione selezionata.

WordPress serializza/deserializza automaticamente i dati degli array in un singolo campo meta (così come fanno le funzioni delle opzioni), non dovresti serializzare/deserializzare manualmente.

@Milo perché delete_post_meta
in questa risposta non deseleziona o rimuove la prima opzione selezionata.

@Milo, ottimo rilevamento, ero confuso con la spiegazione nel codex e nel portale per sviluppatori, ma guardando il codice sorgente, posso confermare che WordPress esegue automaticamente la serializzazione/deserializzazione per noi; risposta aggiornata.

Non stai utilizzando correttamente la funzione selected()
. La funzione selected()
richiede 1 parametro obbligatorio e 2 opzionali. Nel tuo caso, è meglio utilizzare $selected e $current.
Manca l'underscore prima del nome del tuo meta-field nel nome del select.
Per selected():
selected( $selected, $current, $echo);
Puoi leggere di più a riguardo sul codex riferimento alla funzione selected()
Il tuo select dovrebbe essere così:
<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>

Ho usato il tuo codice ma mostra ancora l'errore, penso che l'errore sia in $item->content_multiple che deve essere salvato come array perché $item->content_multiple salva anche un singolo valore e non salva più valori come array

Ok, verifica che il nome del tuo meta-field sia sempre lo stesso, attualmente non lo è. Se vuoi che abbia il prefisso underscore, usa sempre questo underscore, e nomina il tuo select con underscore o con trattino. update_post_meta funziona ma nessun valore verrà salvato.

Ho aggiunto più di 10 campi come il campo sopra e tutti funzionano senza problemi. Dico che l'errore è in $item->content_multiple perché questo campo salva anche un singolo valore e non salva più valori contemporaneamente perché non viene aggiornato come array. Prima del ciclo foreach quando metto $item->content_multiple = array(); funziona e non mi mostra alcun errore ma non salva i valori

Non sono proprio sicuro, ma verifica il tipo di $item, è un oggetto o un array? ok il contenuto è un array, ma prova a convertirlo in un array per la funzione in_array, prima del ciclo foreach (array)$item e in selected() usalo come array in questo modo: $item['content_multiple']
