WordPress.org

Make WordPress Core

Opened 3 years ago

Closed 3 years ago

Last modified 3 years ago

#37270 closed defect (bug) (fixed)

Improve handling of active state for dynamically-created controls/sections/panels

Reported by: westonruter Owned by: westonruter
Milestone: 4.7 Priority: normal
Severity: normal Version: 4.0
Component: Customize Keywords: has-patch
Focuses: javascript Cc:
PR Number:

Description (last modified by westonruter)

When a control, section, or panel is dynamically created in JS and doesn't have a corresponding construct that gets created in PHP, then when the preview refreshes the construct won't be included among the activeControls, activeSections, or activePanels and so it will get its active state set to false. A workaround as used for nav menu items is to define control.active.validate to override whatever is being sent from the preview:

control.active.validate = function() {
        var value, section = api.section( control.section() );
        if ( section ) {
                value = section.active();
        } else {
                value = false;
        }
        return value;
};

The problematic code in Core is:

var active = !! ( activeConstructs && activeConstructs[ id ] );

This is not ideal, and it means that a plugin cannot programmatically do control.active.set( false ).

As suggested in an issue on Customize Posts, we could improve the situation by discontinuing from considering constructs that are absent in the preview when determining whether to change the active state, which would specifically be for any constructs that are dynamically created:

var active, isDynamicallyCreated;
if ( ! _.isUndefined( activeConstructs[ id ] ) {
    active = _.isUndefined( activeConstructs[ id ];
} else {
    isDynamicallyCreated = ! _.isUndefined( wp.customize.settings[ type + 's' ][ id ] );
    active = isDynamicallyCreated ? null : false;
}
if ( _.isBoolean( active ) ) {
...

Contextual controls were introduced in #27993 with contextual sections/panels in #29758.

Attachments (2)

37270-patch.diff (847 bytes) - added by sayedwp 3 years ago.
Prevents dynamically created constructs from getting deactivated.
37270.3.diff (1.5 KB) - added by westonruter 3 years ago.

Download all attachments as: .zip

Change History (7)

#1 @westonruter
3 years ago

  • Description modified (diff)
  • Keywords needs-patch added
  • Version set to 4.0

@sayedwp
3 years ago

Prevents dynamically created constructs from getting deactivated.

#2 @sayedwp
3 years ago

@westonruter Can we do it more simply like this

var isDynamicallyCreated = _.isUndefined( wp.customize.settings[ type + 's' ][ id ] ),
    active = ! _.isUndefined( activeConstructs[ id ] );

if ( ! isDynamicallyCreated ) {
   if ( active ) {
     construct.activate();
   } else {
     construct.deactivate();
   }
}
Last edited 3 years ago by sayedwp (previous) (diff)

#3 @westonruter
3 years ago

  • Keywords has-patch added; needs-patch removed
  • Milestone changed from Future Release to 4.7
  • Owner set to westonruter
  • Status changed from new to accepted

@sayedwp that does look good!

@westonruter
3 years ago

#4 @westonruter
3 years ago

  • Resolution set to fixed
  • Status changed from accepted to closed

In 38464:

Customize: Improve handling of active state for dynamically-created controls/sections/panels.

When a customizer construct (panel, section, control) is not added in PHP, the JS has interpreted this to mean that a given construct should be deactivated (because it is gone). This is problematic for dynamically-created constructs in JS, as it has meant that the construct would also have to be created in PHP to ensure the active callback is called, or else a hack would be required to add a construct.active.validate = function() { return true }; to forcibly prevent the construct from getting deactivated.

These workarounds can be eliminated by treating constructs differently when they are created dynamically in JS (after page load) as opposed to being created statically in PHP (on the server). Namely, if a construct is dynamically-created then its absence in a preview refresh should not signal that the construct should be deactivated. Rather, a dynamic construct should only have its activation state toggled if it has a corresponding construct created in PHP when the preview refreshes to explicitly indicate its active state. Otherwise, the management of the active state for a construct created in JS should also be the responsibility of client-side code.

Props westonruter, sayedwp.
Fixes #37270.

#5 @westonruter
3 years ago

Example code which can be eliminated once this is released: https://github.com/xwp/wp-customize-posts/pull/235/files

Note: See TracTickets for help on using tickets.