Skip to content

Commit 48ab1a3

Browse files
committed
fix(import): gate smilie conversion off at activation via use_smilies option
Imported literal emoticon text (:) was lost to WP core smilie conversion. Set the owning site option use_smilies=false when materialization activates the imported theme, instead of a companion-plugin filter that is never scaffolded for plain artifacts. The receipt reports runtime_policy.disable_smilies as {requested, applied}; applied is only true when the activation-time update_option actually ran. Defaults on so ordinary imports keep literal text. Refs #780 #788
1 parent 1b5f0e0 commit 48ab1a3

6 files changed

Lines changed: 61 additions & 12 deletions

includes/abilities.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,12 @@ function static_site_importer_register_abilities(): void {
125125
'input_schema' => array(
126126
'type' => 'object',
127127
'properties' => array(
128-
'plan' => array( 'type' => 'object' ),
129-
'slug' => array( 'type' => 'string' ),
130-
'activate' => array( 'type' => 'boolean' ),
131-
'site_title' => array( 'type' => 'string' ),
132-
'overwrite' => array( 'type' => 'boolean' ),
128+
'plan' => array( 'type' => 'object' ),
129+
'slug' => array( 'type' => 'string' ),
130+
'activate' => array( 'type' => 'boolean' ),
131+
'site_title' => array( 'type' => 'string' ),
132+
'overwrite' => array( 'type' => 'boolean' ),
133+
'disable_smilies' => array( 'type' => 'boolean' ),
133134
),
134135
'required' => array( 'plan', 'slug' ),
135136
),

includes/class-static-site-importer-website-artifact-import-input.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class Static_Site_Importer_Website_Artifact_Import_Input {
2525
),
2626
'activate' => array( 'type' => 'boolean' ),
2727
'overwrite' => array( 'type' => 'boolean' ),
28+
'disable_smilies' => array( 'type' => 'boolean' ),
2829
'fail_on_quality' => array( 'type' => 'boolean' ),
2930
'allow_missing_woocommerce' => array( 'type' => 'boolean' ),
3031
'allow_missing_jetpack' => array( 'type' => 'boolean' ),
@@ -61,6 +62,7 @@ public static function normalize( array $input, array $defaults = array() ): arr
6162
'stale_page_action' => '',
6263
'activate' => false,
6364
'overwrite' => false,
65+
'disable_smilies' => true,
6466
'fail_on_quality' => false,
6567
'allow_missing_woocommerce' => false,
6668
'allow_missing_jetpack' => false,
@@ -89,7 +91,7 @@ public static function normalize( array $input, array $defaults = array() ): arr
8991
foreach ( array( 'slug', 'name', 'site_title', 'stale_page_action', 'report', 'asset_materialization_policy' ) as $field ) {
9092
$values[ $field ] = is_scalar( $values[ $field ] ) ? (string) $values[ $field ] : '';
9193
}
92-
foreach ( array( 'activate', 'overwrite', 'fail_on_quality', 'allow_missing_woocommerce', 'allow_missing_jetpack', 'materialize_dependencies', 'require_proven_dynamic_client_assets', 'seed_entities', 'write_theme_report_artifacts' ) as $field ) {
94+
foreach ( array( 'activate', 'overwrite', 'disable_smilies', 'fail_on_quality', 'allow_missing_woocommerce', 'allow_missing_jetpack', 'materialize_dependencies', 'require_proven_dynamic_client_assets', 'seed_entities', 'write_theme_report_artifacts' ) as $field ) {
9395
$values[ $field ] = (bool) $values[ $field ];
9496
}
9597
foreach ( array( 'products_manifest', 'commerce_context', 'asset_map', 'compiler_options', 'source_metadata', 'validation_artifacts' ) as $field ) {

includes/class-static-site-importer-wordpress-site-plan-materializer.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@ public static function materialize_prepared( array $prepared ): array {
251251
'kind' => 'activate_theme',
252252
'theme_slug' => $state['theme']['slug'],
253253
);
254+
if ( ! isset( $args['disable_smilies'] ) || false !== (bool) $args['disable_smilies'] ) {
255+
if ( false === update_option( 'use_smilies', false ) ) {
256+
return self::failed_receipt( $state, 'disable_smilies_not_applied' );
257+
}
258+
$state['applied']['runtime_policy']['disable_smilies'] = true;
259+
}
254260
if ( '' !== trim( (string) ( $args['site_title'] ?? '' ) ) ) {
255261
update_option( 'blogname', sanitize_text_field( (string) $args['site_title'] ) );
256262
$state['applied']['operations'][] = array( 'kind' => 'site_title' );
@@ -1025,6 +1031,12 @@ private static function receipt( string $status, array $state ): array {
10251031
'files' => array(),
10261032
'diagnostics' => array(),
10271033
),
1034+
'runtime_policy' => array(
1035+
'disable_smilies' => array(
1036+
'requested' => isset( $state['args']['disable_smilies'] ) ? (bool) $state['args']['disable_smilies'] : true,
1037+
'applied' => isset( $state['applied']['runtime_policy']['disable_smilies'] ) && true === $state['applied']['runtime_policy']['disable_smilies'],
1038+
),
1039+
),
10281040
'materialized_pages' => $materialized_pages,
10291041
'block_provenance' => $block_provenance,
10301042
'block_provenance_count' => $block_provenance_count,

static-site-importer.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,10 @@ static function ( array $args, array $assoc_args ): void {
138138
}
139139
$receipt = static_site_importer_ability_materialize_wordpress_site_plan(
140140
array(
141-
'plan' => $plan,
142-
'slug' => (string) $assoc_args['slug'],
143-
'overwrite' => isset( $assoc_args['overwrite'] ),
141+
'plan' => $plan,
142+
'slug' => (string) $assoc_args['slug'],
143+
'overwrite' => isset( $assoc_args['overwrite'] ),
144+
'disable_smilies' => ! isset( $assoc_args['no-disable-smilies'] ),
144145
)
145146
);
146147
WP_CLI::line( (string) wp_json_encode( $receipt, JSON_UNESCAPED_SLASHES ) );
@@ -202,6 +203,7 @@ static function ( array $args, array $assoc_args ): void {
202203
'name' => isset( $assoc_args['name'] ) ? (string) $assoc_args['name'] : '',
203204
'activate' => isset( $assoc_args['activate'] ),
204205
'overwrite' => isset( $assoc_args['overwrite'] ),
206+
'disable_smilies' => ! isset( $assoc_args['no-disable-smilies'] ),
205207
'fail_on_quality' => isset( $assoc_args['fail-on-quality'] ),
206208
'allow_missing_woocommerce' => isset( $assoc_args['allow-missing-woocommerce'] ),
207209
'materialize_dependencies' => ! isset( $assoc_args['skip-dependency-materialization'] ),
@@ -248,6 +250,7 @@ static function ( array $args, array $assoc_args ): void {
248250
'site_title' => isset( $assoc_args['site-title'] ) ? (string) $assoc_args['site-title'] : '',
249251
'activate' => isset( $assoc_args['activate'] ),
250252
'overwrite' => isset( $assoc_args['overwrite'] ),
253+
'disable_smilies' => ! isset( $assoc_args['no-disable-smilies'] ),
251254
'fail_on_quality' => isset( $assoc_args['fail-on-quality'] ),
252255
'allow_missing_woocommerce' => isset( $assoc_args['allow-missing-woocommerce'] ),
253256
'report' => isset( $assoc_args['report'] ) ? (string) $assoc_args['report'] : '',

tests/smoke-website-artifact-import-input.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ public static function import_website_artifact( array $artifact, array $args = a
106106
'stale_page_action' => 'draft',
107107
'activate' => true,
108108
'overwrite' => true,
109+
'disable_smilies' => true,
109110
'fail_on_quality' => true,
110111
'allow_missing_woocommerce' => true,
111112
'allow_missing_jetpack' => true,
@@ -124,6 +125,12 @@ public static function import_website_artifact( array $artifact, array $args = a
124125
);
125126
$direct = Static_Site_Importer_Website_Artifact_Import_Input::normalize( $input );
126127

128+
// disable_smilies (issue #780) defaults on so ordinary imports keep literal text.
129+
$default_input = Static_Site_Importer_Website_Artifact_Import_Input::normalize( array( 'slug' => 'default-theme' ) );
130+
$assert( true === $default_input['disable_smilies'], 'disable-smilies-defaults-true' );
131+
$assert( true === Static_Site_Importer_Website_Artifact_Import_Input::normalize( array( 'disable_smilies' => '1' ) )['disable_smilies'], 'disable-smilies-coerces-true-string' );
132+
$assert( false === Static_Site_Importer_Website_Artifact_Import_Input::normalize( array( 'disable_smilies' => '0' ) )['disable_smilies'], 'disable-smilies-coerces-false-string' );
133+
127134
static_site_importer_ability_import_website_artifact( array_merge( $input, array( 'artifact' => array( 'schema' => 'test/artifact/v1' ) ) ) );
128135
$direct_entrypoint = Static_Site_Importer_Theme_Generator::$last_args;
129136

tests/smoke-wordpress-site-plan-materializer.php

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
$GLOBALS['ssi_plan_root'] = sys_get_temp_dir() . '/ssi-plan-' . bin2hex( random_bytes( 4 ) );
2222
$GLOBALS['ssi_plan_posts'] = array();
2323
$GLOBALS['ssi_plan_meta'] = array();
24-
$GLOBALS['ssi_plan_options'] = array( 'show_on_front' => 'posts', 'page_on_front' => 0, 'blogname' => 'Before' );
24+
$GLOBALS['ssi_plan_options'] = array( 'show_on_front' => 'posts', 'page_on_front' => 0, 'blogname' => 'Before', 'use_smilies' => true );
2525
$GLOBALS['ssi_plan_fail_after'] = 0;
2626
$GLOBALS['ssi_plan_font_requests'] = array();
2727
mkdir( $GLOBALS['ssi_plan_root'], 0777, true );
@@ -64,8 +64,9 @@ function wp_safe_remote_get( string $url, array $args ) {
6464
}
6565
function wp_remote_retrieve_response_code( $response ): int { return (int) ( $response['response']['code'] ?? 0 ); }
6666
function wp_remote_retrieve_body( $response ): string { return (string) ( $response['body'] ?? '' ); }
67-
function update_option( string $key, $value ): void { $GLOBALS['ssi_plan_options'][ $key ] = $value; }
67+
function update_option( string $key, $value ): bool { $GLOBALS['ssi_plan_options'][ $key ] = $value; return true; }
6868
function switch_theme( string $slug ): void { $GLOBALS['ssi_plan_options']['stylesheet'] = $slug; }
69+
function convert_smilies( string $content, string $which = 'content' ): string { return ( $GLOBALS['ssi_plan_options']['use_smilies'] ?? true ) ? 'smilied-' . $which : $content; }
6970
function sanitize_text_field( string $value ): string { return $value; }
7071
function update_post_meta( int $id, string $key, string $value ): void { $GLOBALS['ssi_plan_meta'][ $id ][ $key ] = $value; }
7172
function get_post_meta( int $id, string $key, bool $single = true ): string { return (string) ( $GLOBALS['ssi_plan_meta'][ $id ][ $key ] ?? '' ); }
@@ -349,14 +350,37 @@ function wp_insert_post( array $post, bool $wp_error ) {
349350
$assert( hash_file( 'sha256', $publication_file ) === ( $publication_report['actual_content_hash'] ?? '' ) && $publication_plan['runtime_declarations'][0]['expected_content_hash'] === ( $publication_report['expected_content_hash'] ?? '' ), 'publication receipt proves canonical and resolved content integrity' );
350351
$assert( str_contains( file_get_contents( $publication_file ), 'https://example.test/wp-content/themes/publication-plan/assets/assets/font.woff2' ), 'font-bearing SVG resolves only its declared local font URL' );
351352

352-
$GLOBALS['ssi_plan_options'] = array( 'show_on_front' => 'posts', 'page_on_front' => 0, 'blogname' => 'Before' );
353+
$GLOBALS['ssi_plan_options'] = array( 'show_on_front' => 'posts', 'page_on_front' => 0, 'blogname' => 'Before', 'use_smilies' => true );
353354
$preview = Static_Site_Importer_WordPress_Site_Plan_Materializer::materialize( $plan, array( 'slug' => 'site-plan', 'overwrite' => true ) );
354355
$assert( 'completed' === $preview['status'], 'preview materialization completes' );
355356
$assert( array( 'canonical_validations' => 1, 'plan_resolutions' => 1, 'destination_preflights' => 2, 'immutable_projection_reused' => true ) === ( $preview['preparation'] ?? array() ), 'materialization reuses one immutable projection while repeating destination preflight' );
356357
$assert( 'posts' === $GLOBALS['ssi_plan_options']['show_on_front'] && ! isset( $GLOBALS['ssi_plan_options']['stylesheet'] ), 'activate=false preserves runtime options' );
357358
$activated = Static_Site_Importer_WordPress_Site_Plan_Materializer::materialize( $plan, array( 'slug' => 'site-plan', 'overwrite' => true, 'activate' => true, 'site_title' => 'Activated Plan' ) );
358359
$assert( 'site-plan' === $GLOBALS['ssi_plan_options']['stylesheet'] && 'page' === $GLOBALS['ssi_plan_options']['show_on_front'] && 'Activated Plan' === $GLOBALS['ssi_plan_options']['blogname'], 'activate=true applies theme title and reading policy' );
359360

361+
// disable_smilies (issue #780): non-activating import must not touch the global option.
362+
$GLOBALS['ssi_plan_options'] = array( 'show_on_front' => 'posts', 'page_on_front' => 0, 'blogname' => 'Before', 'use_smilies' => true );
363+
$receipt_default = Static_Site_Importer_WordPress_Site_Plan_Materializer::materialize( $plan, array( 'slug' => 'site-plan', 'overwrite' => true ) );
364+
$assert( true === ( $receipt_default['completed']['runtime_policy']['disable_smilies']['requested'] ?? null ), 'disable-smilies-defaults-requested-true' );
365+
$assert( false === ( $receipt_default['completed']['runtime_policy']['disable_smilies']['applied'] ?? null ), 'disable-smilies-not-applied-without-activate' );
366+
$assert( true === $GLOBALS['ssi_plan_options']['use_smilies'], 'non-activating-import-preserves-use-smilies' );
367+
368+
// Explicit opt-out, non-activating: requested and applied both false.
369+
$receipt_off = Static_Site_Importer_WordPress_Site_Plan_Materializer::materialize( $plan, array( 'slug' => 'site-plan', 'overwrite' => true, 'disable_smilies' => false ) );
370+
$assert( false === ( $receipt_off['completed']['runtime_policy']['disable_smilies']['requested'] ?? null ) && false === ( $receipt_off['completed']['runtime_policy']['disable_smilies']['applied'] ?? null ), 'disable-smilies-false-requested-and-applied-false' );
371+
372+
// Activating import with default policy flips the option so literal :) stays text.
373+
$activated_smilies = Static_Site_Importer_WordPress_Site_Plan_Materializer::materialize( $plan, array( 'slug' => 'site-plan', 'overwrite' => true, 'activate' => true, 'site_title' => 'Activated Plan' ) );
374+
$assert( false === $GLOBALS['ssi_plan_options']['use_smilies'], 'activating-import-sets-use-smilies-false' );
375+
$assert( 'Hello :)' === convert_smilies( 'Hello :)' ), 'convert-smilies-output-unchanged-when-disabled' );
376+
$assert( true === ( $activated_smilies['completed']['runtime_policy']['disable_smilies']['requested'] ?? null ) && true === ( $activated_smilies['completed']['runtime_policy']['disable_smilies']['applied'] ?? null ), 'activating-import-records-requested-and-applied' );
377+
378+
// Explicit opt-out, activating: option untouched, policy not applied.
379+
$GLOBALS['ssi_plan_options'] = array( 'show_on_front' => 'posts', 'page_on_front' => 0, 'blogname' => 'Before', 'use_smilies' => true );
380+
$activated_off = Static_Site_Importer_WordPress_Site_Plan_Materializer::materialize( $plan, array( 'slug' => 'site-plan', 'overwrite' => true, 'activate' => true, 'disable_smilies' => false, 'site_title' => 'Activated Off' ) );
381+
$assert( true === $GLOBALS['ssi_plan_options']['use_smilies'], 'activate-with-disable-smilies-false-keeps-smilies' );
382+
$assert( false === ( $activated_off['completed']['runtime_policy']['disable_smilies']['requested'] ?? null ) && false === ( $activated_off['completed']['runtime_policy']['disable_smilies']['applied'] ?? null ), 'disable-smilies-false-not-applied-on-activate' );
383+
360384
$repeat = Static_Site_Importer_WordPress_Site_Plan_Materializer::materialize( $plan, array( 'slug' => 'site-plan' ) );
361385
$assert( 'completed' === $repeat['status'], 'reconciliation repeat completes' );
362386
$assert( count( $GLOBALS['ssi_plan_posts'] ) === count( $plan['pages'] ), 'reconciliation preserves source page identity' );

0 commit comments

Comments
 (0)