Podgląd zmian kolorów motywu na ekranie personalizacji

Ekran personalizacji motywu to świetne narzędzie, które umożliwia łatwy podgląd zmian, które chcemy nanieść w naszym motywie z użyciem jego opcji. Jedną z ciekawszych opcji jakie możemy zaoferować użytkownikom naszego motywu jest możliwość zmiany kolorów w motywie z podglądem „na żywo” w ekranie personalizacji.

Dodanie obsługi zmiany koloru jest relatywnie proste – zaczynamy od stworzenia dodatkowego ustawienia dla naszego motywu:

$wp_customize->add_setting(
    'my_theme_primary_color',
    array(
        'default' => '#e83a34',
        'capability' => 'edit_theme_options',
        'transport' => 'postMessage'
    )
);

Kluczowym elementem w powyższym kodzie jest parametr transport, który jest ustawiony tak żeby umożliwić przesyłanie wartości zmienionej opcji bezpośrednio do ramki z podglądem motywu poprzez JavaScript. Dzięki temu będziemy mogli stworzyć podgląd „na żywo” wprowadzanych zmian.

Kolejny krok to dodanie kontrolki obsługującej nasz dodatkowy kolor:

$wp_customize->add_control(
    new WP_Customize_Color_Control(
        $wp_customize,
        'my_theme_primary_color',
        array(
            'label' => __('Primary Color', 'my-theme'),
            'section' => 'colors',
            'settings' => 'my_theme_primary_color'
        )
    )
);

Nasza kontrolka zostanie dodana do domyślnej sekcji z kolorami pod nazwą Primary Color. Oczywiście aby tak się stało musimy oba powyższe kawałki kodu opakować w funkcję np. o nazwie my_theme_init_customizer, którą dodamy do akcji customize_register:

add_action( 'customize_register', 'my_theme_init_customizer' );

Po tej operacji powinniśmy uzyskać w ekranie personalizacji mniej więcej taki wygląd:

primary-color

Oczywiście nasza kontrolka jeszcze nic nie robi, ponieważ zmiany wartości nowej opcji nie są nigdzie odwzorowywane w motywie – zaimplementujmy więc to.

function my_theme_customizer_css() {
    $primary_color = get_theme_mod('my_theme_primary_color', '#e83a34');

    ?>
    <style type="text/css">
        a,
        button,
        input[type="submit"],
        input[type="button"],
        input[type="reset"] {
        	color: <?php echo $primary_color; ?>;
        }
    </style>
    <?php
}

add_action( 'wp_head', 'my_theme_customizer_css' );

Powyższy kod pobiera z ustawień motywu wartość naszej nowej opcji oraz wstawia ją do kodu CSS, który jest umieszczany w sekcji head naszego motywu. Od tej pory nasze zmiany nowej opcji będą widoczne w motywie… ale tylko po odświeżeniu strony – musimy jeszcze powiązać zmiany naszej opcji z odpowiednim kodem JavaScript, aby uzyskać podgląd „na żywo” tych zmian.

Zaczynamy od dodania akcji, która wywoła dodanie akcji wp_footer w trybie podglądu motywu:

function my_theme_customize_register($wp_customize) {
    if ($wp_customize->is_preview() && !is_admin()) {
        add_action('wp_footer', 'my_theme_customize_preview', 21);
    }
}

add_action( 'customize_register', 'my_theme_customize_register' );

Powyższy kod odpowiada za wywołanie funkcji my_theme_customize_preview w stopce strony tylko wtedy gdy motyw wyświetlany jest w trybie podglądu. Tym samym przechodzimy do finalnego kroku – czyli zdefiniowania funkcji my_theme_customize_preview:

function my_theme_customize_preview() {
    ?>
    <script>
    (function( $ ){
    	wp.customize('my_theme_primary_color', function(value) {
    	    value.bind(function(final_value) {
    	    	final_value = final_value ? final_value : '#e83a34';
    	        $('a, button, input[type="submit"], input[type="button"], input[type="reset"]').css('color', final_value);
    	    });
    	});
    })(jQuery);
    </script>
    <?php
}

Powyższy kod zadziała dzięki temu, że uprzednio dla naszej nowej opcji określiliśmy parametr transport na postMessage. W większości wypadków takie rozwiązanie będzie wystarczające.

Optymalizacja kodu JavaScript

Czasami jednak zdarzy się, że będziemy mieli do zmiany kolor w bardzo dużej liczbie elementów, których nie będzie można zunifikować w postaci kilku selektorów CSS. W takim wypadku sugeruję zastosowanie innego kodu:

function my_theme_customize_preview() {
    ?>
    <script>
    (function( $ ){
    	wp.customize('my_theme_primary_color', function(value) {
    	    value.bind( function( to ) {
    	    	final_value = final_value ? final_value : '#e83a34';
    	    	var new_css = 'a, button, input[type="submit"], input[type="button"], input[type="reset"] { color: ' + final_value + '; }';

    	    	if($(document).find('#my-theme-new-css').length) {
    	    		$(document).find('#my-theme-new-css').remove();
    	    	}

    	    	$(document).find('head').append($('<style id="my-theme-new-css">' + new_css + '</style>'));
    	    });
    	});
    })(jQuery);
    </script>
    <?php
}

Powyższy kod działa sprytniej niż poprzedni – tworzymy w locie kod CSS, który umieszczamy w znaczniku style dokładanym na końcu sekcji head – dzięki temu nadpiszemy wszystkie pozostałe pliki CSS. Oczywiście jak widać uprzednio usuwamy poprzednio wstawiony znacznik style aby uniknąć kilkuset elementów style w sekcji head, jeżeli trafimy na wyjątkowo niezdecydowanego przy wyborze koloru użytkownika. Dzięki temu wykonamy dwie proste operacje na drzewie dokumentu – usunięcie i dodanie elementu, zamiast (potencjalnie) kilku tysięcy selekcji i modyfikacji elementów.