General context: I have a plugin which implements a widget and I would like to make the widget into a shortcode.

The widget has many options some of them mutually exclusive, and it is never good UX to have widgets with 20 attributes in your content in any case.

The solution seems to be to use the customizer but how do I let it know about the shortcode's existence and where to store the settings?

One plugin that does a kind of virtual sidebar as a shortcode just ignores the customizer.

For the sake of the discussion we can assume only a small (less then 4) such shortcodes per content so that scale is not an issue.

Two directions I was considering but both have some "missing links"

  1. Create virtual sidebars

    • The problems are: (lesser) mapping a shortcode to a sidebar, and (bigger) preventing users from trying to drag widgets in and out of it.
  2. Use postmeta to store the settings

    • I don't know of anything that lets the customizer change postmeta.
  3. Use an option to store the settings globally without making it an actual widget.

    • This doesn't sound appetizing from a modularization POV.

Is there an option I missed or do I just fear too much of any of the listed options?

  • Shortcodes are content specific, the customiser is intended for site wide changes/options. I would suggest either the shortcode/widget does too much, or if you really need a UI, to look into TinyMCE views. Perhaps you can have multiple shortcodes that refer to the same code but with different options?
    – Tom J Nowell
    Commented May 20, 2016 at 8:38
  • @TomJNowell, it doesn't matter what the theory is, it matters much more what users want. The widget is this - wordpress.org/plugins/category-posts, and it is basically just a wrapper around wp_query. other plugins which implement a shortcode functionality are like this - wordpress.org/plugins/list-category-posts and you can look in the faq how ugly it can be. It is true that a better solution is to have dynamic creation of "in content" sidebars in core, but this is unlikely to happen before 2020. Commented May 20, 2016 at 9:30
  • It is a macro functionality which makes it a true shortcode, but it also has a lot of front end details which make it natural to be managed in the customizer. TinyMCE can be used to configure the shortcode, but it doesn't give you the immidiate feedback on the front end, but I am happy to accept this direction as well if I can apply changes directly to the post editor without hurting the edit experience. Commented May 20, 2016 at 9:31
  • Changes here obviously require to run the query at server context and are more then JS and CSS manipulation Commented May 20, 2016 at 9:40
  • 1
    This is an XY problem. Problem X is that you have a usability problem, Problem Y is that you want to solve Problem X using the customizer. I suspect that Problem X is also an XY problem, and that there is a problem V which you're trying to solve with the shortcode. Problem Z would be the live preview issue. Perhaps we should return to what the original issue is involving putting something inline with content?
    – Tom J Nowell
    Commented May 20, 2016 at 13:27

1 Answer 1


High level description of what I ended doing, it is actually not too bad to do such an implementation and save you the effort of having different code for the widget and customizer forms, but there are many small details to take care of.

  • Store settings as a meta values for the post
  • Create proper customizer sections
    • Associate the section with a "virtual" option that is used only in the context of the customizer. The options stores the settings of all the shortcodes as an array.
    • When customizer is entered poulate the option from the meta values
    • When customizer saves update the meta values for whatever was changed and delete the option
    • To generate the "form", take the widget form and do some regexp to add data-customize-setting-link attribute that will associate with the relevant setting

ob_start(); $widget->form(array()); $form = ob_get_clean(); $form = preg_replace_callback('/<(input|select)\s+.*name=("|\').*\[\d*\]\[([^\]]*)\][^>]*>/', function ($matches) use ($p, $wp_customize, $meta) { $setting = '_virtual-'.WIDGET_BASE_ID.'['.$p->ID.']['.$matches[3].']'; $wp_customize->add_setting( $setting, array( 'default' => $meta[$matches[3]], // set default to current value 'type' => 'option' ) );

  return str_replace('<'.$matches[1],'<'.$matches[1].' data-customize-setting-link="'.$setting.'"',$matches[0]);
  • For the actual rendering code check if the page is being customized, and if so use the option, otherwise use the meta

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.