Overview

All The Parts Catalog is a JavaScript widget that brings the full Parts Europe product catalog (132,000+ motorcycle & powersport parts) into any WordPress + WooCommerce store.

132,000+ Products

Parts, accessories, gear from 300+ brands. Synced automatically.

82,000 Vehicles

Search by make, model, year. Fitment data for every part.

WooCommerce Cart

Add to cart directly. Products created on-demand in WC.

Dual EUR/BGN Pricing

Legal dual display with VAT. Auto-converted at fixed rate.

15+ Filters

Brand, category, vehicle, price, availability, warehouse, alerts.

74KB Bundle

Preact + Shadow DOM. No conflicts with your theme. 21KB gzip.

Demo: catalog.alltheparts.eu/demo

Quick Start

1. Install the plugin

Download and install the WordPress plugin:

https://catalog.alltheparts.eu/plugin.zip

In WordPress admin: Plugins → Add New → Upload Plugin → select the ZIP → Install → Activate.

2. Create a page

Create a new WordPress page (e.g. "Catalog") and add the shortcode:

[partseurope]

3. Done

The catalog widget loads automatically. Products, filters, search, and cart integration all work out of the box.

Auto-updates: The plugin checks for updates every 6 hours. You'll see the update in WordPress dashboard just like any other plugin.

Catalog & Filters

The catalog shows a product grid with a collapsible filter sidebar. Every filter updates the URL, so filtered views can be shared or bookmarked.

Available Filters

FilterTypeDescription
BrandMulti-select + search300+ brands with product counts
CategoryTree (expand/collapse)59 categories, 595 subcategories
VehicleCascade dropdownMake → Model → Year. Shows only matching parts.
WarehouseBadge buttonsS1 (EU Central), S2, S3, D4 (US East), D5
AvailabilityRadioAll / EU in stock / US in stock / Out of stock
Price rangeMin-Max inputsEUR range
Product typeCheckboxesHas image, has fitments, on sale
Warehouse regionBadge buttonsNL, DE, US, etc.
ShippingCheckboxesHazardous, air restricted, truck only, etc.

Active Filter Tags

Selected filters appear as removable tags above the product grid. Click × on a tag to remove that filter, or "Clear all" to reset everything.

Views

Grid view — product cards with image, brand, name, SKU, price, availability.
List view — compact rows with thumbnail, details, and price aligned right.

Sort options

Pricing (EUR/BGN + VAT)

Legal requirement: Bulgaria joined the Eurozone on 01.01.2026. Dual pricing (EUR + BGN) is mandatory until 31.12.2026. Both currencies must be shown in equal font size and weight.

Display format

Product cards:

€45.99 / 89.95 лв.
с ДДС: €55.19 / 107.94 лв.

Product detail:

€45.99 / 89.95 лв. без ДДС
с ДДС: €55.19 / 107.94 лв.

Conversion rules

ParameterValue
Exchange rate1 EUR = 1.95583 BGN (fixed, irrevocable)
VAT rate20% (Bulgarian standard)
Rounding2 decimal places (≥5 rounds up)
Source priceEUR excl. VAT (from Parts Europe API)

Product Detail

Click any product to open the detail view. Includes:

Cart Integration

The widget integrates with WooCommerce via the Store API using a single shared placeholder product plus per-line cart_item_data — the same pattern WooCommerce Bookings and Product Add-Ons use. No per-SKU products are ever created, so the WC catalog and media library stay clean no matter how many parts get added to carts. When a user clicks "Add to Cart":

  1. The widget POSTs one request to /wc/store/v1/cart/add-item with { id: placeholderId, quantity, extensions: { pe: { sku, … } } }.
  2. The plugin pulls extensions.pe into the cart line's cart_item_data (the SKU is part of the cart-key hash, so different SKUs stay on separate lines).
  3. On every totals calculation the plugin re-fetches the real price + weight from the catalog API by SKU, server-side — the client-sent price is never trusted — and renders the real PE name/image/SKU in cart, checkout, order and emails.
  4. A pe:cart-updated event is dispatched (items count + total).
