Theme Integration Guide

Customize WP Sell Services appearance to match your WordPress theme through template overrides, CSS customization, and template hooks.

Template Override System

The plugin uses TemplateLoader (src/Frontend/TemplateLoader.php) to load templates with theme override support. When a template is requested, the loader checks locations in this order:

  1. Child theme: wp-content/themes/child-theme/wp-sell-services/{template}.php
  2. Parent theme: wp-content/themes/parent-theme/wp-sell-services/{template}.php
  3. Plugin default: wp-content/plugins/wp-sell-services/templates/{template}.php

Setting Up Overrides

  1. Create wp-sell-services/ directory in your theme
  2. Copy the template you want to customize from wp-sell-services/templates/
  3. Edit the copied file in your theme directory
  4. Clear page cache and refresh

Only copy templates you need to change. Uncopied templates continue using plugin defaults.

Available Templates

Top-Level Templates

Template Purpose
single-service.php Single service page
archive-service.php Service archive/listing page
single-request.php Single buyer request page
archive-request.php Buyer request archive page
content-service-card.php Service card in grids and listings
content-request-card.php Buyer request card in listings
content-no-services.php Empty state when no services found
content-no-requests.php Empty state when no requests found

Partial Templates (templates/partials/)

Template Purpose
partials/service-gallery.php Image gallery on single service page
partials/service-packages.php Pricing packages (Basic/Standard/Premium)
partials/service-reviews.php Reviews section on single service page
partials/service-faqs.php FAQ accordion on single service page
partials/vendor-card.php Vendor info card on service page sidebar
partials/vendor-portfolio.php Public vendor portfolio lightbox and grid

Order Templates (templates/order/)

Template Purpose
order/order-view.php Order details page
order/order-requirements.php Requirements submission page
order/order-confirmation.php Order confirmation/thank you page
order/requirements-form.php Requirements form template
order/conversation.php Order messaging/conversation view

Order URLs route as: /service-order/{id}/ (view), /service-order/{id}/requirements/, /service-order/{id}/delivery/, /service-order/{id}/review/.

Dashboard Templates (templates/dashboard/sections/)

Template Purpose
dashboard/sections/orders.php Orders section
dashboard/sections/sales.php Sales section (vendor)
dashboard/sections/services.php Services management
dashboard/sections/earnings.php Earnings section
dashboard/sections/messages.php Messages section
dashboard/sections/profile.php Profile editing
dashboard/sections/requests.php Buyer requests
dashboard/sections/create.php Service creation
dashboard/sections/create-request.php Buyer request creation
dashboard/sections/edit-request.php Edit an existing buyer request

WooCommerce Account Templates (templates/myaccount/)

Template Purpose
myaccount/service-orders.php Service orders in WooCommerce My Account
myaccount/vendor-dashboard.php Vendor dashboard in My Account
myaccount/vendor-services.php Vendor services list
myaccount/notifications.php Notifications tab

Cart Templates (templates/cart/)

Template Purpose
cart/cart.php Shopping cart page for standalone checkout mode

Other Templates

  • Vendor: vendor/profile.php -- Public vendor profile page (served at /provider/{username}/ by default, customizable via the wpss_vendor_slug filter)

Email Templates (templates/emails/)

All email templates are theme-overridable at yourtheme/wp-sell-services/emails/.

26 HTML templates:

Template Purpose
emails/new-order.php New order notification
emails/order-in-progress.php Vendor started work
emails/delivery-ready.php Delivery submitted for review
emails/order-completed.php Order completed
emails/order-cancelled.php Order cancelled
emails/requirements-submitted.php Buyer submitted requirements
emails/requirements-reminder.php Reminder to submit requirements
emails/revision-requested.php Buyer requested revision
emails/cancellation-requested.php Cancellation request filed
emails/new-message.php New order message
emails/dispute-opened.php Dispute opened
emails/dispute-escalated.php Dispute escalated to admin
emails/seller-level-promotion.php Vendor promoted to new seller level
emails/moderation-pending.php Service submitted for moderation
emails/moderation-approved.php Service approved
emails/moderation-rejected.php Service rejected
emails/moderation-response.php Vendor responded to moderation feedback
emails/vendor-contact.php Vendor contact form submission
emails/withdrawal-requested.php Vendor requested withdrawal
emails/withdrawal-approved.php Withdrawal approved
emails/withdrawal-rejected.php Withdrawal rejected
emails/withdrawal-auto.php Automatic withdrawal processed
emails/generic.php Generic notification template
emails/test-email.php Test email (from settings)
emails/email-header.php Shared email header with logo and branding
emails/email-footer.php Shared email footer

10 plain text variants at emails/plain/:

Template Purpose
emails/plain/new-order.php Plain text new order
emails/plain/order-in-progress.php Plain text order started
emails/plain/order-completed.php Plain text order completed
emails/plain/order-cancelled.php Plain text order cancelled
emails/plain/delivery-ready.php Plain text delivery submitted
emails/plain/requirements-submitted.php Plain text requirements submitted
emails/plain/requirements-reminder.php Plain text requirements reminder
emails/plain/revision-requested.php Plain text revision requested
emails/plain/new-message.php Plain text new message
emails/plain/dispute-opened.php Plain text dispute opened

See Email Customization for how to override email content, headers, footers, and sender details using filters.

Template Functions

// Load a template part (like WP get_template_part but with plugin fallback)
wpss_get_template_part( 'content', 'service-card' );
// Searches: theme/wp-sell-services/content-service-card.php then plugin/templates/

// With arguments
wpss_get_template_part( 'partials/vendor-card', '', [ 'vendor_id' => 42 ] );

// Load a specific template file
wpss_get_template( 'order/order-view.php', [ 'order' => $order ] );

Template Filters

// Redirect template loading without copying files
add_filter( 'wpss_locate_template', function( $template, $template_name, $template_path ) {
    if ( 'single-service.php' === $template_name ) {
        return '/path/to/my/custom-single-service.php';
    }
    return $template;
}, 10, 3 );

// Override a dashboard section template
add_filter( 'wpss_dashboard_section_template', function( $template_path, $section ) {
    if ( 'earnings' === $section ) {
        return get_stylesheet_directory() . '/my-earnings-template.php';
    }
    return $template_path;
}, 10, 2 );

Single Service Page Hooks

The SingleServiceView class (src/Frontend/SingleServiceView.php) renders each section via action hooks. You can add, remove, or reorder sections without overriding the entire template.

Default Hook Registration

Hook Callback Priority
wpss_single_service_header render_breadcrumb 5
wpss_single_service_header render_title 10
wpss_single_service_header render_meta 15
wpss_single_service_gallery render_gallery 10
wpss_single_service_content render_description 10
wpss_single_service_content render_vacation_notice 1
wpss_single_service_content render_about_vendor 20
wpss_single_service_faqs render_faqs 10
wpss_single_service_reviews render_reviews 10
wpss_single_service_sidebar render_packages 10
wpss_single_service_portfolio render_portfolio 10
wpss_single_service_related render_related_services 10
wpss_after_single_service render_order_modal 10
wpss_after_single_service render_contact_modal 20

Customizing Sections

// Add content after service title (priority 12 = after title at 10, before meta at 15)
add_action( 'wpss_single_service_header', function( $service ) {
    if ( get_post_meta( $service->id, '_wpss_featured', true ) ) {
        echo '<span class="wpss-featured-badge">Featured</span>';
    }
}, 12 );

// Remove FAQ section
remove_action( 'wpss_single_service_faqs', [ wpss()->get_single_service_view(), 'render_faqs' ], 10 );

// Move the packages block later so your own content can sit above it.
// Match the priority in the table exactly - remove_action() is a no-op if the
// priority is wrong, and you will end up with the section rendered twice.
$view = wpss()->get_single_service_view();
remove_action( 'wpss_single_service_sidebar', [ $view, 'render_packages' ], 10 );
add_action( 'wpss_single_service_sidebar', [ $view, 'render_packages' ], 20 );

Dashboard Customization

// Control section access
add_filter( 'wpss_can_access_dashboard_section', function( $allowed, $section, $user_id ) {
    if ( 'earnings' === $section ) {
        return (bool) get_user_meta( $user_id, '_wpss_vendor_verified', true );
    }
    return $allowed;
}, 10, 3 );

// Add custom dashboard sections
add_filter( 'wpss_dashboard_sections', function( $sections, $user_id, $is_vendor ) {
    if ( $is_vendor ) {
        $sections['analytics'] = [ 'label' => 'Analytics', 'icon' => 'chart' ];
    }
    return $sections;
}, 10, 3 );

// Rename section titles
add_filter( 'wpss_dashboard_section_titles', function( $titles ) {
    $titles['orders'] = 'My Purchases';
    $titles['sales']  = 'My Sales';
    return $titles;
} );

Full-width Plugin Pages

Since 1.2.0, the plugin's app-like pages — Dashboard, Cart, Checkout, and Become a Vendor — render full-width without a theme sidebar. This prevents marketplace UI from appearing next to widgets such as Recent Posts.

How it works per theme

The plugin detects the active theme and uses its native mechanism rather than hiding the sidebar with CSS:

Theme Method
Reign Sets Reign's native per-page layout meta (reign_wbcom_metabox_data), the same mechanism Reign uses for FluentCart. Reign's page wrappers and subheader remain intact.
BuddyX / BuddyX Pro Uses the theme's bundled "Page No Sidebar" template (page-templates/full-width-container.php).
Any other theme Falls back to templates/wpss-fullwidth-template.php, which calls get_header() / get_footer() and emits a contained full-width wrapper.

If a site owner has already set a specific Page Template on a plugin page in the editor, that choice wins and the plugin does not override it.

Customizing the fallback template

Copy templates/wpss-fullwidth-template.php into your theme to override the fallback wrapper:

yourtheme/wp-sell-services/wpss-fullwidth-template.php

Opting out and controlling scope

Turn off full-width handling entirely — the active theme's normal sidebar layout will be used on all plugin pages:

add_filter( 'wpss_use_fullwidth_template', '__return_false' );

Control which plugin pages receive the full-width treatment (default: dashboard, cart, checkout, become_vendor):

// Remove the dashboard from full-width treatment
add_filter( 'wpss_fullwidth_page_keys', function( $keys ) {
    return array_diff( $keys, [ 'dashboard' ] );
} );

See also wpss_use_fullwidth_template and wpss_fullwidth_page_keys in the hooks reference.

CSS Classes Reference

The plugin uses wpss- prefixed CSS classes. Verified classes from SingleServiceView.php:

.wpss-breadcrumb / .wpss-breadcrumb-list / .wpss-breadcrumb-item / .wpss-breadcrumb-current
.wpss-service-title / .wpss-service-meta / .wpss-meta-item
.wpss-meta-vendor / .wpss-meta-rating / .wpss-meta-orders / .wpss-meta-queue
.wpss-vendor-mini-avatar / .wpss-vendor-name / .wpss-verified-badge
.wpss-rating-link / .wpss-rating-value / .wpss-rating-count
.wpss-star / .wpss-star.filled

Enqueued Stylesheets

Handle File Purpose
wpss-design-system assets/css/design-system.css CSS custom properties and tokens
wpss-frontend assets/css/frontend.css Base frontend styles
wpss-single-service assets/css/single-service.css Single service page
wpss-unified-dashboard assets/css/unified-dashboard.css Dashboard styles

Overriding Styles

// Enqueue a custom stylesheet after plugin styles
add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_style( 'mytheme-wpss', get_stylesheet_directory_uri() . '/css/wpss-custom.css', [ 'wpss-frontend' ], '1.0.0' );
}, 20 );

// Or dequeue plugin styles entirely
add_action( 'wp_enqueue_scripts', function() {
    wp_dequeue_style( 'wpss-frontend' );
    wp_deregister_style( 'wpss-frontend' );
}, 100 );

