From 4cf22a5e3ba9893e4f012e50626ca76828acc67b Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Tue, 11 Jul 2023 13:04:17 +1200 Subject: [PATCH] Add wporg/time block --- mu-plugins/blocks/time/index.php | 175 ++++++++++++++++++++++++++ mu-plugins/blocks/time/src/block.json | 29 +++++ mu-plugins/blocks/time/src/index.js | 32 +++++ mu-plugins/loader.php | 1 + 4 files changed, 237 insertions(+) create mode 100644 mu-plugins/blocks/time/index.php create mode 100644 mu-plugins/blocks/time/src/block.json create mode 100644 mu-plugins/blocks/time/src/index.js diff --git a/mu-plugins/blocks/time/index.php b/mu-plugins/blocks/time/index.php new file mode 100644 index 000000000..b2d646987 --- /dev/null +++ b/mu-plugins/blocks/time/index.php @@ -0,0 +1,175 @@ +[time]any-valid-time-string-here[/time] and creates a format that shows it in the viewers local time zone. + * + * @package wporg + */ + +namespace WordPressdotorg\MU_Plugins\Time; + +use function WordPressdotorg\MU_Plugins\Helpers\register_assets_from_metadata; + +add_action( 'init', __NAMESPACE__ . '\init' ); + +/** + * Registers the block using the metadata loaded from the `block.json` file. + * Behind the scenes, it registers also all assets so they can be enqueued + * through the block editor in the corresponding context. + * + * @see https://developer.wordpress.org/reference/functions/register_block_type/ + */ +function init() { + register_block_type( __DIR__ . '/build' ); + add_filter('the_content', __NAMESPACE__ . '\transform_time_blocks', 99, 1); +} + +/** + * Builds the time block output. + * + * This implements replacing the raw time strings with formatted local times in post content. + * + * @param string $content Post content. + * @return string Content with display times reformatted. + */ +function transform_time_blocks( $content) { + // Find the time block elements by the classname "wporg-time" + $dom = new \DOMDocument(); + $dom->loadHTML( $content ); + $xpath = new \DOMXPath( $dom ); + $time_elements = $xpath->query( "//*[contains(concat(' ', normalize-space(@class), ' '), ' wporg-time ')]" ); + + foreach ( $time_elements as $time_element ) { + $time_content = $time_element->nodeValue; + $parsed_time = parse_time( $time_content ); + + if ( $parsed_time === null ) { + continue; + } + + // Build the link and abbr microformat. + $time_element->setAttribute( 'href', 'https://www.timeanddate.com/worldclock/fixedtime.html?iso=' . gmdate( 'Ymd\THi', $time ) ); + + $new_time_content = $dom->createElement( 'abbr', $time_content ); + $new_time_content->setAttribute( 'class', 'wporg-time-date' ); + $new_time_content->setAttribute( 'title', gmdate( 'c', $parsed_time ) ); + + // Replace the raw time with the formatted time + $time_element->nodeValue = null; + $time_element->appendChild( $new_time_content ); + } + + $content = $dom->saveHTML( ); + + return $content; +} + +/** + * Parse the datetime description string and return a timestamp. + * + * @param string $content Datetime description, eg. `Monday, April 6 at 19:00 UTC` + * @return string Unix timestamp or null if the time string could not be parsed. + */ +function parse_time( $content ) { + // Replace non-breaking spaces with a regular white space. + $gmtcontent = preg_replace( '/\xC2\xA0| /', ' ', $content ); + + // PHP understands "GMT" better than "UTC" for timezones. + $gmtcontent = str_replace( 'UTC', 'GMT', $gmtcontent ); + + // Remove the word "at" from the string, if present. Allows strings like "Monday, April 6 at 19:00 UTC" to work. + $gmtcontent = str_replace( ' at ', ' ', $gmtcontent ); + + // Try to parse the time, relative to the post time. Or current time, if an attr is set. + $timestamp = ! isset( $attr[0] ) ? get_the_date( 'U' ) : time(); + $time = strtotime( $gmtcontent, $timestamp ); + + // If that didn't work, give up. + if ( false === $time || -1 === $time ) { + return null; + } + + // Add the time converter JS code. + if ( ! has_action( 'wp_footer', __NAMESPACE__ . '\time_converter_script' ) ) { + add_action( 'wp_footer', __NAMESPACE__ . '\time_converter_script', 999 ); + } + + return $time; +} + +/** + * Prints script to convert time in the viewers local time zone. + */ +function time_converter_script() { + ?> + +[time]any-valid-time-string-here[/time] and creates a format that shows it in the viewers local time zone.", + "textdomain": "wporg", + "attributes": { + "content": { + "type": "string", + "source": "html", + "selector": "p" + } + }, + "supports": { + "color": { + "text": true, + "background": true, + "link": false + }, + "typography": { + "fontSize": true, + "lineHeight": true + } + }, + "editorScript": "file:./index.js", +} \ No newline at end of file diff --git a/mu-plugins/blocks/time/src/index.js b/mu-plugins/blocks/time/src/index.js new file mode 100644 index 000000000..6b26df235 --- /dev/null +++ b/mu-plugins/blocks/time/src/index.js @@ -0,0 +1,32 @@ +/** + * WordPress dependencies + */ +import { registerFormatType, toggleFormat } from '@wordpress/rich-text'; +import { RichTextToolbarButton } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import metadata from './block.json'; + +const Edit = ( { isActive, onChange, value } ) => ( + { + onChange( + toggleFormat( value, { + type: 'wporg/time', + } ) + ); + } } + isActive={ isActive } + /> +); + +registerFormatType( 'wporg/time', { + title: metadata.title, + tagName: 'a', + className: 'wporg-time', + edit: Edit, +} ); diff --git a/mu-plugins/loader.php b/mu-plugins/loader.php index 784297ecb..a56471a34 100644 --- a/mu-plugins/loader.php +++ b/mu-plugins/loader.php @@ -38,6 +38,7 @@ require_once __DIR__ . '/blocks/screenshot-preview/block.php'; require_once __DIR__ . '/blocks/site-breadcrumbs/index.php'; require_once __DIR__ . '/blocks/table-of-contents/index.php'; +require_once __DIR__ . '/blocks/time/index.php'; require_once __DIR__ . '/global-fonts/index.php'; require_once __DIR__ . '/plugin-tweaks/index.php'; require_once __DIR__ . '/rest-api/index.php';