Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .monorepo-source.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"productId": "funkycommerce-headless",
"repository": "coded-letter/superfunky-theme",
"source": "coded-letter/coded-letter-monorepo@91926789228a613709e0e3e6557551f58e9c4868",
"source": "coded-letter/coded-letter-monorepo@8a3dad247c946945214407d0f08eecb328d42e3d",
"sourcePath": "workspace/backend/wordpress/themes/free/funkycommerce-headless",
"installSlug": "funkycommerce-headless",
"kind": "theme",
Expand Down
2 changes: 1 addition & 1 deletion functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
exit;
}

define( 'FUNKYCOMMERCE_HEADLESS_VERSION', '1.2.32' );
define( 'FUNKYCOMMERCE_HEADLESS_VERSION', '1.2.33' );

/**
* Whether Superfunky Pro is active and licensed.
Expand Down
10 changes: 5 additions & 5 deletions inc/control-center-schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -650,19 +650,19 @@ function funkycommerce_control_center_sections() {
),
'build' => array(
'title' => __( 'Build & Deploy', 'funkycommerce-headless' ),
'description' => __( 'Frontend routing, deployment hooks, and scheduled rebuilds.', 'funkycommerce-headless' ),
'description' => __( 'Frontend routing, portable static-first SSG, artifact generation, and explicit publishing controls.', 'funkycommerce-headless' ),
'headless_only' => true,
'fields' => array(
'frontend_url' => array( 'label' => __( 'Frontend URL', 'funkycommerce-headless' ), 'type' => 'url', 'tier' => 'free', 'default' => 'https://funkycommerce.netlify.app', 'description' => __( 'Deployment target used by account emails and headless redirects. Authentication controls remain plugin-owned.', 'funkycommerce-headless' ) ),
'artifact_mode' => array( 'label' => __( 'Dynamic content delivery', 'funkycommerce-headless' ), 'type' => 'select', 'tier' => 'free', 'default' => 'build-webhook', 'options' => array( 'build-webhook' => __( 'Legacy build webhook', 'funkycommerce-headless' ), 'shadow' => __( 'Generate artifacts in shadow mode', 'funkycommerce-headless' ), 'artifact' => __( 'Serve generated artifacts', 'funkycommerce-headless' ) ), 'description' => __( 'Keep legacy mode until shadow generation and the production fallback have passed validation.', 'funkycommerce-headless' ) ),
'artifact_mode' => array( 'label' => __( 'Dynamic content delivery', 'funkycommerce-headless' ), 'type' => 'select', 'tier' => 'free', 'default' => 'build-webhook', 'options' => array( 'build-webhook' => __( 'Legacy build webhook', 'funkycommerce-headless' ), 'shadow' => __( 'Generate artifacts in shadow mode', 'funkycommerce-headless' ), 'artifact' => __( 'Serve generated artifacts', 'funkycommerce-headless' ) ), 'description' => __( 'Static-first SSG uses artifact mode for background generation while the host serves complete generated route documents. Validate shadow mode first, then switch to artifact mode.', 'funkycommerce-headless' ) ),
'artifact_site_key' => array( 'label' => __( 'Artifact site key', 'funkycommerce-headless' ), 'type' => 'slug', 'tier' => 'free', 'default' => '', 'description' => __( 'Stable lowercase deployment key. Multisite installations require a different key for every public site.', 'funkycommerce-headless' ) ),
'artifact_signing_secret' => array( 'label' => __( 'Artifact signing secret', 'funkycommerce-headless' ), 'type' => 'password', 'tier' => 'free', 'default' => '', 'description' => __( 'At least 32 characters. Stored separately from public storefront settings and never returned by an API.', 'funkycommerce-headless' ) ),
'artifact_cache_ttl' => array( 'label' => __( 'Artifact shared-cache TTL (seconds)', 'funkycommerce-headless' ), 'type' => 'number', 'tier' => 'free', 'default' => '60', 'min' => '0', 'max' => '3600', 'step' => '1' ),
'artifact_retention_days' => array( 'label' => __( 'Artifact retention (days)', 'funkycommerce-headless' ), 'type' => 'number', 'tier' => 'free', 'default' => '30', 'min' => '1', 'max' => '365', 'step' => '1' ),
'build_webhook_url' => array( 'label' => __( 'Build webhook URL', 'funkycommerce-headless' ), 'type' => 'url', 'tier' => 'pro' ),
'periodic_rebuild' => array( 'label' => __( 'Periodic rebuilds', 'funkycommerce-headless' ), 'type' => 'toggle', 'tier' => 'pro', 'default' => 'no' ),
'build_webhook_url' => array( 'label' => __( 'Build webhook URL', 'funkycommerce-headless' ), 'type' => 'url', 'tier' => 'pro', 'description' => __( 'Used by the Rebuild storefront action in the top admin bar. Static-first content changes are published only after this hook completes.', 'funkycommerce-headless' ) ),
'periodic_rebuild' => array( 'label' => __( 'Periodic rebuilds', 'funkycommerce-headless' ), 'type' => 'toggle', 'tier' => 'pro', 'default' => 'no', 'description' => __( 'Optional. Leave disabled for explicit, cost-controlled publishing through the admin-bar rebuild action.', 'funkycommerce-headless' ) ),
'rebuild_interval' => array( 'label' => __( 'Rebuild interval (hours)', 'funkycommerce-headless' ), 'type' => 'number', 'tier' => 'pro', 'default' => '12', 'min' => '1', 'max' => '168', 'step' => '1' ),
'build_badge_id' => array( 'label' => __( 'Build status badge ID', 'funkycommerce-headless' ), 'type' => 'text', 'tier' => 'pro' ),
'build_badge_id' => array( 'label' => __( 'Build status badge ID', 'funkycommerce-headless' ), 'type' => 'text', 'tier' => 'pro', 'description' => __( 'For Netlify, enter the site ID to show its deploy status below Rebuild storefront in the admin bar.', 'funkycommerce-headless' ) ),
'backend_preview_enabled' => array( 'label' => __( 'Mirrored native previews', 'funkycommerce-headless' ), 'type' => 'toggle', 'tier' => 'free', 'default' => 'yes', 'description' => __( 'When an editor uses WordPress\' native Preview, style it with the current layout settings and show the real header/footer menus. Preview access itself always requires sign-in and edit permission, whether this is on or off.', 'funkycommerce-headless' ) ),
'backend_redirect_enabled' => array( 'label' => __( 'Redirect public backend requests to the frontend', 'funkycommerce-headless' ), 'type' => 'toggle', 'tier' => 'free', 'default' => 'no', 'description' => __( 'Sends ordinary (non-preview) visitors of this WordPress backend to their equivalent Frontend URL page. Admin, login, REST, GraphQL, cron, feeds, and native previews are never redirected.', 'funkycommerce-headless' ) ),
),
Expand Down
24 changes: 24 additions & 0 deletions inc/control-center.php
Original file line number Diff line number Diff line change
Expand Up @@ -1435,6 +1435,26 @@ function funkycommerce_render_control_center() {
<?php settings_fields( 'funkycommerce_control_center' ); ?>
<section class="fc-panel">
<div class="fc-panel-heading"><div><h2><?php echo esc_html( $section['title'] ); ?></h2><p><?php echo esc_html( $section['description'] ); ?></p></div><span><?php echo esc_html( count( $section['fields'] ) ); ?> <?php esc_html_e( 'controls', 'funkycommerce-headless' ); ?></span></div>
<?php if ( 'build' === $section_key ) : ?>
<div class="fc-operator-guide">
<h3><?php esc_html_e( 'Static-first SSG rollout', 'funkycommerce-headless' ); ?></h3>
<p><?php esc_html_e( 'Use this mode when the static host should serve complete generated HTML immediately, while WordPress remains the content source and artifact control plane.', 'funkycommerce-headless' ); ?></p>
<ol>
<li><?php esc_html_e( 'Set Frontend URL, a unique Artifact site key, and the same 32+ character signing secret in WordPress and the storefront deployment.', 'funkycommerce-headless' ); ?></li>
<li><?php esc_html_e( 'Validate generation in shadow mode. Confirm the Artifacts panel reports a healthy active shell, background runner, and no failed or exhausted current-shell jobs.', 'funkycommerce-headless' ); ?></li>
<li><?php esc_html_e( 'Set Dynamic content delivery to Serve generated artifacts and configure the storefront variables shown below.', 'funkycommerce-headless' ); ?></li>
<li><?php esc_html_e( 'Configure a build webhook. After editing content, use Rebuild storefront in the top admin bar and wait for the deployment badge to succeed.', 'funkycommerce-headless' ); ?></li>
</ol>
<pre><code>STOREFRONT_ARTIFACT_MODE=artifact
STOREFRONT_ARTIFACT_DELIVERY=static-first
STOREFRONT_ARTIFACT_ORIGIN=<?php echo esc_html( untrailingslashit( home_url( '/' ) ) ); ?>
STOREFRONT_ARTIFACT_SITE_KEY=<?php echo esc_html( $settings['artifact_site_key'] ?: 'unique-site-key' ); ?>
STOREFRONT_ARTIFACT_SIGNING_SECRET=&lt;same-secret-as-wordpress&gt;
VITE_ARTIFACT_ROUTE_HYDRATION=true</code></pre>
<p><strong><?php esc_html_e( 'Freshness:', 'funkycommerce-headless' ); ?></strong> <?php esc_html_e( 'WordPress collects changes and regenerates artifacts automatically, but static-first public HTML changes only after a storefront build. Until then, visitors keep the previous known-good deployment.', 'funkycommerce-headless' ); ?></p>
<p><strong><?php esc_html_e( 'Rollback:', 'funkycommerce-headless' ); ?></strong> <?php esc_html_e( 'Restore the previous static deployment or set STOREFRONT_ARTIFACT_DELIVERY=proxy and rebuild. Never reuse one artifact site key across public sites.', 'funkycommerce-headless' ); ?></p>
</div>
<?php endif; ?>
<?php if ( ! empty( $section['preview'] ) ) : ?>
<div class="fc-layout-preview" data-layout-preview style="--preview-width:<?php echo esc_attr( $settings['layout_theme_max_width_px'] ?? '1280' ); ?>px;--preview-radius:<?php echo esc_attr( $settings['layout_theme_radius_px'] ?? '16' ); ?>px">
<div class="fc-layout-preview-toolbar"><strong><?php esc_html_e( 'Control Center preview', 'funkycommerce-headless' ); ?></strong><span><?php esc_html_e( 'Updates as controls change; the storefront remains canonical.', 'funkycommerce-headless' ); ?></span></div>
Expand Down Expand Up @@ -1533,6 +1553,10 @@ function funkycommerce_render_control_center() {
.fc-panel-heading { align-items: start; background: #fafafa; border-bottom: 1px solid #e7e7e9; display: flex; justify-content: space-between; padding: 20px 24px; }
.fc-panel-heading h2 { font-size: 21px; margin: 0 0 5px; } .fc-panel-heading p { color: #646970; margin: 0; }
.fc-panel-heading > span { background: #ede9fe; border-radius: 999px; color: #5b21b6; font-size: 11px; font-weight: 700; padding: 5px 9px; white-space: nowrap; }
.fc-operator-guide { background:#f6f7f7; border-bottom:1px solid #dcdcde; padding:18px 24px; }
.fc-operator-guide h3 { margin:0 0 8px; }
.fc-operator-guide ol { margin-left:20px; }
.fc-operator-guide pre { background:#1d2327; border-radius:6px; color:#f0f0f1; overflow:auto; padding:14px; }
.fc-layout-preview { background:#f4f4f5; border-bottom:1px solid var(--fc-border); padding:18px 24px; }
.fc-layout-preview-toolbar { align-items:center; display:flex; justify-content:space-between; margin-bottom:10px; }
.fc-layout-preview-toolbar span { color:#646970; font-size:12px; }
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "funkycommerce-headless-theme",
"private": true,
"version": "1.2.32",
"version": "1.2.33",
"description": "Tailwind/build tooling for the FunkyCommerce Headless WordPress theme's native frontend assets (block templates, template parts, loader, and Spotify slot).",
"scripts": {
"build:css": "tailwindcss -i ./assets/css/theme-source.css -o ./assets/dist/theme.css --minify",
Expand Down
42 changes: 41 additions & 1 deletion readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Tags: headless, woocommerce, wpgraphql, full-site-editing
Requires at least: 6.7
Tested up to: 6.8
Requires PHP: 7.4
Stable tag: 1.2.32
Stable tag: 1.2.33
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Expand All @@ -15,6 +15,46 @@ Control Center, the theme also ships a complete native WordPress rendering path
"Native frontend theme" below) with accessible header/footer/navigation templates and
core front/home/singular/archive/search/404 routes styled to match the storefront.

== 1.2.33 highlights ==

* Documents the portable static-first SSG rollout and rollback workflow in Build & Deploy.
* Explains explicit admin-bar publishing, artifact freshness, per-site keys, and required storefront variables.

== Static-first SSG setup ==

Static-first delivery keeps WordPress as the content and artifact control plane while the
frontend host serves complete generated route documents. It is portable across static hosts;
the examples below use environment-variable names from the Superfunky storefront.

1. Configure the public Frontend URL in Build & Deploy.
2. Create a unique Artifact site key for this public site. Never share a key between sites.
3. Generate a random signing secret of at least 32 characters. Save the exact same value in
WordPress and the frontend deployment environment.
4. Start with Generate artifacts in shadow mode. Confirm the Artifacts panel shows a healthy
active shell, a working Action Scheduler or WP-Cron runner, and no failed/exhausted jobs
for the current shell.
5. Switch Dynamic content delivery to Serve generated artifacts.
6. Configure the frontend deployment:

STOREFRONT_ARTIFACT_MODE=artifact
STOREFRONT_ARTIFACT_DELIVERY=static-first
STOREFRONT_ARTIFACT_ORIGIN=https://wordpress.example.com
STOREFRONT_ARTIFACT_SITE_KEY=unique-site-key
STOREFRONT_ARTIFACT_SIGNING_SECRET=same-secret-as-wordpress
VITE_ARTIFACT_ROUTE_HYDRATION=true

7. Configure the host build webhook in WordPress. Netlify users may also enter the Netlify
site ID as Build status badge ID.
8. Edit and preview content in WordPress. When ready to publish, click Rebuild storefront in
the top admin bar. Wait for the deploy badge to succeed before testing the public site.

WordPress invalidation and artifact regeneration happen automatically, but they do not replace
static-first public HTML. A storefront build is the explicit publish boundary. Until that build
finishes, visitors continue receiving the previous known-good static deployment.

To roll back, restore the previous static-host deployment. To return to proxy delivery, set
STOREFRONT_ARTIFACT_DELIVERY=proxy and rebuild the storefront.

== 1.2.32 highlights ==

* Adds an administrator-toolbar action for manually publishing changed WordPress content to the static storefront.
Expand Down
2 changes: 1 addition & 1 deletion style.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Description: A minimal, content-first block theme for polished WordPress preview
Requires at least: 6.7
Tested up to: 6.8
Requires PHP: 7.4
Version: 1.2.32
Version: 1.2.33
Update URI: https://github.com/coded-letter/superfunky-theme
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Expand Down
Loading