Requirements: WooCommerce 10.6+ (uses the Nonce header). One hidden placeholder product (PE-PLACEHOLDER) is auto-created and self-heals on every cart call; it is protected from deletion while the plugin is active. Works with both the classic cart shortcode and the Cart/Checkout Blocks. Prices/weights are cached for 10 min with a 3 s HTTP timeout.

Cart event

Listen for cart updates in your theme:

document.addEventListener('pe:cart-updated', (e) => {
  console.log('Items:', e.detail.count);
  console.log('Total:', e.detail.total);
  // Update your cart icon / counter
});

Coupons & Discounts

Promo codes are created in WooCommerce the usual way (Marketing → Coupons) and can be scoped to PartsEurope category, sub-category, brand or specific SKUs — even though the whole catalog rides on a single placeholder product. The plugin reads each cart line's PE SKU, resolves its attributes server-side from the catalog API, and gates the coupon per line.

Setting the scope

On the coupon edit screen, the Usage restriction tab gains a "PartsEurope scope" panel with four dropdowns fed from the live catalog (the panel labels follow the WordPress admin language):

Leave everything empty for an unrestricted (whole-store) coupon. Fill several fields and the coupon applies only where all of them match — so "Category: Helmets" + "Brand: Alpinestars" = Alpinestars helmets only. Within one field, any value matches (OR).

Coupon type matters: scope works with Percentage discount and Fixed product discount (WooCommerce evaluates these per cart line). Fixed cart discount always applies to the whole order and ignores the scope.

How it behaves

No WooCommerce taxonomy or product import is needed — the scope matches against PartsEurope attributes directly. The matching core is built tier-agnostic so an external (client-managed) promo manager can reuse it later. Design: plans/2026-06-13-promo-codes-discounts.md.

URL State

Every filter, sort option, page, and view mode is stored in the URL hash. This means:

URL examples

URLResult
#/Catalog, no filters
#/?brands=0837&category=01Filtered by brand + category
#/?search=steering&sort=price_ascSearch + sort by price
#/?availability=eu_in_stock&view=listEU in stock, list view
#/product/06410329Product detail page

Link directly to filtered views or specific products from WordPress menus, banners, emails, or any external page. Add query parameters with the pe_ prefix to your catalog page URL.

Important: All parameters use the pe_ prefix (e.g. pe_category, not category). This prevents conflicts with WordPress reserved query variables.

Product link

/catalog/?pe_product=06410329

Opens the product detail page directly. Also works with pe_sku:

/catalog/?pe_sku=06410329

Category link

/catalog/?pe_category=01          ← Helmets
/catalog/?pe_category=03          ← Tires & Tubes
/catalog/?pe_category=12          ← Drive & Transmission

Brand link

/catalog/?pe_brands=0837          ← Moose Offroad
/catalog/?pe_brands=1275,1276     ← Alpinestars (Road + Casuals)

Combined filters

/catalog/?pe_category=01&pe_brands=0112              ← Z1R Helmets
/catalog/?pe_search=brake+pad&pe_availability=eu_in_stock  ← Brake pads, EU stock
/catalog/?pe_category=03&pe_sort=price_asc&pe_view=list    ← Tires, cheapest, list

All supported parameters

ParameterExampleDescription
pe_product / pe_sku06410329Open product detail
pe_brands0837,0120Filter by brand code(s)
pe_category01,03Filter by category code(s)
pe_subCategory01:02Filter by subcategory (comCode:subCode)
pe_searchbrake+padText search
pe_sortprice_ascSort order
pe_availabilityeu_in_stockStock filter
pe_statusS1,S2Warehouse status
pe_priceMin / pe_priceMax10 / 500Price range (EUR)
pe_viewlistView mode: grid or list
pe_page3Page number

WordPress menu examples

In Appearance → Menus, add Custom Links:

Menu labelURL
Каски/catalog/?pe_category=01
Гуми/catalog/?pe_category=03
Вериги и трансмисия/catalog/?pe_category=12
Alpinestars/catalog/?pe_brands=1275,1276,0821
Налични EU/catalog/?pe_availability=eu_in_stock
С отстъпка/catalog/?pe_hasDiscount=true
Tip: Query parameters are only used on first page load. Once the widget is loaded, all navigation happens via hash URLs. Users can then change filters, and the URL updates automatically for sharing.

WP Plugin

