• Resolved jimwright2

    (@jimwright2)


    I’m implementing a font selection choice in my theme, once the user selects the desired font, I need to run some code to present them with a list of the available font weights (Google Fonts). Not all fonts have all weights available, so I need this as a sanity check to avoid undesirable values.

    The simplest route to do this seemed to be with Javascript firing an OnChange event, but after some trial and error, I found that I wasn’t able to get this to work. In my functions.php at the very bottom (after my customizer sections have been set up) I have this:

    <script>
    document.getElementByID("_customize-input-body_font").onchange = function() {setSizesBody()};
    
    function setSizesBody() {
    alert ("This is a warning message!");
       var theFont = document.getElementByID("_customize-input-body_font");
       var arrayOptions = [];
    
       document.getElementByID("_customize-input-body_font_weight").innerHTML = arrayOptions,join();
    
    }
    </script>

    Full disclosure, it’s been years since I’ve worked with Javascript, so I’m googling a bit more than usual on this. But from what I’m reading, the above code should have set up an onchange trigger for the body_font field, and when a new value there is updated, I should then have gotten a visible alert on my screen, and this never happens. The following code there should have just blanked out the available selections for the weight setting, I can finish that code easily enough once I can get this part to work.

    My customizer controls are set up as follows, the sanitize function I have on the font choice just makes sure the font name entered is a valid Google font, that is working correctly.

    $wp_customize->add_setting( 'body_font',
    	array(
    		'default'        => $the_fonts['body'],
    		'transport'            => 'refresh',
    		'sanitize_callback' => 'throwback_sanitize_font_body',
    	)
    );
    $wp_customize->add_control( 'body_font',
    	array(
    		'label'    => __( 'Google font for content', 'throwback' ),
    		'section'  => 'font_family-settings',
    		'type'     => 'text',
    		'input_attrs' => array(
    			'placeholder' => __( 'Enter any Google Font name', 'throwback' ),
    			'list'  => 'throwback-fonts-list',
    		),
    	)
    );
    
    $wp_customize->add_setting(
    	'body_font_weight',
    	array(
    		'transport' => 'refresh',
    		'default' => 400,
    		'sanitize_callback' => 'throwback_sanitize_number_absint',
    	)
    );
    $wp_customize->add_control(
    	'body_font_weight',
    	array(
    		'type' => 'select',
    		'label' => __( 'Weight', 'throwback' ),
    		'section' => 'font_settings',
    		'choices' => $body_sizes,
    	)
    );
Viewing 7 replies - 1 through 7 (of 7 total)
  • Moderator bcworkz

    (@bcworkz)

    Hi Jim!
    JavaScript is case sensitive. You spelled ID wrong, it’s .getElementById(). I cannot tell you how many times I’ve made the same mistake. The only reason I noticed is I tried your script on one of my form’s fields and got a not a function console error.

    Thread Starter jimwright2

    (@jimwright2)

    Yes indeed, that was definitely an error, but not my main issue. I found that when I viewed the page source from the Customizer screen that my javascript was at the very top of the page, and it actually needs to be much lower, the very end of the html if at all possible after my controls are defined, which looking at the HTML is part of _wpCustomizeSettings.controls.

    I’m getting this error now:

    Uncaught TypeError: document.getElementById(...) is null

    I’m using this line to enqueue the script, but it’s still coming in far too early in the HTML:

    wp_enqueue_script ( 'throwback_font_js', get_template_directory_uri().'/inc/font.js', array('wp-tinymce'), false, true);

    Is there some way to enqueue to be at the very end of the HTML? If not then my only other workaround would be to insert this manually after I’ve defined my controls.

    Moderator bcworkz

    (@bcworkz)

    The $in_footer arg really just means “not in head”. In most cases script enqueued “in footer” does appear near the end of all HTML… except with the customizer. Being REACT driven, your script ends up loaded somewhere in the middle of everything.

    Your JS always needs to be within some sort of event listener that does not trigger until the elements you’re referencing actually exist. The common $(document).ready() (or the JavaScript equivalent) is usually adequate, but perhaps not with the customizer? Your elements might not be available until their panel is expanded. You may need to listen for the click that expands their panel.

    Thread Starter jimwright2

    (@jimwright2)

    I’ve played with this some more and I’ve been able to get my code where it looks like it should be, but I still can’t get the onchange to fire within the customizer.

    I’m trying a different tactic on this, new thread started to see if that avenue may work better.

    Thread Starter jimwright2

    (@jimwright2)

    Just updating this to keep anyone from spending time on it, I’m making progress on this finally, I’m now able to check when a control is updated and then update another control’s options as a result. (Yay!) I can upload some sample code here when I have this completed in a day or so.

    Thread Starter jimwright2

    (@jimwright2)

    I think the big part of what I was having to overcome was in the way that WordPress builds the HTML page that gets presented, there is a lot of Javascript going on that runs after the initial page source loads. What would otherwise work with some simple Javascript fails to execute because of this. So I had to dig deeper into how WordPress presented and managed everything involved, which for the most part involved JQuery.

    The core of what I needed to do is watch for one Customizer control to change, then update another Customizer control’s choices (Select list) with updated values. This second field would use an array built by PHP to populate these values. To get this set up, my functions.php uses this function:

    function throwback_enqueue() {
       global $theFontsList;
    // Other enqueue setup
       wp_enqueue_script ( 'throwback_font_js', get_template_directory_uri().'/inc/font.js?123', array('customize-controls'), false, true);
    
       wp_add_inline_script( 'throwback_font_js', 'const theFont = ' . json_encode( $theFontsList ), 'before' );
    
    }
    add_action( 'wp_enqueue_scripts', 'throwback_enqueue' );

    My functions.php has already built $theFontsList array, so it’s declared as a global so that the wp_add_inline_script can pass this over to the Javascript side as ‘theFont’. The wp_engueue_script loads my font.js script, and has it load after the ‘customize_controls’ have been loaded. The font.js script is as follows:

    ( function( wp, $ ) {
        wp.customize.control( 'font-body', function( control ) {
            control.setting.bind( function( to ) {
                var selectElem = wp.customize.control( 'font-body-weight' ).container.find( 'select' );
                var fontsList = theFont[0];
                selectElem.empty();
                var option = '<option value="100">100</option>';
                option += '<option value="200">200</option>';
                option += '<option value=' + fontsList + '>Result</option>';
                selectElem.append( option );
     //           $('#select1').append('<option value="${optionValue}">${optionText}</option>');
    
            } );
        } );
    } )( wp, jQuery );

    The above is some working test code to verify the basic functionality. I use wp.customize.control to modify the font-body control, and then bind that to the font-body-weight control, so that the weight’s options are dependent on the body-font selection.

    My full code will use the passed array (theFont) to populate the <option> choices, but for the test code I’m manually deleting the original choices via selectElem.empty(), setting static values of 100 and 200 for the first two options, and then setting a third option pulling a field from the theFont array (element zero) and showing that as the third option.

    For anyone else looking for a starting point, the above should help out.

    Moderator bcworkz

    (@bcworkz)

    Thanks for coming back to report your solution! I’ve no doubt others will find it useful.

Viewing 7 replies - 1 through 7 (of 7 total)
  • The topic ‘Changing Customizer control choices via Javascript’ is closed to new replies.