From be2cc761b3a3d4e93dccc8f74a5ea62a1e99dfdc Mon Sep 17 00:00:00 2001 From: kagg-design Date: Mon, 12 Feb 2024 14:47:21 +0300 Subject: [PATCH 1/6] Improve detection of the Gutenberg editor. --- src/php/Main.php | 45 ++++++++----------------- tests/unit/MainTest.php | 73 ++++++++++++++++++++++++++++++----------- 2 files changed, 68 insertions(+), 50 deletions(-) diff --git a/src/php/Main.php b/src/php/Main.php index 9a06e84..62b7a53 100644 --- a/src/php/Main.php +++ b/src/php/Main.php @@ -536,48 +536,31 @@ public function transliterate( string $str ): string { } /** - * Check if Classic Editor plugin is active. - * - * @link https://kagg.eu/how-to-catch-gutenberg/ + * Check if the Block Editor is active. + * Must only be used after plugins_loaded action is fired. * * @return bool + * @noinspection PhpUndefinedFunctionInspection */ - private function is_classic_editor_plugin_active(): bool { + private function is_gutenberg_editor_active(): bool { + // Gutenberg plugin is installed and activated. + // This filter was removed in WP 5.5. + if ( has_filter( 'replace_editor', 'gutenberg_init' ) ) { + return true; + } + // @codeCoverageIgnoreStart if ( ! function_exists( 'is_plugin_active' ) ) { include_once ABSPATH . 'wp-admin/includes/plugin.php'; } - // @codeCoverageIgnoreEnd - return is_plugin_active( 'classic-editor/classic-editor.php' ); - } - - /** - * Check if Block Editor is active. - * Must only be used after plugins_loaded action is fired. - * - * @link https://kagg.eu/how-to-catch-gutenberg/ - * - * @return bool - */ - private function is_gutenberg_editor_active(): bool { - - // Gutenberg plugin is installed and activated. - $gutenberg = ! ( false === has_filter( 'replace_editor', 'gutenberg_init' ) ); - - // Block editor since 5.0. - $block_editor = version_compare( $GLOBALS['wp_version'], '5.0-beta', '>' ); - - if ( ! $gutenberg && ! $block_editor ) { - return false; + if ( is_plugin_active( 'classic-editor/classic-editor.php' ) ) { + return in_array( get_option( 'classic-editor-replace' ), [ 'no-replace', 'block' ], true ); } - if ( $this->is_classic_editor_plugin_active() ) { - $editor_option = get_option( 'classic-editor-replace' ); - $block_editor_active = [ 'no-replace', 'block' ]; - - return in_array( $editor_option, $block_editor_active, true ); + if ( is_plugin_active( 'disable-gutenberg/disable-gutenberg.php' ) ) { + return ! disable_gutenberg(); } return true; diff --git a/tests/unit/MainTest.php b/tests/unit/MainTest.php index 21d17bd..ff753f4 100644 --- a/tests/unit/MainTest.php +++ b/tests/unit/MainTest.php @@ -53,7 +53,7 @@ class MainTest extends CyrToLatTestCase { public function tearDown(): void { // phpcs:disable WordPress.Security.NonceVerification.Missing // phpcs:disable WordPress.Security.NonceVerification.Recommended - unset( $GLOBALS['wp_version'], $GLOBALS['wpdb'], $GLOBALS['current_screen'], $GLOBALS['product'], $_POST, $_GET ); + unset( $GLOBALS['wpdb'], $GLOBALS['current_screen'], $GLOBALS['product'], $_POST, $_GET ); // phpcs:enable WordPress.Security.NonceVerification.Recommended // phpcs:enable WordPress.Security.NonceVerification.Missing } @@ -1135,8 +1135,6 @@ public static function dp_test_min_suffix(): array { * Test that sanitize_post_name() does nothing if no Block/Gutenberg editor is active */ public function test_sanitize_post_name_without_gutenberg() { - $subject = Mockery::mock( Main::class )->makePartial()->shouldAllowMockingProtectedMethods(); - $data = [ 'something' ]; WP_Mock::userFunction( @@ -1146,13 +1144,6 @@ public function test_sanitize_post_name_without_gutenberg() { 'return' => false, ] ); - - // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - $GLOBALS['wp_version'] = '4.9'; - self::assertSame( $data, $subject->sanitize_post_name( $data ) ); - - FunctionMocker::replace( 'function_exists', true ); - WP_Mock::userFunction( 'is_plugin_active', [ @@ -1161,7 +1152,6 @@ public function test_sanitize_post_name_without_gutenberg() { 'return' => true, ] ); - WP_Mock::userFunction( 'get_option', [ @@ -1171,8 +1161,45 @@ public function test_sanitize_post_name_without_gutenberg() { ] ); - // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - $GLOBALS['wp_version'] = '5.0'; + $subject = Mockery::mock( Main::class )->makePartial()->shouldAllowMockingProtectedMethods(); + + self::assertSame( $data, $subject->sanitize_post_name( $data ) ); + } + + /** + * Test that sanitize_post_name() does nothing if Disable Gutenberg plugin is active + */ + public function test_sanitize_post_name_with_disable_gutenberg_plugin() { + $data = [ 'something' ]; + + WP_Mock::userFunction( + 'has_filter', + [ + 'args' => [ 'replace_editor', 'gutenberg_init' ], + 'return' => false, + ] + ); + WP_Mock::userFunction( + 'is_plugin_active', + [ + 'times' => 1, + 'args' => [ 'classic-editor/classic-editor.php' ], + 'return' => false, + ] + ); + WP_Mock::userFunction( + 'is_plugin_active', + [ + 'times' => 1, + 'args' => [ 'disable-gutenberg/disable-gutenberg.php' ], + 'return' => true, + ] + ); + + $subject = Mockery::mock( Main::class )->makePartial()->shouldAllowMockingProtectedMethods(); + + FunctionMocker::replace( 'disable_gutenberg', true ); + self::assertSame( $data, $subject->sanitize_post_name( $data ) ); } @@ -1190,9 +1217,6 @@ public function test_sanitize_post_name_not_post_edit_screen() { ] ); - // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - $GLOBALS['wp_version'] = '5.0'; - $subject = Mockery::mock( Main::class )->makePartial()->shouldAllowMockingProtectedMethods(); FunctionMocker::replace( 'function_exists', true ); @@ -1203,6 +1227,13 @@ public function test_sanitize_post_name_not_post_edit_screen() { 'return' => false, ] ); + WP_Mock::userFunction( + 'is_plugin_active', + [ + 'args' => [ 'disable-gutenberg/disable-gutenberg.php' ], + 'return' => false, + ] + ); $current_screen = Mockery::mock( WP_Screen::class ); $current_screen->base = 'not post'; @@ -1226,9 +1257,6 @@ public function test_sanitize_post_name_not_post_edit_screen() { */ public function test_sanitize_post_name( array $data, array $expected ) { - // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - $GLOBALS['wp_version'] = '5.0'; - $subject = Mockery::mock( Main::class )->makePartial()->shouldAllowMockingProtectedMethods(); FunctionMocker::replace( 'function_exists', true ); @@ -1239,6 +1267,13 @@ public function test_sanitize_post_name( array $data, array $expected ) { 'return' => false, ] ); + WP_Mock::userFunction( + 'is_plugin_active', + [ + 'args' => [ 'disable-gutenberg/disable-gutenberg.php' ], + 'return' => false, + ] + ); $current_screen = Mockery::mock( WP_Screen::class ); $current_screen->base = 'post'; From 3ec66260b796afbfdb833ce9c784a1ac384922c9 Mon Sep 17 00:00:00 2001 From: kagg-design Date: Mon, 12 Feb 2024 14:48:03 +0300 Subject: [PATCH 2/6] Update readme.txt. --- readme.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readme.txt b/readme.txt index 5848414..c07c99c 100644 --- a/readme.txt +++ b/readme.txt @@ -221,6 +221,9 @@ Yes, you can! == Changelog == += 6.0.8 = +* Improved detection of the Gutenberg editor. + = 6.0.7 (11.02.2024) = * Tested with WooCommerce 8.5. * Added redirect from the cyrillic post title when creating a new post. From 75cd7db22b4482b79ef983b2afbe0dad093a2c41 Mon Sep 17 00:00:00 2001 From: kagg-design Date: Wed, 14 Feb 2024 16:02:55 +0300 Subject: [PATCH 3/6] Fix processing of product attributes. --- src/php/Main.php | 18 ++++++++++++------ tests/unit/MainTest.php | 38 ++++++++++++++++++++------------------ 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/php/Main.php b/src/php/Main.php index 62b7a53..97f1a70 100644 --- a/src/php/Main.php +++ b/src/php/Main.php @@ -384,7 +384,7 @@ public function woocommerce_after_template_part_filter() { * @noinspection PhpUndefinedFunctionInspection */ protected function is_wc_attribute_taxonomy( string $title ): bool { - $title = str_replace( 'pa_', '', $title ); + $title = preg_replace( '/^pa_/', '', $title ); foreach ( wc_get_attribute_taxonomies() as $attribute_taxonomy ) { if ( $title === $attribute_taxonomy->attribute_name ) { @@ -396,22 +396,28 @@ protected function is_wc_attribute_taxonomy( string $title ): bool { } /** - * Check if title is a product attribute. + * Check if title is a product not converted attribute. * * @param string $title Title. * * @return bool * @noinspection PhpUndefinedFunctionInspection */ - protected function is_wc_product_attribute( string $title ): bool { + protected function is_wc_product_not_converted_attribute( string $title ): bool { + global $product; if ( null === $product ) { return false; } - foreach ( $product->get_attributes() as $attribute ) { - if ( $title === $attribute->get_name() ) { + // We have to get attributes from postmeta here to see the converted slug. + $attributes = (array) get_post_meta( $product->get_id(), '_product_attributes', true ); + + foreach ( $attributes as $slug => $attribute ) { + $name = $attribute['name'] ?? ''; + + if ( $name === $title && sanitize_title_with_dashes( $title ) === $slug ) { return true; } } @@ -432,7 +438,7 @@ protected function is_wc_attribute( string $title ): bool { return false; } - return $this->is_wc_attribute_taxonomy( $title ) || $this->is_wc_product_attribute( $title ); + return $this->is_wc_attribute_taxonomy( $title ) || $this->is_wc_product_not_converted_attribute( $title ); } /** diff --git a/tests/unit/MainTest.php b/tests/unit/MainTest.php index ff753f4..ea93e03 100644 --- a/tests/unit/MainTest.php +++ b/tests/unit/MainTest.php @@ -779,36 +779,30 @@ static function ( $function_name ) use ( $is_wc ) { } /** - * Test is_wc_product_attribute(). + * Test is_wc_product_not_converted_attribute(). * * @param string $title Title. * @param bool $is_product Whether it is a product page. - * @param array $names Attribute names. + * @param array $attributes Attribute names. * @param bool $expected Expected result. * * @dataProvider dp_test_is_wc_product_attribute * @throws ReflectionException ReflectionException. */ - public function test_is_wc_product_attribute( string $title, bool $is_product, array $names, bool $expected ) { - $method = 'is_wc_product_attribute'; - $subject = $this->get_subject(); + public function test_is_wc_product_not_converted_attribute( string $title, bool $is_product, array $attributes, bool $expected ) { + $product_id = 5; + $method = 'is_wc_product_not_converted_attribute'; + $subject = $this->get_subject(); $this->set_method_accessibility( $subject, $method ); - $attributes = []; - - foreach ( $names as $name ) { - $attribute = Mockery::mock( 'WC_Product_Attribute' ); - - $attribute->shouldReceive( 'get_name' )->andReturn( $name ); - - $attributes[] = $attribute; - } - $product = Mockery::mock( 'WC_Product' ); - $product->shouldReceive( 'get_attributes' )->andReturn( $attributes ); + $product->shouldReceive( 'get_id' )->andReturn( $product_id ); $GLOBALS['product'] = $is_product ? $product : null; + WP_Mock::userFunction( 'get_post_meta' )->with( $product_id, '_product_attributes', true )->andReturn( $attributes ); + WP_Mock::passthruFunction( 'sanitize_title_with_dashes' ); + self::assertSame( $expected, $subject->$method( $title ) ); } @@ -821,8 +815,16 @@ public function dp_test_is_wc_product_attribute(): array { return [ 'not a product page' => [ 'атрибут 1', false, [], false ], 'no attributes' => [ 'атрибут 1', true, [], false ], - 'no matching' => [ 'атрибут 1', true, [ 'some' ], false ], - 'matching' => [ 'атрибут 1', true, [ 'some', 'атрибут 1' ], true ], + 'no matching' => [ 'атрибут 1', true, [ 'some' => [ 'name' => 'some' ] ], false ], + 'matching' => [ + 'атрибут 1', + true, + [ + 'some' => [ 'name' => 'some' ], + 'атрибут 1' => [ 'name' => 'атрибут 1' ], + ], + true, + ] ]; } From 6cfc651075e14761f3a8348d64c4f225b2babfb7 Mon Sep 17 00:00:00 2001 From: kagg-design Date: Wed, 14 Feb 2024 16:05:41 +0300 Subject: [PATCH 4/6] Bump up version. --- cyr-to-lat.php | 4 ++-- readme.txt | 5 +++-- tests/unit/bootstrap.php | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cyr-to-lat.php b/cyr-to-lat.php index 7a10818..2bcba31 100644 --- a/cyr-to-lat.php +++ b/cyr-to-lat.php @@ -10,7 +10,7 @@ * Plugin Name: Cyr-To-Lat * Plugin URI: https://wordpress.org/plugins/cyr2lat/ * Description: Convert Non-Latin characters in post and term slugs to Latin characters. Useful for creating human-readable URLs. Based on the original plugin by Anton Skorobogatov. - * Version: 6.0.7 + * Version: 6.0.8 * Requires at least: 5.1 * Requires PHP: 7.0.0 * Author: Sergey Biryukov, Mikhail Kobzarev, Igor Gergel @@ -43,7 +43,7 @@ /** * Plugin version. */ -define( 'CYR_TO_LAT_VERSION', '6.0.7' ); +define( 'CYR_TO_LAT_VERSION', '6.0.8' ); /** * Path to the plugin dir. diff --git a/readme.txt b/readme.txt index c07c99c..e115a07 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: SergeyBiryukov, mihdan, karevn, webvitaly, kaggdesign Tags: cyrillic, belorussian, ukrainian, bulgarian, macedonian, georgian, kazakh, latin, l10n, russian, cyr-to-lat, cyr2lat, rustolat, slugs, translations, transliteration Requires at least: 5.1 Tested up to: 6.4 -Stable tag: 6.0.7 +Stable tag: 6.0.8 Requires PHP: 7.0.0 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -221,8 +221,9 @@ Yes, you can! == Changelog == -= 6.0.8 = += 6.0.8 (14.02.2024) = * Improved detection of the Gutenberg editor. +* Fix processing of product attributes. = 6.0.7 (11.02.2024) = * Tested with WooCommerce 8.5. diff --git a/tests/unit/bootstrap.php b/tests/unit/bootstrap.php index 697b6ff..6dc83bd 100644 --- a/tests/unit/bootstrap.php +++ b/tests/unit/bootstrap.php @@ -39,7 +39,7 @@ /** * Plugin version. */ -const CYR_TO_LAT_TEST_VERSION = '6.0.7'; +const CYR_TO_LAT_TEST_VERSION = '6.0.8'; /** * Path to the plugin dir. From b7b5dd255b1eb01a2eb37137dce82786ec34b0b4 Mon Sep 17 00:00:00 2001 From: kagg-design Date: Wed, 14 Feb 2024 16:21:13 +0300 Subject: [PATCH 5/6] Fix fatal when adding the product to the cart. --- readme.txt | 2 +- src/php/Main.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.txt b/readme.txt index e115a07..fd790d8 100644 --- a/readme.txt +++ b/readme.txt @@ -223,7 +223,7 @@ Yes, you can! = 6.0.8 (14.02.2024) = * Improved detection of the Gutenberg editor. -* Fix processing of product attributes. +* Fixed processing of product attributes. = 6.0.7 (11.02.2024) = * Tested with WooCommerce 8.5. diff --git a/src/php/Main.php b/src/php/Main.php index 97f1a70..5e8959f 100644 --- a/src/php/Main.php +++ b/src/php/Main.php @@ -407,7 +407,7 @@ protected function is_wc_product_not_converted_attribute( string $title ): bool global $product; - if ( null === $product ) { + if ( ! is_a( $product, 'WC_Product' ) ) { return false; } From 60d8801dab577e02e93a73404506470ce1dfe337 Mon Sep 17 00:00:00 2001 From: kagg-design Date: Wed, 14 Feb 2024 16:29:29 +0300 Subject: [PATCH 6/6] WPCS. --- tests/unit/MainTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/MainTest.php b/tests/unit/MainTest.php index ea93e03..262d829 100644 --- a/tests/unit/MainTest.php +++ b/tests/unit/MainTest.php @@ -820,11 +820,11 @@ public function dp_test_is_wc_product_attribute(): array { 'атрибут 1', true, [ - 'some' => [ 'name' => 'some' ], + 'some' => [ 'name' => 'some' ], 'атрибут 1' => [ 'name' => 'атрибут 1' ], ], true, - ] + ], ]; }