Fix featured listing expiration lifecycle - #2969
Conversation
There was a problem hiding this comment.
Thanks for working on the featured-listing expiration lifecycle. The normal paid-order synchronization, later-expiration preservation, never-expire handling, and new-table cron path all worked in local testing.
I found a few issues that should be addressed before merge:
-
Zero-cost featured checkout does not set or synchronize expiration. The free-checkout branch updates the original partially initialized order DTO. Since
refis not initialized,is_featured_order()returns false in the before-update hook,expires_atremainsNULL, and the listing keeps its earlier expiration even though it becomes paid and featured. I reproduced this through the rendered zero-cost checkout and confirmed the database state with WP-CLI. -
The force-disable guard is evaluated too early.
FeaturedListingCheckoutis instantiated while Directorist is loading, before providers that register filters onplugins_loadedcan run. A late filter correctly protects the cron callback, but the core featured checkout type and related hooks remain registered. Please evaluate the guard at callback time or defer hook registration until providers can register the filter. -
The cron repository lookup can select another order type.
get_latest_paid_featured_order_by_listing_id()filters byis_featured_listingbut notref_type. A newer paidpricing_planorder can therefore override an active standalonefeatured_listingorder and cause premature unfeaturing. Please constrain the query toref_type = featured_listing. -
The new multiline conditional has a fixable PHPCS error at
class-featured-listing-checkout.php:188.
The current GitHub PHPCS check is failing before analysis because actions/checkout refuses fork code under pull_request_target, so I also ran targeted local PHP lint, diff checks, and PHPCS against the PR head.
RabbiIslamRony
left a comment
There was a problem hiding this comment.
Follow-up re-review of 5af64bf:
The previously reported issues are now fixed. I verified the zero-cost rendered checkout, late provider force-disable behavior, standalone-order cron lookup, and the PHPCS formatting correction locally.
One paid-payment expiration blocker remains:
Paid payment processors can mark a featured order as paid without assigning an expiration. PaymentRepository::create() calls OrderRepository::update_status(), which updates the order with a partial DTO containing only id and status. FeaturedListingCheckout::handle_before_order_update() then returns early because ref_type and listing_id are not initialized, so expires_at is never set.
Local WP-CLI reproduction through the paid payment-repository path produced:
order_status: paid
order_expires_at: null
listing_status: publish
listing_featured: 1
listing_expiry: 2026-08-20 00:00:00
This leaves the paid featured listing using its earlier expiration instead of the configured featured duration. The same partial order update pattern is also used by payment processors such as Stripe.
Please either use the stored $old_order passed by directorist_before_order_update to identify and populate the featured order, or rehydrate a full order DTO before running the update hooks.
The GitHub PHPCS job is still failing before analysis because actions/checkout refuses fork code under pull_request_target; targeted local PHP lint, git diff --check, and PHPCS completed without errors.
PR Type
What kind of change does this PR introduce?
Description
Why is this PR needed?
Featured listing expiration was not synchronized with the paid featured order expiration. The expiration cron also relied on the legacy order post type and post meta instead of the new order table. Core featured listing handling additionally needs to be disableable when another provider owns the feature lifecycle.
What is done in this PR?
How to test
Checklist