Clone a StoreConnect theme — and every one of its children — in seconds.
Duplicating a theme through the API copies rows one at a time and takes eight
or nine minutes. This does it inside the org: the new theme record is inserted
synchronously and its Id comes back immediately, so you can open
?theme-preview=<id> right away while the children copy behind you in a
chained Queueable.
Built for spinning up a per-ticket preview theme instead of full-syncing a new one, but it is a general-purpose theme clone.
StoreConnect Labs — shared as-is, outside the supported product.
- Requirements
- Install
- After installing
- Using it
- How it works
- What gets copied
- Limitations
- Working on it
- StoreConnect managed package v21.0.0 or later. The package declares a
hard dependency on
04tRE000002mEXNYA2(v21.0.0), so it will not install into an org without StoreConnect, and building it against v21 is what guarantees it uses no field newer than v21. - Every custom reference is
s_c__namespaced; the only non-namespaced field touched is the standardName.
An unlocked package, so it installs by link and upgrades in place.
0.1.0-1 — 04tRE0000032LWTYA2, built against StoreConnect 21.0.0, 94% Apex
coverage.
https://login.salesforce.com/packaging/installPackage.apexp?p0=04tRE0000032LWTYA2
Or:
sf package install --package 04tRE0000032LWTYA2 --target-org my-org --wait 20Released, so it installs into production orgs as well as sandboxes and scratch orgs. Unlocked packages upgrade in place, so a later version installs over this one without uninstalling first.
The source deploys directly if you would rather not install anything:
sf project deploy start \
--manifest manifest/package.xml \
--target-org my-org \
--test-level RunSpecifiedTests \
--tests ThemeQuickCloneTest --tests ThemeQuickCloneControllerTestUse RunSpecifiedTests, never RunLocalTests — the latter runs every org-side
test outside this project and fails on coverage that has nothing to do with it.
Assign the Theme Quick Clone permission set, which grants the Apex class and Visualforce page access the entry points need:
sf org assign permset --name Theme_Quick_Clone --target-org my-orgIt deliberately grants no object permissions. Whoever clones a theme already
needs StoreConnect's own access to s_c__Theme__c and its children; this
package does not try to hand that out.
Three entry points, same engine.
Quick Clone Theme takes a source theme Id and a name, and returns the new theme Id.
| Variable | Required | Notes |
|---|---|---|
Source Theme Id |
yes | the s_c__Theme__c to copy |
New Theme Name |
yes | max 69 chars, so the (building) marker fits in Name |
// Name it yourself
Id newThemeId = ThemeQuickClone.cloneTheme(sourceThemeId, 'Support v1 - IT-1346 (HT)');
// Or take "<source name> copy"
Id newThemeId = ThemeQuickClone.cloneTheme(sourceThemeId);cloneTheme returns as soon as the parent is inserted. The children are still
copying at that point.
ThemeQuickCloneController backs a Quick Clone button that clones every
selected theme as <name> copy. The button itself cannot ship in the package —
see unpackaged/README.md for why, and for the two
minutes of clicking that creates it.
cloneTheme() inserts the new s_c__Theme__c synchronously and returns. A
chained Queueable then copies the children in heap-bounded chunks, one phase per
async transaction:
VARIABLES -> ASSETS -> LOCALES -> TRANSLATIONS -> TEMPLATES -> FINALIZE
Templates carry the large Content (up to 131 KB) so they copy 25 at a time;
everything else is tiny and copies 200 at a time. Each chunk runs in a fresh
12 MB heap, so the job scales as the theme grows rather than hitting a wall.
The new theme is named <your name> (building) while children copy. The suffix
is removed when the copy finishes. That is the completion signal — it needs no
extra field, and it is visible in any list view.
If a phase throws, the marker becomes (FAILED) instead and the exception is
swallowed rather than rethrown, so the marker survives the transaction. Check
the debug log for the phase that failed.
Per child record: every createable field except unique, external-id, and lookup fields.
That deliberately drops s_c__sC_Id__c and the s_c__Unique_Theme_*__c keys —
the managed package regenerates those from the new parent on insert — and drops
lookups, because the parent FK is set explicitly to the new record. The serve
path keys off (theme id + key), never the unique key.
The field list comes from a runtime describe, so custom fields you have added to those objects are copied too, and new managed fields are picked up without a code change.
Children copied: theme variables, theme assets, theme locales, each locale's translations, and theme templates.
- Runs
without sharingso an admin clone copies every child regardless of record sharing. That is deliberate; it is dev tooling. - No progress bar. The
(building)suffix is the whole status API. - Not idempotent. Running it twice gives you two clones.
- The button is manual — see above.
Requires a Dev Hub.
# One-off: create the package in your Dev Hub (writes the alias into sfdx-project.json)
sf package create \
--name "Theme Quick Clone" \
--package-type Unlocked \
--path force-app \
--target-dev-hub my-hub
# Build a version. This spins up a scratch org, installs StoreConnect v21 from
# the declared dependency, compiles, and runs the Apex tests.
sf package version create \
--package "Theme Quick Clone" \
--installation-key-bypass \
--code-coverage \
--wait 30 \
--target-dev-hub my-hub
# Ship it. Promotion requires >=75% coverage.
sf package version promote --package "Theme Quick Clone@0.1.0-1" --target-dev-hub my-hubBump the floor by pointing the dependencies entry in sfdx-project.json at a
newer StoreConnect 04t and rebuilding. If the Apex uses a field that did not
exist in the pinned version, the build fails — which is the point.