v1.6.0 Latest
New
- Buyers can upload proof of an offline payment and an admin can approve or reject it, which marks the order paid and credits the vendor through the same path as a card payment. Off by default.
- A paid order has a printable receipt the buyer can save as a PDF.
- Email preferences are role aware, so a buyer is offered the five categories that apply to them rather than a vendor's eight.
- The plugin does not email someone about a message while they are actively using the site. Off by default, and the window is filterable with wpss_presence_window.
- Owners choose which billing fields checkout collects. Name and email are always collected; address fields suit physical goods and can be switched off for digital services.
- [wpss_my_orders] is paginated. A buyer with more than one page of orders can now reach the rest of them.
- [wpss_seller_card] renders a single seller card, so classic-editor and page-builder sites can place one without the block.
- Buyer request blocks accept budget bounds, matching what the shortcode always supported.
- Catalog prices carry their base amount in the markup, so a display-currency add-on can show an approximate price in the shopper's own currency without changing what is charged.
- The order modal total now carries the same information, so the estimate follows the price as extras and quantity change.
- New action wpss_payable_total_after fires wherever a payable total is shown, on both the cart summary and the checkout, so an add-on can state the charge currency at the last screen before payment.
- Buyers can create their account during checkout instead of meeting a sign-in wall before they can pay. Off by default.
- Members can see every device they are signed in on and revoke any one of them, without signing out everywhere.
- Owners can point the site's header cart link at the marketplace cart, for sites running WooCommerce beside the built-in checkout. Off by default.
- A Vendors directory page is created at install, so the Pages setting is no longer a mapping with nothing behind it.
Improve
- An order now records the package the buyer actually bought, so editing or reordering a service later never changes what an existing order says was purchased.
- Packages carry a stable id that does not shift when packages are reordered, and the REST API publishes it.
- Every payment platform reports order status through one shared map, replacing three separate maps that disagreed with each other.
- The member dashboard and [wpss_account] are one screen rather than two that had drifted apart, so both show the same sections.
- Conversation messages render through one shared renderer everywhere, with clickable links and working attachments.
- The setup wizard stops prompting a site that is already configured.
- The plugin uses a single accent colour; the second, unrelated green palette has been retired.
- Vendor and service grids run far fewer queries. A vendor grid dropped from 49 queries to 9 and a service grid from 70 to 30, with identical output.
- Category choosers no longer load every category on the site. The limit is 200 and filterable with wpss_category_terms_limit.
- Shortcodes and blocks that show the same thing now share one renderer and one template, so a theme override applies to both and they cannot drift apart again.
- Prices are marked up identically for every visitor, so a page cache can never serve one shopper's currency to another.
- Saving a vendor profile confirms with the same toast used everywhere else, rather than a banner above the fold the member was not looking at.
- Losing bidders on a buyer request are told in the app rather than by email, so deciding a busy request no longer sends a burst of rejections.
- The dashboard messages list is paginated, so a member with many conversations no longer loads all of them at once.
- SureCart is no longer advertised in Settings or on the Upgrade page, which described an integration Pro does not include.
Fix
- Vendors could not submit a fixed-price proposal. A hidden milestone field was marked required, so the browser blocked the form and reported nothing the vendor could see.
- Orders placed before this release could show the wrong package name and price once a service was edited. Existing orders are repaired on update using what the buyer actually paid.
- The category archive listed buyer requests alongside services.
- Pages with the same title could not be told apart in the Pages settings dropdowns.
- The dashboard Disputes section white-screened for everyone, in both the list and the detail view. It now renders.
- An offline order could not be marked as paid from the admin. The control existed only on a screen that was never reachable.
- The admin order detail screen fataled for every order.
- Cancelling a dispute returned an error and left the order stuck as disputed. The cancel now completes or rolls back as one unit.
- [wpss_vendors], [wpss_top_vendors], [wpss_vendor_profile] and the vendor sections of [wpss_account] fataled instead of rendering.
- The buyer requests block listed expired requests that the shortcode correctly hid, so sellers could pitch for closed work.
- columns="" was ignored by the services and categories grids, which always rendered a single stacked column.
- Category cards and the search form rendered differently depending on whether the block or the shortcode was used.
- A dispute opened automatically for a late order stored a translated label where a reason code belongs, which left non-English sites with an untranslatable reason.
- The disputes table was unreadable on phones, with values pushed to the right against blank labels.
- Demo data sized vendor withdrawals against earnings still inside the clearance window, leaving negative available balances, and re-running the seeder credited every order again.
- Docblocks across the plugin cited @since versions that were never released; every one now names the version it actually shipped in.
- On a site running Easy Digital Downloads, a checkout could complete and mark itself paid before the marketplace had loaded, so no order was created and no vendor was credited.
- Accepting a proposal created an order whose service resolved to whichever page happened to be rendering, so the order showed the wrong title.
- Paying for an existing order offline never recorded the payment method, leaving an order no admin could confirm and no buyer could send proof for.
- Proposals produced no in-app notification at all; the notification types had existed since the first release and nothing ever wrote one.
- A dispute conversation was stored in two places, so each screen showed only half of it.
- A completed order with an open dispute showed no sign of that dispute on the admin order screen.
- A completed order hid the review prompt but never showed the review the buyer had already written.
- Vendor links across the site landed on the directory instead of the vendor's own profile.
- The Become a Vendor page offered registration to members who were already vendors.
- The messages unread count was hidden by a stylesheet rule, so a correct number rendered as a bare dot.
- Settings deep links used a query argument the settings screen no longer reads, and five of them pointed at the wrong section.
- The Create Service page was published but empty; it now sends the member to the service wizard.
- The cart page took the generic /cart/ slug and accumulated orphaned duplicates on sites that already had one.
- The admin screens never loaded the design tokens, so the retired green palette survived in every colour fallback.
- The single service sidebar did not stick at all when a theme clipped overflow, so the price and Order button scrolled out of reach.
- The sticky offset assumed the WordPress admin bar was the only fixed bar on the page and ignored a theme's own sticky header.
- Mapped pages rendered two headings, the theme's and the plugin's.
- The earnings banner offered a withdrawal to vendors whose balance was negative, because it counted money from orders still in progress.
- Ten JavaScript strings were never sent for translation, so every message the favourites feature shows a buyer appeared in English in all locales.
- The skip-email-when-online setting could never fire, because the code that records when a member was last active was never hooked to anything.
- The cart accepted a stable package id and returned an array position, so a client could not match a cart line back to the package it bought.
- The setup wizard rendered an empty browser tab title once setup was complete.
Security
- Mobile app tokens now expire, 30 days after last use or 90 days after they are issued, and are rejected at authentication instead of staying valid forever.
- An app token can no longer be presented in place of the account password to mint further tokens.
- The public vendor search no longer matches WordPress login names, which allowed usernames to be discovered one letter at a time.
Dev
- GET /orders/{id} answers 404 for an order that does not exist, rather than 403.
- An admin-only denial answers wpss_not_admin instead of reusing the ownership code.
- The REST error codes are documented, with a committed contract smoke that checks them across anonymous, buyer, vendor and admin callers.
- New actions wpss_payment_receipt_submitted, wpss_payment_receipt_verified and wpss_payment_receipt_rejected.
- Orders record the paying platform's own order reference, so a platform that uses string ids can be linked back to its order.
- Helper functions moved from one 6,187-line file into eleven files grouped by domain. No function was renamed or resignatured, so no call site changes.
- wpss_admin_order_actions now fires on the order screen admins actually use.
- New wpss_category_card_link and wpss_category_card_classes filters, and a category-card template that themes can override.
- Translation templates regenerated for both plugins, and ambiguous translator comments corrected.
- Hardcoded English fallbacks removed from JavaScript across both plugins, so every message shown to a user is translatable.
- The translation check now fails when the plugin version and the translation template disagree, which is how a template for the previous version shipped before.
- One actor shape across the API: every endpoint describes a person as id, name, avatar and deleted.
- One date format across the API: every timestamp is ISO-8601 with an offset, replacing a mix of that and MySQL datetimes carrying no timezone.
- One service card shape: /services and /favorites return the same keys from a single shared builder.
- Every API change this release is additive, so the REST contract version is unchanged and existing clients keep working.
- New GET /auth/sessions and DELETE /auth/sessions/{uuid} list and revoke a member's app sign-ins.
- New filters wpss_app_token_lifetime and wpss_token_recovery_routes control how long a token lives and which routes stay reachable with an expired one.
- New filter wpss_sticky_top_offset lets a theme declare the height of its own sticky header.
- New filter wpss_messages_per_page sets the dashboard conversation page size.
- wp wpss preflight now asks Action Scheduler, which the plugin actually uses, instead of reporting every job as unscheduled.
- Static analysis and the full test suite run in CI; both had been failing to run at all.