Cómo actualizar el valor de update_post_meta como array

19 oct 2016, 12:00:56
Vistas: 59.1K
Votos: 9

Creé un nuevo campo personalizado dentro de mis elementos de menú de navegación como opciones de selección múltiple usando update_post_meta() como se muestra a continuación

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');

Luego agregué un nuevo campo en el archivo Walker_Nav_Menu_Edit como se muestra a continuación

EDITADO

<?php
$select_options = array (
    'key_1' => 'opción1', 
    'key_2' => 'opción2', 
    'key_3' => 'opción3'
); 
?>
<p class="field-content-multiple description description-thin">
<label for="edit-menu-item-content-multiple-<?php echo $item_id; ?>">
    <?php _e( 'Contenido Múltiple' ); ?><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>

Mi código funciona con el cuadro de selección única sin ningún problema, pero cuando uso in_array() en casos de selección múltiple devuelve este error

Warning: in_array() expects parameter 2 to be array, null given
3
Comentarios

Los mensajes de error son bastante descriptivos. ¿Qué es lo que no entiendes? Por favor, explícalo. in_array() requiere que el segundo parámetro sea un array, consulta la documentación de PHP. Así que solo necesitas asegurarte de que el segundo parámetro que pasas a in_array() es un array. Eso es todo sobre el mensaje de error. Además, ten en cuenta que esta pregunta, tal como está, es sobre un error genérico de PHP, lo cual está fuera del alcance de este sitio.

cybmeta cybmeta
19 oct 2016 12:50:28

@cybmeta después de usar el código de tu respuesta y poner false en get_post_meta ahora el segundo parámetro $item->content_multiple es un array pero cuando selecciono múltiples opciones solo guarda la última opción y no guarda todas las opciones seleccionadas

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

Por favor, deja los comentarios sobre la respuesta en la respuesta misma, de lo contrario puede confundir a otros usuarios.

cybmeta cybmeta
19 oct 2016 15:19:29
Todas las respuestas a la pregunta 2
14
22

Tú haces esto:

$item->content_multiple = get_post_meta($item->ID, '_menu_item_content_multiple', true);

Observa cómo estableces el tercer parámetro de get_post_meta() como true, lo que significa que solo se devolverá un valor. Si lees la documentación, verás que, si el tercer parámetro es false, obtendrás un array con todos los valores para ese campo meta.

Recuerda que los campos meta pueden ser únicos o múltiples. O pueden ser únicos con una cadena de datos serializada.

Tal como está, tu código parece almacenar todos los valores del select múltiple en un solo campo meta. Entonces, obtienes un array en la solicitud y lo pasas como un único valor del campo meta. Cuando el valor de un campo meta es un array, WordPress lo convierte en una cadena serializada antes de almacenarlo en la base de datos; esto se hace internamente con la función maybe_serialize(). Luego, cuando intentas obtener el valor del campo meta, si es una cadena serializada, WordPress la pasa por maybe_unserialize(), así que la cadena serializada se convierte de nuevo al array:

Vamos a explicarlo con un ejemplo genérico.

Este será el array de valores a almacenar en la base de datos:

$valores = [ 'rojo', 'amarillo', 'azul', 'rosa' ];

Si tu clave meta es "color", entonces tienes dos opciones:

Múltiples entradas para la misma clave meta

$valores = [ 'rojo', 'amarillo', 'azul', 'rosa' ];
foreach( $valores as $valor ) {
    // Este método usa `add_post_meta()` en lugar de `update_post_meta()`
    add_post_meta( $item_id, 'color', $valor );
}

Ahora, el elemento identificado con $item_id tendrá varias entradas para la clave meta color. Luego, puedes usar get_post_meta() con el tercer parámetro establecido como false y obtendrás un array con todos los valores:

// Realmente no necesitas establecer el tercer parámetro
// porque es false por defecto
$colores = get_post_meta( $item_id, 'color' );

// $colores debería ser un array con todos los valores meta para la clave meta color
var_dump( $colores );

