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';