Settings¶
SEO Suite Pro keeps its settings in OpenCart's own setting table, under the
module_seo group. You set them at
Admin > Extensions > Extensions > Modules > SEO Suite Pro.
Each key below carries where it applies. per store means a multi-store install can hold a different answer per storefront, and both are honoured: a read takes what that store holds, then what the default store holds, then the shipped default. install-wide means one thing serves every storefront, and the key's own description names that one thing.
Suite¶
| Key | Default | What it does |
|---|---|---|
module_seo_statusinstall-wide |
0 |
Whether SEO Suite Pro does anything at all. Off on a fresh install, the way every module in this repo arrives off, so that installing it changes no page until a merchant has been through the five screens and chosen what should run. Install-wide, because it is the switch core itself reads to decide whether the suite shows as enabled in the extension list, and core keeps one row for that. |
URLs & meta · Scope¶
| Key | Default | What it does |
|---|---|---|
module_seo_basics_statusper store |
0 |
Whether this storefront uses the extension at all. Off, the canonical handler returns before it reads anything and the screen still generates on request, because generating is something you press rather than something the shop does. Per store, because the tag it governs is emitted as a page is rendered. |
module_seo_basics_canonicalper store |
0 |
Whether this storefront's listing pages carry a canonical link tag — the one that tells a search engine which of several URLs for the same list is the one to index. Off, and it ships off: switching it on is a search-visibility decision, and it is not one an extension makes on a live shop's behalf the moment it is installed. |
module_seo_basics_generate_productper store |
1 |
Whether a run generates for this shop's products. On, and all three ship on, because that is what a run did before there was anything to say otherwise with. Per store, because a run walks shop by shop: a shop whose categories are curated by hand can be left out of that half of the run while the shop beside it is not. |
module_seo_basics_generate_categoryper store |
1 |
Whether a run generates for this shop's categories. Off is how a store that writes its own category keywords says so — until now the only way to leave them alone was to remember not to press the button. |
module_seo_basics_generate_manufacturerper store |
1 |
Whether a run generates for this shop's manufacturers. A manufacturer has a URL keyword and nothing else — OpenCart holds no meta title or description for one anywhere in its schema. |
URLs & meta · Templates¶
| Key | Default | What it does |
|---|---|---|
module_seo_basics_product_keywordinstall-wide |
[name] |
The pattern a product's URL keyword is generated from. Install-wide, like every template here: a run is one press of one button applying one set of patterns to whichever shops you ticked for it, and what it writes for a product is shared by every shop that sells it. |
module_seo_basics_product_meta_titleinstall-wide |
[name] |
The pattern a product's meta title is generated from — the line a search result shows as its heading. About sixty characters of it are displayed; the screen counts as you type and says so rather than cutting it off, because a sentence stopped mid-word is worse than a long one. |
module_seo_basics_product_meta_descriptioninstall-wide |
empty | The pattern a product's meta description is generated from — the sentence a shopper reads in a search result before deciding whether to click. It ships empty, which generates nothing; why no default is invented for it is below, under what this extension will not change. |
module_seo_basics_category_keywordinstall-wide |
[name] |
The pattern a category's URL keyword is generated from. A category has no category of its own, so [category_path] here is its own path read top down and [parent_category] the step above it. |
module_seo_basics_category_meta_titleinstall-wide |
[name] |
The pattern a category's meta title is generated from. |
module_seo_basics_category_meta_descriptioninstall-wide |
empty | The pattern a category's meta description is generated from. Empty, and generating nothing, for the reason the product's is. |
module_seo_basics_manufacturer_keywordinstall-wide |
[name] |
The pattern a manufacturer's URL keyword is generated from, and the only output a manufacturer has: OpenCart holds no meta title or description for one, and its name is not even per language, so every language generates from the same one. |
URLs & meta · Advanced¶
| Key | Default | What it does |
|---|---|---|
module_seo_basics_path_separatorinstall-wide |
|
What joins the names of a category path where a template asks for [category_path]. A space — which is what it has always been — makes Men Shirts, and a > makes Men > Shirts, which is a decision about what a shopper reads in a search result. It reaches a URL keyword as words to be slugged rather than as punctuation, so a keyword generated from it is the same shape either way. Install-wide because it is part of how a template renders, and the templates are. |
module_seo_basics_batchinstall-wide |
200 |
How many entities one request of a run writes for before the screen asks again. Install-wide because the one thing it governs is the host this admin is running on: it is a bound on what one request is asked to do, and a shop cannot have a different web server from the shop beside it. There is a ceiling over it; see below. |
module_seo_basics_diary_verbose_untilinstall-wide |
0 |
When detailed logging stops, as a unix timestamp, and 0 is off. Turning Detailed logging on from this extension's settings form stores the moment two days from now; the writer compares that against the clock every time it is asked for a DEBUG line, so the window closes on its own with no scheduled task and nothing to clean up. While it is open this extension records what it did in far more detail, and the shared diary consequently holds less history. |
Markup · Scope¶
| Key | Default | What it does |
|---|---|---|
module_seo_markup_statusper store |
0 |
Whether this storefront emits any of this extension's markup at all. Off, every handler returns before it reads anything and the pages carry exactly what your theme puts there. Per store, because the markup is emitted as a page is rendered: one shop can be describing itself to crawlers while the other is not. |
Markup · Social sharing¶
| Key | Default | What it does |
|---|---|---|
module_seo_markup_og_statusper store |
1 |
Whether the og: tags are emitted — the ones Facebook, LinkedIn, Slack, WhatsApp and most everything else read. A product page also carries its price, currency and availability. |
module_seo_markup_twitter_statusper store |
1 |
Whether the Twitter Card tags are emitted. A scraper that reads neither these nor the og: tags falls back to whatever it can find in the page, which is usually the first image and the first paragraph. |
module_seo_markup_cardper store |
summary_large_image |
Which Twitter Card type is asked for: a large image or a summary. A large image is the shipped answer because the reason to share a product link at all is the photograph — a network given summary_large_image for a page with no picture falls back to the small card by itself. Only these two are on offer; see below. |
module_seo_markup_site_nameper store |
empty | The name the tags call this site. Empty falls back to this storefront's own name from Settings, which is what most stores want — it is here for the shop whose legal name and whose brand are not the same string. |
module_seo_markup_handleper store |
empty | The social account the Twitter Card credits, stored and emitted without its @. A whole profile URL may be pasted in and is reduced to the account name; anything that is not a valid account name is refused on the form rather than emitted as a tag naming nobody. |
module_seo_markup_imageper store |
empty | The image a page with none of its own shares — a category with no image, an information page, the home page. Empty shares no image at all rather than an image from somewhere else on the site. |
Markup · Structured data¶
| Key | Default | What it does |
|---|---|---|
module_seo_markup_product_statusper store |
1 |
Whether a product page is described to a search engine as a Product, with its price, currency and availability, so a result can show them. A star rating is claimed only where the product actually has approved reviews and the store has reviews switched on: a rating with nothing behind it is a violation rather than an inaccuracy, so this never invents one. |
module_seo_markup_product_detailsper store |
0 |
Whether the Product block also carries the product's codes and every photograph the page shows. A GTIN is read from the EAN, then the UPC, then the JAN, and only one whose check digit adds up is emitted; the ISBN and the MPN go out where they are well formed. The codes are read from the page on OpenCart 4.1.0.3 and later, and from the product's own row — one query, on the product page only — before that. Read only while product structured data is on. |
module_seo_markup_breadcrumb_statusper store |
1 |
Whether a page carries BreadcrumbList structured data — the trail a search result shows instead of the raw URL. Emitted from the trail the page itself renders, so it cannot disagree with what a shopper sees. |
module_seo_markup_organization_statusper store |
1 |
Whether the home page carries Organization and WebSite structured data — who this shop is, and the profiles it claims as its own. |
module_seo_markup_profilesper store |
empty | The profile URLs the home page's sameAs claims, one per line — the accounts this shop says are its own. A line that is not a URL is dropped when you save rather than emitted, so the box always shows what is actually being claimed. |
module_seo_markup_availabilityper store |
empty | Which of your stock statuses are reported to a search engine as something other than in or out of stock. Empty — and it ships empty — the status this storefront nominates as its in-stock one is reported InStock and every other wording OutOfStock, which is what core reaches for when there is none to sell. A shop that sells ahead of stock can say so here: a status named 2-3 Days or Pre-Order reported as OutOfStock is a claim about the catalogue that is simply false. Which terms are on offer is fixed; see below. |
Markup · Return policy¶
| Key | Default | What it does |
|---|---|---|
module_seo_markup_return_categoryper store |
empty | Which return policy the home page's Organization block states: finite (returns within a number of days), unlimited, or not_permitted. Empty, and it ships empty, states nothing. The policy is stated once for the whole shop and is checked against nothing: it says what you typed here, and only while Organization structured data is on and at least one country is given. |
module_seo_markup_return_daysper store |
30 |
How many days a shopper has to return something, from 1 to 365. Read only for a finite policy; a value outside that range is refused on the form rather than stored. |
module_seo_markup_return_countriesper store |
empty | The countries the policy applies in, as two-letter ISO 3166-1 codes separated by commas, such as NL,BE. Stored upper-cased; anything that does not read as a list of two-letter codes is refused on the form. With none, no policy is stated. |
module_seo_markup_return_feesper store |
free |
Who pays for a return: free or customer. Not stated for a policy that accepts no returns. |
module_seo_markup_return_methodper store |
mail |
How a return reaches the shop: mail, store or kiosk. Not stated for a policy that accepts no returns. |
Markup · Alternates¶
| Key | Default | What it does |
|---|---|---|
module_seo_markup_hreflang_statusper store |
1 |
Whether a page carries hreflang alternates — the set telling a search engine which other languages the same page exists in. A store selling in one language emits none, because one language has no alternates. |
module_seo_markup_default_languageper store |
empty | Which language x-default names — the page a visitor a search engine cannot place is sent to. Empty falls back to this storefront's own default language, which is where core would have sent them anyway, and it ships empty deliberately: a store that adds a language later should not find x-default pinned to whichever language happened to be default the day the module went on. A language this storefront no longer sells in falls back the same way rather than naming a page that is not there. |
Markup · Advanced¶
| Key | Default | What it does |
|---|---|---|
module_seo_markup_diary_verbose_untilinstall-wide |
0 |
When detailed logging stops, as a unix timestamp, and 0 is off. Turning Detailed logging on from this extension's settings form stores the moment two days from now; the writer compares that against the clock every time it is asked for a DEBUG line, so the window closes on its own with no scheduled task and nothing to clean up. While it is open this extension records what it did in far more detail, and the shared diary consequently holds less history. |
Alt text · Scope¶
| Key | Default | What it does |
|---|---|---|
module_seo_alt_text_statusper store |
0 |
Whether this storefront rewrites the alt attribute of a product image at all. Off, the two storefront handlers return before they read anything, so a shop with it off is a shop this extension costs nothing. Per store, because the rewriting happens as a page is rendered: one shop can be showing the descriptions while the other shows what its theme would have shown. |
Alt text · Wording¶
| Key | Default | What it does |
|---|---|---|
module_seo_alt_text_copyinstall-wide |
empty | The pattern a run fills in for each image, one per language, written in the store's own words — {product}, image {position} of {count} until somebody writes their own. A language nobody has written is absent and falls back to the shipped sentence, so what is stored here is only ever wording somebody typed. Install-wide because what it writes is: a description is one row per product, image and language with no store of its own, so one photograph has one description and every storefront shows the same one. |
Alt text · Advanced¶
| Key | Default | What it does |
|---|---|---|
module_seo_alt_text_batchinstall-wide |
25 |
How many products one request of a run goes through before the screen asks again. Products rather than images, because a product is the unit a run resumes at. Install-wide because the one thing it governs is the host this admin is running on: it is a bound on what one request is asked to do, and a shop cannot have a different web server from the shop beside it. |
module_seo_alt_text_diary_verbose_untilinstall-wide |
0 |
When detailed logging stops, as a unix timestamp, and 0 is off. Turning Detailed logging on from this extension's settings form stores the moment two days from now; the writer compares that against the clock every time it is asked for a DEBUG line, so the window closes on its own with no scheduled task and nothing to clean up. While it is open this extension records what it did in far more detail, and the shared diary consequently holds less history. |
Redirects · Scope¶
| Key | Default | What it does |
|---|---|---|
module_seo_redirects_statusper store |
0 |
Whether this storefront answers redirects and records broken URLs at all. Off, the handler returns before it touches the table, so an extension switched off costs a request nothing. Per store, because a rule is per store: one shop can be serving its redirects while the other is not. |
Redirects · Capture¶
| Key | Default | What it does |
|---|---|---|
module_seo_redirects_captureinstall-wide |
0 |
Whether a slug renamed in the admin is captured as a redirect from the old URL to the new one. Off by default, and it is the one setting here that has to be: a store that renames slugs deliberately — reorganising a catalogue over a weekend — would otherwise find a redirect for every one of them, made on its behalf and never asked for. Read once for the whole installation rather than per store, because the one thing it governs is the admin screen where a slug is renamed, and that screen has no store of its own: one rename writes every store's row in one save. |
Redirects · Defaults¶
| Key | Default | What it does |
|---|---|---|
module_seo_redirects_responseper store |
301 |
The response code a new rule for this store starts with, and the one a captured rename is written with. It is a starting value rather than a rule: every row carries its own code and you may change any of them afterwards. A merchant reorganising a catalogue works in 302s for a week and would otherwise re-pick it on every row. The set of codes on offer is fixed — see below. |
Redirects · Advanced¶
| Key | Default | What it does |
|---|---|---|
module_seo_redirects_capinstall-wide |
1000 |
How many rows the log is allowed to hold. When a storefront records a miss past this, the least recently seen rows are pruned to fit. Install-wide because the one thing it governs is one table and one screen over it: the screen shows every shop's broken URLs together, so a per-store cap would be whichever shop took the last request deciding the size of everybody's log. |
module_seo_redirects_diary_verbose_untilinstall-wide |
0 |
When detailed logging stops, as a unix timestamp, and 0 is off. Turning Detailed logging on from this extension's settings form stores the moment two days from now; the writer compares that against the clock every time it is asked for a DEBUG line, so the window closes on its own with no scheduled task and nothing to clean up. While it is open this extension records what it did in far more detail, and the shared diary consequently holds less history. |
XML sitemap · Scope¶
| Key | Default | What it does |
|---|---|---|
module_seo_xml_sitemap_statusinstall-wide |
0 |
Whether the extension writes anything into robots.txt at all, and whether a scheduled run does anything when it wakes. Install-wide because the one thing it governs is one file: an OpenCart multi-store install is several shops over one physical document root, so there is one robots.txt and every shop is served the same bytes of it. |
module_seo_xml_sitemap_cycleinstall-wide |
empty | How often the sitemap regenerates on its own: every hour, day, week or month, or never, in which case it regenerates when you press the button. Install-wide because the one thing it governs is one scheduled run, which covers every shop on the installation in one pass — the cron row itself wakes hourly whatever this says, and this is what that wake-up is measured against. |
XML sitemap · What the sitemap carries¶
| Key | Default | What it does |
|---|---|---|
module_seo_xml_sitemap_include_productper store |
1 |
Whether this shop's sitemap carries its products. On, and all four ship on, because that is what every earlier release published and a sitemap that quietly stopped listing a catalogue is exactly what nobody watches for. Per store, because the files are: there is a sitemap-store2.xml and there has been for as long as there has been a multi-store install. |
module_seo_xml_sitemap_include_imagesper store |
0 |
Whether each product in this shop's sitemap also lists its photographs — the main image first, then the additional ones in the order the product page shows them — as Google's image sitemap extension describes. Only files that are actually in the image directory are listed, and each as the original file rather than a resized copy, which may not have been made yet. It does nothing while products are left out of the sitemap, and the screen greys it then. Off, and the files are the same bytes they were before this setting existed. |
module_seo_xml_sitemap_include_categoryper store |
1 |
Whether this shop's sitemap carries its categories. |
module_seo_xml_sitemap_include_manufacturerper store |
1 |
Whether this shop's sitemap carries its manufacturers. |
module_seo_xml_sitemap_include_informationper store |
1 |
Whether this shop's sitemap carries its information pages — the delivery, privacy and about pages a shop writes once. Off is how a shop that would rather a crawler spent its time on the catalogue says so. |
XML sitemap · Crawl rules¶
| Key | Default | What it does |
|---|---|---|
seo_xml_sitemap_rulesinstall-wide |
empty | The crawl rules written into robots.txt, verbatim, inside a block this extension manages and between two markers it puts there. Anything outside that block is left exactly as it is, including rules somebody else wrote. Install-wide because there is one robots.txt for the whole document root, and a per-shop answer would be one shop's rules overwriting another's every time a run finished. It survives an update under a code of this extension's own, which no uninstall deletes. |
XML sitemap · Advanced¶
| Key | Default | What it does |
|---|---|---|
module_seo_xml_sitemap_prefixinstall-wide |
sitemap |
What every published file's name begins with — sitemap-store2.xml, sitemap-store0-lang1-1.xml and the rest. Install-wide because there is one web root and one set of files in it. It is here so that a name a search console already points at can stay what it is: changing it republishes under new names and removes the old ones, and a submission naming one of those stops resolving. |
module_seo_xml_sitemap_indexinstall-wide |
sitemap.xml |
What the default store's index is called — the document at the top, listing the files rather than the URLs, and the one a crawler looks for without being told. It is named on its own rather than following the prefix because it is the name a store owner has most likely already submitted somewhere, and every earlier release of this extension wrote a Sitemap: line pointing at it. |
module_seo_xml_sitemap_diary_verbose_untilinstall-wide |
0 |
When detailed logging stops, as a unix timestamp, and 0 is off. Turning Detailed logging on from this extension's settings form stores the moment two days from now; the writer compares that against the clock every time it is asked for a DEBUG line, so the window closes on its own with no scheduled task and nothing to clean up. While it is open this extension records what it did in far more detail, and the shared diary consequently holds less history. |
What you cannot change, and why¶
These are fixed on purpose. Each one is a decision with a reason beside it rather than a setting nobody got round to adding.
URLs & meta · Scope¶
Which shops and which languages a run covers, and whether it fills in blanks or overwrites what is there, are chosen per press of the button and never saved. They are the scope of one run rather than a setting: a store owner who generated for German last week is not saying that this week's run is German too. The confirmation that turns filling in blanks into overwriting a catalogue is a field of its own rather than a second button posting the same form, because the difference between the two is the difference between filling in blanks and overwriting a catalogue — and the request that overwrites has to be one nothing but a deliberate answer to the question can produce.
URLs & meta · Templates¶
The meta description ships empty and generates nothing, and no default is invented for it. A description is the sentence a shopper reads in a search result before deciding whether to click, and no default this extension could invent out of a product's name would be worth reading — so the store owner writes one, or gets nothing rather than something they would not have chosen. An empty meta template is allowed where an empty keyword template is not, and the two are different on purpose: a page with no meta description is a page a search engine writes its own snippet for, which is a choice a store owner is entitled to make, while a page with no URL keyword is a page reachable only through index.php?route=.
How much of a meta title and description a search result shows is fixed, and going over it is not an error and is not corrected. They are approximate — what is displayed depends on the pixel width of the words rather than on a count — but they are the numbers every SEO tool states, and a store owner comparing this screen against one of those should not find two different answers. An over-length value is written whole and counted rather than cut off, because a description stopped at 160 characters ends mid-word and a store owner who wanted it shorter would rather shorten the template.
| Rule | Value |
|---|---|
| Meta title, in characters | 60 |
| Meta description, in characters | 160 |
What separates the words of a generated keyword, and what separates the steps of a nested one, are both fixed. A hyphen is what every URL on the web that a person is meant to read uses; the slash is OpenCart's own, and its storefront resolves one segment at a time against it, so a keyword spelled another way would be a keyword its own shop could not find. Changing either after a run would rewrite every URL on the store, which is a migration rather than a setting — and this is not it.
| Rule | Value |
|---|---|
| Between words | - |
| Between steps of a nested one | / |
URLs & meta · Advanced¶
There is a ceiling over how many entities one request may be asked to write for, and it is a ceiling rather than trust: the number reaches a LIMIT and a loop, so a run configured at a million is a run back to timing out halfway through, which is the thing batching exists to stop. Generous enough that a host which can take it is not held back, low enough that no host is asked for more than it has.
| Rule | Value |
|---|---|
| Most entities one request may write for | 5000 |
Markup · Social sharing¶
Twitter's player and app cards are not offered, and the summary and large-image cards are the whole set. One needs a video player and the other an app store id, and a store has neither to give — a card type asked for with nothing behind it renders no card at all, which is worse than the card a scraper would have built for itself.
Markup · Overrides¶
A per-page override may be written for the five pages this extension's markup itself speaks for, and deliberately not one more: a page it emits nothing on is a page it has no slot on to emit an override into either. What may be overridden on those pages is likewise fixed — the canonical URL, the title, the description and four crawler directives — rather than being a free-text box, because a box that took arbitrary markup would be a box that could put anything in your <head>.
Markup · Structured data¶
The schema.org terms a stock status may be reported as are a fixed list rather than a box you type into. They are the vocabulary a crawler understands, so a term outside it is markup nothing reads and a typo is markup nothing reads that looks as though it works. The terms on offer are listed on the settings screen beside each of your stock statuses.
No shippingDetails is emitted, ever. OpenCart prices shipping per address and per cart, so a rate typed into a settings screen is a price the checkout can contradict — which is exactly the disagreement reading every price off the page exists to prevent. For the same reason no item condition is claimed: OpenCart records none, and a condition typed once for a whole catalogue is a claim about products nobody looked at.
Markup · Return policy¶
The return policy is stated once, on the home page's Organization, which is the nesting Google recommends for a policy that covers the whole shop. It is not repeated on every offer, because one store-wide statement cannot disagree with itself and a copy on every product page can go stale one page at a time.
Markup · Overrides¶
How many override rows one import may carry, and how many the screen lists before the CSV is the better way to read them. A file larger than the ceiling is a store owner who has generated it, and a generated override file is a rule rather than a correction — which is the other half of this extension and not this table. Both are bounds on what one request is asked to do on the host it is running on, which is not something a store owner has any way to judge.
| Rule | Value |
|---|---|
| Rows per import | 2000 |
| Overrides on screen | 100 |
Alt text · Generation¶
Words somebody typed are never overwritten, and there is no setting that would. A store owner who described their best-selling product by hand and then pressed Generate must find their sentence exactly where they left it: a run that improved on it would teach them never to press the button again, and there is no undo for ten thousand rows. So a stored description is read before anything is rendered, and a non-empty one ends that image there, counted as kept.
A pattern that renders to nothing writes nothing, rather than writing alt="". An alt="" is not the absence of a description — it tells a screen reader the image is decoration and to skip it — so it is worse than the product name the theme would otherwise have used. The image is counted as blank and left for the store owner to read on the run's summary.
| Rule | Value |
|---|---|
| Longest description a row holds, in characters | 255 |
Alt text · Wording¶
Which placeholders a pattern may use is fixed: the product's name, its model, its manufacturer, and the position and count of the image within the product's own gallery. They are listed on the settings screen beside the box. Describing an image by its category, its price or a custom attribute is a feature rather than a setting — every one of them is a second question about where the value comes from and what happens when it is empty — and a pattern naming a placeholder this extension does not have is refused on the form rather than rendered as itself across a catalogue.
Alt text · Where the text appears¶
Which template files are rewritten, and the markup this extension looks for inside them, are fixed: the product card and the product page gallery, each found by the alt attribute the shipped theme puts there. A theme whose markup differs is left alone rather than guessed at, and a gallery that will not line up emits nothing at all rather than half of it — a description attached to the wrong photograph is worse than none. There is no setting for either, because the honest control is a template override rather than a box on this screen that takes a regular expression somebody typed.
Redirects · Rules¶
A rule is one row for one exact path, and there are no wildcards and no regular expressions. The largest single thing this extension is asked for, and it is a different feature rather than a setting: a pattern language needs a precedence rule for two patterns that both match, a way to preview what a pattern would catch before it catches it, and an answer for the loop a pattern can make with itself. A box on this screen that took a regular expression would turn a support conversation about a URL into a support conversation about a pattern somebody typed.
| Rule | Value |
|---|---|
| Longest path a rule may be written for | 255 |
| Longest target a rule may point at | 255 |
What counts as a broken URL is core's own answer and not a nicer one: a request carrying a path, at least one segment of which OpenCart's own keyword lookup would not match, on a store with SEO URLs switched on. There is nothing to record on a store that has them off, because core never looks a keyword up there and every URL in the shop would be logged as broken. The rule has to be core's because a segment this disagreed about would be either a miss nobody logged or, worse, a working URL logged as broken.
XML sitemap · What the sitemap carries¶
A sitemap is split automatically when it reaches either of the protocol's limits, and neither is a setting. Both numbers are the sitemap protocol's, not ours: a file may hold 50,000 URLs and may be 50MB uncompressed, and a crawler handed one that breaches either rejects the file rather than the entries past the limit. A store owner whose catalogue grew past 50,000 products would find out from their search console, months later, that the sitemap they were paying for had stopped being read — which is exactly the kind of thing nobody watches for, and the reason splitting is automatic rather than a setting. Two ceilings rather than one because they are reached by different stores: the URL count is what a large catalogue hits, and the byte count is what a store with long keywords and deep category paths hits first.
| Rule | Value |
|---|---|
| URLs per file | 50000 |
| Bytes per file | 52428800 |
A listed photograph carries where it is and nothing else: <image:loc>, and no caption, title, geographic location or licence. Google deprecated all four and reads none of them, so a setting for any would be a field a store owner fills in for nobody. Only products list photographs; a category or manufacturer image is a thumbnail beside a list, not something a crawler looks for. One URL lists at most a thousand, which is Google's limit, and a product with more has the first thousand listed.
| Rule | Value |
|---|---|
| Images per URL | 1000 |
Every URL carries where it is and when it last changed, and nothing else. There is no changefreq and no priority, and there will not be: both are hints the major crawlers have said outright they ignore, so a setting for either would be a control that changes a document nobody reads differently. What does get read is lastmod, and it is written from the store's own dates rather than from the moment the file was generated — a sitemap claiming every page changed today is a sitemap a crawler learns to distrust.
XML sitemap · Scope¶
How much of a run one scheduled wake-up does before it stops and leaves the rest for the next one is fixed. The screen can drive a run to the end because there is a browser posting again as soon as each batch comes back, and somebody watching it; a scheduled tick has neither, and whatever execution limit the host imposes applies to it like any other request. A run that is going to be interrupted is better interrupted on purpose, at a position it stored. Twenty seconds because the floor most shared hosts impose is thirty, and the tick has to store its position and rename a file afterwards — a budget equal to the limit is a budget that never gets to write down where it got to. A wrong value here is not a slower sitemap; it is no sitemap at all.
| Rule | Value |
|---|---|
| Seconds per wake-up | 20 |
| Batches per wake-up | 40 |
How long a run holds the web root before another driver may take it over is fixed. It is a lease rather than a flag, which is why it is a moment rather than a 1: somebody who presses Generate and closes the tab, or a process the host killed, would otherwise leave a lock nobody can clear and a sitemap that never regenerates again. Five minutes rather than one because the gap between two batches is however long the driver takes to come back, which for the screen is a round trip over whatever connection the store owner has — reclaiming a run that was merely being driven slowly would put a second writer on a file the first is still appending to.
| Rule | Value |
|---|---|
| Seconds before a stamp is stale | 300 |
XML sitemap · Advanced¶
The files are written into the web root and delivered as files, and robots.txt is how a crawler is told where they are. Serving them from a route instead is a feature rather than a setting, and it is not one this extension has: core's own rewrite configuration exempts robots.txt by name and rewrites only paths that are not real files, so a file on disk is answered by the web server and OpenCart never sees the request. What a store owner can set is the names; where they go, they cannot. When the directory is missing, unwritable, or holds a file this extension may not overwrite, the screen says which of the three it is rather than reporting that generation failed.