diff --git a/lib/client-assets.php b/lib/client-assets.php index 2302345beaa8d..3030459fbfce8 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -840,6 +840,67 @@ function gutenberg_get_available_image_sizes() { return $all_sizes; } +/** + * Extends block editor settings to include Gutenberg's `editor-styles.css` as + * taking precedent those styles shipped with core. + * + * @param array $settings Default editor settings. + * + * @return array Filtered editor settings. + */ +function gutenberg_extend_block_editor_styles( $settings ) { + $editor_styles_file = gutenberg_dir_path() . 'build/editor/editor-styles.css'; + + /* + * If, for whatever reason, the built editor styles do not exist, avoid + * override and fall back to the default. + */ + if ( ! file_exists( $editor_styles_file ) ) { + return $settings; + } + + if ( empty( $settings['styles'] ) ) { + $settings['styles'] = array(); + } else { + /* + * The styles setting is an array of CSS strings, so there is no direct + * way to find the default styles. To maximize stability, load (again) + * the default styles from disk and find its place in the array. + * + * See: https://github.com/WordPress/wordpress-develop/blob/5.0.3/src/wp-admin/edit-form-blocks.php#L168-L175 + */ + + $default_styles = file_get_contents( + ABSPATH . WPINC . '/css/dist/editor/editor-styles.css' + ); + + /* + * Iterate backwards from the end of the array since the preferred + * insertion point in case not found is prepended as first entry. + */ + for ( $i = count( $settings['styles'] ) - 1; $i >= 0; $i-- ) { + if ( isset( $settings['styles'][ $i ]['css'] ) && + $default_styles === $settings['styles'][ $i ]['css'] ) { + break; + } + } + } + + $editor_styles = array( + 'css' => file_get_contents( $editor_styles_file ), + ); + + // Substitute default styles if found. Otherwise, prepend to setting array. + if ( isset( $i ) && $i >= 0 ) { + $settings['styles'][ $i ] = $editor_styles; + } else { + array_unshift( $settings['styles'], $editor_styles ); + } + + return $settings; +} +add_filter( 'block_editor_settings', 'gutenberg_extend_block_editor_styles' ); + /** * Scripts & Styles. * @@ -1002,7 +1063,7 @@ function gutenberg_editor_scripts_and_styles( $hook ) { $styles = array( array( 'css' => file_get_contents( - gutenberg_dir_path() . 'build/editor/editor-styles.css' + ABSPATH . WPINC . '/css/dist/editor/editor-styles.css' ), ), ); diff --git a/phpunit/class-extend-styles-test.php b/phpunit/class-extend-styles-test.php new file mode 100644 index 0000000000000..6ae12ada22797 --- /dev/null +++ b/phpunit/class-extend-styles-test.php @@ -0,0 +1,185 @@ +restore_editor_styles(); + } + + /** + * Restores the existence of `editor-styles.css` to its original state. + */ + protected function restore_editor_styles() { + $path = gutenberg_dir_path() . 'build/editor/editor-styles.css'; + + if ( $this->original_file ) { + if ( $this->original_file !== $path ) { + rename( $this->original_file, $path ); + } + } elseif ( file_exists( $path ) ) { + unlink( $path ); + } + + $this->style_contents = null; + $this->original_file = null; + } + + /** + * Guarantees that an `editor-styles.css` file exists, if and only if it + * should exist. Assigns `style_contents` according to the contents of the + * file if it should exist. Renames the existing file temporarily if it + * exists but should not. + * + * @param bool $should_exist Whether the editor styles file should exist. + */ + protected function ensure_editor_styles( $should_exist = true ) { + $path = gutenberg_dir_path() . 'build/editor/editor-styles.css'; + + if ( file_exists( $path ) ) { + if ( $should_exist ) { + $this->style_contents = file_get_contents( $path ); + $this->original_file = $path; + } else { + rename( $path, $path . '.bak' ); + $this->original_file = $path . '.bak'; + } + } elseif ( $should_exist ) { + $this->style_contents = ''; + file_put_contents( $path, $this->style_contents ); + $this->original_file = null; + } + } + + /** + * Tests a non-existent build `styles`. + */ + function test_without_built_styles() { + $this->ensure_editor_styles( false ); + + $settings = array( + 'styles' => array( + array( 'css' => 'original' ), + array( 'css' => 'someother' ), + ), + ); + + $result = gutenberg_extend_block_editor_styles( $settings ); + + $this->assertEquals( $settings, $result ); + } + + /** + * Tests an unset `styles` setting. + */ + function test_unset_editor_settings_style() { + $this->ensure_editor_styles(); + + $settings = array(); + + $settings = gutenberg_extend_block_editor_styles( $settings ); + + $this->assertEquals( + array( array( 'css' => $this->style_contents ) ), + $settings['styles'] + ); + } + + /** + * Tests replacing the default styles. + */ + function test_replace_default_editor_styles() { + $this->ensure_editor_styles(); + $default_styles = file_get_contents( + ABSPATH . WPINC . '/css/dist/editor/editor-styles.css' + ); + + $settings = array( + 'styles' => array( + array( 'css' => $default_styles ), + array( 'css' => 'someother' ), + ), + ); + + $settings = gutenberg_extend_block_editor_styles( $settings ); + + $this->assertEquals( + array( + array( 'css' => $this->style_contents ), + array( 'css' => 'someother' ), + ), + $settings['styles'] + ); + } + + /** + * Tests replacing the rearranged default styles. + */ + function test_replace_rearranged_default_editor_styles() { + $this->ensure_editor_styles(); + $default_styles = file_get_contents( + ABSPATH . WPINC . '/css/dist/editor/editor-styles.css' + ); + + $settings = array( + 'styles' => array( + array( 'css' => 'someother' ), + array( 'css' => $default_styles ), + ), + ); + + $settings = gutenberg_extend_block_editor_styles( $settings ); + + $this->assertEquals( + array( + array( 'css' => 'someother' ), + array( 'css' => $this->style_contents ), + ), + $settings['styles'] + ); + } + + /** + * Tests when the default styles aren't in the styles setting. + */ + function test_without_default_editor_styles() { + $this->ensure_editor_styles(); + + $settings = array( + 'styles' => array( + array( 'css' => 'someother' ), + ), + ); + + $settings = gutenberg_extend_block_editor_styles( $settings ); + + $this->assertEquals( + array( + array( 'css' => $this->style_contents ), + array( 'css' => 'someother' ), + ), + $settings['styles'] + ); + } + +}