Campos de entrada dinámicos en widgets de WordPress

18 minutos de lectura

avatar de usuario
Hombre de la lluvia

Estoy tratando de crear campos de entrada dinámicos para un conjunto de etiquetas predefinidas en un widget personalizado para un tema en el que estoy trabajando. Quiero lograr algo como esto:

CourseName           FieldONE             FieldTWO
-------------------------------------------------------------
Chemistry            Sprint 2015          Summer 2015  ( - )
                     Spring 2016          Summer 2016  ( - )
                                                       ( + )
-------------------------------------------------------------
Biology              Sprint 2015          Summer 2015  ( - )
                     Fall 2015            Winter 2015  ( - )
                     Spring 2016          Summer 2016  ( - )
                                                       ( + )
--------------------------------------------------------------
Math                 Fall 2015            Winter 2015  ( - )
                                                       ( + )
--------------------------------------------------------------
Physics              Fall 2015            Winter 2015  ( - )
                                                       ( + )
--------------------------------------------------------------

dónde CourseName es Química, Biología, Matemáticas y Física (solo etiquetas predefinidas, máximo de 4) y FieldONE y FieldTWO son entradas dinámicas donde quiero ingresar diferentes términos para cada curso.

Así que si hago clic en ( + )dos campos FieldOne y FieldTWO se crean para esa etiqueta. Y si hago clic en el ( - )ambos campos se eliminan.

traté de usar esta esencia que crea una entrada dinámica similar a metabox, y hasta ahora obtuve esto:

<?php
/*
Plugin Name: Dynamic Fields Widget
Description: Dynamic Fields
Version: 0.0
Author: Rain Man
*/
// Creating the widget
class dynamic_widget extends WP_Widget
{
    public function __construct()
    {
        parent::__construct(
          // Base ID of your widget
          'dynamic_widget',

          // Widget name will appear in UI
          __('Dynamic Widget', 'dynamic_widget_domain'),

          // Widget description
          array('description' => __('Sample Dynamic Widget', 'dynamic_widget_domain'))
        );
    }

// widget
public function widget($args, $instance)
{
    $title = apply_filters('widget_title', $instance['title']);
// This is where you run the code and display the output
echo __('Hello, World!', 'dynamic_widget_domain');
    echo $args['after_widget'];
}

// form
public function form($instance)
{
    if (isset($instance[ 'title' ])) {
        $title = $instance[ 'title' ];
    } else {
        $title = __('New title', 'dynamic_widget_domain');
    }
// Widget admin form

    $repeatable_fields = array();
    $courses = array(
      'Chemistry'    => array(
        'coursecode'   => 'Chemistry 2059',
        'professor' => 'Dr. James Bond',
      ),
      'Biology'   => array(
        'coursecode'   => 'Biology 3029',
        'professor' => 'Dr. James Bond',
      ),
      'Math' => array(
        'coursecode'   => 'Math 2043',
        'professor' => 'Dr. James Bond',
      ),
      'Physics'  => array(
        'coursecode'   => 'Physics 2075',
        'professor' => 'Dr. James Bond',
      )
    );
     ?>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

<script type="text/javascript">
jQuery(document).ready(function( $ ){
  $( '#add-row' ).on('click', function() {
    var row = $( '.empty-row.screen-reader-text' ).clone(true);
    row.removeClass( 'empty-row screen-reader-text' );
    row.insertBefore( '#repeatable-fieldset-one tbody>tr:last' );
    return false;
  });

  $( '.remove-row' ).on('click', function() {
    $(this).parents('tr').remove();
    return false;
  });
});
</script>
<?php foreach ($courses as $course_key => $course_info) { ?>
<label><?php echo $course_info['coursecode']; ?></label>
<table id="repeatable-fieldset-one" width="100%">
<thead>
  <tr>
    <th width="40%">Fall Term</th>
    <th width="40%">Winter Term</th>
    <th width="8%"></th>
  </tr>
</thead>
<tbody>
<?php

if ($repeatable_fields) :

foreach ($repeatable_fields as $field) {
    ?>
<tr>
  <td><input type="text" class="widefat" name="name[]" value="<?php if ($field['name'] != '') {
    echo esc_attr($field['name']);
} ?>" /></td>

  <td>
  </td>

  <td><input type="text" class="widefat" name="url[]" value="<?php if ($field['url'] != '') {
    echo esc_attr($field['url']);
} else {
    echo '';
} ?>" /></td>

  <td><a class="button remove-row" href="#">Remove</a></td>
  <td><a id="add-row" class="button" href="#">Add</a></td>

</tr>
<?php

} else :
// show a blank one

?>
<tr>
  <td><input type="text" class="widefat" name="name[]" /></td>


