Skip to content

Commit

Permalink
fix: ensure prompts with expiration dates expire correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
dkoo committed Nov 19, 2024
1 parent 9aafe70 commit f0e691f
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 15 deletions.
48 changes: 36 additions & 12 deletions includes/class-newspack-popups-expiry.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,38 +27,62 @@ public static function init() {
}
}

/**
* Check if a given date should be considered expired.
* A date is expired if it's at or before the next occuring midnight.
*
* @param string $date The date string to check.
*
* @return bool True if the date is expired, false otherwise.
*/
public static function is_expired( $date ) {
$expiration_date = strtotime( $date );
if ( $expiration_date && $expiration_date <= strtotime( 'tomorrow' ) ) {
return true;
}
return false;
}

/**
* Revert expired prompts to draft state.
*/
public static function revert_expired_to_draft() {
// Get all prompts with the expiration_date in the past.
$expired_prompts = get_posts(
$prompts_with_expiration = get_posts(
[
'post_type' => Newspack_Popups::NEWSPACK_POPUPS_CPT,
'post_status' => 'publish',
'posts_per_page' => -1,
'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
'relation' => 'AND',
[
'key' => 'expiration_date',
'value' => gmdate( 'Y-m-d H:i:s' ),
'compare' => '<=',
'compare' => 'EXISTS',
],
[
'key' => 'expiration_date',
'compare' => 'REGEXP', // phpcs:ignore WordPressVIPMinimum.Performance.RegexpCompare.compare_compare
'value' => '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}',
'compare' => '!=',
'value' => '',
],
],
]
);
foreach ( $expired_prompts as $prompt_post ) {
foreach ( $prompts_with_expiration as $prompt ) {
// Change the post status to draft.
wp_update_post(
[
'ID' => $prompt_post->ID,
'post_status' => 'draft',
]
);
if ( self::is_expired( get_post_meta( $prompt->ID, 'expiration_date', true ) ) ) {
wp_update_post(
[
'ID' => $prompt->ID,
'post_status' => 'draft',
]
);
Newspack_Popups_Logger::log(
sprintf(
'Prompt "%s" has expired and reverted to draft status.',
$prompt->post_title
)
);
}
}
}

Expand Down
9 changes: 7 additions & 2 deletions src/editor/ExpirationPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import { ToggleControl, DatePicker } from '@wordpress/components';
import { isInTheFuture } from '@wordpress/date';
import { useEffect, useState, useMemo } from '@wordpress/element';

/**
* Internal dependencies
*/
import { convertDateToString } from './utils';

const ExpirationPanel = ( {
expiration_date = null,
postStatus,
Expand Down Expand Up @@ -57,7 +62,7 @@ const ExpirationPanel = ( {
const defaultExpirationDate = useMemo( () => {
const date = new Date();
date.setHours( date.getHours() + 24 );
return date;
return convertDateToString( date );
}, [] );

return (
Expand All @@ -76,7 +81,7 @@ const ExpirationPanel = ( {
{ expiration_date ? (
<DatePicker
currentDate={ expiration_date }
onChange={ value => onMetaFieldChange( { expiration_date: value } ) }
onChange={ value => onMetaFieldChange( { expiration_date: convertDateToString( new Date( value ) ) } ) }
isInvalidDate={ date => ! isInTheFuture( date ) }
/>
) : null }
Expand Down
15 changes: 15 additions & 0 deletions src/editor/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,18 @@ export const getPlacementHelpMessage = props => {
return __( 'The placement where the prompt can appear.', 'newspack-popups' );
}
};

/**
* Convert a date object to a string in YYYY-MM-DDTHH:MM:SS format.
* Omit Z timezone so the date is parsed in the site's local timezone.
*
* @param {Date} date
* @return {string} Date string in Y-m-d H:i:s format or empty string if the given date can't be parsed.
*/
export const convertDateToString = date => {
if ( ! ( date instanceof Date ) ) {
return '';
}

return date.toISOString().split( '.' )[ 0 ];
}
52 changes: 51 additions & 1 deletion tests/test-popups-expiry.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function test_prompt_expiry_init() {
}

/**
* Test the revert_expired_to_draft function.
* Test the revert_expired_to_draft function with PHP date format (YYYY-MM-DD HH:MM:SS).
*/
public function test_prompt_expiry_revert_expired_to_draft() {
// Create a post with an expiration date in the past.
Expand Down Expand Up @@ -98,4 +98,54 @@ public function test_prompt_expiry_invalid_meta() {
// Should not have been reverted to draft.
$this->assertEquals( 'publish', get_post_status( $post_id ) );
}

/**
* Test different expiry logic with various date string formats.
*/
public function test_date_string_formats() {
$this->assertTrue(
Newspack_Popups_Expiry::is_expired( gmdate( 'Y-m-d H:i:s', strtotime( '-1 day' ) ) ),
'Anytime yesterday in PHP date format (YYYY-MM-DD HH:MM:SS) is expired.'
);
$this->assertTrue(
Newspack_Popups_Expiry::is_expired( gmdate( 'Y-m-d H:i:s', time() ) ),
'Anytime today in PHP date format (YYYY-MM-DD HH:MM:SS) is expired.'
);
$this->assertFalse(
Newspack_Popups_Expiry::is_expired( gmdate( 'Y-m-d H:i:s', strtotime( '+1 day' ) ) ),
'Anytime tomorrow in PHP date format (YYYY-MM-DD HH:MM:SS) is NOT expired.'
);
$this->assertTrue(
Newspack_Popups_Expiry::is_expired( gmdate( 'Y-m-d\TH:i:s', strtotime( '-1 day' ) ) ),
'Anytime yesterday in JS date format (YYYY-MM-DDTHH:MM:SS) is expired.'
);
$this->assertTrue(
Newspack_Popups_Expiry::is_expired( gmdate( 'Y-m-d\TH:i:s', time() ) ),
'Anytime today in JS date format (YYYY-MM-DDTHH:MM:SS) is expired.'
);
$this->assertFalse(
Newspack_Popups_Expiry::is_expired( gmdate( 'Y-m-d\TH:i:s', strtotime( '+1 day' ) ) ),
'Anytime tomorrow in JS date format (YYYY-MM-DDTHH:MM:SS) is NOT expired.'
);
$this->assertTrue(
Newspack_Popups_Expiry::is_expired( gmdate( 'F j, Y g:i:s A', strtotime( '-1 day' ) ) ),
'Anytime yesterday in human-readable date format is expired.'
);
$this->assertTrue(
Newspack_Popups_Expiry::is_expired( gmdate( 'F j, Y g:i:s A', time() ) ),
'Anytime today in human-readable date format is expired.'
);
$this->assertFalse(
Newspack_Popups_Expiry::is_expired( gmdate( 'F j, Y g:i:s A', strtotime( '+1 day' ) ) ),
'Anytime tomorrow in human-readable date format is NOT expired.'
);
$this->assertFalse(
Newspack_Popups_Expiry::is_expired( 'invalid date' ),
'Invalid date string is NOT expired.'
);
$this->assertFalse(
Newspack_Popups_Expiry::is_expired( '' ),
'Empty date string is NOT expired.'
);
}
}

0 comments on commit f0e691f

Please sign in to comment.