This is a Docker microservice for generating XML catalogs from WooCommerce.
XML feeds files will be stored in /app/feeds
This service retrieves products data from your WooCommerce REST API and generates periodically XML files for your campaigns. The output files are fully customizable with desired tags and values for each type of product.
xmlcatalog:
image: lotrekagency/wc_xml_catalog
volumes:
- ./xmlfeeds:/app/feeds
- ./your_config.json:/app/config.json
depends_on:
- redis
env_file: ./envs/prod/myxmlcatalog.env
networks:
- webnet
redis:
image: library/redis:latest
restart: unless-stopped
networks:
- webnet
The service needs to be configured by setting up some environment variables.
WOO_HOST=https://www.mywoocommerce.com/wp-json/wc/v3
WOO_CONSUMER_KEY=ck_f4k3889898tgddfrr709eaade5e39a361c782
WOO_CONSUMER_SECRET=cs_4g41nf4ke69797adsas23458af18253aad51a
XML_SITE_NAME=My Woo Commerce
XML_SITE_HOST=www.mywoocommerce.com
XML_FEED_FILENAME=feedXML
XML_FEED_DESCRIPTION=Feed XML autogenerated
XML_CONFIG_FILENAME=config.json
PRODUCTS_STATUS_CODE=publish
CRONTAB_HOUR=*/7
[email protected]
The WOO_HOST
, WOO_CONSUMER_KEY
and the WOO_CONSUMER_SECRET
are the three main WooCommerce API parameters for products retrieving.
XML_SITE_NAME
is the name of your WooCommerce site.
XML_SITE_HOST
is the URL of your WooCommerce site.
XML_FEED_FILENAME
is the name of the generated feed file. It's optional.
XML_FEED_DESCRIPTION
contains the description in the feed file. It's optional.
XML_CONFIG_FILENAME
contains the filename of the configuration file. Default value is config.json
.
PRODUCTS_STATUS_CODE
contains the status code for list product filtering from REST API. Default value is publish
.
CRONTAB_HOUR
contains the string for the interval of cron events. Default value is */7
, which stands for "event every seven hours".
SENTRY_URL
contains the URL of your sentry service. If it's not set any exception will be sent to Sentry.
The output feed can be customized by modifying the JSON configuration file. The configuration contains the attribute mapping for every file indicated. The attribute mapping is related to product types, so one file can contain more product types with the specified attribute mapping.
In the following example two types of products are configured: variable
and variation
.
{
"first_file" : {
"languages" : {
"it" : "it",
"multilanguage" : ["it", "en"]
},
"types" : {
"variable" : {
"g:brand" : {
"default" : "XML_SITE_NAME"
},
"g:id" : {
"attribute" : "id"
},
"g:title" : {
"attribute" : "name"
},
"g:condition": {
"static" : "New"
},
"g:image_link" : {
"attribute" : "images[0].src"
},
"g:availability": {
"attribute": "stock_status",
"replacer": {
"instock": "in stock",
"onbackorder": "out of stock"
}
}
},
"variation" : {
"g:title" : {
"parent" : "meta_data(key=title).value",
"attribute" : "attributes[0].option"
},
"g:shipping" : {
"default" : "default_shippings",
"unique" : true
},
"g:sale_price" : {
"attribute" : "sale_price",
"suffix" : " EUR"
},
"g:category" : {
"attribute" : "categories.name",
"separator" : " - "
},
"g:description" : {
"attribute" : "meta_data(key=description).value"
}
}
}
}
}
The service will generate the file first_file.xml
in different languages with the variable
and variation
product types retrieved from the WC REST API.
Each file configuration must include the languages
dictionary, which contains the language versions of the generated file.
Example:
"languages" : {
"it" : "it",
"multilanguage" : ["it", "en"]
}
With this configuration, the service will generate two versions of file: the first will be named it
and it will contain italian products, the second version will be named multilanguage
and it will contain italian and english products.
Version names are appended to the file name, so for the first_file
the service will generate feedXML_it_first_file
and feedXML_it_en_first_file
.
In addition, file configurations must include the types
dictionary, which contains the attribute mapping of every product type contained in a file.
Each product type configuration contains objects for each tag in the output feed.
Example:
"g:title" : {
"attribute" : "name"
}
With this configuration the output will be the following.
<g:title>
Your product name
</g:title>
As you can see, the name of the objects is related to the tag name. The tag object contains the output value paths. The values can be retrieved in four ways:
static
, for static strings outputsattribute
, for values retrieving from products fieldsparent
, for values retrieving from parent products fieldsdefault
, for values retrieving from default service variables
The static
will output it's string value.
Example:
"g:condition" : {
"static" : "New"
}
The output will be the following.
<g:condition>
New
</g:condition>
This tag may also relate to a list of configuration objects: in this way it's possibile to configure a tag with sub-tags.
The attribute
relates to the value retrieving by field path of the product object.
It's possibile to indicate the specific path of a value by indexing a list object or selecting it.
Example:
"g:image_link" : {
"attribute" : "images[0].src"
}
It retrieves the src
value from images[0]
and the output will be like the following.
<g:image_link>
https://yourimage.png
</g:image_link>
Another example with list selecting method:
"g:description" : {
"attribute" : "meta_data(key=description).value"
}
It retrieves the value
value from the meta_data
object were key
is equal to description
.
The output will be like the following.
<g:description>
Your description
</g:description>
If the penultimate field is a list, the service relates all the fields of every object of the list.
The parent
key works like attribute
but refers to parent fields.
Parents are set automatically from the service only on variations product, and so variations products have their father products as parents.
An example with this tag:
"g:title" : {
"parent" : "title"
}
It retrieves the parent product title
value, and the output will be the following.
<g:title>
Parent product description
</g:title>
The default
key relates to the service variables.
Available variables are:
XML_SITE_NAME
, contains the site nameXML_SITE_HOST
, contains the site hostXML_FEED_DESCRIPTION
, contains the site descriptiondefault_shippings
, contains the list of all the shippings retrieveddefault_tax_rates
, contains the list of all the tax rates retrievedcurrent_language
, contains the language code of the processing generationcurrent_tax_rate
, contains the tax rate of the processing generation
Example:
"g:brand" : {
"default" : "XML_SITE_NAME"
}
It takes the value of the attribute set up in the first configuration and the output will be like the following.
<g:brand>
Your brand name
</g:brand>
There are some extra keys for strings formatting:
suffix
, contains the suffix stringprefix
, contains the prefix stringseparator
, contains the string which will separate the values of every object listreplacer
, contains a dictionary with the values that need to be replaced in the output feed, if there is no match with value and dictionary it's possibile to output thereplacer_fail
value contained in the replacer dictfatal
, if it'strue
and the retrieved value it'sNone
or if the value retrieved is not contained in a specified value list ("fatal" : [...]
) or is not equal to a single value ("fatal" : "example"
), the father object will not loaded on the output feedexclude
, if it'strue
and the retrieved value exists or if the value is contained in the exclusion list ("exclude" : [...]
) the object will not loaded on the feedvisible
, if it'sfalse
the attribute will not be loaded on the XML file, default value istrue
A JSON object in the configuration represents a tag in the output XML file. And so, it's also possible to add sub-elements, concatenate values and handle multiple tags.
If there are keys with different names from main and extra keys in the dict, then a sub-element will be added to the main tag.
Example:
"g:description" : {
"short" : {
"static" : "This is a short description."
},
"long" : {
"static" : "This is a long description."
}
}
The output will be the following.
<g:description>
<short>
This is a short description.
</short>
<long>
This is a long description.
</long>
</g:description>
It's possibile to concatenate retrieved values.
Example:
"g:name" : {
"attribute" : "id",
"static" : "Example"
}
The output will be the following.
<g:name>
My product ID, Example
</g:name>
If you want to concatenate values from the same tag you must setup your tag config with a list.
Example:
"g:name" : {
"attribute" : ["id", "name"]
}
The output will be the following.
<g:name>
My product ID, My product name
</g:name>
Values will be separated by a comma if the separator
key will not found in the config dict.
Example with a separator:
"g:name" : {
"attribute" : ["id", "name"],
"separator" : " - "
}
The output will be the following.
<g:name>
My product ID - My product name
</g:name>
If a tag has a list as value in the configuration, the service will repeat the XML tag for every JSON object in the configuration list.
Example:
"g:shipping" : [
{
"g:country" : {
"static" : "IT"
},
"g:price: {
"static" : "5.99 EUR"
}
},
{
"g:country" : {
"static" : "EN"
},
"g:price: {
"static" : "9.99 EUR"
}
}
]
The output will be the following.
<g:shipping>
<g:country>IT</g:country>
<g:price>5.99 EUR</g:price>
</g:shipping>
<g:shipping>
<g:country>EN</g:country>
<g:price>9.99 EUR</g:price>
</g:shipping>
It's possibile to organize your XML files generation in folders: if you insert the desiderd path for your file in the file name value of your configuration, the service will generate the files with indicated path.
Example:
"facebook/products" : {
"products" : {
...
}
},
"google_products" : {
"products" : {
...
}
}
The service will generate two files with different paths:
feeds/facebook/feedXML_products
feeds/feedXML_google_products
cd tests/
pytest .