Commit 5e41b855da2 for woocommerce
commit 5e41b855da2afec3c0c412ab25cc8f0c09b8fe77
Author: Chris Lilitsas <1105590+xristos3490@users.noreply.github.com>
Date: Tue Sep 8 14:51:04 2026 +0300
Make the stock notifications My Account endpoint slug configurable (WOOPLUG-7656) (#68291)
* Add My Account endpoint for back in stock notifications
Registers the back-in-stock-notifications endpoint under WC > My Account
with a matching template that renders the current user's signups as an
accessible table. Wired via woocommerce_get_query_vars (rewrite endpoint),
woocommerce_account_menu_items (menu label), and the standard
woocommerce_account_<slug>_endpoint action. Notifications are fetched
exclusively via NotificationQuery::get_notifications() scoped to
get_current_user_id(), never by client-supplied ids.
The whole MyAccountEndpoint is instantiated from StockNotifications
init_hooks(), which is already gated behind WOOCOMMERCE_BIS_ALPHA_ENABLED
in class-woocommerce.php, so the endpoint and menu item stay hidden
whenever the alpha constant is off.
* Add PHPUnit coverage for My Account BIS endpoint
Covers the customer-facing scenarios that were previously only exercised
in ad-hoc manual testing:
- Endpoint helper returns only the current user's notifications.
- User A cannot see user B's notifications.
- Anonymous visitors get an empty list (no query by client ids).
- Empty state for users with no signups.
- Cancel with a valid per-notification nonce flips to cancelled +
records cancellation source = user.
- Cancel with an invalid nonce is a no-op.
- Cross-notification nonce replay (A's nonce + B's id) is a no-op.
- Ownership check blocks user A cancelling user B's notification.
- Anonymous cancel POST is silently dropped.
- Menu filter registers the label and preserves Log out at the end.
- Query var filter adds the expected slug.
* Add Playwright coverage for My Account BIS tab
Covers the customer-facing surface in tests/e2e-pw:
- Logged-in customer with one pending + one active notification sees
both in the tab with the expected Status cells.
- Clicking Cancel on a pending row flips it to Cancelled and disables
the button.
- Empty state renders the friendly copy and a Browse products link.
- Anonymous visitor hitting /my-account/back-in-stock-notifications/
gets the standard WC login form.
The helper file utils/back-in-stock-notifications.ts matches the
version on rsm-437-e2e-followup so the two branches merge cleanly
without duplicating or forking the helper surface.
* Drop the Status column from the My Account BIS notifications table
The status (active / pending / sent / cancelled) is implicit from the
Cancel button state — the button is disabled for sent/cancelled rows
and active for everything else — so the dedicated column was just
visual noise. Drop the column header, cell, and status-label map.
The underlying `$status` is still computed because the Cancel-button
gating and the row's `--status-<value>` CSS hook both depend on it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Shorten the My Account menu label to "Stock notifications"
"Back in stock notifications" was wider than every other My Account
sidebar item ("Orders", "Downloads", "Addresses", "Account details",
"Log out") and pushed the column off-grid. The endpoint slug stays
`back-in-stock-notifications` for URL stability; only the label and
the endpoint page title shorten.
Updates the matching PHPUnit + Playwright assertions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Paginate the My Account stock notifications table
Default `per_page` is 10. The current page comes from WC's rewrite
endpoint capture — `/my-account/back-in-stock-notifications/2/` lands
in the `woocommerce_account_back-in-stock-notifications_endpoint` hook
as the first arg, mirroring how `/my-account/orders/2/` works.
Implementation notes:
- `NotificationQuery` gains a `count_notifications()` wrapper so the
endpoint can ask for a total without going through `get_notifications`,
whose `array` return type can't honour the data store's `int` count
return. Both wrappers funnel through a single private `run_query`
helper so the existing `WC_Data_Store::query()` PHPStan suppression
in `phpstan-baseline.neon` keeps applying to one call site, not two.
- `MyAccountEndpoint::get_current_user_notifications_page()` returns a
struct with `notifications`, `current_page`, `total_pages`,
`total_items`. Out-of-range page numbers clamp to the last page so a
stale link doesn't render an empty table.
- Per-page count is filterable via `woocommerce_account_back_in_stock_notifications_per_page`.
- Template renders WP core's `paginate_links()` below the table when
more than one page exists, matching the orders endpoint's pattern.
Drive-by PHPStan cleanups:
- Drop a redundant `is_array()` check on a value already guaranteed to
be an array by `NotificationQuery::get_notifications()`'s return type.
- Narrow `Factory::get_notification()` returns with
`instanceof Notification` in the cancel handler, since the helper
returns `Notification|true` and the previous truthy-only check
couldn't filter `true` out.
Tests:
- Existing endpoint-helper tests migrated to the new
`get_current_user_notifications_page()` signature.
- New tests cover pagination math (page 2 of 7 with per_page=3 returns
rows 4-6 in `id` DESC order) and the out-of-range clamp.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Hide SENT and CANCELLED notifications from the My Account view
The My Account view is "what am I waiting for" — once the email has
been dispatched (SENT) or the customer has cancelled, the row is just
noise. Filter the query to PENDING + ACTIVE only and let the merchant
see the full history in the BIS admin (which already shows everything).
Knock-on simplifications:
- Drop the `disabled` Cancel button branch from the template — every
visible row is actionable now, so the button is always live.
- Drop the `$is_cancelled` / `$is_sent` template variables and the
`NotificationStatus` import from the template, both unused.
- Cancelling a row makes it vanish from the table; the toast notice
("Back in stock notification for X cancelled.") is the only feedback.
Cleaner than leaving a tombstone row with a disabled button.
Plumbing:
- `StockNotificationsDataStore::query()` now accepts an array for
`status` (mirroring how `product_id` already accepts arrays) and
emits `status IN (...)`. Backwards-compatible — single-string status
args still work via the `(array)` cast.
- Default statuses are filterable via
`woocommerce_account_back_in_stock_notifications_statuses` for
merchants who want a different view (e.g. include SENT for a
history-style listing).
Tests:
- New PHPUnit case asserts SENT + CANCELLED are excluded.
- Playwright cancel test rewritten — used to assert "Cancelled" cell +
disabled button; now asserts the row is gone + a notice is shown.
- Two-rows test stops asserting Status cells (Status column was
dropped earlier; the assertion was leftover).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Rename the My Account endpoint slug to `stock-notifications`
URL goes from `/my-account/back-in-stock-notifications/` to
`/my-account/stock-notifications/` to match the menu label "Stock
notifications". Renames:
- `MyAccountEndpoint::ENDPOINT` constant.
- The endpoint template, `myaccount/back-in-stock-notifications.php`
→ `myaccount/stock-notifications.php` (matching the WC convention
that template basename equals the endpoint slug — see
`myaccount/orders.php`, `myaccount/downloads.php`).
- Pagination `aria-label` to "Stock notifications pagination".
- Slug references in docblocks and the e2e spec URLs.
Knock-on auto-changes:
- The endpoint dispatch hook becomes
`woocommerce_account_stock-notifications_endpoint` (driven by the
new constant).
- The query var driving `is_stock_notifications_endpoint` checks is
now `$wp->query_vars['stock-notifications']`.
Deliberately NOT renamed (these name the FEATURE, not the URL):
- `woocommerce_account_back_in_stock_notifications_per_page` filter.
- `woocommerce_account_back_in_stock_notifications_statuses` filter.
- `woocommerce_before_account_back_in_stock_notifications` /
`woocommerce_after_account_back_in_stock_notifications` actions.
- `.woocommerce-back-in-stock-notifications-*` CSS classes.
- The e2e test directory + utils module path.
Production sites will need a one-time `wp rewrite flush` (or any
permalink-settings save) after upgrading for the new URL to resolve.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* style: fix phpcs and eslint findings in My Account BIS files
* refactor: rename BIS my-account classes and hooks to customer-stock-notifications
* fix: wrap stock notifications table headers in nobr spans
* fix: make stock notifications Product cell a row header for screen readers
* fix: drop redundant Actions label from stock notifications table on mobile
* fix: show stock notification variations under the My Account product name
* add: changelog entry for the My Account stock notifications tab
* fix: exit after the stock notification cancel redirect so the notice shows
* test: fix stale My Account stock notifications Playwright spec
* style: drop unescaped exception message from stock notifications tests
* fix: only offer Cancel on cancellable stock notifications
* fix: name the product in each stock notification Cancel button
* fix: report an error when a stock notification cancel fails
* docs: drop orders-pagination reference from stock notifications hook
* perf: prime the post cache for My Account stock notification products
* fix: report an error when a stock notification cancel doesn't persist
* test: use exact string locators in the My Account stock notifications spec
* refactor: fold stock notifications table CSS into existing responsive rules
* fix: keep stock notifications Product column visible without custom CSS
* feat: make the stock notifications My Account endpoint slug configurable
* test: expect the stock notifications endpoint in the core account tests
* fix: place the stock notifications endpoint setting right after Downloads
* perf: hydrate stock notification objects from the rows already queried
* fix: keep the customer on their page after cancelling a stock notification
* revert: restore the per-row read on stock notification object queries
* fix: escape the account endpoint URLs in stock notification notices
* test: clean up stock notifications endpoint option in tearDown
---------
Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/wooplug-7656-configurable-endpoint-slug b/plugins/woocommerce/changelog/wooplug-7656-configurable-endpoint-slug
new file mode 100644
index 00000000000..e85e59d28ca
--- /dev/null
+++ b/plugins/woocommerce/changelog/wooplug-7656-configurable-endpoint-slug
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add a Stock notifications setting under Settings > Advanced > Account endpoints, so the My Account endpoint slug can be renamed or cleared to turn the page off.
diff --git a/plugins/woocommerce/src/Internal/StockNotifications/Admin/SettingsController.php b/plugins/woocommerce/src/Internal/StockNotifications/Admin/SettingsController.php
index 0c34e4660a5..8edbc1de0b5 100644
--- a/plugins/woocommerce/src/Internal/StockNotifications/Admin/SettingsController.php
+++ b/plugins/woocommerce/src/Internal/StockNotifications/Admin/SettingsController.php
@@ -5,6 +5,7 @@ declare( strict_types = 1 );
namespace Automattic\WooCommerce\Internal\StockNotifications\Admin;
use Automattic\WooCommerce\Internal\StockNotifications\Config;
+use Automattic\WooCommerce\Internal\StockNotifications\Frontend\MyAccountEndpoint;
/**
* Settings controller for Customer Stock Notifications.
@@ -22,6 +23,9 @@ class SettingsController {
// Add the Customer Stock Notifications settings.
add_filter( 'woocommerce_get_settings_products', array( $this, 'add_customer_stock_notifications_settings' ), 100, 2 );
+ // Add the My Account endpoint setting to the Advanced tab.
+ add_filter( 'woocommerce_get_settings_advanced', array( $this, 'add_my_account_endpoint_setting' ), 100, 2 );
+
// Display admin notices about incompatible settings combinations.
add_action( 'admin_notices', array( $this, 'output_admin_notices' ) );
@@ -30,6 +34,62 @@ class SettingsController {
add_action( 'woocommerce_admin_process_product_object', array( $this, 'process_product_object' ) );
}
+ /**
+ * Add the stock notifications endpoint setting to Settings > Advanced > Account endpoints.
+ *
+ * Sits with the core account endpoints rather than in the feature's own section, since
+ * everything that reads it is the endpoint plumbing core owns. Unlike the core entries it
+ * only shows while the feature is enabled, because this controller loads with the feature.
+ *
+ * @param array $settings Original settings.
+ * @param string $section_id Settings section identifier.
+ * @return array New settings.
+ */
+ public function add_my_account_endpoint_setting( $settings, $section_id ) {
+
+ if ( ! is_array( $settings ) ) {
+ return $settings;
+ }
+
+ if ( '' !== $section_id ) {
+ return $settings;
+ }
+
+ $setting = array(
+ 'title' => __( 'Stock notifications', 'woocommerce' ),
+ 'desc' => __( 'Endpoint for the "My account → Stock notifications" page.', 'woocommerce' ),
+ 'id' => MyAccountEndpoint::ENDPOINT_OPTION,
+ 'type' => 'text',
+ 'default' => MyAccountEndpoint::ENDPOINT,
+ 'desc_tip' => true,
+ );
+
+ // Slot it right after Downloads so it sits with the other list endpoints,
+ // otherwise before Logout so Logout stays last, otherwise at the end of the group.
+ $position = 0;
+ foreach ( array_values( $settings ) as $index => $field ) {
+ if ( ! is_array( $field ) || ! isset( $field['id'] ) ) {
+ continue;
+ }
+ if ( 'woocommerce_myaccount_downloads_endpoint' === $field['id'] ) {
+ $position = $index + 1;
+ break;
+ }
+ if ( 'woocommerce_logout_endpoint' === $field['id'] || ( 'account_endpoint_options' === $field['id'] && 'sectionend' === ( $field['type'] ?? '' ) ) ) {
+ $position = $index;
+ break;
+ }
+ }
+
+ if ( 0 === $position ) {
+ return $settings;
+ }
+
+ array_splice( $settings, $position, 0, array( $setting ) );
+
+ return $settings;
+ }
+
/**
* Add a 'Customer stock notifications' section to Products settings.
*
diff --git a/plugins/woocommerce/src/Internal/StockNotifications/Frontend/MyAccountEndpoint.php b/plugins/woocommerce/src/Internal/StockNotifications/Frontend/MyAccountEndpoint.php
index aaebc1dffed..fa990de0941 100644
--- a/plugins/woocommerce/src/Internal/StockNotifications/Frontend/MyAccountEndpoint.php
+++ b/plugins/woocommerce/src/Internal/StockNotifications/Frontend/MyAccountEndpoint.php
@@ -28,6 +28,26 @@ class MyAccountEndpoint {
*/
public const ENDPOINT = 'stock-notifications';
+ /**
+ * Option holding the endpoint slug, editable under Settings > Advanced > Account endpoints.
+ */
+ public const ENDPOINT_OPTION = 'woocommerce_myaccount_stock_notifications_endpoint';
+
+ /**
+ * Get the configured endpoint slug.
+ *
+ * The slug is what appears in the URL. {@see self::ENDPOINT} stays the query var
+ * key everything else is wired to, the same split core uses for its own endpoints.
+ * An empty slug disables the endpoint.
+ *
+ * @return string The configured slug, or an empty string when the endpoint is disabled.
+ */
+ public static function get_endpoint_slug(): string {
+ $slug = get_option( self::ENDPOINT_OPTION, self::ENDPOINT );
+
+ return is_string( $slug ) ? $slug : self::ENDPOINT;
+ }
+
/**
* Query argument triggered by the cancel form post.
*/
@@ -79,12 +99,13 @@ class MyAccountEndpoint {
}
/**
- * Register the `stock-notifications` rewrite endpoint / query var.
+ * Register the stock notifications rewrite endpoint / query var.
*
* Hooking `woocommerce_get_query_vars` wires us into {@see \WC_Query::add_endpoints()}
* so WordPress registers the rewrite rule and our slug lands in `$wp->query_vars`.
+ * `add_endpoints()` skips empty slugs, so a blank setting leaves the endpoint unregistered.
*
- * @param array<string, string> $vars Existing query vars keyed by endpoint slug.
+ * @param array<string, string> $vars Existing query vars keyed by endpoint key.
* @return array<string, string>
*/
public function register_query_var( $vars ) {
@@ -92,7 +113,7 @@ class MyAccountEndpoint {
return $vars;
}
- $vars[ self::ENDPOINT ] = self::ENDPOINT;
+ $vars[ self::ENDPOINT ] = self::get_endpoint_slug();
return $vars;
}
@@ -111,6 +132,11 @@ class MyAccountEndpoint {
return $items;
}
+ // A blank endpoint slug disables the endpoint, so the link would 404.
+ if ( '' === self::get_endpoint_slug() ) {
+ return $items;
+ }
+
$new_item = array(
self::ENDPOINT => __( 'Stock notifications', 'woocommerce' ),
);
diff --git a/plugins/woocommerce/src/Internal/StockNotifications/Frontend/ProductPageIntegration.php b/plugins/woocommerce/src/Internal/StockNotifications/Frontend/ProductPageIntegration.php
index bbd4b51ffb0..19ba734f30a 100644
--- a/plugins/woocommerce/src/Internal/StockNotifications/Frontend/ProductPageIntegration.php
+++ b/plugins/woocommerce/src/Internal/StockNotifications/Frontend/ProductPageIntegration.php
@@ -6,6 +6,7 @@ namespace Automattic\WooCommerce\Internal\StockNotifications\Frontend;
use Automattic\WooCommerce\Internal\StockNotifications\Config;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EligibilityService;
+use Automattic\WooCommerce\Internal\StockNotifications\Frontend\MyAccountEndpoint;
use Automattic\WooCommerce\Internal\StockNotifications\Frontend\SignupService;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use WC_Product;
@@ -152,7 +153,7 @@ class ProductPageIntegration {
}
$text = __( 'Please {login_link} to sign up for stock notifications.', 'woocommerce' );
- $text = str_replace( '{login_link}', '<a href="' . wc_get_account_endpoint_url( 'my-account' ) . '">' . _x( 'log in', 'back in stock form', 'woocommerce' ) . '</a>', $text );
+ $text = str_replace( '{login_link}', '<a href="' . esc_url( wc_get_account_endpoint_url( 'my-account' ) ) . '">' . _x( 'log in', 'back in stock form', 'woocommerce' ) . '</a>', $text );
wc_print_notice( $text, 'notice' );
}
@@ -181,8 +182,14 @@ class ProductPageIntegration {
return;
}
+ // The endpoint can be switched off from Settings > Advanced, leaving nowhere to link to.
+ if ( '' === MyAccountEndpoint::get_endpoint_slug() ) {
+ wc_print_notice( __( 'You have already joined the waitlist!', 'woocommerce' ), 'notice' );
+ return;
+ }
+
$text = __( 'You have already joined the waitlist! Click {manage_account_link} to manage your notifications.', 'woocommerce' );
- $text = str_replace( '{manage_account_link}', '<a href="' . wc_get_account_endpoint_url( 'stock-notifications' ) . '">' . _x( 'here', 'back in stock form', 'woocommerce' ) . '</a>', $text );
+ $text = str_replace( '{manage_account_link}', '<a href="' . esc_url( wc_get_account_endpoint_url( MyAccountEndpoint::ENDPOINT ) ) . '">' . _x( 'here', 'back in stock form', 'woocommerce' ) . '</a>', $text );
wc_print_notice( $text, 'notice' );
}
diff --git a/plugins/woocommerce/src/Internal/StockNotifications/Frontend/SignupService.php b/plugins/woocommerce/src/Internal/StockNotifications/Frontend/SignupService.php
index 977b56ba7f7..530b4e370d5 100644
--- a/plugins/woocommerce/src/Internal/StockNotifications/Frontend/SignupService.php
+++ b/plugins/woocommerce/src/Internal/StockNotifications/Frontend/SignupService.php
@@ -7,6 +7,7 @@ use Automattic\WooCommerce\Internal\StockNotifications\Config;
use Automattic\WooCommerce\Internal\StockNotifications\Emails\EmailManager;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
+use Automattic\WooCommerce\Internal\StockNotifications\Frontend\MyAccountEndpoint;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\NotificationQuery;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EligibilityService;
@@ -535,10 +536,11 @@ class SignupService {
break;
}
- if ( is_user_logged_in() && ! $has_action_button ) {
+ // The endpoint can be switched off from Settings > Advanced, leaving nowhere to link to.
+ if ( is_user_logged_in() && ! $has_action_button && '' !== MyAccountEndpoint::get_endpoint_slug() ) {
$button_class = \wc_wp_theme_get_element_class_name( 'button' );
$wp_button_class = $button_class ? ' ' . $button_class : '';
- $message = sprintf( '<a href="%s" class="button wc-forward%s">%s</a> %s', \wc_get_account_endpoint_url( 'stock-notifications' ), $wp_button_class, esc_html_x( 'Manage notifications', 'notice action', 'woocommerce' ), $message );
+ $message = sprintf( '<a href="%s" class="button wc-forward%s">%s</a> %s', esc_url( \wc_get_account_endpoint_url( MyAccountEndpoint::ENDPOINT ) ), $wp_button_class, esc_html_x( 'Manage notifications', 'notice action', 'woocommerce' ), $message );
}
return $message;
diff --git a/plugins/woocommerce/tests/php/src/Internal/StockNotifications/Admin/SettingsControllerTests.php b/plugins/woocommerce/tests/php/src/Internal/StockNotifications/Admin/SettingsControllerTests.php
index ee26ec7571c..5c15c609f0c 100644
--- a/plugins/woocommerce/tests/php/src/Internal/StockNotifications/Admin/SettingsControllerTests.php
+++ b/plugins/woocommerce/tests/php/src/Internal/StockNotifications/Admin/SettingsControllerTests.php
@@ -4,6 +4,8 @@ declare( strict_types = 1 );
namespace Automattic\WooCommerce\Tests\Internal\StockNotifications\Admin;
use Automattic\WooCommerce\Internal\StockNotifications\Admin\SettingsController as StockNotificationsSettings;
+use Automattic\WooCommerce\Internal\StockNotifications\Frontend\MyAccountEndpoint;
+use WC_Settings_Advanced;
use WC_Settings_Products;
/**
@@ -36,4 +38,37 @@ class SettingsControllerTests extends \WC_Settings_Unit_Test_Case {
$this->assertEquals( $expected, $setting_ids_and_types );
}
+
+ /**
+ * @testdox The My Account endpoint setting is added to the Advanced tab, inside the account endpoints group, right after Downloads.
+ */
+ public function test_my_account_endpoint_setting_is_added_to_the_advanced_tab() {
+ // Instantiated directly rather than through the container: the container caches the
+ // instance from the previous test, whose hooks the test case has since torn down.
+ new StockNotificationsSettings();
+
+ $sut = new WC_Settings_Advanced();
+
+ $settings = $sut->get_settings_for_section( '' );
+ $ids = wp_list_pluck( $settings, 'id' );
+
+ $setting_index = array_search( MyAccountEndpoint::ENDPOINT_OPTION, $ids, true );
+
+ $this->assertNotFalse( $setting_index, 'The endpoint setting should be registered.' );
+
+ // It must land inside the account endpoints group, before its sectionend.
+ $group_end = null;
+ foreach ( $settings as $index => $setting ) {
+ if ( isset( $setting['type'], $setting['id'] ) && 'sectionend' === $setting['type'] && 'account_endpoint_options' === $setting['id'] ) {
+ $group_end = $index;
+ break;
+ }
+ }
+
+ $this->assertNotNull( $group_end, 'The account endpoints group should exist.' );
+ $this->assertLessThan( $group_end, $setting_index );
+ $this->assertSame( 'woocommerce_myaccount_downloads_endpoint', $ids[ $setting_index - 1 ], 'The endpoint setting should sit right after Downloads.' );
+ $this->assertSame( 'text', $settings[ $setting_index ]['type'] );
+ $this->assertSame( MyAccountEndpoint::ENDPOINT, $settings[ $setting_index ]['default'] );
+ }
}
diff --git a/plugins/woocommerce/tests/php/src/Internal/StockNotifications/Frontend/MyAccountEndpointTests.php b/plugins/woocommerce/tests/php/src/Internal/StockNotifications/Frontend/MyAccountEndpointTests.php
index d71ef059c20..1da3f8c1269 100644
--- a/plugins/woocommerce/tests/php/src/Internal/StockNotifications/Frontend/MyAccountEndpointTests.php
+++ b/plugins/woocommerce/tests/php/src/Internal/StockNotifications/Frontend/MyAccountEndpointTests.php
@@ -44,6 +44,7 @@ class MyAccountEndpointTests extends \WC_Unit_Test_Case {
$this->redirect_location = null;
\wc_clear_notices();
\wp_set_current_user( 0 );
+ delete_option( MyAccountEndpoint::ENDPOINT_OPTION );
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$_POST = array();
global $wp;
@@ -533,6 +534,41 @@ class MyAccountEndpointTests extends \WC_Unit_Test_Case {
$this->assertSame( MyAccountEndpoint::ENDPOINT, $vars[ MyAccountEndpoint::ENDPOINT ] );
}
+ /**
+ * A blank endpoint setting drops the menu item, since the endpoint is unregistered.
+ */
+ public function test_menu_item_is_skipped_when_the_endpoint_is_disabled(): void {
+ update_option( MyAccountEndpoint::ENDPOINT_OPTION, '' );
+
+ $endpoint = new MyAccountEndpoint();
+ $items = $endpoint->register_menu_item( array( 'downloads' => 'Downloads' ), array() );
+
+ $this->assertArrayNotHasKey( MyAccountEndpoint::ENDPOINT, $items );
+ }
+
+ /**
+ * The query var keeps its key and takes its slug from the endpoint setting.
+ */
+ public function test_query_var_uses_the_configured_slug(): void {
+ update_option( MyAccountEndpoint::ENDPOINT_OPTION, 'restock-alerts' );
+
+ $endpoint = new MyAccountEndpoint();
+ $vars = $endpoint->register_query_var( array( 'orders' => 'orders' ) );
+
+ $this->assertSame( 'restock-alerts', $vars[ MyAccountEndpoint::ENDPOINT ] );
+ }
+
+ /**
+ * The slug falls back to the default when the option is unset or not a string.
+ */
+ public function test_get_endpoint_slug_falls_back_to_the_default(): void {
+ delete_option( MyAccountEndpoint::ENDPOINT_OPTION );
+ $this->assertSame( MyAccountEndpoint::ENDPOINT, MyAccountEndpoint::get_endpoint_slug() );
+
+ update_option( MyAccountEndpoint::ENDPOINT_OPTION, array( 'not-a-string' ) );
+ $this->assertSame( MyAccountEndpoint::ENDPOINT, MyAccountEndpoint::get_endpoint_slug() );
+ }
+
/**
* @testdox Should return the customer to the page they cancelled from.
*/