Plugin Directory

Changeset 3797104


Ignore:
Timestamp:
11/11/2026 09:17:24 PM (less than one hour ago)
Author:
falselight
Message:

Release 1.1.5: restore conditional clock delivery for server-rendered HTML

Preserve saved Gutenberg blocks and metadata fixes; deliver zero plugin scripts on clock-free pages.
Accepted package SHA-256: 2b6b2ed361115aec5dbddad058bf38411534c53705ccc5315b1fd6e756386aa2
Git source: 3ba350f9865fa70e844c199c893788fb8791e738

Location:
simple-digital-clock
Files:
2 added
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • simple-digital-clock/tags/1.1.5/includes/simple-digital-clock-assets.php

    r3796553 r3797104  
    55}
    66
    7 /** Register stable handles only when rendering or previewing an owned clock. */
     7/** Register stable handles without sending frontend resources. */
    88function SDCW_register_assets() {
    99    if (!wp_script_is('simple-digital-clock', 'registered')) {
    … …  
    1717    }
    1818    if (!wp_style_is('simple-digital-clock-block-style', 'registered')) {
    19         // A source-free handle prints only this host-layout rule, without a request.
    20         wp_register_style('simple-digital-clock-block-style', false, array(), '1.1.4');
     19        wp_register_style('simple-digital-clock-block-style', false, array(), '1.1.5');
    2120        wp_add_inline_style(
    2221            'simple-digital-clock-block-style',
    … …  
    2524    }
    2625}
     26add_action('init', 'SDCW_register_assets', 9);
    2727
    28 /** WordPress deduplicates each stable handle within the current document. */
     28/** Editors enqueue normally; frontend runtime delivery follows actual HTML. */
    2929function SDCW_enqueue_scripts() {
    3030    SDCW_register_assets();
    31     wp_enqueue_script('simple-digital-clock');
     31    if (is_admin()) {
     32        wp_enqueue_script('simple-digital-clock');
     33    }
    3234    wp_enqueue_style('simple-digital-clock-block-style');
    3335    if (!is_admin()) {
    34         // Content and footer sidebars can enqueue the inline rule after wp_head.
    3536        add_action('wp_footer', 'SDCW_print_clock_styles', 19);
    3637        if (did_action('wp_print_footer_scripts')) {
    37             // Explicit late rendering still uses Core's filters and done lists.
    3838            SDCW_print_clock_styles();
    39             if (!wp_script_is('simple-digital-clock', 'done')) {
    40                 wp_print_scripts(array('simple-digital-clock'));
    41             }
    4239        }
    4340    }
    4441}
    4542
    46 /**
    47  * Only the owned block's render event automatically enqueues frontend assets.
    48  * No page, content, sidebar option or response stream is inspected.
    49  */
     43/** Preserve the owned block's layout policy without leaking frontend scripts. */
    5044function SDCW_enqueue_rendered_clock_assets($block_content) {
    5145    if ('' !== trim($block_content) && !is_admin() && !is_feed() && !is_robots() &&
    … …  
    5751add_filter('render_block_simple-digital-clock-block/widget-block', 'SDCW_enqueue_rendered_clock_assets');
    5852
    59 /** Print only a pending owned inline rule; Core deduplicates head/footer output. */
     53/** Inline layout may remain after a later filter discards an owned block. */
    6054function SDCW_print_clock_styles() {
    6155    if (wp_style_is('simple-digital-clock-block-style', 'enqueued') &&
    … …  
    6559}
    6660
    67 /** Empty editors still need preview assets, including their iframe canvas. */
     61require_once SDCW_PATH . 'includes/simple-digital-clock-output.php';
     62
     63/** Only ordinary HTML may receive generated script tags. */
     64function SDCW_is_frontend_html() {
     65    foreach (headers_list() as $header) {
     66        if (0 === stripos($header, 'Content-Type:') && !preg_match('~^Content-Type:\s*text/html(?:\s*;|\s*$)~i', $header)) {
     67            return false;
     68        }
     69    }
     70    return true;
     71}
     72
     73/** Insertion changes response length; never retain a stale fixed length. */
     74function SDCW_prepare_frontend_length() {
     75    foreach (headers_list() as $header) {
     76        if (0 === stripos($header, 'Content-Length:')) {
     77            if (headers_sent()) {
     78                $GLOBALS['SDCW_frontend_output_blocker'] = 'content_length_already_sent';
     79                return false;
     80            }
     81            header_remove('Content-Length');
     82            break;
     83        }
     84    }
     85    return true;
     86}
     87
     88/** Observe delivered chunks; cleaned writes never change lexical history. */
     89function SDCW_filter_frontend_output($html, $phase) {
     90    if (($phase & PHP_OUTPUT_HANDLER_CLEAN) || !empty($GLOBALS['SDCW_frontend_assets_delivered'])) {
     91        return $html;
     92    }
     93    if (!SDCW_is_frontend_html() || !SDCW_prepare_frontend_length()) {
     94        return $html;
     95    }
     96    $ready = isset($GLOBALS['SDCW_frontend_asset_markup']);
     97    $position = $GLOBALS['SDCW_frontend_observer']->feed($html, $ready);
     98    if ($ready && null !== $position) {
     99        $GLOBALS['SDCW_frontend_assets_delivered'] = true;
     100        return substr($html, 0, $position) . $GLOBALS['SDCW_frontend_asset_markup'] . substr($html, $position);
     101    }
     102    return $html;
     103}
     104
     105function SDCW_start_frontend_output() {
     106    if (is_admin() || is_feed() || is_robots() || is_trackback() || wp_is_json_request() ||
     107        isset($GLOBALS['SDCW_frontend_observer']) || !SDCW_is_frontend_html()) {
     108        return;
     109    }
     110    if (!SDCW_prepare_frontend_length()) {
     111        return;
     112    }
     113    $GLOBALS['SDCW_frontend_observer'] = new SDCW_Clock_Output_Observer();
     114    ob_start('SDCW_filter_frontend_output', 1);
     115    add_action('wp_footer', 'SDCW_capture_frontend_assets', 19);
     116}
     117add_action('template_redirect', 'SDCW_start_frontend_output', PHP_INT_MAX);
     118
     119/** Capture only Core-generated runtime tags, not page content or layout CSS. */
     120function SDCW_capture_frontend_assets() {
     121    if (isset($GLOBALS['SDCW_frontend_asset_markup']) || !SDCW_is_frontend_html() ||
     122        !SDCW_prepare_frontend_length()) {
     123        return;
     124    }
     125    SDCW_register_assets();
     126    ob_start();
     127    wp_scripts()->do_items(array('simple-digital-clock'), 1);
     128    $GLOBALS['SDCW_frontend_asset_markup'] = ob_get_clean();
     129    // A late owned render must still print its layout after footer priority 19.
     130    add_action('wp_footer', 'SDCW_print_clock_styles', PHP_INT_MAX);
     131    echo '<!-- -->';
     132}
     133
    68134function SDCW_enqueue_editor_clock_assets() {
    69135    $screen = function_exists('get_current_screen') ? get_current_screen() : null;
  • simple-digital-clock/tags/1.1.5/languages/simple-digital-clock.pot

    r3796553 r3797104  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Simple Digital Clock 🕒 1.1.4\n"
     5"Project-Id-Version: Simple Digital Clock 🕒 1.1.5\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/simple-digital-clock\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
  • simple-digital-clock/tags/1.1.5/readme.txt

    r3796553 r3797104  
    66Requires at least: 6.3
    77Requires PHP: 7.0
    8 Stable tag: 1.1.4
     8Stable tag: 1.1.5
    99License: GPLv2 or later
    1010License URI: http://www.gnu.org/licenses/gpl-2.0.html
    … …  
    7474
    7575= Is it fast? =
    76 Yes. The bundled clock widget is about 12.2 KiB gzip and is served locally without a runtime JavaScript CDN dependency. Frontend JavaScript and the inline layout rule are queued when WordPress renders the Simple Digital Clock block, including block-based widget areas. The plugin does not scan or buffer page HTML. Custom templates, shortcodes or raw HTML integrations must call SDCW_enqueue_scripts() when they output a clock. If another plugin removes an already rendered clock later, its queued assets may remain. Multiple clocks share one runtime script and one inline layout rule per page; no external plugin stylesheet is loaded.
     76Yes. The bundled clock widget is about 12.2 KiB gzip and is served locally without a runtime JavaScript CDN dependency. On the frontend, the runtime is delivered only when a clock is present in the server-rendered page HTML; clock-free pages receive no plugin script or browser loader. Multiple clocks share one runtime script. The inline layout rule remains scoped to rendered Simple Digital Clock blocks and explicit integrations; raw HTML keeps its existing layout. No external plugin stylesheet is loaded. Server-side HTML observation adds PHP work, including on clock-free pages.
    7777
     78= What about clocks created later by custom JavaScript? =
     79Automatic delivery detects server-rendered clocks. An integration that creates its first clock only after page load must load the widget runtime itself. Calling SDCW_enqueue_scripts() without rendering a clock on the server does not bypass the zero-script rule.
     80
     81= What if my site caches complete HTML pages? =
     82Regenerate full-page caches after updating so visitors receive the corrected HTML. Cached pages served without WordPress running are not rewritten by the plugin.
    7883== Screenshots ==
    7984
    … …  
    102107
    103108== Changelog ==
     109
     110= 1.1.5 =
     111* Restore automatic clock rendering in existing raw HTML, Custom HTML/Text widgets, templates and shortcode integrations after updating from 1.1.2 or 1.1.4.
     112* Load the runtime only for actual server-rendered clocks, including raw HTML and cached fragments, while preserving raw HTML layout.
     113* Retain the Gutenberg, legacy metadata and localization fixes from 1.1.4 without changing stored content.
    104114
    105115= 1.1.4 =
    … …  
    182192🕒 Sync Time: [UTC](https://utctime.info/)
    183193🗓️ Today's Date: [TodaysDateNow](https://todaysdatenow.com/)
     194
     195== Upgrade Notice ==
     196
     197= 1.1.5 =
     198Restores clocks in existing HTML, widget and template integrations. No content migration is required.
  • simple-digital-clock/tags/1.1.5/widget_init.php

    r3796553 r3797104  
    22
    33/**
    4  * @version 1.1.4
     4 * @version 1.1.5
    55 */
    66
    … …  
    99Plugin URI: https://utctime.info/
    1010Description: It is 🪄 a magical and easy-to-use digital clock with a beautiful UI, supporting multiple languages, locales, dates, captions, and time zones.
    11 Version: 1.1.4
     11Version: 1.1.5
    1212Requires at least: 6.3
    1313Requires PHP: 7.0
  • simple-digital-clock/trunk/includes/simple-digital-clock-assets.php

    r3796553 r3797104  
    55}
    66
    7 /** Register stable handles only when rendering or previewing an owned clock. */
     7/** Register stable handles without sending frontend resources. */
    88function SDCW_register_assets() {
    99    if (!wp_script_is('simple-digital-clock', 'registered')) {
    … …  
    1717    }
    1818    if (!wp_style_is('simple-digital-clock-block-style', 'registered')) {
    19         // A source-free handle prints only this host-layout rule, without a request.
    20         wp_register_style('simple-digital-clock-block-style', false, array(), '1.1.4');
     19        wp_register_style('simple-digital-clock-block-style', false, array(), '1.1.5');
    2120        wp_add_inline_style(
    2221            'simple-digital-clock-block-style',
    … …  
    2524    }
    2625}
     26add_action('init', 'SDCW_register_assets', 9);
    2727
    28 /** WordPress deduplicates each stable handle within the current document. */
     28/** Editors enqueue normally; frontend runtime delivery follows actual HTML. */
    2929function SDCW_enqueue_scripts() {
    3030    SDCW_register_assets();
    31     wp_enqueue_script('simple-digital-clock');
     31    if (is_admin()) {
     32        wp_enqueue_script('simple-digital-clock');
     33    }
    3234    wp_enqueue_style('simple-digital-clock-block-style');
    3335    if (!is_admin()) {
    34         // Content and footer sidebars can enqueue the inline rule after wp_head.
    3536        add_action('wp_footer', 'SDCW_print_clock_styles', 19);
    3637        if (did_action('wp_print_footer_scripts')) {
    37             // Explicit late rendering still uses Core's filters and done lists.
    3838            SDCW_print_clock_styles();
    39             if (!wp_script_is('simple-digital-clock', 'done')) {
    40                 wp_print_scripts(array('simple-digital-clock'));
    41             }
    4239        }
    4340    }
    4441}
    4542
    46 /**
    47  * Only the owned block's render event automatically enqueues frontend assets.
    48  * No page, content, sidebar option or response stream is inspected.
    49  */
     43/** Preserve the owned block's layout policy without leaking frontend scripts. */
    5044function SDCW_enqueue_rendered_clock_assets($block_content) {
    5145    if ('' !== trim($block_content) && !is_admin() && !is_feed() && !is_robots() &&
    … …  
    5751add_filter('render_block_simple-digital-clock-block/widget-block', 'SDCW_enqueue_rendered_clock_assets');
    5852
    59 /** Print only a pending owned inline rule; Core deduplicates head/footer output. */
     53/** Inline layout may remain after a later filter discards an owned block. */
    6054function SDCW_print_clock_styles() {
    6155    if (wp_style_is('simple-digital-clock-block-style', 'enqueued') &&
    … …  
    6559}
    6660
    67 /** Empty editors still need preview assets, including their iframe canvas. */
     61require_once SDCW_PATH . 'includes/simple-digital-clock-output.php';
     62
     63/** Only ordinary HTML may receive generated script tags. */
     64function SDCW_is_frontend_html() {
     65    foreach (headers_list() as $header) {
     66        if (0 === stripos($header, 'Content-Type:') && !preg_match('~^Content-Type:\s*text/html(?:\s*;|\s*$)~i', $header)) {
     67            return false;
     68        }
     69    }
     70    return true;
     71}
     72
     73/** Insertion changes response length; never retain a stale fixed length. */
     74function SDCW_prepare_frontend_length() {
     75    foreach (headers_list() as $header) {
     76        if (0 === stripos($header, 'Content-Length:')) {
     77            if (headers_sent()) {
     78                $GLOBALS['SDCW_frontend_output_blocker'] = 'content_length_already_sent';
     79                return false;
     80            }
     81            header_remove('Content-Length');
     82            break;
     83        }
     84    }
     85    return true;
     86}
     87
     88/** Observe delivered chunks; cleaned writes never change lexical history. */
     89function SDCW_filter_frontend_output($html, $phase) {
     90    if (($phase & PHP_OUTPUT_HANDLER_CLEAN) || !empty($GLOBALS['SDCW_frontend_assets_delivered'])) {
     91        return $html;
     92    }
     93    if (!SDCW_is_frontend_html() || !SDCW_prepare_frontend_length()) {
     94        return $html;
     95    }
     96    $ready = isset($GLOBALS['SDCW_frontend_asset_markup']);
     97    $position = $GLOBALS['SDCW_frontend_observer']->feed($html, $ready);
     98    if ($ready && null !== $position) {
     99        $GLOBALS['SDCW_frontend_assets_delivered'] = true;
     100        return substr($html, 0, $position) . $GLOBALS['SDCW_frontend_asset_markup'] . substr($html, $position);
     101    }
     102    return $html;
     103}
     104
     105function SDCW_start_frontend_output() {
     106    if (is_admin() || is_feed() || is_robots() || is_trackback() || wp_is_json_request() ||
     107        isset($GLOBALS['SDCW_frontend_observer']) || !SDCW_is_frontend_html()) {
     108        return;
     109    }
     110    if (!SDCW_prepare_frontend_length()) {
     111        return;
     112    }
     113    $GLOBALS['SDCW_frontend_observer'] = new SDCW_Clock_Output_Observer();
     114    ob_start('SDCW_filter_frontend_output', 1);
     115    add_action('wp_footer', 'SDCW_capture_frontend_assets', 19);
     116}
     117add_action('template_redirect', 'SDCW_start_frontend_output', PHP_INT_MAX);
     118
     119/** Capture only Core-generated runtime tags, not page content or layout CSS. */
     120function SDCW_capture_frontend_assets() {
     121    if (isset($GLOBALS['SDCW_frontend_asset_markup']) || !SDCW_is_frontend_html() ||
     122        !SDCW_prepare_frontend_length()) {
     123        return;
     124    }
     125    SDCW_register_assets();
     126    ob_start();
     127    wp_scripts()->do_items(array('simple-digital-clock'), 1);
     128    $GLOBALS['SDCW_frontend_asset_markup'] = ob_get_clean();
     129    // A late owned render must still print its layout after footer priority 19.
     130    add_action('wp_footer', 'SDCW_print_clock_styles', PHP_INT_MAX);
     131    echo '<!-- -->';
     132}
     133
    68134function SDCW_enqueue_editor_clock_assets() {
    69135    $screen = function_exists('get_current_screen') ? get_current_screen() : null;
  • simple-digital-clock/trunk/languages/simple-digital-clock.pot

    r3796553 r3797104  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Simple Digital Clock 🕒 1.1.4\n"
     5"Project-Id-Version: Simple Digital Clock 🕒 1.1.5\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/simple-digital-clock\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
  • simple-digital-clock/trunk/readme.txt

    r3796553 r3797104  
    66Requires at least: 6.3
    77Requires PHP: 7.0
    8 Stable tag: 1.1.4
     8Stable tag: 1.1.5
    99License: GPLv2 or later
    1010License URI: http://www.gnu.org/licenses/gpl-2.0.html
    … …  
    7474
    7575= Is it fast? =
    76 Yes. The bundled clock widget is about 12.2 KiB gzip and is served locally without a runtime JavaScript CDN dependency. Frontend JavaScript and the inline layout rule are queued when WordPress renders the Simple Digital Clock block, including block-based widget areas. The plugin does not scan or buffer page HTML. Custom templates, shortcodes or raw HTML integrations must call SDCW_enqueue_scripts() when they output a clock. If another plugin removes an already rendered clock later, its queued assets may remain. Multiple clocks share one runtime script and one inline layout rule per page; no external plugin stylesheet is loaded.
     76Yes. The bundled clock widget is about 12.2 KiB gzip and is served locally without a runtime JavaScript CDN dependency. On the frontend, the runtime is delivered only when a clock is present in the server-rendered page HTML; clock-free pages receive no plugin script or browser loader. Multiple clocks share one runtime script. The inline layout rule remains scoped to rendered Simple Digital Clock blocks and explicit integrations; raw HTML keeps its existing layout. No external plugin stylesheet is loaded. Server-side HTML observation adds PHP work, including on clock-free pages.
    7777
     78= What about clocks created later by custom JavaScript? =
     79Automatic delivery detects server-rendered clocks. An integration that creates its first clock only after page load must load the widget runtime itself. Calling SDCW_enqueue_scripts() without rendering a clock on the server does not bypass the zero-script rule.
     80
     81= What if my site caches complete HTML pages? =
     82Regenerate full-page caches after updating so visitors receive the corrected HTML. Cached pages served without WordPress running are not rewritten by the plugin.
    7883== Screenshots ==
    7984
    … …  
    102107
    103108== Changelog ==
     109
     110= 1.1.5 =
     111* Restore automatic clock rendering in existing raw HTML, Custom HTML/Text widgets, templates and shortcode integrations after updating from 1.1.2 or 1.1.4.
     112* Load the runtime only for actual server-rendered clocks, including raw HTML and cached fragments, while preserving raw HTML layout.
     113* Retain the Gutenberg, legacy metadata and localization fixes from 1.1.4 without changing stored content.
    104114
    105115= 1.1.4 =
    … …  
    182192🕒 Sync Time: [UTC](https://utctime.info/)
    183193🗓️ Today's Date: [TodaysDateNow](https://todaysdatenow.com/)
     194
     195== Upgrade Notice ==
     196
     197= 1.1.5 =
     198Restores clocks in existing HTML, widget and template integrations. No content migration is required.
  • simple-digital-clock/trunk/widget_init.php

    r3796553 r3797104  
    22
    33/**
    4  * @version 1.1.4
     4 * @version 1.1.5
    55 */
    66
    … …  
    99Plugin URI: https://utctime.info/
    1010Description: It is 🪄 a magical and easy-to-use digital clock with a beautiful UI, supporting multiple languages, locales, dates, captions, and time zones.
    11 Version: 1.1.4
     11Version: 1.1.5
    1212Requires at least: 6.3
    1313Requires PHP: 7.0
Note: See TracChangeset for help on using the changeset viewer.