diff --git a/inc/customizer.php b/inc/customizer.php index 979c0a6..b1d742d 100644 --- a/inc/customizer.php +++ b/inc/customizer.php @@ -27,7 +27,7 @@ function radiate_customize_register( $wp_customize ) { * Binds JS handlers to make Theme Customizer preview reload changes asynchronously. */ function radiate_customize_preview_js() { - wp_enqueue_script( 'radiate_customizer', get_template_directory_uri() . '/js/customizer.js', array( 'customize-preview' ), '20130508', true ); + wp_enqueue_script( 'radiate_customizer', get_template_directory_uri() . '/js/customizer.js', array( 'customize-preview' ), wp_get_theme( get_template() )->get( 'Version' ), true ); } add_action( 'customize_preview_init', 'radiate_customize_preview_js' ); diff --git a/js/customizer.js b/js/customizer.js index a83540d..50e45c5 100644 --- a/js/customizer.js +++ b/js/customizer.js @@ -33,4 +33,23 @@ } } ); } ); + + // Custom background: core rewrites the theme's background style element, but the theme paints #content. + function radiateUpdateBackground() { + var image = wp.customize( 'background_image' )(); + + $( '#content' ).css( { + 'background-color' : wp.customize( 'background_color' )() || '', + 'background-image' : image ? 'url("' + image + '")' : 'none', + 'background-repeat' : wp.customize( 'background_repeat' )(), + 'background-position' : 'top ' + wp.customize( 'background_position_x' )(), + 'background-attachment': wp.customize( 'background_attachment' )() + } ); + } + + $.each( [ 'color', 'image', 'repeat', 'position_x', 'attachment' ], function ( i, prop ) { + wp.customize( 'background_' + prop, function ( value ) { + value.bind( radiateUpdateBackground ); + } ); + } ); } )( jQuery ); diff --git a/tests/e2e/specs/customizer/background-image-preview.spec.ts b/tests/e2e/specs/customizer/background-image-preview.spec.ts new file mode 100644 index 0000000..35c3b38 --- /dev/null +++ b/tests/e2e/specs/customizer/background-image-preview.spec.ts @@ -0,0 +1,40 @@ +import { test, expect } from "../../fixtures"; +import { ADMIN_STATE, hasAdminCredentials } from "../../utils/login"; + +test.use({ storageState: ADMIN_STATE }); + +/** + * @area customizer + * @tier fresh + * @guards radiate-pro#48 + * @source fix/48-background-image-preview 2026-09-29; js/customizer.js + * @why WordPress live-previews the background settings by rewriting the theme's + * background style element, but Radiate paints its background on #content, + * so choosing an image changed nothing in the Customizer preview until + * publishing. The image is only previewed, never saved. Guards image and + * repeat; position, attachment and colour share the same handler and are + * deliberately not asserted separately. + */ +test("the Customizer previews a background image and its repeat setting live @fresh @customizer", async ({ + page, +}) => { + test.skip(!hasAdminCredentials(), "needs TGQA_ADMIN_USER / TGQA_ADMIN_PASS"); + test.setTimeout(120_000); + page.on("dialog", (dialog) => dialog.accept()); + await page.goto("/wp-admin/customize.php"); + await expect(page.locator("#customize-theme-controls")).toBeVisible({ timeout: 90_000 }); + + const preview = page.frameLocator("#customize-preview iframe").last(); + const content = preview.locator("#content"); + await expect(content).toBeVisible({ timeout: 60_000 }); + + // Any URL works: only the computed style is read, the file need not load. + await page.evaluate(() => { + const api = (window as any).wp.customize; + api("background_image").set(`${api.settings.url.home}/wp-content/themes/radiate/screenshot.png`); + api("background_repeat").set("no-repeat"); + }); + + await expect(content).toHaveCSS("background-image", /radiate\/screenshot\.png/); + await expect(content).toHaveCSS("background-repeat", "no-repeat"); +});