Skip to content

Automatically clear transient upon settings change #37

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

Merged
merged 6 commits into from
Jun 26, 2020
Merged
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ Configuration for Limit Orders for WooCommerce is available through WooCommerce

![The settings screen for Limit Orders for WooCommerce](.wordpress-org/screenshot-1.png)

⚠️ **Please be aware** that any changes made to the settings will take effect immediately.

For example, if you're using an hourly interval and switch it to daily, the plugin will re-calculate whether or not to disable ordering based on the number of orders received since the start of the current day (midnight, by default).

### General settings

These settings determine how and when order limiting should take effect.

<dl>
<dt>Enable Order Limiting</dt>
<dd>Check this box to enable order limiting.</dd>
Expand Down
1 change: 0 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
<testsuites>
<testsuite name="unit">
<directory suffix="Test.php">./tests/</directory>
<exclude>./tests/SampleTest.php</exclude>
</testsuite>
</testsuites>
<filter>
Expand Down
24 changes: 23 additions & 1 deletion src/OrderLimiter.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public function __construct( \DateTimeImmutable $now = null ) {
*/
public function init() {
add_action( 'woocommerce_new_order', [ $this, 'regenerate_transient' ] );
add_action( 'update_option_' . self::OPTION_KEY, [ $this, 'reset_limiter' ], 10, 2 );
}

/**
Expand Down Expand Up @@ -274,7 +275,16 @@ public function get_seconds_until_next_interval() {
}

/**
* Determine whether or not the given store has reached its limits.
* Determine whether or not the store has any orders in the given interval.
*
* @return bool
*/
public function has_orders_in_current_interval() {
return $this->get_limit() > $this->get_remaining_orders();
}

/**
* Determine whether or not the store has reached its limits.
*
* @return bool
*/
Expand Down Expand Up @@ -349,6 +359,18 @@ public function regenerate_transient() {
return $count;
}

/**
* Reset the limiter when its configuration changes.
*
* @param mixed $previous The previous value of the option.
* @param mixed $new The new option value.
*/
public function reset_limiter( $previous, $new ) {
if ( $previous !== $new ) {
delete_transient( self::TRANSIENT_NAME );
}
}

/**
* Count the number of qualifying orders.
*
Expand Down
10 changes: 9 additions & 1 deletion src/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,16 @@ public function __construct( OrderLimiter $limiter ) {
*/
public function get_settings() {
$placeholders = (array) $this->limiter->get_placeholders();
$update_warning = '';
$available_placeholders = '';

// Warn users if changes will impact current limits.
if ( $this->limiter->has_orders_in_current_interval() ) {
$update_warning = '<div class="notice notice-info"><p>';
$update_warning .= __( 'Please be aware that making changes to these settings will recalculate limits for the current interval.', 'limit-orders' );
$update_warning .= '</p></div>';
}

// Build a list of available placeholders.
if ( ! empty( $placeholders ) ) {
$available_placeholders = __( 'Available placeholders:', 'limit-orders' ) . ' <var>';
Expand All @@ -50,7 +58,7 @@ public function get_settings() {
'id' => 'limit-orders-general',
'type' => 'title',
'name' => _x( 'Order Limiting', 'settings section title', 'limit-orders' ),
'desc' => __( 'Automatically turn off new orders once the store\'s limit has been met.', 'limit-orders' ),
'desc' => __( 'Automatically turn off new orders once the store\'s limit has been met.', 'limit-orders' ) . $update_warning,
],
[
'id' => OrderLimiter::OPTION_KEY . '[enabled]',
Expand Down
3 changes: 0 additions & 3 deletions tests/AdminTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@

use Nexcess\LimitOrders\Admin;
use Nexcess\LimitOrders\OrderLimiter;
use WC_Admin;
use WC_Settings_General;
use WP_UnitTestCase as TestCase;

/**
* @covers Nexcess\LimitOrders\Admin
Expand Down
85 changes: 66 additions & 19 deletions tests/OrderLimiterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
namespace Tests;

use Nexcess\LimitOrders\OrderLimiter;
use WC_Checkout;
use WC_Form_Handler;
use WC_Helper_Product;
use WP_UnitTestCase as TestCase;

/**
* @covers Nexcess\LimitOrders\OrderLimiter
Expand Down Expand Up @@ -648,6 +645,25 @@ public function get_seconds_until_next_interval_for_monthly() {
);
}

/**
* @test
*/
public function has_orders_in_current_interval_should_compare_the_limit_to_remaining_order() {
update_option( OrderLimiter::OPTION_KEY, [
'enabled' => true,
'limit' => 5,
] );

$limiter = new OrderLimiter();
$limiter->init();

$this->assertFalse( $limiter->has_orders_in_current_interval() );

$this->generate_order();

$this->assertTrue( $limiter->has_orders_in_current_interval() );
}

/**
* @test
* @testdox has_reached_limit() should return false if the order count meets the limit
Expand Down Expand Up @@ -853,39 +869,70 @@ public function the_transient_should_be_updated_each_time_an_order_is_placed() {
}
}

/**
* @test
* @ticket https://github.com/nexcess/limit-orders/issues/36
*/
public function the_limiter_should_be_reset_when_settings_are_changed() {
set_transient( OrderLimiter::TRANSIENT_NAME, uniqid() );
update_option( OrderLimiter::OPTION_KEY, [
'enabled' => true,
'interval' => 'daily',
'limit' => 5,
] );

( new OrderLimiter() )->init();

update_option( OrderLimiter::OPTION_KEY, [
'enabled' => true,
'interval' => 'hourly',
'limit' => 2,
] );

$this->assertFalse( get_transient( OrderLimiter::TRANSIENT_NAME ) );
}

/**
* @test
* @ticket https://github.com/nexcess/limit-orders/issues/36
*/
public function the_limiter_should_be_not_reset_unless_settings_have_actually_been_updated() {
$transient = uniqid();

set_transient( OrderLimiter::TRANSIENT_NAME, $transient );
update_option( OrderLimiter::OPTION_KEY, [
'enabled' => true,
'interval' => 'daily',
'limit' => 5,
] );

( new OrderLimiter() )->init();

update_option( OrderLimiter::OPTION_KEY, get_option( OrderLimiter::OPTION_KEY ) );

$this->assertSame( $transient, get_transient( OrderLimiter::TRANSIENT_NAME ) );
}

/**
* @test
* @ticket https://github.com/nexcess/limit-orders/pull/13
*/
public function count_qualifying_orders_should_not_limit_results() {
update_option( 'posts_per_page', 2 ); // Lower the default to improve test performance.
update_option( OrderLimiter::OPTION_KEY, [
'enabled' => true,
'interval' => 'daily',
'limit' => 100,
] );

for ( $i = 0; $i < 24; $i++ ) {
for ( $i = 0; $i < 5; $i++ ) {
$this->generate_order();
}

$instance = new OrderLimiter();
$method = new \ReflectionMethod( $instance, 'count_qualifying_orders' );
$method->setAccessible( true );

$this->assertSame( 24, $method->invoke( $instance ) );
}

/**
* Create a new order by emulating the checkout process.
*/
protected function generate_order() {
$product = WC_Helper_Product::create_simple_product( true );

WC()->cart->add_to_cart( $product->get_id(), 1 );

return WC_Checkout::instance()->create_order( [
'billing_email' => '[email protected]',
'payment_method' => 'dummy_payment_gateway',
] );
$this->assertSame( 5, $method->invoke( $instance ) );
}
}
20 changes: 0 additions & 20 deletions tests/SampleTest.php

This file was deleted.

93 changes: 70 additions & 23 deletions tests/SettingsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

use Nexcess\LimitOrders\OrderLimiter;
use Nexcess\LimitOrders\Settings;
use WP_UnitTestCase as TestCase;

/**
* @covers Nexcess\LimitOrders\Settings
Expand All @@ -21,11 +20,10 @@ class SettingsTest extends TestCase {
/**
* @test
*/
public function the_options_should_be_added_to_their_own_page() {
$settings = ( new Settings( new OrderLimiter() ) )->get_settings();
public function the_settings_should_be_added_to_their_own_page() {
$instance = new Settings( new OrderLimiter() );

$this->assertSame( 'title', $settings[0]['type'] );
$this->assertSame( 'limit-orders-general', $settings[0]['id'] );
$this->assertSame( 'limit-orders', $instance->get_id() );
}

/**
Expand Down Expand Up @@ -58,35 +56,84 @@ public function available_intervals_should_be_filterable() {
return $intervals;
} );

// Find the interval setting and inspect its options.
foreach ( ( new Settings( new OrderLimiter() ) )->get_settings() as $setting ) {
if ( OrderLimiter::OPTION_KEY . '[interval]' !== $setting['id'] ) {
continue;
}
$setting = $this->get_setting_by_id( OrderLimiter::OPTION_KEY . '[interval]' );

$this->assertSame( $intervals, $setting['options'] );
return;
}

$this->fail( 'Did not find setting with ID "'. OrderLimiter::OPTION_KEY . '[interval]".' );
$this->assertArrayHasKey( 'options', $setting );
$this->assertSame( $intervals, $setting['options'] );
}

/**
* @test
* @group Placeholders
*/
public function available_placeholders_should_be_shown_in_the_messages_section() {
$limiter = new OrderLimiter();
$sections = array_filter( ( new Settings( new OrderLimiter() ) )->get_settings(), function ( $section ) {
return 'limit-orders-messaging' === $section['id'] && 'title' === $section['type'];
} );

$this->assertCount( 1, $sections, 'Expected to see only one instance of "limit-orders-messaging".' );

$description = current( $sections )['desc'];
$limiter = new OrderLimiter();
$instance = new Settings( $limiter );
$description = $this->get_setting_by_id( 'limit-orders-messaging', $instance )['desc'];

foreach ( $limiter->get_placeholders() as $placeholder => $value ) {
$this->assertContains( '<var>' . $placeholder . '</var>', $description );
}
}

/**
* @test
* @ticket https://github.com/nexcess/limit-orders/issues/36
*/
public function a_notice_should_be_shown_if_there_have_been_orders_in_the_current_interval() {
update_option( OrderLimiter::OPTION_KEY, [
'enabled' => true,
'limit' => 10,
] );

$this->generate_order();

$limiter = new OrderLimiter();
$limiter->init();

$this->assertStringContainsString(
'<div class="notice notice-info">',
$this->get_setting_by_id( 'limit-orders-general', new Settings( $limiter ) )['desc'],
'Expected to see a notice about limits being recalculated.'
);
}

/**
* @test
* @ticket https://github.com/nexcess/limit-orders/issues/36
*/
public function a_notice_should_not_be_shown_if_there_have_not_been_any_orders_in_the_current_interval() {
update_option( OrderLimiter::OPTION_KEY, [
'enabled' => true,
'limit' => 10,
] );

$limiter = new OrderLimiter();
$limiter->init();

$this->assertStringNotContainsString(
'<div class="notice notice-info">',
$this->get_setting_by_id( 'limit-orders-general', new Settings( $limiter ) )['desc'],
'Did not expect to see a notice about limits being recalculated.'
);
}

/**
* Retrieve the given setting by ID.
*
* If more than one setting matches, the first result will be returned.
*
* @param string $section_id The setting ID.
* @param Settings $instance Optional. An instantiated Settings object, if available.
*
* @return array|null Either the first matching setting or null if no matches were found.
*/
protected function get_setting_by_id( $setting_id, Settings $instance = null ) {
$instance = $instance ?: new Settings( new OrderLimiter() );
$settings = array_filter( $instance->get_settings(), function ( $setting ) use ( $setting_id ) {
return $setting_id === $setting['id'];
} );

return current( $settings );
}
}
Loading