Opened 11 years ago
Closed 11 years ago
#27993 closed enhancement (fixed)
Support for contexts in the Customizer
Reported by: |
|
Owned by: | |
---|---|---|---|
Milestone: | 4.0 | Priority: | normal |
Severity: | normal | Version: | |
Component: | Customize | Keywords: | has-patch commit |
Focuses: | ui, javascript | Cc: |
Description
To provide contextually-relevant customization experiences, it would be nice if Customizer sections and controls supported contexts like is_home()
or is_singular()
.
Attachments (2)
Change History (31)
This ticket was mentioned in IRC in #wordpress-dev by danielbachhuber. View the logs.
11 years ago
#3
@
11 years ago
This is what I ended up with: https://github.com/INN/Largo/pull/228/files
I suppose the scope of this ticket would be able to register one or more contexts with a section or control, and have the Customizer do essentially this PR behind the scenes.
#5
@
11 years ago
Yes. Love this. It could be as simple as the Customizer Section or Customizer Control taking a callback argument that returns true
or false
based on whether or not it is relevant to the currently-previewed URL. Each section and control could be iterated over in the preview, and the callbacks could be fired and then exported to the parent customizer frame which in turn would toggle the visibility of the respective Sections and Controls. (We may want to use the Customizer Setting instead of the Customizer Control for attaching these context callbacks, as I believe this would more easily facilitate dynamically-created Controls since the settings are what get POSTed to the preview, not the controls.)
Just to note that the Widget Customizer takes this same approach of passing upstream the context (which dynamic_sidebar()
calls are used at the previewed URL), but it's now using postMessage
passing instead of doing direct cross-frame communication. We were using cross-frame communication initially and I never encountered a problem with cross-domain security (since the previewed is rendered via document.write()
), but just to be safe we used the message passing system that the Customizer makes available.
IFRAME: customize-preview-widgets.js
this.preview.bind( 'active', function() { self.preview.send( 'rendered-sidebars', self.renderedSidebars ); self.preview.send( 'rendered-widgets', self.renderedWidgets ); } );
Customizer parent frame: customize-widgets.js
// Update widget control to indicate whether it is currently rendered api.Widgets.Previewer.bind( 'rendered-widgets', function( renderedWidgets ) { var isRendered = !! renderedWidgets[self.params.widget_id]; self.container.toggleClass( 'widget-rendered', isRendered ); } ); /* ... */ // Update the model with whether or not the sidebar is rendered api.Widgets.Previewer.bind( 'rendered-sidebars', function( renderedSidebars ) { var isRendered = !! renderedSidebars[self.params.sidebar_id]; registeredSidebar.set( 'is_rendered', isRendered ); } );
#6
@
11 years ago
@danielbachhuber: Regarding the need to reduce clutter in the Customizer by not always showing all sections (e.g. hiding global ones), one approach is suggested in #27406 where we could introduce a Customizer Section Page, or even just electing for certain Customizer Sections to open in a maximized view, where all other sections are removed from view until the user goes back up a level.
#7
@
11 years ago
When implemented, the Widget Customizer code referred to above should be reworked to leverage these generalized customizer contexts.
This ticket was mentioned in IRC in #wordpress-dev by westonruter. View the logs.
11 years ago
#9
follow-up:
↓ 19
@
11 years ago
- Focuses ui javascript added
- Keywords has-patch added; needs-patch removed
- Milestone changed from Future Release to 4.0
In 27993.diff, introduce WP_Customize_Control::active()
to access whether the control is relevant to the current context (i.e. to the current URL being previewed). Control can indicate its active state by a subclass overriding the active_callback
method, by supplying a callable active_callback
argument into the control’s constructor, or by filtering customize_control_active
.
When the preview loads, the active controls are sent along with the ready
state as a activeControls
argument. Each control has a new active
state which gets toggled based on the corresponding values in activeControls
. By default, when a control's active
state becomes false
, the control will slideUp
, and then slideDown
when it becomes true
again. Controls may override this default toggle
behavior by overwriting this method.
I've implemented this new active
capability for Widget Customizer. The toggle
method for the WidgetControl
has been overridden to toggle the widget-rendered
class name on the control container, which results in the partially-faded widget control title for widgets that are not rendered in the current preview (e.g. for Jetpack's Widget Visibility). Likewise, the toggle
method for the SidebarControl
has also been overridden to toggle the visibility the containing Customizer section when the control's active
state is changed.
Ideally when all controls in a given section are not active
, the section would in general also collapse automatically. The same goes for the new Customizer panels (#27406). However, there is currently no JS models provided for managing the state of the Sections or Panels. I've filed #28709 to introduce these models.
For some examples.
To add a control which only appears on the front page, presumably because only the front-page.php
template renders the associated setting, you may supply is_front_page
as the active_callback
argument:
$wp_customize->add_control( 'front_page_greeting', array( 'label' => __( 'Greeting' ), 'section' => 'title_tagline', 'active_callback' => 'is_front_page', ) );
Alternatively, you may do so via a subclass:
class WP_Greeting_Control extends WP_Customize_Control { // ... function active_callback() { return is_front_page(); } }
Or you may do so via the customize_control_active
filter:
add_filter( 'customize_control_active', function ( $active, $control ) { if ( 'front_page_greeting' === $control->id ) { $active = is_front_page(); } return $active; }, 10, 2 );
In each case, the active_callback
will get fired when customize.php
initially loads, and then again when the preview loads (and for each page load as the user navigates around the site within the preview). Depending on of the control is expected to be hidden more than shown, then it may be desirable for the callback to return false
if is_admin()
so that it would be hidden by default, and then only appear when the user visits a URL for which the control is contextual.
#10
@
11 years ago
This is really awesome. Looking through the patch, the implementation is pretty solid. Having three different ways to specify the callback is really good, and they all fit within the existing API structures as I would expect. It lends itself to both simple usages like is_front_page
and complex ones like widgets well. And it's extendable on the JS side too.
We should make sure that the docs specify the priority of the different callback options, looks like it's: filter overrides subclass overrides parameter, which makes sense.
I think we should definitely be able to get this into 4.0.
This ticket was mentioned in IRC in #wordpress-dev by helen. View the logs.
11 years ago
#14
follow-up:
↓ 15
@
11 years ago
Maybe this is a newb mistake but I did some testing and couldn't get this to work. I applied the patch (I can see the updated source code applied), and modified a TwentyFourteen control (screenshot: http://cld.wthms.co/xG1I) with the active_callback
argument and no matter where I go on the site via the customizer I still see the control.
Am I doing something wrong here? Am I leaving something obvious out?
#15
in reply to:
↑ 14
@
11 years ago
Replying to BFTrick:
Maybe this is a newb mistake but I did some testing and couldn't get this to work. I applied the patch (I can see the updated source code applied), and modified a TwentyFourteen control (screenshot: http://cld.wthms.co/xG1I) with the
active_callback
argument and no matter where I go on the site via the customizer I still see the control.
Am I doing something wrong here? Am I leaving something obvious out?
Humm, works for me. Now that it has been committed to core, can you try again to see if your addition of the active_callback
argument to the featured_content_layout
control has the desired effect? Perhaps there was a problem with applying the patch.
I tried a similar test on the latest on trunk [29057], but used an active_callback
which returned a random true
/false
value. As expected, the control expanded and collapsed randomly as I navigated around the site in the customizer preview:
-
src/wp-content/themes/twentyfourteen/inc/customizer.php
function twentyfourteen_customize_register( $wp_customize ) { 54 54 'grid' => __( 'Grid', 'twentyfourteen' ), 55 55 'slider' => __( 'Slider', 'twentyfourteen' ), 56 56 ), 57 'active_callback' => function () { return (bool) rand( 0, 1 ); }, 57 58 ) ); 58 59 } 59 60 add_action( 'customize_register', 'twentyfourteen_customize_register' );
#16
@
11 years ago
Yep. Looks like it was a noob mistake. I used the 4.0-b1 release and it worked just fine. Well done sir. :)
#19
in reply to:
↑ 9
@
11 years ago
I'm coming to this late, so apologies in advance if this has already been addressed. A question regarding the following statement:
Replying to westonruter:
Ideally when all controls in a given section are not
active
, the section would in general also collapse automatically. The same goes for the new Customizer panels (#27406). However, there is currently no JS models provided for managing the state of the Sections or Panels. I've filed #28709 to introduce these models.
So that I'm clear about this enhancement, does this apply to both controls and sections or only controls? active_callback
currently works beautifully with add_control
but it does not seem to affect add_section
. I can see a case where entire sections are contextual, and custom controls (say, five or so) inside of a context-dependent section wouldn't need active_callback
if the add_section
call itself had active_callback
on it.
Again, sorry if I've missed something above or in other discussions. Want to make sure that I'm clear on this change, as I'm already implementing this against Core in a few themes. I'm a big fan of this enhancement.
#20
follow-up:
↓ 22
@
11 years ago
That would probably be how we'd want to do that - if the section is hidden, all of the controls inside of it would also be hidden, and vice-versa. But this isn't implemented at all for add_section
or add_panel
yet - that'll come once we get an expanded JS API to support it, hopefully in 4.1. For now, core support for contextual Customizer UI is limited to controls.
In 4.0, you have to manually hide empty sections where all controls are hidden, and although it's possible (widget areas do it), it's messy.
We'll likely try to use exactly the same API for contextual sections when we do get there. Worth noting that when we do implement it for sections we'll get it for panels with minimal extra work since panels are sections.
This ticket was mentioned in IRC in #wordpress-dev by celloexpressions. View the logs.
11 years ago
#22
in reply to:
↑ 20
@
11 years ago
Replying to celloexpressions:
That would probably be how we'd want to do that - if the section is hidden, all of the controls inside of it would also be hidden, and vice-versa. But this isn't implemented at all for
add_section
oradd_panel
yet - that'll come once we get an expanded JS API to support it, hopefully in 4.1. For now, core support for contextual Customizer UI is limited to controls.
Sounds great. Until a more section/panel-specific hiding mechanism is in place I think I'll hold off on trying to get too clever with sections that have controls that are all contextual. Seems like it'd be a lot of messy code, as you've said. Thanks for clearing everything up for me!
This ticket was mentioned in IRC in #wordpress-dev by celloexpressions. View the logs.
11 years ago
#24
@
11 years ago
- Resolution set to fixed
- Status changed from new to closed
Looks like this is holding up well. Please reopen with any issues until 4.0, or open a new ticket and reference this one.
#25
follow-up:
↓ 26
@
11 years ago
- Resolution fixed deleted
- Status changed from closed to reopened
Noticed this isn't fully back compat, the Jetpack "Social Links" Customizer panel controls are hidden after the changes in r29051. Looks like specifically the control.active.bind
"active" value is true during the Customizer load but false just as it ends loading.
To repeat:
- Activate latest Jetpack version (3.0.2) on an install of latest WP trunk (4.0-beta2-20140729)
- Enable "Publicize" module and connect to a social service like Twitter, Facebook, etc
- Go to Customizer and as the page loads, open the "Connect" panel -- you'll see the controls are visible
- Just before the page is loaded fully the controls disappear as
display: none
is added to the container element
#26
in reply to:
↑ 25
@
11 years ago
- Keywords commit removed
Replying to lancewillett: Looks like the problem here is that Jetpack checks is_admin()
before hooking to customize_register
. That code runs both on the customizer frame as well as the preview frame, and for the preview frame is_admin()
returns false, so the preview frame has really no idea about the registered controls.
Proposed fix in 27993.2.diff which doesn't touch controls that the preview frame has no information about. Here's also some simple plugin code to reproduce.
#27
@
11 years ago
- Keywords commit added
+1 for 27993.2.diff. This was also causing issues with dynamically-added controls in the Menu Customizer, and controls that aren't previewed. We should default to showing controls that the preview doesn't know about.
Only hooking into customize_register
if is_admin()
is not a good idea (considering several potential enhancements coming in the future), and simply is unnecessary. Generally, it's a bad idea to consider the Customizer to be part of wp-admin
; rather, it's its own thing that bridges the front-end and the admin, and will become more front-end-oriented moving forward.
For an example for how to accomplish this, see the code for Widget Customizer now in core. It toggles customizer sections for widget areas based on whether there is a corresponding
dynamic_sidebar()
call used in the rendered preview.