  <td><input type="text" class="widefat" name="url[]" value="" /></td>

  <td><a class="button remove-row" href="#">Remove</a></td>
  <td><a id="add-row" class="button" href="#">Add</a></td>

</tr>
<?php endif; ?>
<? } ?>


<!-- empty hidden one for jQuery -->
<tr class="empty-row screen-reader-text">
  <td><input type="text" class="widefat" name="name[]" /></td>

  <td><input type="text" class="widefat" name="url[]" value="" /></td>

  <td><a class="button remove-row" href="#">Remove</a></td>
  <td><a id="add-row" class="button" href="#">Add</a></td>

</tr>
</tbody>
</table>
</p>
<?php

}

// update
public function update($new_instance, $old_instance)
{
    $instance = array();
    $instance['title'] = (!empty($new_instance['title'])) ? strip_tags($new_instance['title']) : '';

    return $instance;
}
} // Class dynamic_widget ends here

// Register and load the widget
function wpb_load_widget()
{
    register_widget('dynamic_widget');
}
add_action('widgets_init', 'wpb_load_widget');

y aquí hay una captura de pantalla:

ingrese la descripción de la imagen aquí

hay muchos problemas en este momento, primero el botón “Agregar” de javascript ya no funciona y no estoy seguro de cómo guardar los datos para acceder más tarde.

¿Alguna idea de cómo hacer campos de entrada dinámicos para las etiquetas? No tiene que ser similar al código de la esencia que compartí, pero sería mejor si podemos hacer que mis modificaciones funcionen.

  • En primer lugar, está agregando jQuery (y no correctamente), que generalmente no se requiere en WordPress y puede causar dolores de cabeza por conflicto

    –Tim Hallman

    13 de diciembre de 2016 a las 22:54

  • @TimHallman sí, esto es solo para probar, el javascript no funcionaba, así que lo estaba probando agregando una biblioteca jquery.

    – Hombre de la lluvia

    13 de diciembre de 2016 a las 23:13

  • hola @RainMan, necesitas que este widget sea visible en la interfaz, ¿verdad? y estos campos deben recopilar datos de los usuarios y ser accesibles para los usuarios administradores, ¿correcto?

    – Kresimir Pendic

    16 de diciembre de 2016 a las 12:18

  • @oserk sí, eso es correcto

    – Hombre de la lluvia

    16 de diciembre de 2016 a las 12:21

Prueba este código, lo probé y funciona. El código js debe insertarse en el pie de página, no en el widget; de lo contrario, el botón de clic se ejecutará dos veces.

En el widget de función (), verá el bucle para mostrar los valores de entrada.

    <?php
