Last active
June 16, 2025 12:05
-
-
Save pramodjodhani/fbec33ad84fec1a60c0ac00894ad0899 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
<?php | |
/** | |
* Plugin Name: Recurring Slot Calculator Test | |
* Plugin URI: https://iconicwp.com | |
* Description: Test plugin for RecurringSlotCalculator class | |
* Version: 1.0.0 | |
* Author: IconicWP | |
* Text Domain: recurring-slot-test | |
* | |
* @package RecurringSlotTest | |
*/ | |
namespace RecurringSlotTest; | |
use Iconic_WDS\Subscriptions\RecurringSlotCalculator; | |
use Iconic_WDS\Subscriptions\Dto\SubscriptionOrderMetaData; | |
use DateTime; | |
use Exception; | |
defined( 'ABSPATH' ) || exit; | |
/** | |
* Main test plugin class. | |
*/ | |
class RecurringSlotTest { | |
/** | |
* Plugin instance. | |
* | |
* @var RecurringSlotTest | |
*/ | |
private static $instance = null; | |
/** | |
* Get plugin instance. | |
* | |
* @return RecurringSlotTest | |
*/ | |
public static function instance() { | |
if ( null === self::$instance ) { | |
self::$instance = new self(); | |
} | |
return self::$instance; | |
} | |
/** | |
* Constructor. | |
*/ | |
private function __construct() { | |
add_action( 'admin_menu', array( $this, 'add_admin_menu' ) ); | |
add_action( 'admin_init', array( $this, 'handle_form_submission' ) ); | |
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); | |
} | |
/** | |
* Add admin menu. | |
*/ | |
public function add_admin_menu() { | |
add_menu_page( | |
__( 'Recurring Slot Test', 'recurring-slot-test' ), | |
__( 'Slot Calculator Test', 'recurring-slot-test' ), | |
'manage_options', | |
'recurring-slot-test', | |
array( $this, 'admin_page_callback' ), | |
'dashicons-calendar-alt', | |
30 | |
); | |
} | |
/** | |
* Enqueue scripts. | |
* | |
* @param string $hook Current admin page hook. | |
*/ | |
public function enqueue_scripts( $hook ) { | |
if ( 'toplevel_page_recurring-slot-test' !== $hook ) { | |
return; | |
} | |
wp_enqueue_script( 'jquery' ); | |
wp_enqueue_script( 'jquery-ui-datepicker' ); | |
wp_enqueue_style( 'jquery-ui-datepicker', 'https://code.jquery.com/ui/1.12.1/themes/ui-lightness/jquery-ui.css', array(), '1.12.1' ); | |
} | |
/** | |
* Handle form submission. | |
*/ | |
public function handle_form_submission() { | |
if ( ! isset( $_POST['recurring_slot_test_nonce'] ) || | |
! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['recurring_slot_test_nonce'] ) ), 'recurring_slot_test' ) ) { | |
return; | |
} | |
if ( ! isset( $_POST['submit_test'] ) ) { | |
return; | |
} | |
$this->process_test_form(); | |
} | |
/** | |
* Process the test form. | |
* | |
* @throws Exception When validation fails or calculation errors occur. | |
*/ | |
private function process_test_form() { | |
try { | |
// Validate nonce first. | |
if ( ! isset( $_POST['recurring_slot_test_nonce'] ) || | |
! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['recurring_slot_test_nonce'] ) ), 'recurring_slot_test' ) ) { | |
throw new Exception( 'Invalid nonce verification.' ); | |
} | |
// Sanitize input data. | |
$subscription_id = isset( $_POST['subscription_id'] ) ? absint( $_POST['subscription_id'] ) : 0; | |
$start_date_string = isset( $_POST['start_date'] ) ? sanitize_text_field( wp_unslash( $_POST['start_date'] ) ) : ''; | |
$order_date_string = isset( $_POST['order_date'] ) ? sanitize_text_field( wp_unslash( $_POST['order_date'] ) ) : ''; | |
// Validate required fields. | |
if ( empty( $subscription_id ) || empty( $start_date_string ) || empty( $order_date_string ) ) { | |
throw new Exception( 'Subscription ID, Start Date, and Order Date are required.' ); | |
} | |
// Get subscription data. | |
if ( ! function_exists( 'wcs_get_subscription' ) ) { | |
throw new Exception( 'WooCommerce Subscriptions is not active.' ); | |
} | |
$subscription = wcs_get_subscription( $subscription_id ); | |
if ( ! $subscription ) { | |
throw new Exception( 'Subscription not found with ID: ' . $subscription_id ); | |
} | |
// Get subscription period and interval. | |
$period = $subscription->get_billing_period(); | |
$interval = $subscription->get_billing_interval(); | |
// Get the anchor day from the subscription's parent order. | |
$parent_order = $subscription->get_parent(); | |
if ( ! $parent_order ) { | |
throw new Exception( 'Parent order not found for subscription.' ); | |
} | |
$order_meta_data = SubscriptionOrderMetaData::from_order( $parent_order ); | |
$anchor_day = $order_meta_data->timeslot_anchor_day; | |
// Create DateTime objects. | |
$start_date = DateTime::createFromFormat( 'Y-m-d', $start_date_string, wp_timezone() ); | |
$order_date = DateTime::createFromFormat( 'Y-m-d', $order_date_string, wp_timezone() ); | |
if ( ! $start_date || ! $order_date ) { | |
throw new Exception( 'Invalid date format. Please use YYYY-MM-DD format.' ); | |
} | |
// Create calculator instance. | |
$calculator_data = array( | |
'anchor_day' => $anchor_day, | |
'period' => $period, | |
'interval' => $interval, | |
'start_date' => $start_date, | |
'subscription_id' => $subscription_id, | |
); | |
$calculator = RecurringSlotCalculator::from_array( $calculator_data ); | |
// Calculate delivery date. | |
$delivery_date = $calculator->calculate_adjusted_delivery_date( $order_date ); | |
// Store result for display. | |
set_transient( | |
'recurring_slot_test_result', | |
array( | |
'success' => true, | |
'delivery_date' => $delivery_date ? $delivery_date->format( 'Y-m-d H:i:s' ) : null, | |
'input_data' => $calculator_data, | |
'subscription_id' => $subscription_id, | |
'start_date' => $start_date_string, | |
'order_date' => $order_date_string, | |
), | |
300 | |
); | |
// Store form values for maintaining state. | |
set_transient( | |
'recurring_slot_test_form_values', | |
array( | |
'subscription_id' => $subscription_id, | |
'start_date' => $start_date_string, | |
'order_date' => $order_date_string, | |
), | |
300 | |
); | |
} catch ( Exception $e ) { | |
// Store error for display. | |
set_transient( | |
'recurring_slot_test_result', | |
array( | |
'success' => false, | |
'error' => $e->getMessage(), | |
), | |
300 | |
); | |
// Store form values even on error for maintaining state. | |
$subscription_id = isset( $_POST['subscription_id'] ) ? absint( $_POST['subscription_id'] ) : 0; | |
$start_date_string = isset( $_POST['start_date'] ) ? sanitize_text_field( wp_unslash( $_POST['start_date'] ) ) : ''; | |
$order_date_string = isset( $_POST['order_date'] ) ? sanitize_text_field( wp_unslash( $_POST['order_date'] ) ) : ''; | |
set_transient( | |
'recurring_slot_test_form_values', | |
array( | |
'subscription_id' => $subscription_id, | |
'start_date' => $start_date_string, | |
'order_date' => $order_date_string, | |
), | |
300 | |
); | |
} | |
// Redirect to avoid resubmission. | |
wp_redirect( admin_url( 'admin.php?page=recurring-slot-test&calculated=1' ) ); | |
exit; | |
} | |
/** | |
* Get a sanitized POST value safely. | |
* | |
* @param string $key The POST key. | |
* @param mixed $default Default value. | |
* @return mixed The sanitized value or default. | |
*/ | |
private function get_post_value( $key, $default = '' ) { | |
if ( ! isset( $_POST['recurring_slot_test_nonce'] ) || | |
! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['recurring_slot_test_nonce'] ) ), 'recurring_slot_test' ) ) { | |
return $default; | |
} | |
if ( ! isset( $_POST[ $key ] ) ) { | |
return $default; | |
} | |
if ( is_numeric( $default ) ) { | |
return absint( $_POST[ $key ] ); | |
} | |
return sanitize_text_field( wp_unslash( $_POST[ $key ] ) ); | |
} | |
/** | |
* Admin page callback. | |
*/ | |
public function admin_page_callback() { | |
// Get saved form values from transient first, then fall back to POST or defaults. | |
$saved_values = get_transient( 'recurring_slot_test_form_values' ); | |
if ( $saved_values ) { | |
$prev_subscription_id = $saved_values['subscription_id']; | |
$prev_start_date = $saved_values['start_date']; | |
$prev_order_date = $saved_values['order_date']; | |
} else { | |
// Fall back to POST values or defaults. | |
$prev_subscription_id = $this->get_post_value( 'subscription_id', 1 ); | |
$prev_start_date = $this->get_post_value( 'start_date', gmdate( 'Y-m-d' ) ); | |
$prev_order_date = $this->get_post_value( 'order_date', gmdate( 'Y-m-d' ) ); | |
} | |
?> | |
<div class="wrap"> | |
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1> | |
<?php $this->display_result(); ?> | |
<div class="card" style="max-width: 800px;"> | |
<h2>Test RecurringSlotCalculator</h2> | |
<form method="post" action=""> | |
<?php wp_nonce_field( 'recurring_slot_test', 'recurring_slot_test_nonce' ); ?> | |
<table class="form-table"> | |
<tr> | |
<th scope="row"> | |
<label for="subscription_id">Subscription ID</label> | |
</th> | |
<td> | |
<input type="number" id="subscription_id" name="subscription_id" | |
value="<?php echo esc_attr( $prev_subscription_id ); ?>" | |
min="1" required class="regular-text" /> | |
<p class="description">The subscription ID to get anchor day, period, and interval from</p> | |
</td> | |
</tr> | |
<tr> | |
<th scope="row"> | |
<label for="start_date">Subscription Start Date</label> | |
</th> | |
<td> | |
<input type="text" id="start_date" name="start_date" | |
value="<?php echo esc_attr( $prev_start_date ); ?>" | |
required class="regular-text datepicker" /> | |
<p class="description">The first delivery date for the subscription (YYYY-MM-DD)</p> | |
</td> | |
</tr> | |
<tr> | |
<th scope="row"> | |
<label for="order_date">Recurring Order Creation Date</label> | |
</th> | |
<td> | |
<input type="text" id="order_date" name="order_date" | |
value="<?php echo esc_attr( $prev_order_date ); ?>" | |
required class="regular-text datepicker" /> | |
<p class="description">The date when the recurring order is created (YYYY-MM-DD)</p> | |
</td> | |
</tr> | |
</table> | |
<?php submit_button( 'Calculate Delivery Date', 'primary', 'submit_test' ); ?> | |
</form> | |
</div> | |
<div class="card" style="max-width: 800px; margin-top: 20px;"> | |
<h3>How it works</h3> | |
<p>This tool tests the <code>RecurringSlotCalculator::calculate_adjusted_delivery_date()</code> method using data from an actual subscription.</p> | |
<ul> | |
<li><strong>Subscription ID:</strong> The system will automatically extract the anchor day, period, and interval from this subscription</li> | |
<li><strong>Subscription Start Date:</strong> The first delivery date for the subscription (manually entered)</li> | |
<li><strong>Recurring Order Creation Date:</strong> The date when a new recurring order is created</li> | |
<li><strong>Anchor Day:</strong> Automatically retrieved from the subscription's parent order meta</li> | |
<li><strong>Period & Interval:</strong> Automatically retrieved from the subscription settings</li> | |
</ul> | |
</div> | |
</div> | |
<script> | |
jQuery(document).ready(function($) { | |
$('.datepicker').datepicker({ | |
dateFormat: 'yy-mm-dd', | |
changeMonth: true, | |
changeYear: true | |
}); | |
}); | |
</script> | |
<style> | |
.card { | |
background: #fff; | |
border: 1px solid #ccd0d4; | |
box-shadow: 0 1px 1px rgba(0,0,0,.04); | |
padding: 20px; | |
margin: 20px 0; | |
} | |
.result-success { | |
background: #d4edda; | |
color: #155724; | |
border: 1px solid #c3e6cb; | |
border-radius: 4px; | |
padding: 15px; | |
margin: 20px 0; | |
} | |
.result-error { | |
background: #f8d7da; | |
color: #721c24; | |
border: 1px solid #f5c6cb; | |
border-radius: 4px; | |
padding: 15px; | |
margin: 20px 0; | |
} | |
</style> | |
<?php | |
} | |
/** | |
* Display calculation result. | |
*/ | |
private function display_result() { | |
if ( ! isset( $_GET['calculated'] ) ) { | |
return; | |
} | |
$result = get_transient( 'recurring_slot_test_result' ); | |
if ( ! $result ) { | |
return; | |
} | |
// Delete the result transient after displaying, but keep form values. | |
delete_transient( 'recurring_slot_test_result' ); | |
if ( $result['success'] ) { | |
?> | |
<div class="result-success"> | |
<h3>✅ Calculation Result</h3> | |
<?php if ( $result['delivery_date'] ) : ?> | |
<p><strong>Calculated Delivery Date:</strong> <?php echo esc_html( $result['delivery_date'] ); ?></p> | |
<?php else : ?> | |
<p><strong>Result:</strong> No delivery date could be calculated (returned null)</p> | |
<?php endif; ?> | |
<details> | |
<summary>Input Parameters</summary> | |
<ul> | |
<li><strong>Subscription ID:</strong> <?php echo esc_html( $result['subscription_id'] ); ?></li> | |
<li><strong>Start Date:</strong> <?php echo esc_html( $result['start_date'] ); ?></li> | |
<li><strong>Order Date:</strong> <?php echo esc_html( $result['order_date'] ); ?></li> | |
<li><strong>Anchor Day:</strong> <?php echo esc_html( $result['input_data']['anchor_day'] ); ?> (from subscription)</li> | |
<li><strong>Period:</strong> <?php echo esc_html( $result['input_data']['period'] ); ?> (from subscription)</li> | |
<li><strong>Interval:</strong> <?php echo esc_html( $result['input_data']['interval'] ); ?> (from subscription)</li> | |
</ul> | |
</details> | |
</div> | |
<?php | |
} else { | |
?> | |
<div class="result-error"> | |
<h3>❌ Error</h3> | |
<p><?php echo esc_html( $result['error'] ); ?></p> | |
</div> | |
<?php | |
} | |
} | |
} | |
// Initialize the plugin. | |
add_action( 'plugins_loaded', array( 'RecurringSlotTest\RecurringSlotTest', 'instance' ) ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment