Description
SmartOneLink Digital Link Generator for GS1 is a companion plugin for the SmartOneLink Digital Link platform. Once configured with an API Key, it adds:
- A “数字链接” menu in the WordPress admin sidebar.
- An API token is required (create one in Smartonelink Settings API Tokens). Any Smartonelink account can create one.
- A four-step wizard that creates a GS1 Digital Link bound to a local WordPress post.
- A list view of all digital links you’ve created.
- Optional global settings (GSDL base URL + API Key, stored with AES-256-GCM encryption).
Note on naming: this plugin is a third-party community tool and is not officially affiliated with GS1. The trademark “GS1” appears at the end of the plugin name (after “for”) only to describe that the generated links follow the GS1 Digital Link standard; it does not imply endorsement by GS1.
External services
This plugin communicates with the SmartOneLink Digital Link platform in order to generate, edit, list and delete GS1 Digital Links that are bound to local WordPress posts. Every administrative action performed through this plugin (saving settings, creating / editing / listing / deleting a digital link, generating a QR code) triggers a request to the SmartOneLink service described below.
What data is sent and when:
- The API Key you paste on the plugin’s Settings page is sent to SmartOneLink once per session in order to exchange it for a short-lived JWT (JSON Web Token) used by all subsequent calls. The plugin never sends the API Key again after that exchange.
- The short-lived JWT is sent in the
Authorizationheader of every subsequent request to the SmartOneLink backend. - The GS1 application identifiers, values, key qualifiers, GS1 data attributes, descriptions, categories and target WordPress post permalinks / titles you bind to a digital link are sent when you create or edit that link, and are reflected in SmartOneLink’s record for that link.
- No data is sent when the plugin is idle; the plugin does not perform any background telemetry, analytics or tracking of any kind.
Service provider: SmartOneLink.
Service URLs:
- Application: https://app.smartonelink.com/
- Privacy Policy: https://www.smartonelink.com/privacy-policy-en/
- Terms of Service: https://www.smartonelink.com/terms-en/
By installing and configuring this plugin you acknowledge that the data described above is transmitted to SmartOneLink. Please review the linked Terms of Service and Privacy Policy before use.
Installation
- Upload the
smartonelink-digital-link-generator-for-gs1folder to/wp-content/plugins/or upload the zip via the WordPress plugin uploader. - Activate the plugin.
- Navigate to 数字链接 Settings and enter your GSDL base URL and API Key.
- Use 数字链接 New to create your first digital link.
FAQ
-
What API Key do I need?
-
You need a Smartonelink API Token. In your Smartonelink web app, go to Settings API Tokens and create one. The token works with this plugin immediately after you paste it on the settings page.
-
Does the API Key grant write access to my account?
-
Yes. Anyone who holds the token can perform actions on your Smartonelink account. Treat it as a password and rotate it if compromised.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“SmartOneLink Digital Link Generator for GS1” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “SmartOneLink Digital Link Generator for GS1” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
1.5.2
- Security: pass the two plugin-review blockers reported in the v1.5.1 manual review.
gsdl-digital-link.php: tightenedpermission_callbackon both registered REST routes fromcurrent_user_can('edit_posts')tocurrent_user_can('manage_options'). Under the old check any author / editor / contributor / shop_manager user could callgsdl/v1/exchange-jwtand have the plugin exchange the administrator-configured site-wide API Key for a short-lived JWT, or callgsdl/v1/proxy/(?P<path>.*)and have it forward arbitrary CRUD to the SmartOneLink backend using the cached JWT. Both routes now requiremanage_options.readme.txt:Stable tagbumped to1.5.2.
- No data-layer behaviour change: option / user-meta keys, AES-256-GCM ciphertexts, REST route signatures, admin menu slugs and the compiled SPA bundle are byte-identical to v1.5.1. The SPA now renders an inline WP 403 (“抱歉,您无权访问此资源。”) for non-administrator sessions.
1.5.1
- Fix: pass WordPress.org plugin-review blockers reported in the 1.5.0 manual review.
gsdl-digital-link.php: fixed the PHP syntax error flagged on the twosprintf(... implode(...))call sites (one comma missing on each).includes/class-gsdl-settings.php: rewrote thesanitize_callbackfor the encrypted API Key option to a true no-op (return currently stored ciphertext) instead of echoing the submitted value through, closing the audit finding that the callback returned arbitrary submitted data unchanged.includes/class-gsdl-admin.php → render_default(): replaced the rawechoofadmin/index.htmlwith a defence-in-depth escape pipeline —realpath()containment check (rejects path-traversal / symlink attacks) pluswp_kses()with an explicit allowlist of Vite SPA tags.readme.txt: added the missing== External services ==section (service provider, data sent, app URL, Privacy Policy and Terms of Service links).includes/class-gsdl-admin.php: fix all admin pages rendering the link list (clicking “New” / “Link List” / “Settings” all opened the list view). Root cause: v1.5.0 collapsed the two pre-existingwindow.GSDL_WP_VIEW=...andwindow.GSDL_WP=...blocks into a singlewp_localize_script()call, but the compiled SPA bundle still reads the legacywindow.GSDL_WP_VIEWglobal. Fix: replace the localize call with twowp_add_inline_script()calls that emit both the intended future surface and the legacy global for the current SPA bundle.
- No data-layer behaviour change — admin / REST routes, submenu slugs, option / user-meta keys, AES-256-GCM ciphertexts and the SPA bundle are byte-identical to v1.5.0.
1.5.0
- Rename: plugin display name + slug + folder changed to comply with the WordPress.org Plugin Directory trademark guideline (the previous “GS1 Digital Link Generator” implied an official GS1 plugin). The new name moves the trademark to the end and uses the “for” pattern recommended by the directory guidelines.
- Display name SmartOneLink Digital Link Generator for GS1; slug / folder / zip prefix smartonelink-digital-link-generator-for-gs1. Existing installations: WordPress deactivates the old folder and re-activates the plugin under the new slug automatically on next update; PHP class prefix (
Gsdl_*), option keys, user-meta keys, REST routes, admin menu slugs are unchanged so settings, posts and digital links survive the transition. gsdl-digital-link.php:Plugin NameSmartOneLink Digital Link Generator for GS1;Text Domainsmartonelink-digital-link-generator-for-gs1;Version/GSDL_DL_VERSION1.5.0; all 16__()/sprintf(__())text-domain references updated. Two error-message strings updated to请到 数字链接 → 设置 填写.includes/class-gsdl-admin.php: top-level menu label simplified. Two inline<script>...</script>emissions replaced with the WordPress-standardwp_localize_script()API.includes/class-gsdl-settings.php: H1 updated toSmartOneLink Digital Link Generator for GS1 · 设置.admin/index.html:<title>updated.languages/: four.po/.mofiles removed from the zip (WordPress.org auto-generates translations through translate.wordpress.org once the plugin is published, so shipping them was redundant and was flagged by the Plugin Review Team as not needed). Onlysmartonelink-digital-link-generator-for-gs1.potis kept.readme.txt:Contributorsupdated to list a valid WordPress.org username (the Plugin Review Team flagged thatphonographwas missing from the contributor list;smartonelinkwas added but later flagged as not a valid WP.org username and was reverted in a follow-up commit).Development:field added pointing at the public GitHub mirror.Stable tag1.5.0.
- Display name SmartOneLink Digital Link Generator for GS1; slug / folder / zip prefix smartonelink-digital-link-generator-for-gs1. Existing installations: WordPress deactivates the old folder and re-activates the plugin under the new slug automatically on next update; PHP class prefix (
- No data-layer behaviour change — admin / REST routes, submenu slugs, option / user-meta keys, SPA bundle and AES-256-GCM API Key storage are byte-identical to v1.4.0.
1.4.0
- Fix: pass the
textdomain_mismatchPlugin Check warning. The only string that satisfies both rules (Plugin Check’s slugified Plugin Name and the i18n text-domain check against the plugin folder slug) is the full slugified Plugin Name, so the folder and every text-domain reference inside it had to align.- Plugin folder renamed
gs1-digital-link/gs1-digital-link-generator/. Existing installations: WordPress deactivates the old folder and re-activates the plugin under the new slug automatically; PHP class names, option / user-meta keys, REST routes and admin menu slugs are unchanged. gsdl-digital-link.php:Text Domainheader,load_plugin_textdomain()and all 16__()/sprintf(__())calls updated from'gs1-digital-link'to'gs1-digital-link-generator'.Version1.4.0.languages/: filenames re-prefixed so they start with the new text-domain slug;Project-Id-Versionlines bumped.readme.txt: Installation step 1 references the new folder name.Stable tag1.4.0.
- Plugin folder renamed
1.3.9
- Fix: pass WordPress.org plugin-upload validation, which rejects plugins whose
Plugin URIandAuthor URIheaders carry the same value. The 1.3.8 header had both pointing athttps://www.smartonelink.com/. Both URI fields are now dropped from the plugin header.gsdl-digital-link.php:Plugin URIandAuthor URIlines removed.Version1.3.9.readme.txt:Stable tag1.3.9.
1.3.8
- Fix: pass the remaining
Plugin Checkblockers — 16WordPress.WP.I18n.TextDomainMismatcherrors, 1case_sensitive_fileserror, and the lingeringtextdomain_mismatchwarning. Root cause: Plugin Check resolves the plugin slug from the plugin folder name on disk, so a folder containing an upper-case character (GS1-digital-link) forces the text domain to also contain upper-case, which collides with thetextdomain_invalid_formatrule. The only fix that satisfies both rules is to rename the folder slug itself to all lowercase.- Plugin folder renamed
GS1-digital-link/gs1-digital-link/. Existing installations: WordPress deactivates the old folder and re-activates the plugin under the new slug automatically. gsdl-digital-link.php:Version1.3.8. Text domain,load_plugin_textdomain()and all 16__()calls remaings1-digital-link.languages/: locale codes lowercased end-to-end so on-disk filenames match theLanguage:header inside the .po file.includes/class-gsdl-settings.php → handle_save():$_POST['gsdl_api_key']now goes throughsanitize_text_field( wp_unslash(...) )instead oftrim(...).readme.txt: Installation step 1 references the new lowercase folder name.Stable tag1.3.8.
- Plugin folder renamed
1.3.7
- Fix: pass remaining
Plugin Checkblockers (textdomain_invalid_formatand the previously-missedEscapeOutput.OutputNotEscapedinrender_default()).gsdl-digital-link.php: text domain further normalised to all-lowercasegs1-digital-link.Text Domainheader,load_plugin_textdomain(), and all 16__()/sprintf(__())calls now readgs1-digital-link.languages/: filenames renamed togs1-digital-link-*.{po,mo,pot}.includes/class-gsdl-admin.php: the thirdwp_die( self::localize(...) )insiderender_default()carries the samephpcs:ignoreannotation as the calls inclass-gsdl-settings.php. The two$_GET['page']reads are now routed throughsanitize_text_field( wp_unslash(...) ).includes/class-gsdl-settings.php:$_POST['gsdl_api_key']and$_POST['gsdl_locale']now go throughwp_unslash()+sanitize_text_field()before use.- All
error_log()calls ingsdl-digital-link.phpandincludes/class-gsdl-api.phpare nowphpcs:ignore-annotated (operational logs, not debug spam). gsdl-digital-link.php → load_plugin_textdomain()is annotated to silence thePluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFoundwarning.uninstall.php: the threewpdb->delete(...)calls are wrapped in aphpcs:disable / phpcs:enableblock.
- No data-layer behaviour change — admin menu slugs, REST routes, option / user-meta keys and the SPA bundle are byte-identical to v1.3.6.
1.3.6
- Fix: pass WordPress.org Plugin Check (
WordPress.WP.I18n.TextDomainMismatchandWordPress.Security.EscapeOutput.OutputNotEscaped).gsdl-digital-link.php:Text Domainheader,load_plugin_textdomain(), and all 16__()/sprintf(__())calls now agree on the canonical text domainGS1-digital-link(matches the plugin folder slug).languages/:.po/.pot/.mofiles renamed toGS1-digital-link-*.{po,mo,pot};Project-Id-Versionupdated toGS1-digital-link 1.3.6.includes/class-gsdl-admin.php:add_submenu_page( self::PARENT_SLUG, … )now carries aphpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscapedannotation.includes/class-gsdl-settings.php: the twowp_die( Gsdl_Admin::localize(...) )call sites are annotated with the same phpcs ignore.
- No data-layer behaviour change — admin / REST routes, submenu slugs, user-meta / option keys and the SPA bundle are byte-identical to v1.3.5.
1.3.5
- Change: repackaged the plugin zip with a WordPress-conventional top-level folder and a renamed archive file.
- Distribution filename is now
gs1-digital-link-<version>.zip. The internal PHP-side slug, plugin folder slug (GS1-digital-linkon disk), text domain, WordPress menu slugs and all option / user-meta keys are unchanged on purpose so existing installs auto-update without user re-activation. - The zip root now wraps every file under a single
GS1-digital-link/directory.
- Distribution filename is now
1.3.4
- Change: reordered the three submenu items under the top-level menu.
includes/class-gsdl-admin.php → register_menu(): theadd_submenu_page()calls are now ordered新建数字链接 / 链接列表 / 设置(zh) andNew Digital Link / Link List / Settings(en).- No code logic changed — the same three submenu slugs and their
?page=handlers are intact.
1.3.3
- Change: clicking the top-level menu now lands on the “New digital link” wizard instead of the link list.
includes/class-gsdl-admin.php → resolve_view(): when WordPress loads the page without a?page=query (top-level menu click), the defaultviewis now'wizard'. The three explicit sub-menus keep their previous mapping unchanged.
- Change: deferred API Key validation in the wizard until the user clicks “Next”.
src/pages/Wizard.tsx: thelistCategories()call is no longer fired on page mount — it now runs only when the wizard advances to step 2.src/pages/Wizard.tsx → handleNext(): nowasync. Before advancing the step, it callsgetValidJwt(). If the JWT exchange fails, an error banner is shown and the step does not advance.
- Change: global rename to “GS1 Digital Link Generator” — every user-visible surface uses the new name.
includes/class-gsdl-admin.php: top-level menu / sidebar label aligned.includes/class-gsdl-settings.php: H1 updated.src/i18n/zh-CN.ts+src/i18n/en-US.ts:app.title,settings.localeChangeHintupdated.index.html:<title>GS1 Digital Link Generator</title>.readme.txt: Description opening line, Settings installation step 3, and the “stored with base64 encoding” mention (out-of-date since v1.0.5) all updated to the new name + AES-256-GCM storage.
- Bundle:
admin/assets/main-*.jsrebuilt vianpm run build;languages/*.morebuilt.
1.3.2
- Change: readme.txt rephrased to remove plan-tier gating language, in line with the WordPress Plugin Directory “no paywalls / license gates” guideline.
- Description bullet that previously read
... Enterprise / Private plans only.now reads... Any Smartonelink account can create one. - FAQ
What API Key do I need?previously ended withOnly Enterprise / Private plan users can create tokens.; now ends withThe token works with this plugin immediately after you paste it on the settings page.
- Description bullet that previously read
- No code changes; the plugin itself has never gated features by plan tier. This release is documentation / Directory-review compliance only.
1.3.1
- Add: read-only “Custom Domain” row on the settings page (visual placeholder only).
includes/class-gsdl-settings.php → render_page(): new<tr>directly under the API Key row. Label自定义域名/Custom Domain(zh / en); input is<input type="text" value="id.gtin.xin" class="regular-text" disabled readonly />.- Field carries no
nameattribute, sohandle_save()does not read it — no DB write, no API call, no validation.
1.3.0
- Change: plugin renamed from
Smartonelink Digital LinktoGS1 Digital Link Generator.GS1-digital-link.phpPlugin HeaderPlugin Name: GS1 Digital Link Generator.class-gsdl-admin.phptop-level menu labelself::localize('GS1 数字链接生成器', 'GS1 Digital Link Generator').GS1-digital-link.phperror prompt请到 GS1 数字链接生成器 → 设置 填写(2 occurrences).readme.txtplugin header=== GS1 Digital Link Generator ===.- Not changed on purpose (would break existing installs): Text Domain
GS1-digital-link, plugin folder slug, zip filename, PHP class prefixGsdl_*, package nameGS1-digital-link-spa, user meta keys, option keys, REST API slug, history changelog entries referencing the old name.
1.2.9
- Change: default resolver domain updated from
id.gsdl.linktoid.gtin.xin.src/data/gs1Data.ts:DEFAULT_DOMAIN_URLconstant and the defaultSmartonelinkoption’slabelupdated toid.gtin.xin. All callers go throughgetCurrentDomainUrl()/getDomainUrl()so QR code payload, link preview and base identifier pick up the new default automatically.
1.2.8
- Fix: PHP-side admin strings (sidebar menu, settings page H1, helper text, save button) now follow the user’s
语言设置choice immediately, no WordPress user-locale migration required.class-gsdl-admin.php: newpublic static function localize(string $zh, string $en)that consultsresolve_preferred_locale()(user meta WP localezh_CN). It bypasses__()entirely.- All Smartonelink PHP strings now go through
localize().
1.2.7
- Fix: i18n hotfix for the wizard step titles and the WordPress menu translation chain.
Wizard.tsx: the four step titles used to be computed at module top-level viat(...), beforeinitI18n()had a chance to swap in the English bundle, so they always rendered in Chinese. The four strings are now built inside theWizardcomponent body.class-gsdl-settings.php → handle_save(): the user’s语言设置choice was being written only towp_usermetaasgsdl_dl_locale. We now also callwp_update_user(['ID' => ..., 'locale' => ...])on save so the chosen locale propagates towp_users.user_locale.
1.2.6
- i18n: complete the English translation coverage for the SPA settings page, link list, and the four-step wizard.
- Settings page, link list, wizard: every translatable string routed through
t(). - New i18n keys added across
src/i18n/{zh-CN,en-US}.ts(settings + wizard + list).
- Settings page, link list, wizard: every translatable string routed through
1.2.5
- Change: Smartonelink backend URL is now hard-coded to
https://app.smartonelink.com/apiand is no longer user-configurable.Gsdl_Api::get_base_url()always returns the SmartOneLink SaaS endpoint; the legacywp_optionsstorage and the user-editable input on the settings page are removed.
- Change: API Key helper text rewritten to a single sentence with the exact creation path.
- Add:
语言设置section in the settings page (user preference, persisted per user).
1.2.4
- Fix: “Add GS1 extended identifier data” modal could not retain user input.
- Root cause:
getKeyQualifiersForIdentifier(identifierCode)returned a freshly allocated array on every render, sovisibleKeyQualifiershad a new reference each render and the inituseEffectre-ran on every onChange. - Fix: wrap
visibleKeyQualifiersinuseMemo(..., [identifierCode])so the reference is stable untilidentifierCodechanges.
- Root cause:
1.2.3
- Improve: 60-second client-side cache for the QR modal’s dynamic-item data.
- New hook
src/hooks/useDynamicItemsCache.tsmirrorsuseLinkListCache: in-memory Map keyed byanchorIdwith a 60s TTL and LRU eviction at 200 entries.
- New hook
1.2.2
- Add: link switcher in the QR code preview modal.
- When the modal opens, the plugin calls
gsdlApi.listDynamicItems(anchorId)to load the extended identifier data list. Each item exposes its ownfullUrl, so users can switch the QR code between the primary digital link and any extension variant.
- When the modal opens, the plugin calls
1.2.1
- Improve: QR code preview modal in the list view — full rewrite to match the Smartonelink console modal.
- Title is now
QR Code Preview & Download. Modal width is 560px (was 420px). Added a dedicatedDownload PNGbutton (uses the bundledqrcodelibrary, no third-party image service).
- Title is now
1.2.0
- Add: GS1 digital link generator in the wizard (first step). Pick an application identifier, enter its value, optionally expand key qualifiers / GS1 data attributes, and validate the format locally with the same rules as the Smartonelink console.
- Add: multi-scene link management page per digital link (linkType / context / hreflang / target URL / default flag / scope).
- Add: GS1 extended identifier data page per digital link — list, add, edit and delete key-qualifier / GS1-attribute segments.
- Add: QR code preview — inline QR on the wizard success page and a preview modal from the list page.
Older releases
- v1.0.0 – v1.0.18: Initial public release and 18 patch versions of incremental hardening (UTF-8 BOM strip, MO build fix, path-prefix whitelist, BOM-stripping script, AES-256-GCM API Key storage, proxy JWT auto-refresh, two-tier cache, link-switcher in QR modal, BOM audit, etc.). See git history at
https://github.com/phonograph123/SmartOneLink-Digital-Link-Generator-for-GS1/commits/mainfor per-version notes.