/*
Plugin Name: Dynamic Fields Widget
Description: Dynamic Fields
Version: 0.0
Author: Rain Man
*/
// Creating the widget
class dynamic_widget extends WP_Widget
{
    public $courses;
    public function __construct()
    {
        parent::__construct(
          // Base ID of your widget
          'dynamic_widget',

          // Widget name will appear in UI
          __('Dynamic Widget', 'dynamic_widget_domain'),

          // Widget description
          array('description' => __('Sample Dynamic Widget', 'dynamic_widget_domain'))
        );
        $this->courses = array(
          'Chemistry'    => array(
            'coursecode'   => 'Chemistry 2059',
            'professor' => 'Dr. James Bond',
          ),
          'Biology'   => array(
            'coursecode'   => 'Biology 3029',
            'professor' => 'Dr. James Bond',
          ),
          'Math' => array(
            'coursecode'   => 'Math 2043',
            'professor' => 'Dr. James Bond',
          ),
          'Physics'  => array(
            'coursecode'   => 'Physics 2075',
            'professor' => 'Dr. James Bond',
          )
        );
        add_action( 'in_admin_footer',array( $this,'jsfooter'));
    }
    public function jsfooter() {
    ?>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

    <script type="text/javascript">
    jQuery(document).ready(function( $ ){
        $(document ).off('click').on('click','div.open .add-row' , function() {

        var row = $(this).closest('tr').clone(true);
        row.find('input').each(function(){
            $(this).val("");
        });
        // row.insertBefore( '#repeatable-fieldset-one tbody>tr:last' );
        $(this).parents('tr').after(row);

        return false;
      });

      $( document).on('click',  'div.open .remove-row',function() {
          if ($(this).parents('tbody').find('tr').length >1) {
            $(this).parents('tr').remove(); 
        }
        return false;
      });
    });
    </script>
    <?php
    }

// widget
public function widget($args, $instance)
{
    $title = apply_filters('widget_title', $instance['title']);
// This is where you run the code and display the output
    foreach ($this->courses as $course_key => $course_info) {
        echo $course_info['coursecode'] .'<br>'; 
        foreach ($instance['repeat'][$course_key ]["fall"] as $k=>$field) {
            echo 'Fall Term ' . $field ."https://stackoverflow.com/";
            echo 'Winter Term ' . $instance['repeat'][$course_key ]["winter"][$k] .'<br>';
        }
    }

    echo $args['after_widget'];
}

// form
public function form($instance)
{
    if (isset($instance[ 'title' ])) {
        $title = $instance[ 'title' ];
    } else {
        $title = __('New title', 'dynamic_widget_domain');
    }
// Widget admin form
    $repeatable_fields= isset ( $instance['repeat'] ) ? $instance['repeat'] : array();
     ?>

<?php foreach ($this->courses as $course_key => $course_info) { ?>
<label><?php echo $course_info['coursecode']; ?></label>
<table id="repeatable-fieldset-one" width="100%">
<thead>
  <tr>
    <th width="40%">Fall Term</th>
    <th width="40%">Winter Term</th>
    <th width="8%"></th>
    <th width="8%"></th>
  </tr>
</thead>
<tbody>
<?php

if ($repeatable_fields[$course_key ]["fall"] || $repeatable_fields[$course_key ]["winter"]) :
foreach ($repeatable_fields[$course_key ]["fall"] as $k=>$field) {
    ?>
<tr>
  <td><input type="text" class="widefat" name="<?php echo $this->get_field_name( 'repeat' )?>[<?php echo $course_key;?>][fall][]" value="<?php echo $field; ?>" /></td>

  <td><input type="text" class="widefat" name="<?php echo $this->get_field_name( 'repeat' )?>[<?php echo $course_key;?>][winter][]" value="<?php echo $repeatable_fields[$course_key ]["winter"][$k]; ?>" /></td>

  <td><a class="button remove-row" href="#">Remove</a></td>
  <td><a class="button add-row" class="button" href="#">Add</a></td>

</tr>
<?php
} else :
// show a blank one

?>
<tr>
  <td><input type="text" class="widefat" name="<?php echo $this->get_field_name( 'repeat' )?>[<?php echo $course_key;?>][fall][]" /></td>


  <td><input type="text" class="widefat" name="<?php echo $this->get_field_name( 'repeat' )?>[<?php echo $course_key;?>][winter][]" value="" /></td>

  <td><a class="button remove-row" href="#">Remove</a></td>
  <td><a class="button add-row" class="button" href="#">Add</a></td>

</tr>
<?php endif; ?>
</tbody>
</table>
<?php } ?>


<!-- empty hidden one for jQuery -->

<?php

}

// update
public function update($new_instance, $old_instance)
{
    $instance = array();
    $instance['title'] = (!empty($new_instance['title'])) ? strip_tags($new_instance['title']) : '';
    $instance['repeat'] = array();

    if ( isset ( $new_instance['repeat'] ) )
    {
        foreach ( $new_instance['repeat'] as $k =>$value )
        {
                $instance['repeat'][$k] = $value;
        }
    }

    return $instance;
}
} // Class dynamic_widget ends here

// Register and load the widget
function wpb_load_widget()
{
    register_widget('dynamic_widget');
}
add_action('widgets_init', 'wpb_load_widget');