Almacenar el array en una única entrada meta

En este caso, el array de valores se serializa antes de almacenarse en la base de datos:

$valores = [ 'rojo', 'amarillo', 'azul', 'rosa' ];
// WordPress hace esto automáticamente cuando se pasa un array como valor meta
// $valores = maybe_serialize( $valores );
update_post_meta( $item_id, 'color', $valores );

Ahora, el elemento identificado con $item_id tendrá solo una entrada para la clave meta color; el valor es una cadena serializada que representa el array original. Luego, puedes usar get_post_meta(), con el tercer parámetro establecido como true, ya que solo tienes una entrada, y luego deserializar la cadena para obtener el array de nuevo:

$colores = get_post_meta( $item_id, 'color', true );
// WordPress hace esto automáticamente cuando el valor meta es un array serializado
// $colores = maybe_unserialize( $colores );

// $colores debería ser un array
var_dump( $colores );

Puedes seguir el mismo enfoque con el select múltiple de tu formulario.

Con solo una entrada para la clave meta:

if( ! empty( $_REQUEST['menu-item-content-multiple'][$menu_item_db_id] ) ) {
    $valor_campo_meta = $_REQUEST['menu-item-content-multiple'][$menu_item_db_id];
    // $valor_campo_meta será serializado automáticamente por WordPress
    update_post_meta( $menu_item_db_id, '_menu_item_content_multiple', $valor_campo_meta );
}

Luego, puedes usar el valor como array:

 // El valor devuelto por get_post_meta() es deserializado automáticamente por WordPress
 $item->content_multiple = get_post_meta( $item->ID, '_menu_item_content_multiple', true );

Con múltiples entradas:

El concepto aquí es un poco diferente; tendrás varias entradas en la base de datos con la misma clave meta, por lo que necesitas usar add_post_meta() en lugar de update_post_meta() para añadir una nueva entrada por cada valor.

if( ! empty( $_REQUEST['menu-item-content-multiple'][$menu_item_db_id] ) ) {
    $valores = $_REQUEST[ 'menu-item-content-multiple' . $menu_item_db_id ];
    foreach( $valores as $valor ) {
        add_post_meta( $menu_item_db_id, '_menu_item_content_multiple', $valor );
    }
}

Ahora, puedes usar get_post_meta() con el tercer parámetro establecido como false (es el valor por defecto, así que puedes omitirlo):

$item->content_multiple = get_post_meta( $item->ID, '_menu_item_content_multiple', false );

Ambas opciones son correctas, debes decidir cuál es mejor para organizar los datos dentro de tu proyecto.

Nota adicional: deberías hacer alguna sanitización antes de usar los datos de entrada, pero no conozco los requisitos para ti, aquí un ejemplo:

array_map( 'sanitize_text_field', wp_unslash( $_REQUEST['menu-item-content-multiple'][$menu_item_db_id] ) );
19 oct 2016 13:01:35
Comentarios

Gracias, ¿debo usar false en lugar de true? Pero también usaste true en get_post_meta !!!

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

Según está tu código, no, debes usar el método serialize y unserialize. Para poder usar false en get_post_meta() deberías también guardar cada valor de tu select en una entrada separada en la base de datos, con la misma clave pero múltiples veces, es decir, usar update_post_meta() para cada valor pero siempre con la misma clave; entonces podrías usar false en get_post_meta() para obtener todos ellos. Espero que entiendas lo que quiero decir.

cybmeta cybmeta
19 oct 2016 13:50:05

He actualizado la respuesta con, espero, una mejor explicación.

cybmeta cybmeta
19 oct 2016 13:59:53

Gracias, tu publicación resolvió el mensaje de error, edité mi publicación y agregué un cuadro de selección de campo personalizado como en mi archivo. Pero el problema es que cuando selecciono múltiples opciones después de guardar la configuración, solo se guarda la última opción y no todas las opciones seleccionadas. ¿Por qué? ¿Hay algún error al usar la función selected() de WordPress? <?php echo selected(in_array($key, $item->content_multiple)); ?> (usé tu segunda opción de código)

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