Installation

  1. Download: catalog.alltheparts.eu/plugin.zip
  2. WordPress Admin → Plugins → Add New → Upload Plugin
  3. Activate "All The Parts Catalog"

Requirements

RequirementMinimum
WordPress5.8+
WooCommerce10.6+ (for cart)
PHP8.0+

Auto-updates

The plugin checks /plugin-info.json every 6 hours. When a new version is available, it appears in WordPress → Updates, just like any plugin. Enable "Auto-update" in the Plugins page to update automatically.

What the plugin does

Size & Spec Finders

Dedicated landing pages show a category-specific hero: sub-category tiles on top (curated display_order), then the size/spec finder, then a brand filter listing every brand in the category with exact facet counts. All chip counts are live — they re-count against the other active filters on every change (bitmap facets), and chips that would yield 0 results disable. Parity with partseurope.eu.

CategoryHero componentFinder
Tires (03)TireHeroCascading width × aspect ratio × diameter
Chains (12)ChainHeroPitch (520/525/530) + links count + ring-type (O/X/Z) + join-type
Helmets (01)HelmetHeroSub-categories + size + material (Carbon/Fiberglass) + MIPS
Footwear (34)ApparelHeroEU shoe sizes "43 (US 9.5)" + letter sizes
Apparel (28, 33, ...)ApparelHeroSize (letter/waist/EU chest) + audience (Men/Women/Kids)
OtherGenericCategoryHeroSub-categories + category brand filter
Structured attributes: every product is parsed into parts_attributes (size, pitch, ring type, material, etc.) via background parsers that run on sync. Recall: 95% for tires, 90% for apparel, 100% for chains/helmets on matched categories.

Variant Grouping & Siblings

Products from the same model (different sizes / lengths) are grouped automatically. On a product detail page, users see size chips with live stock badges — click to switch variants without leaving the page.

How siblings are detected

Endpoint

GET /catalog-api/products/:sku/siblings

Returns an ordered list of sibling SKUs with canonical labels and availability.

Full-text search runs against the search_tsv tsvector (GIN index) with Bulgarian brand aliases. Target latency: <100ms end-to-end.

Features

Performance

EndpointBeforeAfter
/products?search=43s (hang)~35ms DB / <200ms E2E
/suggest?q=3-4s<100ms
/filters2-6s<50ms (60s LRU cache)

Shortcodes

The plugin registers 10 shortcodes: a main catalog shortcode, 7 dedicated category landings, a standalone search widget, and a carousel. Each can be dropped into any page or Elementor block.

Main shortcode

[partseurope]
AttributeDefaultDescription
langbgbg (Bulgarian) or en (English)
view—Pre-select grid or list
category—Pre-filter by category code
brand—Pre-filter by brand code
sku—Open specific product detail

Dedicated category shortcodes

Each renders the full catalog pre-scoped to that category, with a dedicated hero (sub-category tiles on top, size/spec finder, category brand filter at the bottom).

ShortcodeCategoryHero / Finder
[partseurope_tires]03 Tires & TubesWidth × Aspect × Diameter cascade
[partseurope_chains]12 Drive & TransmissionPitch + Links + Ring-type
[partseurope_helmets]01 HelmetsSize + Material + MIPS
[partseurope_apparel]28 Apparel (jackets/pants)Size + Audience chips
[partseurope_gloves]33 GlovesSize + Audience chips
[partseurope_boots]34 Footwear & SocksEU shoe sizes "43 (US 9.5)" + letter sizes
[partseurope_parts]all otherGeneric landing (sub-cats + category brand filter)

Examples

<!-- English language -->
[partseurope lang="en"]

<!-- Dedicated tire landing with size cascade -->
[partseurope_tires]

<!-- Dedicated helmets landing -->
[partseurope_helmets]

<!-- Single product detail -->
[partseurope sku="06410329"]

Typical WordPress pages

Page slugShortcode
/gumi/[partseurope_tires]
/verigi/[partseurope_chains]
/kaski/[partseurope_helmets]
/ekipirovka/[partseurope_apparel]
/rukavici/[partseurope_gloves]
/botushi/[partseurope_boots]
/chasti/[partseurope_parts]

Carousels

