Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic input fields in WordPress widgets

I am trying to create dynamic input fields for set of predefined labels in a custom widget for a theme I am working on. I want to achieve something like this:

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  ( - )
                                                       ( + )
--------------------------------------------------------------

where CourseName is Chemistry , Biology, Math and Physics (only predefined labels, max of 4) and FieldONE and FieldTWO are dynamic inputs where I want to enter different terms for each course.

So if I click on ( + ), two fields FieldOne and FieldTWO are created for that label. And if I click the ( - ), both fields are deleted.

I tried to use this Gist which creates similar dynamic input as metabox, and so far I got this:

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

and here is a screenshot:

enter image description here

there are a lot of problems right now, first the javascript "Add" button no longer works and I am not sure how to save the data to access later.

any idea how to make dynamic input fields for the labels? It does not have to be similar to the code from the gist I shared, but it would be best if we can get my modifications to work.

like image 606
Rain Man Avatar asked Dec 11 '16 21:12

Rain Man


People also ask

How do you add input fields dynamically?

If you want to dynamically add elements, you should have a container where to place them. For instance, a <div id="container"> . Create new elements by means of document. createElement() , and use appendChild() to append each of them to the container.

How do I customize widgets in WordPress?

Using WordPress Custom WidgetGo to the Appearance menu, and select Widgets. You should see a widget named Hostinger Sample Widget in the Available Widgets list. Next, drag the widget and drop it in the Sidebar section on the right side of the page. Save your changes and visit your website.

How do I add a widget to a WordPress script?

Adding Custom Widget in WordPress Classic Editor There will be a new widget called 'WPBeginner Widget' in the list of available widgets. You need to drag and drop this widget into your sidebar. Then, enter a title and click 'Save' to save your widget settings. Your new custom widget will now be live on your website.


2 Answers

Try this code, I tested it and it works. The js code needs to be inserted in footer not in widget, otherwise the click button will be executed twice.

In the function widget(),you will see the loop to display the input values.

    <?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 .' / ';
            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');

The data will be stored in $instance['repeat"] in an array like that (to understand how I made the loop)

    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)
like image 115
Sofiane Achouba Avatar answered Oct 11 '22 16:10

Sofiane Achouba


I think customising this plugin may serve the purpose: https://wordpress.org/plugins/advanced-custom-fields-table-field/installation/

like image 45
Yashpal Puri Avatar answered Oct 11 '22 16:10

Yashpal Puri