Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wpcomsh: bilmur: Add site timezone to tag #41964

Open
wants to merge 9 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions projects/plugins/wpcomsh/changelog/wpcomsh-bilmur-tz
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: changed

Bilmur RUM library now reports the site's timezone
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php
/**
* Wpcomsh Test file.
*
* @package wpcomsh
*/

/**
* Class Test_WPCOMSH_Stats_Timezone_String
*/
// phpcs:disable Squiz.Commenting.FunctionComment.WrongStyle
class Test_WPCOMSH_Stats_Timezone_String extends WP_UnitTestCase {
private $original_timezone_string;
private $original_gmt_offset;

public function setUp(): void {
parent::setUp();
// Backup original options
$this->original_timezone_string = get_option( 'timezone_string' );
$this->original_gmt_offset = get_option( 'gmt_offset' );
}

public function tearDown(): void {
// Restore original options
update_option( 'timezone_string', $this->original_timezone_string );
update_option( 'gmt_offset', $this->original_gmt_offset );
parent::tearDown();
}

// Test with a named timezone (e.g., "America/New_York")
public function test_wpcomsh_stats_timezone_string_with_named_tz() {
update_option( 'timezone_string', 'America/New_York' );
update_option( 'gmt_offset', '' ); // Clear offset to ensure we use timezone_string

$actual_output = wpcomsh_stats_timezone_string();
$expected_output = 'America/New_York';
$this->assertEquals( $expected_output, $actual_output );
}

// Test with integer hour offset (e.g., UTC+5)
public function test_wpcomsh_stats_timezone_string_with_integer_offset() {
update_option( 'timezone_string', '' );
update_option( 'gmt_offset', 5 ); // +5 hours

$actual_output = wpcomsh_stats_timezone_string();
$expected_output = 'Etc/GMT-5'; // Note the flipped sign per the function spec
$this->assertEquals( $expected_output, $actual_output );
}

// Test with negative integer hour offset (e.g., UTC-3)
public function test_wpcomsh_stats_timezone_string_with_negative_integer_offset() {
update_option( 'timezone_string', '' );
update_option( 'gmt_offset', -3 ); // -3 hours

$actual_output = wpcomsh_stats_timezone_string();
$expected_output = 'Etc/GMT+3'; // Note the flipped sign per the function spec
$this->assertEquals( $expected_output, $actual_output );
}

// Test with fractional hour offset (e.g., UTC+5:30)
public function test_wpcomsh_stats_timezone_string_with_fractional_offset() {
update_option( 'timezone_string', '' );
update_option( 'gmt_offset', 5.5 ); // +5 hours 30 minutes

$actual_output = wpcomsh_stats_timezone_string();
// Expecting a city timezone like "Asia/Kolkata" for +5:30
// Note: exact result might depend on PHP's timezone database
$this->assertEquals( 'Asia/Kolkata', $actual_output );
}

// Test with fractional offset that has no city match (fall back to integer)
public function test_wpcomsh_stats_timezone_string_with_unmatched_fractional_offset() {
update_option( 'timezone_string', '' );
update_option( 'gmt_offset', 5.25 ); // +5 hours 15 minutes (no common city match)

$actual_output = wpcomsh_stats_timezone_string();
// Should fall back to integer offset "Etc/GMT-5"
$this->assertEquals( 'Etc/GMT-5', $actual_output );
}

public function test_wpcomsh_stats_timezone_string_with_zero_offset() {
update_option( 'timezone_string', '' );
update_option( 'gmt_offset', 0 );

$actual_output = wpcomsh_stats_timezone_string();
$expected_output = 'Etc/GMT-0';
$this->assertEquals( $expected_output, $actual_output );
}
}
// phpcs:enable Squiz.Commenting.FunctionComment.WrongStyle
50 changes: 48 additions & 2 deletions projects/plugins/wpcomsh/wpcomsh.php
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,49 @@ function wpcom_hide_scan_threats_from_api( $response ) {
}
add_filter( 'rest_post_dispatch', 'wpcom_hide_scan_threats_from_api' );

/**
* Returns a standardized timezone string.
*
* `wp_timezone_string()` sometimes returns offsets (e.g. "-07:00"), which are
* a non-standard representation of a UTC offset that only works in PHP.
* This function returns a standardized timezone string instead, of the form
* "Etc/GMT+7" for integer hour offsets, or a matching "<Area>/<City>" form for
* fractional hour offsets (used e.g. in India).
*/
function wpcomsh_stats_timezone_string() {
$wp_tz = wp_timezone_string();

// Did we get back an offset?
if ( preg_match( '/^([+-])?(\d{1,2}):(\d{2})$/', $wp_tz, $matches ) ) {
$sign = $matches[1] === '-' ? -1 : 1;
$hours = intval( $matches[2], 10 );
$minutes = intval( $matches[3], 10 );

// For fractional hour offsets, use `timezone_name_from_abbr` to get a
// matching "<Area>/<City>" timezone.
if ( $minutes > 0 ) {
$offset = $sign * ( $hours * 3600 + $minutes * 60 );
$city_tz = timezone_name_from_abbr( '', $offset, 0 );

if ( ! empty( $city_tz ) ) {
return $city_tz;
}
}

// For integer hour offsets, use "Etc/GMT(+|-)<offset>".
// The sign is flipped, to match how the `Etc` area is specced.
//
// This codepath is also followed if no city exists to match a
// fractional offset, by simply discarding the fractional part.
// This isn't ideal, but there's no standard way of describing
// these offsets, and is likely to be an extreme edge case.
return 'Etc/GMT' . ( $sign === -1 ? '+' : '-' ) . $hours;
}

// For anything that's not an offset, return the string we got from WP.
return $wp_tz;
}

/**
* Collect RUM performance data
* p9o2xV-XY-p2
Expand Down Expand Up @@ -571,12 +614,15 @@ function wpcomsh_footer_rum_js() {
$rum_kv = '';
}

$data_site_tz = 'data-site-tz="' . esc_attr( wpcomsh_stats_timezone_string() ) . '"';

printf(
'<script defer id="bilmur" %1$s data-provider="wordpress.com" data-service="%2$s" %3$s src="%4$s"></script>' . "\n", //phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
'<script defer id="bilmur" %1$s data-provider="wordpress.com" data-service="%2$s" %3$s src="%4$s" %5$s></script>' . "\n", //phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
$rum_kv, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
esc_attr( $service ),
wp_kses_post( $allow_iframe ),
esc_url( 'https://s0.wp.com/wp-content/js/bilmur.min.js?m=' . gmdate( 'YW' ) )
esc_url( 'https://s0.wp.com/wp-content/js/bilmur.min.js?m=' . gmdate( 'YW' ) ),
$data_site_tz // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
);
}

Expand Down