Embed horizontal product carousels on any page (homepage, category headers, product detail). Use [partseurope_carousel] with a source attribute.

Basic usage

[partseurope_carousel source="bestsellers" title="Най-продавани"]
[partseurope_carousel source="discount" title="С промоция"]
[partseurope_carousel source="category" category="01" title="Каски"]
[partseurope_carousel source="brand" brand="0837" title="Alpinestars"]

Available sources

SourceDescription
popularMost-viewed products (last 30 days)
bestsellersMost added to cart
trendingRising in popularity this week
discountProducts with active discount
newNewest arrivals (newest first)
categoryScoped by category="01"
brandScoped by brand="0837"
manualHand-picked SKUs via skus="A,B,C"
fitmentCompatible parts for a vehicle via vehicle="..."

Each carousel has a "Виж всички →" button that opens the full catalog with the combined filters applied.

Standalone Search Widget

A compact search box with autocomplete — perfect for homepage heroes, header bars, or sidebars.

[partseurope_search placeholder="Търси по SKU, марка, модел..."]

The widget:

Attributes:

Vehicle Finder Widget

Horizontal "Find parts for your bike" form — three cascading combos (марка / модел / година) and a Search button. Submit redirects to the catalog with the matched vehicle filter pre-applied.

[partseurope_vehicle_finder]
[partseurope_vehicle_finder title="Търсене по мотор"]
[partseurope_vehicle_finder default_category="03"]   

Attributes:

Layout:

Analytics (GTM)

The widget pushes GA4 e-commerce events to window.dataLayer. To collect them, add a Google Tag Manager snippet to your WordPress site.

Events

EventWhenKey data
view_item_listProduct listing loadeditems[] (up to 24), item_list_name
view_itemProduct detail openeditem_id, item_name, item_brand, price, currency
add_to_cartAdded to WC cartitem_id, price, quantity
searchSearch submittedsearch_term, pe_results_count
pe_filterFilter changedpe_filter_type, pe_filter_value
pe_page_viewSPA navigationpage_path

All e-commerce events follow the GA4 e-commerce specification and work with GA4's built-in e-commerce reports.

GTM setup

  1. Create a GTM container at tagmanager.google.com
  2. Add the GTM snippet to your WordPress <head> (via theme or plugin like "Insert Headers and Footers")
  3. In GTM, create a GA4 Configuration tag with your Measurement ID
  4. Create triggers for each event (Custom Event trigger, event name = view_item_list, etc.)
  5. The e-commerce data flows automatically — GA4 reads the ecommerce object from dataLayer

API Reference

The Catalog API is publicly accessible at catalog.alltheparts.eu/catalog-api/. Read-only, CORS enabled for all origins.

GET /catalog-api/filters

Returns all available filter options with product counts.

{
  "brands": [{ "code": "0837", "name": "Alpinestars", "count": 4521 }, ...],
  "categories": [{ "code": "01", "name": "Helmets", "count": 8234 }, ...],
  "subCategories": [{ "comCode": "01", "subCode": "02", "name": "Full Face", "count": 3100 }, ...],
  "statuses": [{ "status": "S1", "count": 89000 }, ...],
  "priceRange": { "min": 0.50, "max": 12500.00 },
  "warehouseCountries": [{ "country": "NL", "count": 95000 }, ...]
}

GET /catalog-api/products

Paginated product listing with filters.

ParamTypeDescription
pageintPage number (default 1)
limitintItems per page (default 24, max 100)
searchstringFull-text search (part number, name, brand)
brandsstringComma-separated brand codes
categorystringComma-separated category codes
subCategorystringComposite keys: 01:02,03:05
statusstringWarehouse status: S1,S2,D4
availabilitystringeu_in_stock, us_in_stock, out_of_stock
priceMinnumberMin price (EUR)
priceMaxnumberMax price (EUR)
vehiclestringComma-separated vehicle IDs
hasImagebooleanOnly products with images
hasFitmentsbooleanOnly products with fitment data
hasDiscountbooleanOnly discounted products
alertsstringhazardous,air_restricted,truck_only,drop_shipment,freight_collect
warehouseCountrystringComma-separated country codes
sortstringprice_asc, price_desc, name_asc, newest, availability_desc