Los datos se almacenarán en $ instancia[‘repeat”] en una matriz como esa (para entender cómo hice el bucle)

    array (size=4)
  'Chemistry' => 
    array (size=2)
      'fall' => 
        array (size=1)
          0 => string 'AAA' (length=3)
      'winter' => 
        array (size=1)
          0 => string 'BBBBBBB' (length=7)
  'Biology' => 
    array (size=2)
      'fall' => 
        array (size=2)
          0 => string 'CCCCCC' (length=6)
          1 => string 'EEEEEEE' (length=7)
      'winter' => 
        array (size=2)
          0 => string 'DDDD' (length=4)
          1 => string 'FFFFFFFF' (length=8)
  'Math' => 
    array (size=2)
      'fall' => 
        array (size=1)
          0 => string 'GGGGGGG' (length=7)
      'winter' => 
        array (size=1)
          0 => string 'HHHHHH' (length=6)
  'Physics' => 
    array (size=2)
      'fall' => 
        array (size=1)
          0 => string 'IIIIIIIII' (length=9)
      'winter' => 
        array (size=1)
          0 => string 'JJJJJJJJ' (length=8)

  • Debo estar perdiendo algo, ¿cómo agrega nuevos campos y llama a get_field_name cuando lo hace con js?

    – nikksan

    26 de abril de 2018 a las 11:44

  • Está funcionando bien en la sección de widgets de wordpress. Pero no funciona con el panel de administración de Elementor debido a que javascript no se está cargando en la página de administración de Elementor. ¿Cómo puedo cargar javascript para Elementor?

    – rishikesh tadaka

    31 de diciembre de 2020 a las 17:30


Creo que personalizar este complemento puede servir para el propósito: https://wordpress.org/plugins/advanced-custom-fields-table-field/installation/

  • Prefiero no usar complementos adicionales

    – Hombre de la lluvia

    14 de diciembre de 2016 a las 7:38

  • @RainMan Si bien entiendo la necesidad de evitar complementos adicionales, Advanced Custom Fields es un complemento muy bien hecho, mantenido activamente y generalmente excelente. Si desea escribir campos personalizados, esta es la forma de hacerlo. Le ahorrará toneladas y toneladas de tiempo de creación de nuevos campos, lo que generalmente es una molestia para usted mismo y para mis propósitos es absolutamente necesario para cada proyecto de WordPress que hago. Básicamente me niego a hacer WordPress sin ACF. La licencia de desarrollo para la versión pro es una tarifa única. Te estarías disparando en el pie al evitar este complemento.

    – dave

    16 de diciembre de 2016 a las 17:43

