I'm trying to build a new custom "media" style customizer field (it lets users select a video from the media library OR paste in a url) and everything works except saving the new value.

My customizer settings are:

$wp_customize->register_control_type( 'WP3432_Video_Control' );
$wp_customize->add_setting('feed_video_setting', array(
    'default' => '',
    'sanitize_callback' => 'absint'

$wp_customize->add_control(new WP3432_Video_Control( $wp_customize,
'feed_video_control', array(
    'label'   => 'Hero Video',
    'section' => 'feed_settings_section',
    'settings' => 'feed_video_setting',

I am setting the setting customizer link manually to_json method:

public function to_json() {
    $this->json['control_name'] = $this->id;
    $this->json['setting_name'] = $this->setting->id;

and setting that attribute manually in the content_template method:

public function content_template() {
    <span class="use-url"> - or use URL -</span>
    <input class="js--video-url"
        id="{{ data.control_name }}"
        name="{{ data.control_name }}"
        data-customize-setting-link = "{{ data.setting_name }}"
        value="{{ data.value }}"

This produces the following markup in the customizer form:

<input class="js--video-url" id="archive_video_control" name="archive_video_control" data-customize-setting-link="archive_video_setting" type="url" value="">

But when I examine the contents of get_theme_mods() I see:

 [archive_video_setting] => 0

1 Answer 1


You're adding a url field in the control but the underlying setting has an absint sanitize callback. When you pass a URL string into absint you get 0. So what you should do is check to see if the value is numeric, and then call absint; otherwise if it is a string then it should be passed through esc_url_raw to sanitize. Here's an example that also includes validation:

$wp_customize->add_setting( 'feed_video_setting', array(
    'default' => '',
    'sanitize_callback' => function( $value ) {
        if ( is_numeric( $value ) ) {
            $value = intval( $value );
            if ( $value < 0 ) {
                return new WP_Error( 'invalid_attachment_id', __( 'Invalid attachment ID', 'myplugin' ) );
        } elseif ( ! empty( $value ) ) {
            $value = esc_url_raw( $value );
            if ( empty( $value ) ) {
                return new WP_Error( 'invalid_video_url', __( 'Invalid URL', 'myplugin' ) );
        return $value;
) );

Please refer also to the external video header control in core for how it is done there:

  • oh that was some pretty careless and shameful copy pasta on my part, I think I grabbed that from the built in media field. Thanks for catching that.
    – rugbert
    Jun 19, 2017 at 18:30

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.