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?

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]);
    },
    $form
);
  • For the actual rendering code check if the page is being customized, and if so use the option, otherwise use the meta

Leave a Reply

Your email address will not be published. Required fields are marked *