Skip to content

Update OrderCountCache to return values for all previously saved statuses #60209

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

Conversation

prettyboymp
Copy link
Contributor

Changes proposed in this Pull Request:

This updates the OrderCountCache::get() method so that it returns all previously stored values for a given order type.

Previously, if $order_statuses were not passed in, the list of statuses that would be fetched from cache would be based on the default list of statuses retrieved from wc_get_order_statuses(). This causes a backward compatibility issue with extensions like WooCommerce Subscriptions which doesn't register all of the statuses it uses to be returned by wc_get_order_statuses().

This changes it so that the OrderCountCache will keep it's own list of saved statuses per order type allowing OrderCountCache->get() to return all previously saved counts for the order type.

Partial Fix for WOOSUBS-867.

This specifically fixes an issue with WooCommerce Subscriptions when running object cache.

(For Bug Fixes) Bug introduced in PR #54034.

To See Previous Bug:

  1. Make sure you have at least 2 active subsccriptions.
  2. Go to WP-Admin -> WooCommerce -> Subscriptions.
  3. Set the screen options -> items per page to less than than the number of active subcriptions you have setup.
  4. Choose to display only Active subscriptions.
  5. Without this patch, the pagination for Active subscriptions will not show because the cached count is not currently being returned for that status.

Screenshots or screen recordings:

Before After

How to test the changes in this Pull Request:

Using the WooCommerce Testing Instructions Guide, include your detailed testing instructions:

  1. Make sure you have at least 2 active subsccriptions.
  2. Go to WP-Admin -> WooCommerce -> Subscriptions.
  3. Set the screen options -> items per page to less than than the number of active subcriptions you have setup.
  4. Choose to display only Active subscriptions.
  5. The pagination for Active subscriptions should correctly show as the cached count is now returned for that status.

Note - The cached count shown within pagination WooCommerce Subscriptions does not get properly updated when a subscription is transitioned from one status to another. This is noted in https://github.com/woocommerce/woocommerce-subscriptions/pull/4973#issuecomment-3154877832. Because Woo Subscriptions overrides the transition method of its extended order, it will need to integrate cache incrementing itself.

Testing that has already taken place:

Changelog entry

  • Automatically create a changelog entry from the details below.
  • This Pull Request does not require a changelog entry. (Comment required below)
Changelog Entry Details

Significance

  • Patch
  • Minor
  • Major

Type

  • Fix - Fixes an existing bug
  • Add - Adds functionality
  • Update - Update existing functionality
  • Dev - Development related task
  • Tweak - A minor adjustment to the codebase
  • Performance - Address performance issues
  • Enhancement - Improvement to existing functionality

Message

Changelog Entry Comment

Comment

@github-actions github-actions bot added the plugin: woocommerce Issues related to the WooCommerce Core plugin. label Aug 5, 2025
@prettyboymp prettyboymp marked this pull request as ready for review August 5, 2025 20:55
@woocommercebot woocommercebot requested review from a team and joshuatf and removed request for a team August 5, 2025 20:55
Copy link
Contributor

github-actions bot commented Aug 5, 2025

Testing Guidelines

Hi @jorgeatorres @joshuatf ,

Apart from reviewing the code changes, please make sure to review the testing instructions (Guide) and verify that relevant tests (E2E, Unit, Integration, etc.) have been added or updated as needed.

Reminder: PR reviewers are required to document testing performed. This includes:

  • 🖼️ Screenshots or screen recordings.
  • 📝 List of functionality tested / steps followed.
  • 🌐 Site details (environment attributes such as hosting type, plugins, theme, store size, store age, and relevant settings).
  • 🔍 Any analysis performed, such as assessing potential impacts on environment attributes and other plugins, conducting performance profiling, or using LLM/AI-based analysis.

⚠️ Within the testing details you provide, please ensure that no sensitive information (such as API keys, passwords, user data, etc.) is included in this public issue.

Copy link
Contributor

