Skip to content

Fix featured listing expiration lifecycle - #2969

Open
syedgalib wants to merge 7 commits into
sovware:developmentfrom
syedgalib:fix/featured-listing-expiration
Open

Fix featured listing expiration lifecycle#2969
syedgalib wants to merge 7 commits into
sovware:developmentfrom
syedgalib:fix/featured-listing-expiration

Conversation

@syedgalib

@syedgalib syedgalib commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Security fix
  • Improvement
  • New Feature
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • Text changes
  • Other... Please describe:

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?

  • Synchronize a listing expiration with the paid featured order expiration while preserving later expiration dates and never-expire listings.
  • Add a filtered force-disable guard to the core featured checkout and expiration cron.
  • Query the latest paid featured order from the new directorist_orders table through the order repository.
  • Use the persisted order expiration, with a created date plus configured duration fallback for migrated orders without an expiration value.
  • Remove the legacy order post and post-meta lookup from the featured expiration cron.

How to test

  1. Enable monetization and featured listings, then configure a featured listing duration.
  2. Submit or upgrade a listing as featured and complete its order so the order status becomes paid.
  3. Verify the listing is featured and its expiration is not earlier than the paid order expiration.
  4. Set the latest paid featured order expiration to a past date and run the Directorist scheduled task.
  5. Verify the cron removes featured status from the listing.
  6. Add a filter that makes directorist_is_force_disabled_featured_listings return true and run the scheduled task again.
  7. Verify core checkout handling is unavailable and the cron does not remove featured status.

Checklist

@RabbiIslamRony RabbiIslamRony left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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:

  1. Zero-cost featured checkout does not set or synchronize expiration. The free-checkout branch updates the original partially initialized order DTO. Since ref is not initialized, is_featured_order() returns false in the before-update hook, expires_at remains NULL, 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.

  2. The force-disable guard is evaluated too early. FeaturedListingCheckout is instantiated while Directorist is loading, before providers that register filters on plugins_loaded can 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.

  3. The cron repository lookup can select another order type. get_latest_paid_featured_order_by_listing_id() filters by is_featured_listing but not ref_type. A newer paid pricing_plan order can therefore override an active standalone featured_listing order and cause premature unfeaturing. Please constrain the query to ref_type = featured_listing.

  4. 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 RabbiIslamRony left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

@RabbiIslamRony RabbiIslamRony left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants