Opened 3 years ago
Last modified 3 years ago
#53625 reopened defect (bug)
The 'explode' function does not work on widget block editor.
Reported by: | subrataemfluence | Owned by: | |
---|---|---|---|
Milestone: | Priority: | normal | |
Severity: | major | Version: | 5.8 |
Component: | Widgets | Keywords: | has-screenshots 2nd-opinion reporter-feedback |
Focuses: | administration | Cc: |
Description
The explode()
function does not seem to be working on the new Widget block editor. I am testing it on the RC-2 version.
I have created a simple widget that accepts Title, Description, and multiple selections from a Checkbox list items (Screenshots attached)
On selecting checkboxes, the values form a comma-separated string (e.g. 123456, 9822310, 457790 etc.) and stored in a textbox.
Inside the update()
function, I am exploding this string and storing the array as $instance['groups']
element, which in turn gets saved in the database (wp_options
table).
The functionality works as expected if I have the widgets-block-editor
support disabled. But when enabled, the explode()
function is not working and nothing is in $instance['groups]
.
<?php public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title'] = strip_tags( $new_instance['title'] ); $instance['about'] = strip_tags( $new_instance['about'] ); $groups = $new_instance['groups']; // the following line is not working and creating an empty array // when widgets-block-editor support is enabled. $instance['groups'] = array_pop ( explode( ',', $groups ) ); return $instance; }
Database:
a:2:{i:2;a:3:{s:5:"title";s:15:"Product Channel";s:5:"about";s:41:"When you subscribe to our Product Channel";s:6:"groups";a:3:{i:0;s:6:"237500";i:1;s:6:"457844";}}s:12:"_multiwidget";i:1;}
However, the values get stored with block editor support enabled as a comma-separated string without the explode()
function, i.e.
<?php public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title'] = strip_tags( $new_instance['title'] ); $instance['about'] = strip_tags( $new_instance['about'] ); $instance['groups'] = $new_instance['groups']; return $instance; }
Attachments (3)
Change History (17)
@
3 years ago
The Widget with block editor support enabled. The explode() function does not work. Getting an empty array
#1
@
3 years ago
Record in the database with widgets-block-editor
support disabled:
a:2:{i:2;a:3:{s:5:"title";s:15:"Product Channel";s:5:"about";s:41:"When you subscribe to our Product Channel";
s:6:"groups";a:3:{i:0;s:6:"237500";i:1;s:6:"457844";}
}s:12:"_multiwidget";i:1;}
And this is what I get with widgets-block-editor
support enabled:
a:2:{i:2;a:3:{s:5:"title";s:15:"Product Channel";s:5:"about";s:41:"When you subscribe to our Product Channel";
s:6:"groups";
s:0:"";}s:12:"_multiwidget";i:1;}
Please notice, there is nothing under groups in the second record.
This ticket was mentioned in Slack in #core by subratasarkar. View the logs.
3 years ago
#3
follow-up:
↓ 4
@
3 years ago
- Keywords reporter-feedback added
HI @subrataemfluence thanks for posting the problem, it's very helpful. Reading the ticket, I believe it's unlikely that explode
is the problem. Most likely something about $groups = $new_instance['groups'];
could be different with the block editor enabled. I'd like to ask you for three things, please:
1) Can you add verbatim what you send to register_widget
for this widget?
2) Could you var_dump
, or inspect in xcode, $groups = $new_instance['groups'];
with and without the block editor enabled? What is the value of $new_instancegroups? in these cases?
3) When is the comma-separated string formed? Clientside or after save?
Alternatively you could attach the entire widget code so we could test without the back and forth.
Thank you!
#4
in reply to:
↑ 3
@
3 years ago
Hi Andrei thanks very much for looking into this! Yes, you are right, explode()
might not be the only one. Because I faced the issue with this, I mentioned it.
3) The comma-separated string is formed clientside when I select/unselect the checkboxes.
I will work on 1 and 2 tomorrow and add as much information I can collect.
Replying to andraganescu:
HI @subrataemfluence thanks for posting the problem, it's very helpful. Reading the ticket, I believe it's unlikely that
explode
is the problem. Most likely something about$groups = $new_instance['groups'];
could be different with the block editor enabled. I'd like to ask you for three things, please:
1) Can you add verbatim what you send to
register_widget
for this widget?
2) Could you
var_dump
, or inspect in xcode,$groups = $new_instance['groups'];
with and without the block editor enabled? What is the value of $new_instancegroups? in these cases?
3) When is the comma-separated string formed? Clientside or after save?
Alternatively you could attach the entire widget code so we could test without the back and forth.
Thank you!
#5
@
3 years ago
Hi, @andraganescu here is the codebase. Please let me know if I need to provide anything else.
The widget is built as a separate file (widget.php) and has been required
in a file called setup.php
. This file also enqueues the JavaScript that I am using. The file structure is like this:
[ A ]
File:
wp-content/plugins/platform-subscribers/index.php
Content:
<?php require_once 'setup.php';
[ B ]
File:
wp-content/plugins/platform-subscribers/setup.php
Content:
<?php require_once 'widget.php'; function ps_load_widget() { $platform_subscriber = new PlatformSubscriber(); register_widget( $platform_subscriber ); } add_action( 'widgets_init', 'ps_load_widget' ); function enqueue_plugin_scripts() { wp_enqueue_script( 'ps-settings', plugins_url( '/ps-settings.js', __FILE__ ), array( 'jquery' ), '1.0', false ); } add_action( 'admin_enqueue_scripts', 'enqueue_plugin_scripts' );
[ C ]
File:
wp-content/plugins/platform-subscribers/widget.php
Content:
<?php class PlatformSubscriber extends WP_Widget { public function __construct() { $id_base = 'platform_subscriber'; $widget_options = array( 'classname' => 'platform_subscriber', 'description' => 'Creates an email signup form for your visitors.' ); $control_options = array( 'width' => 400, 'id_base' => $id_base ); parent::__construct( $id_base, __( 'Platform Subscriber', 'ps_platform' ), $widget_options, $control_options ); } /** * @param array $instance * * @return string|void * Widget backend. */ public function form( $instance ) { $this->create_backend_form( $instance ); } /** * @param array $new_instance * @param array $old_instance * * @return array * * Updating widget replacing old instance with new. */ public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title'] = strip_tags( $new_instance['title'] ); $instance['about'] = strip_tags( $new_instance['about'] ); $groups = $new_instance['groups']; $instance['groups'] = array_pop ( explode( ',', $groups ) ); return $instance; } /** * @param array $args * @param array $instance * * Create the widget front-end. * Will add the actual functionality later */ public function widget( $args, $instance ) { $title = apply_filters( 'widget_title', $instance['title'] ); echo $args['before_widget']; if( ! empty( $title ) ) { echo $args['before_title'] . $title . $args['after_title']; } echo __( 'Hello World!', 'ps_platform' ); echo $args['after_widget']; } /** * @param $instance * Creates the backend form */ protected function create_backend_form( $instance ) { if( ! isset( $instance['title'] ) ) { $title = __( 'New Platform Title', 'ps_platform' ); } else { $title = $instance['title']; } if( ! isset( $instance['about'] ) ) { $about = ''; } else { $about = esc_html( $instance['about'] ); } if( ! isset( $instance['groups'] ) ) { $selectedGroups = ''; } else { $selectedGroups = $instance['groups']; } ?> <p> <label for="<?= $this->get_field_id( 'title' ); ?>"> <?php _e( 'Title ' ) ?> * </label> <input class="widefat" type="text" required id="<?= $this->get_field_id( 'title' ); ?>" name="<?= $this->get_field_name( 'title' ) ?>" value="<?= esc_attr( $title ) ?>" /> </p> <p> <label for="<?= $this->get_field_id( 'about' ) ?>"> <?php _e( 'Description' ) ?> </label> <textarea class="widefat" name="<?= $this->get_field_name( 'about' ) ?>" id="<?= $this->get_field_id( 'about' ) ?>" cols="30" rows="3" maxlength="150" required placeholder="Help text for visitor"><?= $about ?></textarea> </p> <div> <p> <input type="checkbox" id="<?= $this->get_field_id('online-conference-ticket') ?>" name="<?= $this->get_field_name('online-conference-ticket') ?>" value="396060" onclick="updateSelection( this, <?= $this->number ?> );" /> <label id="label-<?= $this->get_field_id('online-conference-ticket') ?>" for="<?= $this->get_field_id('online-conference-ticket') ?>" onclick="updateSelection( this, <?= $this->number ?> );"> Online Conference Ticket </label> </p> <p> <input type="checkbox" id="<?= $this->get_field_id('marketing-platform-demo') ?>" name="<?= $this->get_field_name('marketing-platform-demo') ?>" value="237500" onclick="updateSelection( this, <?= $this->number ?> );" /> <label id="label-<?= $this->get_field_id('marketing-platform-demo') ?>" for="<?= $this->get_field_id('marketing-platform-demo') ?>" onclick="updateSelection( this, <?= $this->number ?> );"> Marketing Platform Demo </label> </p> <p> <input type="checkbox" id="<?= $this->get_field_id('beer-online-conference') ?>" name="<?= $this->get_field_name('beer-online-conference') ?>" value="457844" onclick="updateSelection( this, <?= $this->number ?> );" /> <label id="label-<?= $this->get_field_id('beer-online-conference') ?>" for="<?= $this->get_field_id('beer-online-conference') ?>" onclick="updateSelection( this, <?= $this->number ?> );"> Beer Online Conference </label> </p> </div> <p> <label for="<?= $this->get_field_id( 'groups' ) ?>"> <?php _e( 'Selected groups' ) ?> * </label> <input class="widefat" type="text" required id="<?= $this->get_field_id( 'groups' ); ?>" name="<?= $this->get_field_name( 'groups' ) ?>" value="<?= esc_attr( $selectedGroups ) ?>" /> </p> <?php } }
[ D ]
File:
wp-content/plugins/platform-subscribers/ps-settings.js
Content:
function updateSelection( obj, widget_number ) { var selectedGroupsBoxId = 'widget-platform_subscriber-' + widget_number + '-groups'; var parentDiv = jQuery(obj).closest( 'div' ); var commaGroups = ''; jQuery( parentDiv ).find( 'input:checked' ).each( function() { commaGroups = commaGroups + jQuery(this).attr('value') + ','; } ); jQuery( '#' + selectedGroupsBoxId ).val( commaGroups ); }
#6
@
3 years ago
I don't think this is actually breaking anything, but it's worth pointing out that here:
<?php $instance['groups'] = array_pop ( explode( ',', $groups ) );
A warning is logged:
Only variables can be passed by reference
Because array_pop expects to receive a variable, not a value.
#7
@
3 years ago
- Milestone Awaiting Review deleted
- Resolution set to invalid
- Status changed from new to closed
The problem is a bug in the PlatformSubscriber widget. See the debugger screenshot above.
- The backend receives a value like "396060," and calls
array_pop( explode( ",", $groups ) )
explode()
returns["396060", ""]
array_pop()
pops""
- An empty string of length 0 is stored in the database
I'll close this ticket because it does not seem to be a problem with the widgets editor. Feel free to bring up anything I may have missed.
#8
@
3 years ago
- Resolution invalid deleted
- Status changed from closed to reopened
- Summary changed from The 'explode' function does not work on widget block editor. to The 'explode' function or something else does not work on widget block editor.
Hi @zieladam thanks for looking into the array_pop()
thing. It was a mistake which now I have corrected and no more empty string.
But I am almost certain that either the explode()
functionality is not working or there is something else that is preventing it from working properly in widget block mode. Because everything works as expected when the block support is removed from the theme.
So I am reopening the ticket with more test cases and their results.
Here are my test cases:
<?php function update( $old_instance, $new_instance ) { $instance = $old_instance; $instance['title'] = strip_tags($new_instance['title']); $instance['about'] = strip_tags($new_instance['about']); $instance['groups'] = $new_instance['groups']; return $instance; }
In the above code, I am simply assigning the coma-separated value (100,200,300...) to $instance['groups']
and this saves fine both with and without the widgets-block-editor
theme support. This also proves that the comma-separated values generated at the client-side are properly read.
Then I incorporated the explode()
function:
<?php function update( $old_instance, $new_instance ) { $instance = $old_instance; $instance['title'] = strip_tags($new_instance['title']); $instance['about'] = strip_tags($new_instance['about']); $instance['groups_string'] = $new_instance['groups']; $instance['groups_object'] = explode( ',', $new_instance['groups'] ); return $instance; }
The above snippet works perfectly fine when widgets-block-editor
support is turned off. Here is the record that is saved in the database:
a: 2: { i: 2;a: 4: { s: 5: "title";s: 18: "New Platform Title"; s: 5: "about";s: 0: ""; s: 13: "groups_str";s: 20: "396060,237500,457844"; s: 13: "groups"; a: 3: { i: 0;s: 6: "396060"; i: 1;s: 6: "237500"; i: 2;s: 6: "457844"; } } s: 12: "_multiwidget";i: 1; }
But, whenever I turn it on, either the explode function is not working or something else happening in the background prevents the groups from being saved. The same code above ends up with the following:
a: 2: { i: 2;a: 4: { s: 5: "title";s: 18: "New Platform Title"; s: 5: "about";s: 0: ""; s: 13: "groups_str";s: 20: "396060,237500,457844"; s: 13: "groups";N; } s: 12: "_multiwidget";i: 1; }
There is another strange behavior that I have experienced with the following snippet:
<?php function update( $old_instance, $new_instance ) { $instance = $old_instance; $instance['title'] = strip_tags($new_instance['title']); $instance['about'] = strip_tags($new_instance['about']); $instance['groups_str'] = $new_instance['groups']; $instance['groups'] = explode( ',', $new_instance['groups'] ); return $instance; }
With the theme support enabled, the output becomes:
a: 2: { i: 2;a: 4: { s: 5: "title"; s: 18: "New Platform Title"; s: 5: "about";s: 0: ""; s: 10: "groups_str";a: 2: { i: 0;s: 6: "396060"; i: 1;s: 6: "237500"; } s: 6: "groups";N; } s: 12: "_multiwidget";i: 1; }
The interesting thing in the above output is the value of groups_str. In the code, I have $instance['groups_str'] = $new_instance['groups'];
meaning I am expecting the value to be saved as a string, i.e. 396060,237500
, but surprisingly it is saving as an array. And the next line of code, which is supposed to save the array is actually saving nothing "groups";N;
And this also proves that the value generated by JavaScript is properly read even with the theme support enabled. Just to confirm, that the last snippet of code is working exactly the way I want when theme support is removed.
The question is why the same code is not working in the same way! At least I cannot see any logical issue in widget.php
.
#9
@
3 years ago
- Summary changed from The 'explode' function or something else does not work on widget block editor. to The 'explode' function does not work on widget block editor.
#11
@
3 years ago
- Resolution set to invalid
- Status changed from reopened to closed
@subrataemfluence The signature of update
in WordPress core is as follows:
function update( $new_instance, $old_instance );
However, in your sample, I see it's
function update( $old_instance, $new_instance )
Notice how the arguments are reversed. So when you do $instance['groups'] = explode( ',', $new_instance['groups'] );
the second argument comes from the old widget instance and is already an array.
When I switch the arguments order, it works like a charm.
I did not get to the bottom of the discrepancy between the old editor and the new editor because that seems to be a problem only when the signature is wrong, but I'm happy to keep looking if something still isn't right. I am going to close this one again just to keep things tidy, but don't take it as me pushing for closure. Absolutely feel free to reopen if there are still some problems left to explore here.
#13
@
3 years ago
Thanks for your detailed reply @zieladam . But IMO there is something wrong.
I am trying to shorten down the area of interest in the code and only with editor support enabled. Please look at the following code snippet:
<?php public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title'] = strip_tags($new_instance['title']); $instance['about'] = strip_tags($new_instance['about']); // Please see the following lines... $instance['groups_str'] = $new_instance['groups']; $instance['groups'] = explode( ',', $new_instance['groups'] ); }
The above code creates the following record in the database:
a:2:{i:2;a:4:{s:5:"title";s:18:"New Platform Title";s:5:"about";s:0:"";s:10:"groups_str";a:2:{i:0;s:6:"237500";i:1;s:6:"457844";}s:6:"groups";N;}s:12:"_multiwidget";i:1;}
Please note, the record saved has an array with the groups ID, i.e.
"groups_str";a:2:{i:0;s:6:"237500";i:1;s:6:"457844";}
But the most noticeable thing here is $instance['groups_str']
is assigned the comma separated string value, not an array, but still it is saving the values as an array in the database!! While, I am expecting the $instance['groups']
to have the array saved against it, but all I get is an 'N'!
Moving forward, if I take out one line ($instance['groups'] = explode( ',', $new_instance['groups'] );
) from the above snippet to make the function to read:
<?php public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title'] = strip_tags($new_instance['title']); $instance['about'] = strip_tags($new_instance['about']); // Please see the following lines... $instance['groups_str'] = $new_instance['groups']; }
the record saved in the database is:
a:2:{i:2;a:3:{s:5:"title";s:18:"New Platform Title";s:5:"about";s:2:"wd";s:10:"groups_str";N;}s:12:"_multiwidget";i:1;}
Please note. I did not change anything in the following line:
$instance['groups_str'] = $new_instance['groups'];
.
I believe there are issues and could be inspected more. At least this is what I am experiencing so far.
My development environment:
WordPress version: Beta RC-4
Theme: 2021 (up to date)
Plugins: Widget plugin I am building
One more thing. The order of the arguments for update method was written wrong in my previous message, but they were correct in the code. Sorry for this confusion.
The Widget in classic mode with block editor support disabled. The comma-separated IDs are rightly converted into an array and saved in the database