Ten en cuenta que para usar múltiples entradas para la misma clave meta, debes ejecutar update_post_meta() para cada valor, pero usando la misma clave cada vez, como hice en la respuesta.

cybmeta cybmeta
19 oct 2016 15:21:03

Sí, quiero múltiples entradas para la misma clave meta, pero no sé cómo usar este método. Por favor ayúdame y explícame esto con código

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

Continuemos esta discusión en el chat.

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

Lo siento cybmeta, pero tengo otro problema con deseleccionar opciones. Cuando quiero deseleccionar una opción ya seleccionada, después de guardar la configuración permanece seleccionada y no puedo deseleccionar ninguna opción después de la selección.

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

Simplemente usa delete_post_meta() cuando lo necesites. He añadido un ejemplo básico.

cybmeta cybmeta
20 oct 2016 10:39:08

Gracias, funciona pero no puedo eliminar todas las opciones seleccionadas y también permanece la primera opción seleccionada. El delete_post_meta no elimina la primera opción seleccionada.

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

WordPress serializa/deserializa automáticamente los datos de arrays en un solo campo meta (al igual que las funciones de opciones), no deberías serializar/deserializar manualmente.

Milo Milo
20 oct 2016 18:10:16

@Milo por qué el delete_post_meta en esta respuesta no deselecciona o elimina la primera opción seleccionada.

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

@Milo, buen ojo, estaba confundido con la explicación en el codex y en el portal de desarrolladores, pero al ver el código fuente, puedo confirmar que WordPress automáticamente hace el serialize/unserialize por nosotros; respuesta actualizada.

cybmeta cybmeta
21 oct 2016 09:59:41

@ShwanNamiq creo que sería mejor si publicas una nueva pregunta para tu nuevo problema.

cybmeta cybmeta
21 oct 2016 10:10:47
Mostrar los 9 comentarios restantes
6

No estás usando la función selected() correctamente. selected() necesita 1 parámetro obligatorio y 2 opcionales. En tu caso, es mejor usar $selected y $current.

Te falta el guión bajo antes del nombre de tu meta-campo en el nombre del select.

Para selected():

selected( $selected, $current, $echo);

Puedes leer más sobre esto en la referencia del codex referencia de función selected()

Tu select debe ser así:

<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
Comentarios

Usé tu código pero también muestra el error, creo que el error está en $item->content_multiple, debe guardarse como array porque $item->content_multiple también guarda un solo valor y no guarda más de un valor como array

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

Ok, verifica que el nombre de tu meta-field sea siempre el mismo, actualmente no lo es. Si quieres que tenga un prefijo de guión bajo, siempre usa este guión bajo, y nombra tu select con guión bajo o con guión. update_post_meta funciona pero no se guardará ningún valor.

Benoti Benoti
19 oct 2016 12:26:45

Agregué más de 10 campos como el campo de arriba, todos funcionan sin ningún problema. Digo que el error está en $item->content_multiple porque este campo también guarda un valor único y no guarda más de un valor al mismo tiempo porque no se actualiza como array. Antes del bucle foreach, cuando pongo $item->content_multiple = array(); funciona y no me muestra ningún error pero no guarda los valores

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

No estoy completamente seguro, pero verifica el tipo de $item, ¿es un objeto o un array? El contenido dentro es un array, pero intenta convertirlo en un array para la función in_array, antes del bucle foreach (array)$item y en el selected() úsalo como un array así: $item['content_multiple']

Benoti Benoti
19 oct 2016 12:50:11

$item es un objeto, no un array()

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

in_array() solo acepta un array como segundo parámetro. Necesitas convertir tu objeto en un array así: (array)$item, pero deja el tercer argumento de get_post_meta como true (para obtener el objeto y luego podrás convertirlo)

Benoti Benoti
19 oct 2016 15:16:32
Mostrar los 1 comentarios restantes