Category-specific filter params

ParamScopeExample values
tireWidth / tireAspect / tireDiameterTires (03)180 / 55 / 17
chainPitch / chainRing / chainJoinChains (12)520,525,530 / O,X,Z
helmetSize / helmetMaterial / helmetMipsHelmets (01)L,XL / carbon,fiberglass / true
apparelSize / apparelWaist / apparelShoeSize / apparelAudienceApparelM,L / 32 / 42 / men,women,kids

GET /catalog-api/products/:partNumber

Full product detail including media, fitments, price/availability history, and structured attributes from parts_attributes.

GET /catalog-api/products/:sku/siblings

Returns variants of the same model (tire sizes, chain lengths, vendor stem group). Used for product-detail size chips.

GET /catalog-api/suggest

Autocomplete for search — returns brands, categories, SKUs matching a prefix. Target latency <100ms.

GET /catalog-api/suggest?q=dunl&lang=bg
{
  "brands": [{ "code": "0837", "name": "Dunlop", "count": 523 }],
  "categories": [...],
  "skus": [{ "part_number": "06410329", "part_name": "..." }]
}

GET /catalog-api/did-you-mean

Fuzzy fallback when search returns 0 results (pg_trgm similarity on brands + categories).

GET /catalog-api/tire-sizes

Cascading width → aspect → diameter counts for tire finder UI.

GET /catalog-api/chain-filters

Available chain pitch / ring-type / join-type values with counts.

GET /catalog-api/helmet-filters

Available helmet size / material / MIPS values with counts.

GET /catalog-api/apparel-filters

Available apparel size / audience values with counts.

GET /catalog-api/vehicles

Cascading vehicle filter. Call without params for producers, with producer for models, with producer+model for years, with all three for matching vehicle IDs.

GET /sitemap.xml · /sitemap-index.xml

SEO sitemap split into 10k URLs per file. Public (no auth). Whitelisted in nginx allowlist.

Data Sync

Product data is synced automatically from the Parts Europe API.

ScheduleFrequencyWhat
Full syncSaturday 19:00 UTCAll products, prices, availability, media, fitments
Update syncMon-Sat, every 2h (05:00-13:00 UTC)Changed products + prices + availability

What gets synced

Stale products

Products that are no longer returned by the PE API are marked as stale and automatically hidden from the catalog. Currently ~1,400 products (~1%) are stale.

FAQ

Why do some products have no image?

About 1,100 products (0.8%) have no image in the Parts Europe API. These show a placeholder. The PE website loads images from an internal CDN that isn't exposed through their API.

How does the EUR/BGN conversion work?

The exchange rate is fixed at 1 EUR = 1.95583 BGN (set by the EU Council). Conversion happens client-side in the widget. VAT (20%) is calculated on top.

Can I add the catalog to multiple pages?

Yes. Use the [partseurope] shortcode on any page. Use attributes to pre-filter, e.g. [partseurope category="01"] for a helmets-only page.

Does it work on mobile?

Yes. The widget is fully responsive. On screens below 960px, filters collapse behind a toggle button. On screens below 600px, the grid switches to 2 columns and SKUs are hidden for space.

How do I change the language?

Use the lang attribute: [partseurope lang="en"]. Available: bg (Bulgarian, default), en (English).

How do I link to a specific category or product?

Add query parameters with the pe_ prefix to your catalog page URL. For example: /catalog/?pe_category=01 for Helmets, or /catalog/?pe_product=06410329 for a specific product. See the Deep Linking section for all options.

Will the widget conflict with my theme's CSS?

No. The widget uses Shadow DOM, which isolates its styles completely. Your theme's CSS cannot affect the widget, and the widget's CSS cannot leak into your page.

How are products added to the WooCommerce cart?

When a user clicks "Add to Cart", the plugin creates a private WC product on-the-fly (if it doesn't exist) and adds it via the WC Store API. Private products don't appear in your shop — they only exist for cart/checkout purposes.

How often is the data updated?

Prices and availability update every 2 hours on weekdays. A full sync (all products, media, fitments) runs every Saturday evening.

What happens if Parts Europe is down?

The widget displays data from our local database, which is always available. Sync will retry automatically when PE API recovers.

All The Parts