-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
53a91ec
commit e6b167e
Showing
4 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
<?php | ||
/** | ||
* Block Name: Time | ||
* Description: Attempts to parse a time string like <code>[time]any-valid-time-string-here[/time]</code> 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 in the post content with formatted times able to be converted to local times with JS. | ||
* | ||
* @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', $parsed_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. | ||
$time = strtotime( $gmtcontent, get_the_date( 'U' ) ); | ||
|
||
// 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() { | ||
?> | ||
<script type="text/javascript" id="time_converter_script"> | ||
( function() { | ||
function convertTime() { | ||
const parseDate = function( text ) { | ||
var m = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})\+00:00$/.exec( text ); | ||
|
||
return new Date( | ||
// Date.UTC(year, monthIndex (0..11), day, hour, minute, second) | ||
Date.UTC( + m[1], + m[2] - 1, + m[3], + m[4], + m[5], + m[6] ) | ||
); | ||
}; | ||
|
||
const formatTime = function( d ) { | ||
return d.toLocaleTimeString( navigator.language, { | ||
weekday : 'long', | ||
month : 'long', | ||
day : 'numeric', | ||
year : 'numeric', | ||
hour : '2-digit', | ||
minute : '2-digit', | ||
timeZoneName: 'short' | ||
} ); | ||
}; | ||
|
||
const formatDate = function( d ) { | ||
return d.toLocaleDateString( navigator.language, { | ||
weekday: 'long', | ||
month : 'long', | ||
day : 'numeric', | ||
year : 'numeric' | ||
} ); | ||
}; | ||
|
||
// Not all browsers, particularly Safari, support arguments to .toLocaleTimeString(). | ||
const toLocaleTimeStringSupportsLocales = ( | ||
function() { | ||
try { | ||
new Date().toLocaleTimeString( 'i' ); | ||
} catch ( e ) { | ||
return e.name === 'RangeError'; | ||
} | ||
|
||
return false; | ||
} | ||
)(); | ||
|
||
document.querySelectorAll('.wporg-time-date').forEach( ( dateElement ) => { | ||
let localTime = ''; | ||
const date = parseDate( dateElement.getAttribute( 'title' ) ); | ||
|
||
if ( date ) { | ||
if ( ! toLocaleTimeStringSupportsLocales ) { | ||
console.log("🚀 ~ file: index.php:143 ~ document.querySelectorAll ~ toLocaleTimeStringSupportsLocales:", toLocaleTimeStringSupportsLocales) | ||
localTime += formatDate( date ); | ||
localTime += ' '; | ||
} | ||
|
||
localTime += formatTime( date ); | ||
|
||
dateElement.innerText = localTime; | ||
} | ||
} ); | ||
} | ||
|
||
document.addEventListener( 'DOMContentLoaded', () => { | ||
convertTime(); | ||
} ); | ||
} )(); | ||
</script> | ||
<?php | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"$schema": "https://schemas.wp.org/trunk/block.json", | ||
"apiVersion": 2, | ||
"name": "wporg/time", | ||
"title": "Time", | ||
"icon": "calendar", | ||
"category": "common", | ||
"description": "Attempts to parse a time string like <code>[time]any-valid-time-string-here[/time]</code> and creates a format that shows it in the viewers local time zone.", | ||
"textdomain": "wporg", | ||
"editorScript": "file:./index.js" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 } ) => ( | ||
<RichTextToolbarButton | ||
icon={ metadata.icon } | ||
title={ metadata.title } | ||
onClick={ () => { | ||
onChange( | ||
toggleFormat( value, { | ||
type: metadata.name, | ||
} ) | ||
); | ||
} } | ||
isActive={ isActive } | ||
/> | ||
); | ||
|
||
registerFormatType( metadata.name, { | ||
title: metadata.title, | ||
tagName: 'a', | ||
className: 'wporg-time', | ||
edit: Edit, | ||
} ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters