Appearance
Vendors & Vendor Pages
Flow ID: CF-19 | Module(s): eshop, Product domain | Complexity: Medium
Business Overview
Vendors (brands) are a core catalog dimension. The storefront provides vendor listing, product pages with filtering, and exclusive vendor detail pages with sliders/videos/builder blocks.
What customers experience:
/vendorspage showing all brands with active products/vendors/{slug}product listing page for a specific brand (with tag/category/variation filters)/vendors/{slug}/{category}category-filtered product listing within a vendor/vendors/{slug}/{line-slug}product line listing within a vendor/vendors/{slug}/detailsexclusive vendor page with rich content (sliders, videos, builder blocks)
Key business behaviors:
- Only vendors with active products (price > 0, stock > 0 or negative_stock) are shown
- Tag filter on vendor pages sets
dofollow = false(SEO nofollow for filtered pages) - Category-filtered vendor pages canonical to base vendor URL
is_exclusive = 1enables/vendors/{slug}/detailspage with rich content- Vendor product pages support tag, variation, and attribute filters via query string
_remap()dispatcher routes all vendor URLs through a single entry point- Per-language vendor slugs with
lang_uriswitcher support
API Reference
REST Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /rest/product/vendor | Guest | List vendors (filter by isPromo, isExclusive, name.{locale}) |
| GET | /rest/product/vendor/{id} | Guest | Get vendor with relations |
| POST | /rest/product/vendor | Backend (Products) | Create vendor (multipart -- logo, banners) |
| POST | /rest/product/vendor/{id} | Backend (Products) | Update vendor |
| DELETE | /rest/product/vendor/{id} | Backend (Products) | Delete vendor |
Relations: translations, products, supplier File fields: logo, vendor_banner, vendor_medium_banner, vendor_small_banner
Legacy Storefront
| URL | Controller Method | Description |
|---|---|---|
/vendors | index() | All vendors listing page |
/vendors/{vendor-slug} | vendors($slug) | Vendor product listing |
/vendors/{vendor-slug}/{category} | vendors($slug, $suffix) | Vendor + category filter |
/vendors/{vendor-slug}/{line-slug} | lines_list($vendorSlug, $lineSlug) | Product line within vendor |
/vendors/{vendor-slug}/details | vendorsDetails($vendorSlug) | Exclusive vendor page |
Code Flow
Step 1: URL Routing via _remap()
File: ecommercen/eshop/controllers/Adv_vendors.php
- Index: Direct call to
index()for bare/vendors - Canonical check: If
useCanonicalenabled, checks for canonical URL redirect - Vendor lookup: Fetches vendor by slug via
vendors_model->get_records()(cached viapscache) - Exclusive check: If suffix is
details, routes tovendorsDetails() - Line check: If suffix matches a product line slug, routes to
lines_list() - Category check: If suffix matches a category slug, routes to
vendors()with category filter - Fallback: 404 if no route matches
Step 2: Vendor Index (All Brands)
File: ecommercen/eshop/controllers/Adv_vendors.php::index()
- Fetch vendors:
vendors_model->getVendorsWithActiveProductsAndValidPrices()(cached) - SEO: Generate meta tags via
seo_lib->create_metatags() - Breadcrumbs: Home > Vendors
- Hook:
indexExtras()— empty by default, override in client - Render:
vendorsAlllayout template
Step 3: Vendor Product Listing
File: ecommercen/eshop/controllers/Adv_vendors.php::vendors()
- Vendor data: Fetch by slug from cache
- Category parsing: Extract category slug and pagination offset from URL suffix
- Filter initialization: Tag filters from query string (
filterQueryStringVar), variation filters, attribute filters - Tag validation: Verify all filter slugs exist in tag records; 404 on invalid tags
- Product query: Fetch products with vendor + optional category + active filters
- SEO:
dofollow = falsewhen tag filters active; canonical to base vendor URL - Hreflang: Per-language vendor URLs via
renderVendorUrls() - Builder blocks:
blockBuilder->frontRender()forvendorDescriptionposition - Hook:
vendorsExtras()— override in client for custom content - Render: Product grid with filters, pagination, breadcrumbs
Step 4: Exclusive Vendor Details Page
File: ecommercen/eshop/controllers/Adv_vendors.php::vendorsDetails()
- Vendor check: Fetch vendor data; 404 if not found or
is_exclusive=0 - Slider: Load slider if
slider_idis set viasliders_model->getFrontMasterRecord() - Videos: Fetch assigned videos via
video_model->getAllVideosAssignedToVendor() - Builder block: Render
vendorExclusiveposition usingexclusive_builder_block_id - Rich content:
fulltextfrom MUI table for vendor description - Breadcrumbs: Home > Vendors > {Vendor Name} > Details
- Hook:
vendorsDetailsExtra()— override in client - Render:
vendorDetailslayout template
Domain Layer
| Component | Path |
|---|---|
| Service | src/Domains/Product/Vendor/Service.php |
| WriteService | src/Domains/Product/Vendor/WriteService.php |
| Validator | src/Domains/Product/Vendor/Validator.php |
| Entity | src/Domains/Product/Vendor/Repository/Entity.php |
| REST Controller | src/Rest/Product/Controllers/Vendor.php (HandlesUploadActions) |
| Legacy Controller | ecommercen/eshop/controllers/Adv_vendors.php |
| Admin Controller | ecommercen/eshop/controllers/Adv_vendors_admin.php |
| Legacy Model | ecommercen/eshop/models/Adv_vendors_model.php |
Data Model
shop_vendor
| Column | Type | Description |
|---|---|---|
id | int (PK, AI) | Vendor ID |
logo | text | Logo image path |
vendor_banner | varchar(255) | Main banner image |
vendor_medium_banner | varchar(254) | Medium banner image |
vendor_small_banner | varchar(254) | Small banner image |
is_promo | tinyint(1) | Whether vendor is promoted |
is_exclusive | int(2) | Whether vendor has exclusive detail page |
order | int | Display sort order |
slider_id | int (FK, nullable) | Linked slider for exclusive page |
supplier_id | int (FK, nullable) | Linked supplier reference |
shop_vendor_mui
| Column | Type | Description |
|---|---|---|
id | int (PK, AI) | MUI entry ID |
vendor_id | int (FK) | Parent vendor |
name | varchar(255) | Vendor display name |
vendor_slug | varchar(255) | URL slug |
fulltext | text | Vendor description (product listing page) |
exclusive_fulltext | text | Description for exclusive detail page |
lang | varchar(2) | Language code |
main_banner_url | varchar(255) | Click-through URL for main banner |
middle_banner_url | varchar(255) | Click-through URL for medium banner |
small_banner_url | varchar(255) | Click-through URL for small banner |
shop_vendor_video_lp
| Column | Type | Description |
|---|---|---|
id | int (PK, AI) | Lookup ID |
video_id | int (FK) | Video reference |
vendor_id | int (FK) | Vendor reference |
Client Extension Points
vendorsExtras()hook: Add custom content to vendor product pagesvendorsDetailsExtra()hook: Customize exclusive vendor detail pageindexExtras()hook: Vendor listing page customizations- Upload fields: Override
uploadFieldsConfig()for custom image fields in REST controller - DI override: Replace Vendor WriteService/Validator via container alias
- Builder blocks:
vendorDescriptionandvendorExclusivepositions for page builder content - Views:
{client_views}/vendors/— vendor listing, product listing, details templates
Related Flows
- CF-01 Product Browsing — shares product grid with tag/variation/attribute filters
- CF-02 Product Detail — canonical vendor URLs for products
- CF-04 Search — vendor results in search autocomplete and results page
- CF-35 Page Builder —
vendorDescriptionandvendorExclusivebuilder block positions - AD-19 Vendor Management — admin CRUD for vendors