Actualizado.

        <?php
        /*
        Plugin Name: Dynamic Fields Widget
        Description: Dynamic Fields
        Version: 0.0
        Author: Rain Man
        */
        // Creating the widget
        class dynamic_widget extends WP_Widget
        {
            public function __construct()
            {
                parent::__construct(
                  'dynamic_widget', __('Dynamic Widget', 'dynamic_widget_domain'),
                  array('description' => __('Sample Dynamic Widget', 'dynamic_widget_domain'))
                );
            }

        // widget
        public function widget($args, $instance)
        {
            $title = apply_filters('widget_title', $instance['title']);
            // This is where you run the code and display the output
            echo __('Hello, World!', 'dynamic_widget_domain');
            echo $args['after_widget'];
        }

        // form
        public function form($instance)
        {
            if (isset($instance[ 'title' ])) {
                $title = $instance[ 'title' ];
            } else {
                $title = __('New title', 'dynamic_widget_domain');
            }
        // Widget admin form

            $repeatable_fields = array();
            $courses = array(
              'Chemistry'    => array(
                'coursecode'   => 'Chemistry 2059',
                'professor' => 'Dr. James Bond',
                'id' => 'test1',
              ),
              'Biology'   => array(
                'coursecode'   => 'Biology 3029',
                'professor' => 'Dr. James Bond',
                    'id' => 'test2',
              ),
              'Math' => array(
                'coursecode'   => 'Math 2043',
                    'id' => 'test3',
              ),
              'Physics'  => array(
                'coursecode'   => 'Physics 2075',
                'id' => 'test4',
              )
            );

        $Inc=1;
        foreach ($courses as $course_key => $course_info) { 
            echo $Inc;
            ?>
        <label><?php echo $course_info['coursecode']; ?></label>
        <table id="repeatable-fieldset-<?php echo $course_info['id']; ?>" width="100%" class="tableclass">
        <thead>
          <tr>
            <th width="40%">Fall Term</th>
            <th width="40%">Winter Term</th>
            <th width="8%"></th>
          </tr>
        </thead>
        <tbody>
        <?php


          if ($repeatable_fields):

                foreach ($repeatable_fields as $field) {        ?>
                    <tr>
                      <td><input type="text" class="widefat" name="name[]" value="<?php if ($field['name'] != '') { echo esc_attr($field['name']);} ?>" /></td>
                      <td></td>
                      <td><input type="text" class="widefat" name="url[]" value="<?php if ($field['url'] != '') {   echo esc_attr($field['url']); } else { echo ''; } ?>" /></td>
                      <td><a class="button remove-row" href="#">Remove</a></td>
                      <td><a id="add-row" class="button addrowbtn" href="#">Add</a></td>
                    </tr>
                <?php   } 

        else:
        // show a blank one

        ?>
        <tr>
          <td><input type="text" class="widefat" name="name[]" /></td>
          <td><input type="text" class="widefat" name="url[]" value="" /></td>
          <td><a class="button remove-row" href="#">Remove</a></td>
          <td><a id="add-row" class="button addrowbtn" href="#">Add</a></td>
        </tr>
        <tr class="tablerowclone">
          <td><input type="text" class="widefat" name="name[]" /></td>
          <td><input type="text" class="widefat" name="url[]" value="" /></td>
          <td><a class="button remove-row" href="#">Remove</a></td>
          <td><a id="add-row" class="button addrowbtn" href="#">Add</a></td>
        </tr>

        <?php endif; } ?>
        <?  $Inc++; } ?>


        </tbody>
        </table>
        <style>
            .tablerowclone{display:none;}
            </style>

        </p>


        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

        <script type="text/javascript">
        jQuery(document).ready(function( $ ){
          jQuery(document).off().on('click',' .addrowbtn', function(event) {
               event.preventDefault();
            var row = jQuery(this).closest(".tableclass").find("tr:last").clone();

            row.removeClass( 'tablerowclone' );
            //row.insertBefore( '#repeatable-fieldset-one tbody>tr:last' );
            row.insertBefore(jQuery(this).closest(".tableclass").find("tbody tr.tablerowclone"));
            return false;
          });

          jQuery(document).on('click', '.remove-row' , function() {
            var RowLenth  = jQuery(this).closest("tbody").children().length;

                if(RowLenth>2){
                    jQuery(this).parents('tr').remove();                        
                }
            return false;
          });
        });
        </script>

        <?php
        }



    public function update($new_instance, $old_instance){
        $instance = array();
        $instance['title'] = (!empty($new_instance['title'])) ? strip_tags($new_instance['title']) : '';

        return $instance;
    }
 } 

function wpb_load_widget()
 {
  register_widget('dynamic_widget');
 }
add_action('widgets_init', 'wpb_load_widget');

