silvershop-suite / product-feed-meta
Meta (Facebook & Instagram) catalog channel connector for silvershop-suite/product-feed (CMS 6): an RSS 2.0 + g: namespace serializer and field map that turns the shared CatalogProductData into a Meta Commerce catalog feed for Facebook Shops, Instagram Shopping and Advantage+/dynamic ads. Reuses Goo
Package info
github.com/silvershop-suite/silvershop-product-feed-meta
Type:silverstripe-vendormodule
pkg:composer/silvershop-suite/product-feed-meta
Requires
- php: ^8.3
- silvershop-suite/product-feed: ^1.0
- silvershop/core: ^6.2
- silverstripe/cms: ^6.0
- silverstripe/framework: ^6.0
Requires (Dev)
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-10-24 13:29:32 UTC
README
The Meta (Facebook & Instagram) Commerce channel connector for
silvershop-suite/product-feed on Silverstripe CMS 6. It plugs a
Meta Commerce catalog channel (Facebook Shops, Instagram Shopping, Advantage+/dynamic ads) into the feed core's
registry seam: an RSS 2.0 + g: namespace serializer, the CatalogProductData → g:* field map, and a
per-category fb_product_category mapping. No core change — the connector registers itself.
product-feed core ──(registry)──▶ MetaChannelFeed.mapItem() ──▶ RssGFormat ──▶ public/feeds/meta.xml
(g: attribute map) (RSS 2.0 + g:) served at /feed/meta
Meta's RSS-XML catalog feed deliberately reuses Google Merchant's g: field vocabulary — the RSS root declares
xmlns:g="http://base.google.com/ns/1.0" and the item fields are g:-prefixed — so this connector mirrors
silvershop-suite/product-feed-google almost verbatim, with a handful of Meta-specific deltas (below). It carries
no dependency on the Google connector: it ships its own copy of the RSS+g: serializer.
Requirements
- PHP 8.3+,
silverstripe/framework^6,silverstripe/cms^6,silvershop/core^6.2 silvershop-suite/product-feed^1 (the feed core; pulls insilvershop-suite/catalog-datatransitively)
Installation
composer require silvershop-suite/product-feed-meta
Then dev/build?flush=all. This:
- adds the per-category Meta product category (
fb_product_category) field toProductCategory; - registers + enables the
metachannel in the feed core (installing the connector means you want the feed).
Mapping categories
Open a product category in the CMS → Meta catalog → paste the category id or full path from Meta's own
product taxonomy (Commerce Manager shows it). A sub-category inherits its nearest mapped ancestor, so setting a
top-level category is usually enough. A product's g:fb_product_category is resolved from its category's value
(walking up the tree).
fb_product_categoryuses Meta's own taxonomy (distinct ids/paths from Google's). It is optional wheng:google_product_categoryis present (Meta accepts and uses the Google category), so this v1 keeps it a simple free-text field rather than bundling the full Meta taxonomy. If the Google connector is also installed, itsgoogle_product_categorymapping is reused automatically (see the map below).
Generating & serving
The feed core owns generation, scheduling and serving (see its README). With this connector installed:
- generate:
sake tasks:ProductFeed-Generate --channel=meta(or let the recurringGenerateProductFeedJobdo it), written topublic/feeds/meta.xml; - serve:
https://your-shop/feed/meta(the core's serving route) — point Meta Commerce Manager at that URL.
The g: field map
Meta attribute (g:-prefixed in RSS) |
Source (CatalogProductData unless noted) |
|---|---|
g:id |
feedId() (= Google feed id = Meta Pixel/CAPI content_ids) |
title / description / link |
title() / description() / link() |
g:image_link / g:additional_image_link |
imageLink() / additionalImageLinks() |
g:availability |
availability() → in stock / out of stock / preorder / available for order (space form) |
g:price / g:sale_price |
formattedPrice() / formattedSalePrice() ("12.95 EUR") |
g:brand / g:gtin / g:mpn |
brand() / gtin() / mpn() (gtin/mpn via silvershop-suite/product-identity) |
g:condition |
condition() → new / refurbished / used |
g:fb_product_category |
the per-category Meta value via the category parent-walk |
g:google_product_category |
reused from the Google connector's taxonomy mapping when it is installed (emit_google_product_category, default on) |
g:product_type |
productType() with the site root trimmed (product_type_trim_segments, default 1) |
g:item_group_id |
itemGroupId() (parent product) — variants are separate <item>s sharing it |
g:color / g:size |
matched from attributes() (color_attributes / size_attributes) |
g:shipping |
opt-in (shipping_enabled, default off) from configured flat rates |
All text is XML-escaped (XSS-safe) and the document is well-formed RSS 2.0.
Meta deltas vs the Google connector
g:availabilityuses the space form (in stock, notin_stock) — Meta's documented tokens.Backordermaps to Meta's nearest value,available for order(Meta has nobackorder).g:identifier_existsis dropped — a Google-only attribute Meta does not document.g:fb_product_categoryis added (Meta's own taxonomy), whileg:google_product_categoryis reused when the Google connector is present.id/title/description/ image limits are all looser on Meta than Google, so the shared VO's caps already satisfy Meta with no truncation divergence.
Config
SilverShop\ProductFeed\Meta\MetaChannelFeed: emit_google_product_category: true # reuse the Google connector's category mapping when installed product_type_trim_segments: 1 # drop the catalogue root from g:product_type shipping_enabled: false shipping: - { country: 'NL', service: 'Standard', price: '4.95 EUR' }
Core knobs (output_dir, chunk_size, regenerate_interval_mins, cache_max_age, access_token, reading stage)
are inherited from the feed core unchanged.
The content_ids tie
g:id is CatalogProductData::feedId() verbatim — the same shared id the Google feed emits and the same value
silvershop-suite/conversion-tracking-meta sends as the Meta Pixel / CAPI content_ids. So the Meta catalog ↔
Pixel/CAPI product matching (and Advantage+/dynamic-ads retargeting) lines up by construction, with no extra
configuration — provided feed and tracking read the same catalog-data id_source (they share one factory, so
they do). Variants are emitted as separate <item>s sharing g:item_group_id, the shape Meta's product_group
events resolve to.
Commerce Manager setup
- Create/claim a Catalog in Meta Commerce Manager (plus a Business + verified domain for Shops/checkout).
- Catalog → Data sources → Data feed → Use a URL (Scheduled) →
https://your-shop/feed/meta→ set the fetch interval (minimum once per hour) to matchGenerateProductFeedJob.regenerate_interval_mins. - For Advantage+/dynamic ads: connect the catalog to the ad account, and ensure the Pixel (from
silvershop-suite/conversion-tracking-meta) is linked to the same catalog socontent_idsmatch. - Map categories (
fb_product_categoryand/orgoogle_product_category) and clear the Commerce Manager diagnostics warnings.
The connector produces a spec-correct feed; catalogue / commerce policy compliance is the merchant's (image rules, prohibited categories, price/availability accuracy). Watch the Commerce Manager diagnostics.
Not in v1
No Graph API / Catalog Batch API / access-token push; no bundled Meta taxonomy tree-picker; no CSV/TSV format; no
quantity_to_sell_on_facebook (on-Meta checkout stock level); no material / gender / age_group / video /
rich-text. These are designed-for follow-ons — the v1 scheduled-URL RSS feed deliberately needs no secrets.
Licence
BSD-3-Clause.
Credits
Built and maintained by Remy Vaartjes (remy@xd.nl) — part of the SilverShop-Suite.