coderabbitai bot commented Aug 5, 2025

📝 Walkthrough

Walkthrough

The changes enhance the OrderCountCache to track and return cached order counts for all previously saved order statuses, including those not currently registered. The cache logic, set/get/flush operations, and related tests are updated to support this broader status tracking, ensuring backward compatibility and improved handling of third-party statuses.

Changes

Cohort / File(s) Change Summary
OrderCountCache Logic and API
plugins/woocommerce/src/Caches/OrderCountCache.php
Enhanced to track and cache all known order statuses per order type, including unregistered ones. Added private methods for managing saved statuses, updated set/get/flush logic, and introduced a set_multiple method. The class now maintains a cache of saved statuses and ensures all cache operations consider these, improving compatibility with extensions and third-party statuses.
Order Count Retrieval Utility
plugins/woocommerce/src/Utilities/OrderUtil.php
Updated the get_count_for_type method to cast $order_type to string and use the new set_multiple method for caching order counts in bulk, aligning with the updated OrderCountCache interface.
OrderCountCache Tests
plugins/woocommerce/tests/php/src/Caching/OrderCountCacheTest.php
Expanded the test_cache_order_counts test to cover caching and retrieval of both known and unknown (unregistered) statuses, ensuring the cache returns counts for all previously saved statuses.
OrderCountCache Service Tests
plugins/woocommerce/tests/php/src/Caching/OrderCountCacheServiceTest.php
Removed an unused import statement. No functional or logic changes to the tests themselves.
Changelog
plugins/woocommerce/changelog/fix-WOOSUBS-867-retrieve-previously-cached-order-counts
Added a changelog entry summarizing the update to return cached order counts for all previously saved statuses, not just those currently registered.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant OrderCountCache

    Caller->>OrderCountCache: set_multiple(order_type, counts)
    OrderCountCache->>OrderCountCache: ensure_statuses_for_type(order_type, statuses)
    OrderCountCache->>OrderCountCache: cache counts and update saved statuses

    Caller->>OrderCountCache: get(order_type)
    OrderCountCache->>OrderCountCache: get_saved_statuses_for_type(order_type)
    OrderCountCache->>OrderCountCache: retrieve counts for all saved statuses
    OrderCountCache-->>Caller: return counts for all previously saved statuses
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ff210f and 8f42101.