avatar de usuario
Vel

        <?php
        /*
        Plugin Name: Dynamic Fields Widget
        Description: Dynamic Fields
        Version: 0.0
        Author: Rain Man
        */
        // Creating the widget
        class dynamic_widget extends WP_Widget
        {
            public function __construct()
            {
                parent::__construct(
                  'dynamic_widget', __('Dynamic Widget', 'dynamic_widget_domain'),
                  array('description' => __('Sample Dynamic Widget', 'dynamic_widget_domain'))
                );
            }

        // widget
        public function widget($args, $instance)
        {
            $title = apply_filters('widget_title', $instance['title']);
            // This is where you run the code and display the output
            echo __('Hello, World!', 'dynamic_widget_domain');
            echo $args['after_widget'];
        }

        // form
        public function form($instance)
        {
            if (isset($instance[ 'title' ])) {
                $title = $instance[ 'title' ];
            } else {
                $title = __('New title', 'dynamic_widget_domain');
            }
        // Widget admin form

            $repeatable_fields = array();
            $courses = array(
              'Chemistry'    => array(
                'coursecode'   => 'Chemistry 2059',
                'professor' => 'Dr. James Bond',
                'id' => 'test1',
              ),
              'Biology'   => array(
                'coursecode'   => 'Biology 3029',
                'professor' => 'Dr. James Bond',
                    'id' => 'test2',
              ),
              'Math' => array(
                'coursecode'   => 'Math 2043',
                    'id' => 'test3',
              ),
              'Physics'  => array(
                'coursecode'   => 'Physics 2075',
                'id' => 'test4',
              )
            );

        $Inc=1;
        foreach ($courses as $course_key => $course_info) { 
            echo $Inc;
            ?>
        <label><?php echo $course_info['coursecode']; ?></label>
        <table id="repeatable-fieldset-<?php echo $course_info['id']; ?>" width="100%" class="tableclass">
        <thead>
          <tr>
            <th width="40%">Fall Term</th>
            <th width="40%">Winter Term</th>
            <th width="8%"></th>
          </tr>
        </thead>
        <tbody>
        <?php


          if ($repeatable_fields):

                foreach ($repeatable_fields as $field) {        ?>
                    <tr>
                      <td><input type="text" class="widefat" name="name[]" value="<?php if ($field['name'] != '') { echo esc_attr($field['name']);} ?>" /></td>
                      <td></td>
                      <td><input type="text" class="widefat" name="url[]" value="<?php if ($field['url'] != '') {   echo esc_attr($field['url']); } else { echo ''; } ?>" /></td>
                      <td><a class="button remove-row" href="#">Remove</a></td>
                      <td><a id="add-row" class="button addrowbtn" href="#">Add</a></td>
                    </tr>
                <?php   } 

        else:
        // show a blank one

        ?>
        <tr>
          <td><input type="text" class="widefat" name="name[]" /></td>
          <td><input type="text" class="widefat" name="url[]" value="" /></td>
          <td><a class="button remove-row" href="#">Remove</a></td>
          <td><a id="add-row" class="button addrowbtn" href="#">Add</a></td>
        </tr>
        <tr class="tablerowclone">
          <td><input type="text" class="widefat" name="name[]" /></td>
          <td><input type="text" class="widefat" name="url[]" value="" /></td>
          <td><a class="button remove-row" href="#">Remove</a></td>
          <td><a id="add-row" class="button addrowbtn" href="#">Add</a></td>
        </tr>

        <?php endif; } ?>
        <?  $Inc++; } ?>


        </tbody>
        </table>
        <style>
            .tablerowclone{display:none;}
            </style>

        </p>


        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

        <script type="text/javascript">
        jQuery(document).ready(function( $ ){
          jQuery(document).off().on('click',' .addrowbtn', function(event) {
               event.preventDefault();
            var row = jQuery(this).closest(".tableclass").find("tr:last").clone();

            row.removeClass( 'tablerowclone' );
            //row.insertBefore( '#repeatable-fieldset-one tbody>tr:last' );
            row.insertBefore(jQuery(this).closest(".tableclass").find("tbody tr.tablerowclone"));
            return false;
          });

          jQuery(document).on('click', '.remove-row' , function() {
            var RowLenth  = jQuery(this).closest("tbody").children().length;

                if(RowLenth>2){
                    jQuery(this).parents('tr').remove();                        
                }
            return false;
          });
        });
        </script>

        <?php
        }



    public function update($new_instance, $old_instance){
        $instance = array();
        $instance['title'] = (!empty($new_instance['title'])) ? strip_tags($new_instance['title']) : '';

        return $instance;
    }
 } 

function wpb_load_widget()
 {
  register_widget('dynamic_widget');
 }
add_action('widgets_init', 'wpb_load_widget');

Actualizado

parece que funciona bien.

El principal problema que encontré personalmente fue no poder usar
$this->get_field_name( '{{field}}' ) al crear dinámicamente filas usando js. Aquí está mi solución al problema:

function getFieldName(field){
    var pattern = '<?=$this->get_field_name( "{{field}}" )?>';
    return pattern.replace('{{field}}', field);
}

Sé que esta no era tu pregunta, pero aun así puede ayudar a alguien.

¿Ha sido útil esta solución?