Dark Mode and Design Tokens

Added in 1.3.0. Every plugin surface is built on CSS custom-property tokens in design-system.css, and the plugin follows the active theme's dark mode rather than the OS preference. This means WP Sell Services goes dark exactly when the theme does, and never darkens on top of a light theme.

How dark mode is triggered

The plugin's dark tokens activate when any of these signals is present on the root element — the same signals BuddyX, BuddyX Pro, and Reign 8.x already set from their own dark-mode toggle:

:root[data-theme="dark"],
:root[data-bx-mode="dark"],
.wpss-dark .wpss-app { /* dark token overrides */ }

If your theme has a dark toggle, set data-bx-mode="dark" (or data-theme="dark") on <html> and the plugin follows automatically — no per-component CSS required. There is deliberately no prefers-color-scheme rule, so the plugin never fights a light theme on a dark OS.

Token model

Components consume semantic and scale tokens, never raw hex. In dark mode the whole system flips in one place:

Token group Light Dark Used for
--wpss-surface #ffffff #1f2937 Card / panel backgrounds
--wpss-text / --wpss-text-muted dark light Body + muted copy
--wpss-gray-* ramp light ramp inverted ramp Raw text + hairlines (ink end resolves light, paper end dark)
--wpss-primary #4f46e5 #4f46e5 Button/badge fills (stays dark enough for white text)
--wpss-primary-accent #4f46e5 #a5b4fc Primary as text/links/icons (lightens on dark)
--wpss-secondary-accent #1e293b #e2e8f0 Emphasis text (prices)
--wpss-block-surface var(--wpss-surface) flips Gutenberg block card backgrounds

Two rules matter when extending the UI:

  1. Use --wpss-primary-accent / --wpss-secondary-accent for text, --wpss-primary / --wpss-secondary for fills. The accent tokens lighten in dark mode so links stay readable on dark surfaces; the fill tokens stay dark so white button text keeps its contrast.
  2. Never hard-code hex for text or surfaces — reach for the tokens above so your addition flips with the rest of the plugin. Lucide icons inherit currentColor, so they follow the text token automatically.

Overriding tokens per theme

Redefine any token under your theme's dark selector to match your palette exactly:

html[data-bx-mode="dark"] {
    --wpss-surface: #12141a;      /* match your theme's card colour */
    --wpss-primary-accent: #93c5fd;
}

JavaScript Integration

Handle File Dependencies
alpinejs assets/js/vendor/alpine.min.js None (defer)
wpss-frontend assets/js/frontend.js alpinejs
wpss-single-service assets/js/single-service.js jquery, wpss-frontend
wpss-unified-dashboard assets/js/unified-dashboard.js jquery

JavaScript Data Objects

wpss: ajaxUrl, restUrl, nonce

wpssData: ajaxUrl, apiUrl, nonce, orderNonce, restNonce, pollingInterval (10000ms), currencyFormat, i18n

wpssService (single service page only): serviceId, ajaxUrl, nonce, checkoutUrl, cartUrl, i18n

// Add custom scripts after plugin JS
add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_script( 'mytheme-wpss-js', get_stylesheet_directory_uri() . '/js/wpss-custom.js', [ 'wpss-frontend' ], '1.0.0', true );
}, 20 );

URL Structure

Pattern Template Filter
/provider/{username}/ vendor/profile.php wpss_vendor_slug
/service-order/{id}/ order/order-view.php wpss_service_order_slug
/service-order/{id}/{action}/ order/order-{action}.php wpss_service_order_slug
/service/ (CPT slug) archive-service.php wpss_service_slug
/buyer-request/ (CPT slug) archive-request.php wpss_buyer_request_slug
/service-checkout/{id}/ Checkout shortcode wpss_checkout_slug

All URL slugs are filterable to avoid conflicts with other plugins. After changing slugs, flush rewrite rules by visiting Settings > Permalinks and clicking Save.

Related Documentation