📒 Files selected for processing (1)
  • plugins/woocommerce/src/Caches/OrderCountCache.php (6 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{php,js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/code-quality.mdc)

**/*.{php,js,jsx,ts,tsx}: Guard against unexpected inputs
Sanitize and validate any potentially dangerous inputs
Ensure code is backwards compatible
Write code that is readable and intuitive
Ensure code has unit or E2E tests where applicable

Files:

  • plugins/woocommerce/src/Caches/OrderCountCache.php
**/*.{php,js,ts,jsx,tsx}

⚙️ CodeRabbit Configuration File

**/*.{php,js,ts,jsx,tsx}: Don't trust that extension developers will follow the best practices, make sure the code:

  • Guards against unexpected inputs.
  • Sanitizes and validates any potentially dangerous inputs.
  • Is backwards compatible.
  • Is readable and intuitive.
  • Has unit or E2E tests where applicable.

Files:

  • plugins/woocommerce/src/Caches/OrderCountCache.php
🧠 Learnings (2)
📚 Learning: in the woocommerce payments settings provider state tracking system (plugins/woocommerce/src/interna...
Learnt from: vladolaru
PR: woocommerce/woocommerce#58784
File: plugins/woocommerce/src/Internal/Admin/Settings/Payments.php:484-488
Timestamp: 2025-06-17T11:30:23.806Z
Learning: In the WooCommerce Payments settings provider state tracking system (plugins/woocommerce/src/Internal/Admin/Settings/Payments.php), when an extension is deactivated and its snapshot key disappears, only the 'extension_active' flag should be set to false while keeping other state flags like 'account_connected', 'needs_setup', 'test_mode', etc. unchanged. This is intentional behavior to preserve historical state information.

Applied to files:

  • plugins/woocommerce/src/Caches/OrderCountCache.php
📚 Learning: in woocommerce codebase, when table names are hardcoded (like `$wpdb->prefix . 'wc_order_coupon_look...
Learnt from: NeosinneR
PR: woocommerce/woocommerce#60129
File: plugins/woocommerce/includes/wc-coupon-functions.php:145-154
Timestamp: 2025-07-31T11:18:02.478Z
Learning: In WooCommerce codebase, when table names are hardcoded (like `$wpdb->prefix . 'wc_order_coupon_lookup'`), the preference is to maintain consistency with existing patterns throughout the codebase rather than making isolated security improvements when the risk is minimal (since $wpdb->prefix is controlled by WordPress and table names are hardcoded constants).

Applied to files:

  • plugins/woocommerce/src/Caches/OrderCountCache.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Core API tests - @woocommerce/plugin-woocommerce [api]
  • GitHub Check: Metrics - @woocommerce/plugin-woocommerce [performance]
  • GitHub Check: Core e2e tests 2/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 6/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Lint - @woocommerce/plugin-woocommerce
  • GitHub Check: Core e2e tests 3/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Core e2e tests 1/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.3] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Core e2e tests 5/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.3] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Core e2e tests 4/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: build
🔇 Additional comments (9)
plugins/woocommerce/src/Caches/OrderCountCache.php (9)

17-22: LGTM - Property declaration follows conventions.

The private property $cache_prefix is appropriately scoped and initialized with a sensible default value.


32-48: LGTM - Robust cache retrieval with proper type handling.

The method correctly handles cache misses by returning an empty array when cached data is not available or not in the expected format, which prevents potential type errors downstream.


50-71: LGTM - Efficient status merging with proper validation.

The method includes appropriate guards against empty inputs and efficiently uses array_diff to avoid unnecessary cache updates when no new statuses need to be added.


77-78: LGTM - Appropriate deprecation notice.

The deprecation notice follows WordPress conventions and provides clear guidance about future removal.


130-130: LGTM - Proper type casting and status tracking integration.

The modification correctly integrates the new status tracking functionality while maintaining type safety through explicit casting.


135-158: LGTM - Efficient batch caching implementation.

The new set_multiple method provides performance benefits by using WordPress's wp_cache_set_multiple function and includes proper input validation and type casting.


185-185: LGTM - Improved comment clarity.

The comment now clearly explains why null is returned when any status is missing from the cache.


231-245: LGTM - Enhanced flush logic with proper cleanup.

The modifications correctly handle the cleanup of both status counts and the saved statuses list when flushing all statuses, preventing stale status tracking data from persisting.


168-175: Ensure backward compatibility of OrderCountCache::get behavior

The get( $order_type, $order_statuses = [] ) method now returns saved statuses when none are provided, instead of falling back to the built-in default statuses. That is a breaking change for any consumers expecting the legacy defaults.

Please manually verify that all existing callers can handle this new behavior:

• Static calls: OrderCountCache::get(…)
• Instance calls: $cache->get(…) on injected or new OrderCountCache objects
• Usages without an explicit $order_statuses argument
• Unit and integration tests that assume default statuses

You can search for potential impact with commands such as:

grep -R "OrderCountCache::get" -n .

grep -R "new OrderCountCache" -n .

grep -R "->get(" -n plugins/woocommerce

Adjust any callers or tests that rely on the previous fallback behavior to ensure they still work with cached statuses.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/WOOSUBS-867-retrieve-previously-cached-order-counts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7ac75c and 12c8aef.

📒 Files selected for processing (5)
  • plugins/woocommerce/changelog/fix-WOOSUBS-867-retrieve-previously-cached-order-counts (1 hunks)
  • plugins/woocommerce/src/Caches/OrderCountCache.php (5 hunks)
  • plugins/woocommerce/src/Utilities/OrderUtil.php (2 hunks)
  • plugins/woocommerce/tests/php/src/Caching/OrderCountCacheServiceTest.php (0 hunks)
  • plugins/woocommerce/tests/php/src/Caching/OrderCountCacheTest.php (2 hunks)
💤 Files with no reviewable changes (1)
  • plugins/woocommerce/tests/php/src/Caching/OrderCountCacheServiceTest.php
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{php,js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/code-quality.mdc)

**/*.{php,js,jsx,ts,tsx}: Guard against unexpected inputs
Sanitize and validate any potentially dangerous inputs
Ensure code is backwards compatible
Write code that is readable and intuitive
Ensure code has unit or E2E tests where applicable

Files:

  • plugins/woocommerce/src/Utilities/OrderUtil.php
  • plugins/woocommerce/tests/php/src/Caching/OrderCountCacheTest.php
  • plugins/woocommerce/src/Caches/OrderCountCache.php
**/*.{php,js,ts,jsx,tsx}

⚙️ CodeRabbit Configuration File

**/*.{php,js,ts,jsx,tsx}: Don't trust that extension developers will follow the best practices, make sure the code:

  • Guards against unexpected inputs.
  • Sanitizes and validates any potentially dangerous inputs.
  • Is backwards compatible.
  • Is readable and intuitive.
  • Has unit or E2E tests where applicable.

Files:

  • plugins/woocommerce/src/Utilities/OrderUtil.php
  • plugins/woocommerce/tests/php/src/Caching/OrderCountCacheTest.php
  • plugins/woocommerce/src/Caches/OrderCountCache.php
🧠 Learnings (2)
📚 Learning: in woocommerce core repository, changelog entries for all prs live in `plugins/woocommerce/changelog...
Learnt from: jorgeatorres
PR: woocommerce/woocommerce#59675
File: .github/workflows/release-bump-as-requirement.yml:48-65
Timestamp: 2025-07-15T15:39:21.856Z
Learning: In WooCommerce core repository, changelog entries for all PRs live in `plugins/woocommerce/changelog/` directory and are processed during releases, not at the repository root level.

Applied to files:

  • plugins/woocommerce/changelog/fix-WOOSUBS-867-retrieve-previously-cached-order-counts
📚 Learning: in the woocommerce payments settings provider state tracking system (plugins/woocommerce/src/interna...
Learnt from: vladolaru
PR: woocommerce/woocommerce#58784
File: plugins/woocommerce/src/Internal/Admin/Settings/Payments.php:484-488
Timestamp: 2025-06-17T11:30:23.806Z
Learning: In the WooCommerce Payments settings provider state tracking system (plugins/woocommerce/src/Internal/Admin/Settings/Payments.php), when an extension is deactivated and its snapshot key disappears, only the 'extension_active' flag should be set to false while keeping other state flags like 'account_connected', 'needs_setup', 'test_mode', etc. unchanged. This is intentional behavior to preserve historical state information.

Applied to files:

  • plugins/woocommerce/src/Caches/OrderCountCache.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (11)
plugins/woocommerce/changelog/fix-WOOSUBS-867-retrieve-previously-cached-order-counts (1)

1-4: LGTM!

The changelog entry follows the correct format and accurately describes the change.

plugins/woocommerce/src/Utilities/OrderUtil.php (2)

209-210: Good defensive programming with explicit type casting.

The explicit cast ensures type safety when the parameter is passed to cache methods.


238-238: Performance improvement with batch caching.

Using set_multiple() is more efficient than individual set() calls in a loop, reducing the number of cache operations.

plugins/woocommerce/tests/php/src/Caching/OrderCountCacheTest.php (1)

34-59: Comprehensive test coverage for registered and unregistered statuses.

The expanded test properly validates that the cache handles both known WooCommerce statuses and third-party unregistered statuses, ensuring backward compatibility as intended.

plugins/woocommerce/src/Caches/OrderCountCache.php (7)

34-41: Well-implemented status retrieval with safe defaults.

The method properly handles cache misses by returning an empty array, preventing potential null/false issues.


51-64: Efficient status tracking with optimized cache updates.

The method efficiently tracks new statuses with early returns to avoid unnecessary cache operations when no new statuses are added.


128-132: Proper status tracking integration in set method.

The method correctly updates the saved statuses list when setting cache values, maintaining consistency.


144-157: Well-implemented batch cache operation.

The method efficiently sets multiple cache values in a single operation while properly tracking all statuses and handling edge cases.


167-174: Correct implementation of expanded status retrieval.

The method properly retrieves all previously saved statuses when none are specified, addressing the backward compatibility issue described in the PR objectives.


184-187: Clear documentation of cache miss behavior.

The updated comment clearly explains why null is returned when any requested status is not found in cache.


229-244: Smart cleanup of saved statuses during full flush.

The method correctly removes the saved statuses list when all statuses are flushed, preventing accumulation of stale status entries.

Copy link
Contributor

github-actions bot commented Aug 5, 2025

Test using WordPress Playground

The changes in this pull request can be previewed and tested using a WordPress Playground instance.
WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Test this pull request with WordPress Playground.

Note that this URL is valid for 30 days from when this comment was last updated. You can update it by closing/reopening the PR or pushing a new commit.

Copy link
Member

@jorgeatorres jorgeatorres left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-approving with some tiny feedback. Tested well. Thanks @prettyboymp!

/**
* Get the default statuses.
*
* @return string[]
*
* @deprecated 10.0.0 This method will be removed in the future.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be 10.1.0 assuming we'll backport the fix.

Comment on lines 67 to 73
/**
* Cache prefix.
*
* @var string
*/
private $cache_prefix = 'order-count';

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to "move" the property declaration here? Not a problem per se, but a bit non-standard?

@prettyboymp prettyboymp merged commit ef282bd into trunk Aug 6, 2025
26 checks passed
@prettyboymp prettyboymp deleted the fix/WOOSUBS-867-retrieve-previously-cached-order-counts branch August 6, 2025 15:21
@prettyboymp prettyboymp added this to the 10.1.0 milestone Aug 6, 2025
github-actions bot pushed a commit that referenced this pull request Aug 6, 2025
…uses (#60209)

* Update OrderCountCache to return values for all previously saved statuses.

* Switch to set_multiple so that status cache doesn't need to be set multiple times

* Fix call to ensure_statuses_for_type within set

* Add some type safety

* Add test for unregistered cache counts

* lint fixes

* more lint fixes

* another equal alignment

* add separator to statuses cache key

* Deprecate get_default_statuses() method

* remove short array syntax

* Address feedback, move private property back to top of class and fix deprecation version
Copy link
Contributor

github-actions bot commented Aug 6, 2025

IMPORTANT: Merging this PR to the appropriate branches is critical to the release process and ensures that the bug does not cause regressions in the future releases.

Cherry picking was successful for release/10.1. Please merge the following PR: [Backport to release/10.1] Update OrderCountCache to return values for all previously saved statuses

prettyboymp added a commit that referenced this pull request Aug 8, 2025
…r all previously saved statuses (#60236)

Update OrderCountCache to return values for all previously saved statuses (#60209)

* Update OrderCountCache to return values for all previously saved statuses.

* Switch to set_multiple so that status cache doesn't need to be set multiple times

* Fix call to ensure_statuses_for_type within set

* Add some type safety

* Add test for unregistered cache counts

* lint fixes

* more lint fixes

* another equal alignment

* add separator to statuses cache key

* Deprecate get_default_statuses() method

* remove short array syntax

* Address feedback, move private property back to top of class and fix deprecation version

Co-authored-by: Michael Pretty <prettyboymp@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugin: woocommerce Issues related to the WooCommerce Core plugin.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants