diff --git a/README.md b/README.md index 996ab3c..3402c40 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,9 @@ Spacefast adds a delivery step after Simply Static has generated and delivered its files but before cleanup. The step hashes the generated bytes, declares a full export as an exact snapshot through Spacefast's normal version API, uploads only the files Spacefast requests, waits for activation, and records -whether that version became live. Partial, update, build, and 404-only exports +whether that version became live. Static WordPress exports are public by +default; an explicit `sf.jsonc` in the export is preserved. Partial, update, +build, and 404-only exports are additive so they cannot accidentally delete omitted site files. After a deletion, the plugin blocks partial publishing until a full export removes old files safely. Upload transfer is paged and processed one file diff --git a/includes/class-spacefast-client.php b/includes/class-spacefast-client.php index 1208d54..a83295b 100644 --- a/includes/class-spacefast-client.php +++ b/includes/class-spacefast-client.php @@ -351,6 +351,9 @@ public function upload_static_file( array $target, string $file_path ): array { } public static function content_type_for_file( string $file_path ): string { + if ( 'jsonc' === strtolower( (string) pathinfo( $file_path, PATHINFO_EXTENSION ) ) ) { + return 'application/json'; + } $filetype = wp_check_filetype( $file_path ); $type = is_array( $filetype ) ? (string) ( $filetype['type'] ?? '' ) : ''; return '' !== $type ? $type : 'application/octet-stream'; diff --git a/includes/class-spacefast-static-publisher.php b/includes/class-spacefast-static-publisher.php index b4f0d4e..d21e9c5 100644 --- a/includes/class-spacefast-static-publisher.php +++ b/includes/class-spacefast-static-publisher.php @@ -123,6 +123,7 @@ public static function step( */ public static function manifest( string $archive_dir ): array { $root = self::archive_root( $archive_dir ); + self::ensure_public_config( $root ); $files = array(); $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $root, FilesystemIterator::SKIP_DOTS ) @@ -162,6 +163,20 @@ public static function reset(): void { delete_option( self::OPTION ); } + private static function ensure_public_config( string $root ): void { + $config = $root . DIRECTORY_SEPARATOR . 'sf.jsonc'; + if ( file_exists( $config ) || is_link( $config ) ) { + if ( ! is_file( $config ) || is_link( $config ) || ! is_readable( $config ) ) { + throw new RuntimeException( 'The generated Spacefast configuration is not a readable file.' ); + } + return; + } + $written = file_put_contents( $config, "{\n \"access\": \"public\"\n}\n", LOCK_EX ); + if ( false === $written ) { + throw new RuntimeException( 'The generated export could not be made public on Spacefast.' ); + } + } + private static function archive_root( string $archive_dir ): string { $root = realpath( $archive_dir ); if ( false === $root || ! is_dir( $root ) || ! is_readable( $root ) ) { diff --git a/readme.txt b/readme.txt index 808ddfc..587cd45 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: spacefast Tags: static site, headless cms, simply static, deployment Requires at least: 6.5 Requires PHP: 8.1 -Stable tag: 0.5.5 +Stable tag: 0.5.6 License: GPLv2 or later Publish a Simply Static export to Spacefast, or rebuild a headless site when WordPress content changes. @@ -31,6 +31,9 @@ OAuth access is limited to the Team you authorize and the mode you choose. WordP == Changelog == += 0.5.6 = +* Make static WordPress exports publicly readable by default while preserving an explicit sf.jsonc access policy. + = 0.5.5 = * Declare and send each exported file's media type so managed hosting accepts binary uploads. diff --git a/spacefast-wordpress.php b/spacefast-wordpress.php index 94f7169..7178ac2 100644 --- a/spacefast-wordpress.php +++ b/spacefast-wordpress.php @@ -3,7 +3,7 @@ * Plugin Name: Spacefast * Plugin URI: https://spacefast.com/ * Description: Publishes static WordPress exports or rebuilds a headless Spacefast site. - * Version: 0.5.5 + * Version: 0.5.6 * Update URI: https://github.com/spacefast/wordpress * Requires at least: 6.5 * Requires PHP: 8.1 @@ -14,7 +14,7 @@ defined( 'ABSPATH' ) || exit; -define( 'SPACEFAST_WORDPRESS_VERSION', '0.5.5' ); +define( 'SPACEFAST_WORDPRESS_VERSION', '0.5.6' ); define( 'SPACEFAST_WORDPRESS_FILE', __FILE__ ); require_once __DIR__ . '/includes/class-spacefast-settings.php'; diff --git a/tests/acceptance/wordpress.php b/tests/acceptance/wordpress.php index b038d3d..90700e7 100644 --- a/tests/acceptance/wordpress.php +++ b/tests/acceptance/wordpress.php @@ -113,7 +113,7 @@ function spacefast_accept( bool $condition, string $message ): void { ); $plugin = get_plugin_data( WP_PLUGIN_DIR . '/spacefast-wordpress/spacefast-wordpress.php', false, false ); -spacefast_accept( '0.5.5' === $plugin['Version'], 'Unexpected plugin version.' ); +spacefast_accept( '0.5.6' === $plugin['Version'], 'Unexpected plugin version.' ); spacefast_accept( 'https://github.com/spacefast/wordpress' === $plugin['UpdateURI'], 'Update URI is missing.' ); Spacefast_Settings::disconnect(); diff --git a/tests/behavior.php b/tests/behavior.php index 3dcbff2..aea1326 100644 --- a/tests/behavior.php +++ b/tests/behavior.php @@ -847,7 +847,7 @@ static function ( string $url ) use ( &$invalid_receipt_requests ): array { file_put_contents( $archive . '/assets/app.js', 'console.log("spacefast")' ); $manifest = Spacefast_Static_Publisher::manifest( $archive ); check( - array( 'assets/app.js', 'index.html' ) === array_column( $manifest, 'path' ), + array( 'assets/app.js', 'index.html', 'sf.jsonc' ) === array_column( $manifest, 'path' ), 'builds a sorted snapshot manifest from generated files' ); check( @@ -855,6 +855,20 @@ static function ( string $url ) use ( &$invalid_receipt_requests ): array { 'hashes the generated bytes instead of trusting exporter metadata' ); check( 'text/javascript' === $manifest[0]['contentType'], 'declares generated asset media types in the publish manifest' ); +check( 'application/json' === $manifest[2]['contentType'], 'declares the generated Spacefast config as JSON' ); +check( + 'public' === ( json_decode( file_get_contents( $archive . '/sf.jsonc' ), true )['access'] ?? '' ), + 'makes a static WordPress export publicly readable by default' +); +$custom_archive = sys_get_temp_dir() . '/spacefast-wordpress-custom-config-' . uniqid(); +mkdir( $custom_archive ); +file_put_contents( $custom_archive . '/index.html', '