From 8b17c7ccfbd5d4b031b2580cf474e4896fbc9e85 Mon Sep 17 00:00:00 2001 From: Vara Date: Mon, 11 Nov 2024 11:31:23 +0530 Subject: [PATCH 01/27] Add Admin user data to JetPack connected event --- includes/Listeners/Jetpack.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/includes/Listeners/Jetpack.php b/includes/Listeners/Jetpack.php index eefa761..9d38836 100644 --- a/includes/Listeners/Jetpack.php +++ b/includes/Listeners/Jetpack.php @@ -56,6 +56,7 @@ public function connected( $id, $secret, $is_public ) { array( 'id' => $id, 'public' => $is_public, + 'users' => array( $this, 'get_admin_users' ), ) ); } @@ -133,4 +134,31 @@ public function detect_plugin_activation( $plugin ) { update_option( 'jetpack_affiliate_code', $this->brand_code[ $brand ] ); } } + + /** + * Get Admin and SuperAdmin user accounts + * + * @return $users Array of Admin & Super Admin users + */ + private function get_admin_users() { + // Get all admin users + $admin_users = get_users([ + 'role' => 'administrator', + ]); + $users = []; + + // Add administrators to the $users and check for super admin + foreach ($admin_users as $user) { + $users[] = [ + 'id' => $user->ID, + 'username' => $user->user_login, + 'email' => $user->user_email, + 'name' => $user->display_name, + 'roles' => $user->roles, + 'super_admin' => is_super_admin($user->ID), + ]; + } + + return $users; + } } From 5b792ee0ac524e10cb697b2acc216590a44505a9 Mon Sep 17 00:00:00 2001 From: Vara Date: Mon, 11 Nov 2024 11:36:36 +0530 Subject: [PATCH 02/27] Fix lint issues --- includes/Listeners/Jetpack.php | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/includes/Listeners/Jetpack.php b/includes/Listeners/Jetpack.php index 9d38836..58387fc 100644 --- a/includes/Listeners/Jetpack.php +++ b/includes/Listeners/Jetpack.php @@ -56,7 +56,7 @@ public function connected( $id, $secret, $is_public ) { array( 'id' => $id, 'public' => $is_public, - 'users' => array( $this, 'get_admin_users' ), + 'users' => array( $this, 'get_admin_users' ), ) ); } @@ -142,21 +142,23 @@ public function detect_plugin_activation( $plugin ) { */ private function get_admin_users() { // Get all admin users - $admin_users = get_users([ - 'role' => 'administrator', - ]); - $users = []; + $admin_users = get_users( + array( + 'role' => 'administrator', + ) + ); + $users = array(); // Add administrators to the $users and check for super admin - foreach ($admin_users as $user) { - $users[] = [ - 'id' => $user->ID, - 'username' => $user->user_login, - 'email' => $user->user_email, - 'name' => $user->display_name, - 'roles' => $user->roles, - 'super_admin' => is_super_admin($user->ID), - ]; + foreach ( $admin_users as $user ) { + $users[] = array( + 'id' => $user->ID, + 'username' => $user->user_login, + 'email' => $user->user_email, + 'name' => $user->display_name, + 'roles' => $user->roles, + 'super_admin' => is_super_admin( $user->ID ), + ); } return $users; From 5a085844159f37c4a19176dc3fab4e4608af4735 Mon Sep 17 00:00:00 2001 From: Vara Date: Mon, 11 Nov 2024 16:43:45 +0530 Subject: [PATCH 03/27] Move the get admin user to Plugin Helper --- includes/Helpers/Plugin.php | 33 +++++++++++++++++++++++++++++++++ includes/Listeners/Jetpack.php | 30 ------------------------------ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/includes/Helpers/Plugin.php b/includes/Helpers/Plugin.php index 5d8855a..c6d7e51 100644 --- a/includes/Helpers/Plugin.php +++ b/includes/Helpers/Plugin.php @@ -66,6 +66,10 @@ public static function get_data( $basename, $data, $mu = false ) { $plugin['mu'] = $mu; $plugin['auto_updates'] = ( ! $mu && self::does_it_autoupdate( $basename ) ); + if (strpos($basename, 'jetpack') !== false) { + $plugin['users'] = self::get_admin_users(); + } + return $plugin; } @@ -87,4 +91,33 @@ public static function does_it_autoupdate( $slug ) { return in_array( $slug, $wp_auto_updates, true ); } + + /** + * Get Admin and SuperAdmin user accounts + * + * @return $users Array of Admin & Super Admin users + */ + private static function get_admin_users() { + // Get all admin users + $admin_users = get_users( + array( + 'role' => 'administrator', + ) + ); + $users = array(); + + // Add administrators to the $users and check for super admin + foreach ( $admin_users as $user ) { + $users[] = array( + 'id' => $user->ID, + 'username' => $user->user_login, + 'email' => $user->user_email, + 'name' => $user->display_name, + 'roles' => $user->roles, + 'super_admin' => is_super_admin( $user->ID ), + ); + } + + return $users; + } } diff --git a/includes/Listeners/Jetpack.php b/includes/Listeners/Jetpack.php index 58387fc..eefa761 100644 --- a/includes/Listeners/Jetpack.php +++ b/includes/Listeners/Jetpack.php @@ -56,7 +56,6 @@ public function connected( $id, $secret, $is_public ) { array( 'id' => $id, 'public' => $is_public, - 'users' => array( $this, 'get_admin_users' ), ) ); } @@ -134,33 +133,4 @@ public function detect_plugin_activation( $plugin ) { update_option( 'jetpack_affiliate_code', $this->brand_code[ $brand ] ); } } - - /** - * Get Admin and SuperAdmin user accounts - * - * @return $users Array of Admin & Super Admin users - */ - private function get_admin_users() { - // Get all admin users - $admin_users = get_users( - array( - 'role' => 'administrator', - ) - ); - $users = array(); - - // Add administrators to the $users and check for super admin - foreach ( $admin_users as $user ) { - $users[] = array( - 'id' => $user->ID, - 'username' => $user->user_login, - 'email' => $user->user_email, - 'name' => $user->display_name, - 'roles' => $user->roles, - 'super_admin' => is_super_admin( $user->ID ), - ); - } - - return $users; - } } From 24014557e88c8caccc85cea057d917c3911aa7bf Mon Sep 17 00:00:00 2001 From: Vara Date: Mon, 11 Nov 2024 16:45:02 +0530 Subject: [PATCH 04/27] Fix lint issues --- includes/Helpers/Plugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/Helpers/Plugin.php b/includes/Helpers/Plugin.php index c6d7e51..46e1a5b 100644 --- a/includes/Helpers/Plugin.php +++ b/includes/Helpers/Plugin.php @@ -66,8 +66,8 @@ public static function get_data( $basename, $data, $mu = false ) { $plugin['mu'] = $mu; $plugin['auto_updates'] = ( ! $mu && self::does_it_autoupdate( $basename ) ); - if (strpos($basename, 'jetpack') !== false) { - $plugin['users'] = self::get_admin_users(); + if ( strpos( $basename, 'jetpack' ) !== false ) { + $plugin['users'] = self::get_admin_users(); } return $plugin; From 96afb63a3d01c8da23f39eb51894d1ef78367066 Mon Sep 17 00:00:00 2001 From: Vara Date: Wed, 13 Nov 2024 07:05:07 +0530 Subject: [PATCH 05/27] Keep important fields only --- includes/Helpers/Plugin.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/includes/Helpers/Plugin.php b/includes/Helpers/Plugin.php index 46e1a5b..2cbd784 100644 --- a/includes/Helpers/Plugin.php +++ b/includes/Helpers/Plugin.php @@ -110,11 +110,7 @@ private static function get_admin_users() { foreach ( $admin_users as $user ) { $users[] = array( 'id' => $user->ID, - 'username' => $user->user_login, 'email' => $user->user_email, - 'name' => $user->display_name, - 'roles' => $user->roles, - 'super_admin' => is_super_admin( $user->ID ), ); } From 80a39609b2d3a06fb05fd685de7ec8f61664086b Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 13:53:20 -0800 Subject: [PATCH 06/27] Add `jetpack` plugin --- composer.json | 1 + composer.lock | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a5d8d2a..1b573dc 100644 --- a/composer.json +++ b/composer.json @@ -121,6 +121,7 @@ "lucatume/wp-browser": "^3.5.8", "newfold-labs/wp-php-standards": "^1.2.3", "phpunit/phpcov": "^5.0", + "wpackagist-plugin/jetpack": "^14.0", "wpackagist-plugin/woocommerce": ">=9" }, "extra": { diff --git a/composer.lock b/composer.lock index 9d16ab6..88be259 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4bbcb858d87850fac8c58931c178bed8", + "content-hash": "7bf05ebfcacc11c210f05f49d53be012", "packages": [ { "name": "doctrine/inflector", @@ -6123,6 +6123,24 @@ ], "time": "2024-03-25T16:39:00+00:00" }, + { + "name": "wpackagist-plugin/jetpack", + "version": "14.0", + "source": { + "type": "svn", + "url": "https://plugins.svn.wordpress.org/jetpack/", + "reference": "tags/14.0" + }, + "dist": { + "type": "zip", + "url": "https://downloads.wordpress.org/plugin/jetpack.14.0.zip" + }, + "require": { + "composer/installers": "^1.0 || ^2.0" + }, + "type": "wordpress-plugin", + "homepage": "https://wordpress.org/plugins/jetpack/" + }, { "name": "wpackagist-plugin/woocommerce", "version": "9.0.0", From 7143ee39a9019326ec4f81f0fd8e1f2c2b84d662 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 14:06:37 -0800 Subject: [PATCH 07/27] Change `static` to instance methods --- includes/Helpers/Plugin.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/includes/Helpers/Plugin.php b/includes/Helpers/Plugin.php index 2cbd784..aa3fb86 100644 --- a/includes/Helpers/Plugin.php +++ b/includes/Helpers/Plugin.php @@ -13,13 +13,13 @@ class Plugin { * * @return array{slug:string, version:string, title:string, url:string, active:bool, mu:bool, auto_updates:bool} Hiive relevant plugin details */ - public static function collect( $basename ) { + public function collect( $basename ) { if ( ! function_exists( 'get_plugin_data' ) ) { require wp_normalize_path( constant( 'ABSPATH' ) . '/wp-admin/includes/plugin.php' ); } - return self::get_data( $basename, get_plugin_data( constant( 'WP_PLUGIN_DIR' ) . '/' . $basename ) ); + return $this->get_data( $basename, get_plugin_data( constant( 'WP_PLUGIN_DIR' ) . '/' . $basename ) ); } /** @@ -27,7 +27,7 @@ public static function collect( $basename ) { * * @return array of plugins */ - public static function collect_installed() { + public function collect_installed() { if ( ! function_exists( 'get_plugins' ) ) { require wp_normalize_path( constant( 'ABSPATH' ) . '/wp-admin/includes/plugin.php' ); } @@ -36,12 +36,12 @@ public static function collect_installed() { // Collect standard plugins foreach ( get_plugins() as $slug => $data ) { - array_push( $plugins, self::get_data( $slug, $data ) ); + array_push( $plugins, $this->get_data( $slug, $data ) ); } // Collect mu plugins foreach ( get_mu_plugins() as $slug => $data ) { - array_push( $plugins, self::get_data( $slug, $data, true ) ); + array_push( $plugins, $this->get_data( $slug, $data, true ) ); } return $plugins; @@ -56,7 +56,7 @@ public static function collect_installed() { * * @return array{slug:string, version:string, title:string, url:string, active:bool, mu:bool, auto_updates:bool} Hiive relevant plugin details */ - public static function get_data( $basename, $data, $mu = false ) { + public function get_data( $basename, $data, $mu = false ) { $plugin = array(); $plugin['slug'] = $basename; $plugin['version'] = $data['Version'] ? $data['Version'] : '0.0'; @@ -64,10 +64,10 @@ public static function get_data( $basename, $data, $mu = false ) { $plugin['url'] = $data['PluginURI'] ? $data['PluginURI'] : ''; $plugin['active'] = is_plugin_active( $basename ); $plugin['mu'] = $mu; - $plugin['auto_updates'] = ( ! $mu && self::does_it_autoupdate( $basename ) ); + $plugin['auto_updates'] = ( ! $mu && $this->does_it_autoupdate( $basename ) ); - if ( strpos( $basename, 'jetpack' ) !== false ) { - $plugin['users'] = self::get_admin_users(); + if ( strpos( $basename, 'jetpack/jetpack.php' ) !== false ) { + $plugin['users'] = $this->get_admin_users(); } return $plugin; @@ -80,7 +80,7 @@ public static function get_data( $basename, $data, $mu = false ) { * * @return bool */ - public static function does_it_autoupdate( $slug ) { + protected function does_it_autoupdate( string $slug ): bool { // Check plugin setting for auto updates on all plugins if ( get_site_option( 'auto_update_plugin', 'true' ) ) { return true; @@ -97,7 +97,7 @@ public static function does_it_autoupdate( $slug ) { * * @return $users Array of Admin & Super Admin users */ - private static function get_admin_users() { + protected function get_admin_users(): array { // Get all admin users $admin_users = get_users( array( From 74d5a28c4ccf67ad551a50803ab27d10d9381f62 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 14:07:59 -0800 Subject: [PATCH 08/27] Add types --- includes/Helpers/Plugin.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/includes/Helpers/Plugin.php b/includes/Helpers/Plugin.php index aa3fb86..6a0cbc2 100644 --- a/includes/Helpers/Plugin.php +++ b/includes/Helpers/Plugin.php @@ -4,6 +4,8 @@ /** * Helper class for gathering and formatting plugin data + * + * @phpstan-type plugin-array array{slug:string, version:string, title:string, url:string, active:bool, mu:bool, auto_updates:bool, users?:array} */ class Plugin { /** @@ -11,9 +13,9 @@ class Plugin { * * @param string $basename The plugin basename (filename relative to WP_PLUGINS_DIR). * - * @return array{slug:string, version:string, title:string, url:string, active:bool, mu:bool, auto_updates:bool} Hiive relevant plugin details + * @return plugin-array Hiive relevant plugin details */ - public function collect( $basename ) { + public function collect( $basename ): array { if ( ! function_exists( 'get_plugin_data' ) ) { require wp_normalize_path( constant( 'ABSPATH' ) . '/wp-admin/includes/plugin.php' ); @@ -25,9 +27,9 @@ public function collect( $basename ) { /** * Prepare plugin data for all plugins * - * @return array of plugins + * @return array of plugins */ - public function collect_installed() { + public function collect_installed(): array { if ( ! function_exists( 'get_plugins' ) ) { require wp_normalize_path( constant( 'ABSPATH' ) . '/wp-admin/includes/plugin.php' ); } @@ -54,9 +56,9 @@ public function collect_installed() { * @param array $data The plugin meta-data from its header. * @param bool $mu Whether the plugin is installed as a must-use plugin. * - * @return array{slug:string, version:string, title:string, url:string, active:bool, mu:bool, auto_updates:bool} Hiive relevant plugin details + * @return plugin-array Hiive relevant plugin details */ - public function get_data( $basename, $data, $mu = false ) { + public function get_data( string $basename, array $data, bool $mu = false ): array { $plugin = array(); $plugin['slug'] = $basename; $plugin['version'] = $data['Version'] ? $data['Version'] : '0.0'; @@ -77,8 +79,6 @@ public function get_data( $basename, $data, $mu = false ) { * Whether the plugin is set to auto update * * @param string $slug Name of the plugin - * - * @return bool */ protected function does_it_autoupdate( string $slug ): bool { // Check plugin setting for auto updates on all plugins @@ -95,7 +95,7 @@ protected function does_it_autoupdate( string $slug ): bool { /** * Get Admin and SuperAdmin user accounts * - * @return $users Array of Admin & Super Admin users + * @return array $users Array of Admin & Super Admin users */ protected function get_admin_users(): array { // Get all admin users @@ -109,8 +109,8 @@ protected function get_admin_users(): array { // Add administrators to the $users and check for super admin foreach ( $admin_users as $user ) { $users[] = array( - 'id' => $user->ID, - 'email' => $user->user_email, + 'id' => $user->ID, + 'email' => $user->user_email, ); } From de93bed6c0d41679259ce19e1ba5256cc3abf322 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 14:22:11 -0800 Subject: [PATCH 09/27] Create PluginWPUnitTest.php --- .../includes/Helpers/PluginWPUnitTest.php | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 tests/wpunit/includes/Helpers/PluginWPUnitTest.php diff --git a/tests/wpunit/includes/Helpers/PluginWPUnitTest.php b/tests/wpunit/includes/Helpers/PluginWPUnitTest.php new file mode 100644 index 0000000..a187180 --- /dev/null +++ b/tests/wpunit/includes/Helpers/PluginWPUnitTest.php @@ -0,0 +1,68 @@ +collect('bluehost-wordpress-plugin/bluehost-wordpress-plugin.php'); + + $this->assertEquals('The Bluehost Plugin', $result['title']); + $this->assertEqualSets(['slug','version','title','url','active','mu','auto_updates'], array_keys($result)); + } + + /** + * @covers ::collect + * @covers ::get_data + * @covers ::get_admin_users + */ + public function test_collect_jetpack(): void { + $new_user_id = wp_create_user('admin2', 'password', 'email@example.com'); + $new_user = new \WP_User($new_user_id); + $new_user->add_role('administrator'); + + $sut = new Plugin(); + + $result = $sut->collect('jetpack/jetpack.php'); + + $this->assertEqualSets(['slug','version','title','url','active','mu','auto_updates','users',], array_keys($result)); + + $this->assertCount(2, $result['users']); + + $this->assertEqualSets(['id','email',], array_keys($result['users'][1])); + } + + /** + * @covers ::collect_installed + */ + public function test_collect_installed(): void { + $sut = new Plugin(); + + $result = $sut->collect_installed(); + + $this->assertGreaterThan(2, count($result)); + } +} From 1b79ec000aa406a9ed3d371c502ba78ee372c74f Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 14:22:30 -0800 Subject: [PATCH 10/27] Add `WP_CONTENT_DIR` to use Composer installed plugins in tests --- tests/wpunit.suite.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/wpunit.suite.yml b/tests/wpunit.suite.yml index b86627a..be14fef 100644 --- a/tests/wpunit.suite.yml +++ b/tests/wpunit.suite.yml @@ -19,4 +19,5 @@ modules: activatePlugins: [] WP_HTTP_BLOCK_EXTERNAL: true + WP_CONTENT_DIR: "wp-content" bootstrap: _bootstrap.php From 38d0ee8777a8adcbadd23c8bedbb632e3fc5f293 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 14:53:39 -0800 Subject: [PATCH 11/27] Use `isset()` --- includes/Helpers/Plugin.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/Helpers/Plugin.php b/includes/Helpers/Plugin.php index 6a0cbc2..dd8203a 100644 --- a/includes/Helpers/Plugin.php +++ b/includes/Helpers/Plugin.php @@ -61,9 +61,9 @@ public function collect_installed(): array { public function get_data( string $basename, array $data, bool $mu = false ): array { $plugin = array(); $plugin['slug'] = $basename; - $plugin['version'] = $data['Version'] ? $data['Version'] : '0.0'; - $plugin['title'] = $data['Name'] ? $data['Name'] : ''; - $plugin['url'] = $data['PluginURI'] ? $data['PluginURI'] : ''; + $plugin['version'] = isset( $data['Version'] ) ? $data['Version'] : '0.0'; + $plugin['title'] = isset( $data['Name'] ) ? $data['Name'] : ''; + $plugin['url'] = isset( $data['PluginURI'] ) ? $data['PluginURI'] : ''; $plugin['active'] = is_plugin_active( $basename ); $plugin['mu'] = $mu; $plugin['auto_updates'] = ( ! $mu && $this->does_it_autoupdate( $basename ) ); From 0d2b3b6587086e14e1450316a9eacd3470b2f895 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 14:54:47 -0800 Subject: [PATCH 12/27] Strict compare the value, otherwise '"false"' would evaluate to 'true' --- includes/Helpers/Plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Helpers/Plugin.php b/includes/Helpers/Plugin.php index dd8203a..9d3643a 100644 --- a/includes/Helpers/Plugin.php +++ b/includes/Helpers/Plugin.php @@ -82,7 +82,7 @@ public function get_data( string $basename, array $data, bool $mu = false ): arr */ protected function does_it_autoupdate( string $slug ): bool { // Check plugin setting for auto updates on all plugins - if ( get_site_option( 'auto_update_plugin', 'true' ) ) { + if ( 'true' === get_site_option( 'auto_update_plugin', 'true' ) ) { return true; } From 0363f528ddf198f8aca038cd7103664addc6cec4 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 14:55:13 -0800 Subject: [PATCH 13/27] Add tests for `NewfoldLabs\WP\Module\Data\Helpers\Plugin` --- tests/phpunit/includes/Helpers/PluginTest.php | 73 +++++++++++++++++++ .../includes/Helpers/PluginWPUnitTest.php | 48 ++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 tests/phpunit/includes/Helpers/PluginTest.php diff --git a/tests/phpunit/includes/Helpers/PluginTest.php b/tests/phpunit/includes/Helpers/PluginTest.php new file mode 100644 index 0000000..026464d --- /dev/null +++ b/tests/phpunit/includes/Helpers/PluginTest.php @@ -0,0 +1,73 @@ +once() + ->andReturn( array( + + ) ); + WP_Mock::userFunction( 'is_plugin_active' ) + ->once() + ->andReturnTrue(); + + WP_Mock::userFunction( 'get_site_option' ) + ->once() + ->with('auto_update_plugin', 'true') + ->andReturnTrue(); + + $sut->collect( 'bluehost-wordpress-plugin/bluehost-wordpress-plugin.php' ); + + $this->assertConditionsMet(); + } +} diff --git a/tests/wpunit/includes/Helpers/PluginWPUnitTest.php b/tests/wpunit/includes/Helpers/PluginWPUnitTest.php index a187180..7bb5f50 100644 --- a/tests/wpunit/includes/Helpers/PluginWPUnitTest.php +++ b/tests/wpunit/includes/Helpers/PluginWPUnitTest.php @@ -65,4 +65,52 @@ public function test_collect_installed(): void { $this->assertGreaterThan(2, count($result)); } + + /** + * @see wp_ajax_toggle_auto_updates() + */ + protected function set_autoupdate(string $basename, bool $enabled): void { + + $state = $enabled ? 'enable' : 'disable'; + + $auto_updates = (array) get_site_option( 'auto_update_plugins', array() ); + $all_plugins = get_plugins(); + + if ( 'disable' === $state ) { + $auto_updates = array_diff( $auto_updates, array( $basename ) ); + } else { + $auto_updates[] = $basename; + $auto_updates = array_unique( $auto_updates ); + } + + $auto_updates = array_intersect( $auto_updates, array_keys( $all_plugins ) ); + + update_site_option( 'auto_update_plugins', $auto_updates ); + } + + /** + * @covers ::does_it_autoupdate + */ + public function test_does_it_autoupdate(): void { + $sut = new Plugin(); + + $this->set_autoupdate('bluehost-wordpress-plugin/bluehost-wordpress-plugin.php', true); + $this->set_autoupdate('jetpack/jetpack.php', false); + + $this->assertTrue($sut->collect('bluehost-wordpress-plugin/bluehost-wordpress-plugin.php')['auto_updates']); + $this->assertFalse($sut->collect('jetpack/jetpack.php')['auto_updates']); + } + + /** + * @covers ::does_it_autoupdate + */ + public function test_does_it_autoupdate_all(): void { + $sut = new Plugin(); + + add_site_option('auto_update_plugin', 'false'); + + $this->set_autoupdate('bluehost-wordpress-plugin/bluehost-wordpress-plugin.php', false); + + $this->assertTrue($sut->collect('bluehost-wordpress-plugin/bluehost-wordpress-plugin.php')['auto_updates']); + } } From dd41adbc0d70161261f33512717ecbf38a932325 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 14:55:18 -0800 Subject: [PATCH 14/27] Update patchwork.json --- patchwork.json | 1 + 1 file changed, 1 insertion(+) diff --git a/patchwork.json b/patchwork.json index 6a91263..f7e6eb4 100644 --- a/patchwork.json +++ b/patchwork.json @@ -3,6 +3,7 @@ "defined", "constant", "file_get_contents", + "function_exists", "time" ] } From db8d4383b24aa291e6b968f8c5eca80afffb2cf7 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 15:02:28 -0800 Subject: [PATCH 15/27] Update clients to use instance of class rather than static methods --- includes/HiiveConnection.php | 2 +- includes/Listeners/Cron.php | 2 +- includes/Listeners/Plugin.php | 31 +++++++++++++++++++++++++------ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/includes/HiiveConnection.php b/includes/HiiveConnection.php index f9a7a77..576f524 100644 --- a/includes/HiiveConnection.php +++ b/includes/HiiveConnection.php @@ -144,7 +144,7 @@ public function connect( string $path = '/sites/v2/connect', ?string $authorizat $data = $this->get_core_data(); $data['verify_token'] = $token; - $data['plugins'] = PluginHelper::collect_installed(); + $data['plugins'] = ( new PluginHelper() )->collect_installed(); $args = array( 'body' => \wp_json_encode( $data ), diff --git a/includes/Listeners/Cron.php b/includes/Listeners/Cron.php index ba8bc47..ddc1bd1 100644 --- a/includes/Listeners/Cron.php +++ b/includes/Listeners/Cron.php @@ -43,7 +43,7 @@ public function register_hooks(): void { */ public function update(): void { $data = array( - 'plugins' => Plugin::collect_installed(), + 'plugins' => ( new Plugin() )->collect_installed(), ); $data = apply_filters( 'newfold_wp_data_module_cron_data_filter', $data ); diff --git a/includes/Listeners/Plugin.php b/includes/Listeners/Plugin.php index d74534c..82f7e37 100644 --- a/includes/Listeners/Plugin.php +++ b/includes/Listeners/Plugin.php @@ -2,6 +2,7 @@ namespace NewfoldLabs\WP\Module\Data\Listeners; +use NewfoldLabs\WP\Module\Data\EventManager; use NewfoldLabs\WP\Module\Data\Helpers\Transient; use NewfoldLabs\WP\Module\Data\Helpers\Plugin as PluginHelper; @@ -9,6 +10,24 @@ * Monitors generic plugin events */ class Plugin extends Listener { + + /** + * Functions for gathering plugin data + * + * @var PluginHelper + */ + protected $plugin_helper; + + /** + * Constructor + * + * @param EventManager $manager Event manager instance + */ + public function __construct( EventManager $manager ) { + parent::__construct( $manager ); + $this->plugin_helper = new PluginHelper(); + } + /** * Register the hooks for the subscriber * @@ -42,7 +61,7 @@ public function register_hooks() { */ public function activated( $plugin, $network_wide ) { $data = array( - 'plugin' => PluginHelper::collect( $plugin ), + 'plugin' => $this->plugin_helper->collect( $plugin ), 'network_wide' => $network_wide, ); $this->push( 'plugin_activated', $data ); @@ -58,7 +77,7 @@ public function activated( $plugin, $network_wide ) { */ public function deactivated( $plugin, $network_wide ) { $data = array( - 'plugin' => PluginHelper::collect( $plugin ), + 'plugin' => $this->plugin_helper->collect( $plugin ), 'network_wide' => $network_wide, ); @@ -76,7 +95,7 @@ public function deactivated( $plugin, $network_wide ) { * @return void */ public function save_deleted( $plugin ) { - update_option( 'deleted_plugin', PluginHelper::collect( $plugin ) ); + update_option( 'deleted_plugin', $this->plugin_helper->collect( $plugin ) ); } /** @@ -137,12 +156,12 @@ protected function updated( array $options ): void { // Manual updates always return array of plugin slugs if ( isset( $options['plugins'] ) && is_array( $options['plugins'] ) ) { foreach ( $options['plugins'] as $slug ) { - array_push( $plugins, PluginHelper::collect( $slug ) ); + array_push( $plugins, $this->plugin_helper->collect( $slug ) ); } } // Auto updates always return a single plugin slug if ( isset( $options['plugin'] ) ) { - array_push( $plugins, PluginHelper::collect( $options['plugin'] ) ); + array_push( $plugins, $this->plugin_helper->collect( $options['plugin'] ) ); } $data = array( @@ -159,7 +178,7 @@ protected function updated( array $options ): void { */ public function installed() { $data = array( - 'plugins' => PluginHelper::collect_installed(), + 'plugins' => $this->plugin_helper->collect_installed(), ); $this->push( 'plugin_installed', $data ); } From 263222f8441d7314fc49ce8bbd2943d4c8251c30 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 15:02:45 -0800 Subject: [PATCH 16/27] Update tests after `auto_update_plugin` fix --- tests/phpunit/includes/Helpers/PluginTest.php | 5 +++++ tests/wpunit/includes/Helpers/PluginWPUnitTest.php | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/phpunit/includes/Helpers/PluginTest.php b/tests/phpunit/includes/Helpers/PluginTest.php index 026464d..3da9512 100644 --- a/tests/phpunit/includes/Helpers/PluginTest.php +++ b/tests/phpunit/includes/Helpers/PluginTest.php @@ -66,6 +66,11 @@ function ( string $function_name ) { ->with('auto_update_plugin', 'true') ->andReturnTrue(); + WP_Mock::userFunction( 'get_site_option' ) + ->once() + ->with('auto_update_plugins', \WP_Mock\Functions::type( 'array' )) + ->andReturn(array()); + $sut->collect( 'bluehost-wordpress-plugin/bluehost-wordpress-plugin.php' ); $this->assertConditionsMet(); diff --git a/tests/wpunit/includes/Helpers/PluginWPUnitTest.php b/tests/wpunit/includes/Helpers/PluginWPUnitTest.php index 7bb5f50..2a520eb 100644 --- a/tests/wpunit/includes/Helpers/PluginWPUnitTest.php +++ b/tests/wpunit/includes/Helpers/PluginWPUnitTest.php @@ -94,6 +94,8 @@ protected function set_autoupdate(string $basename, bool $enabled): void { public function test_does_it_autoupdate(): void { $sut = new Plugin(); + add_site_option('auto_update_plugin', 'false'); + $this->set_autoupdate('bluehost-wordpress-plugin/bluehost-wordpress-plugin.php', true); $this->set_autoupdate('jetpack/jetpack.php', false); @@ -107,7 +109,7 @@ public function test_does_it_autoupdate(): void { public function test_does_it_autoupdate_all(): void { $sut = new Plugin(); - add_site_option('auto_update_plugin', 'false'); + add_site_option('auto_update_plugin', 'true'); $this->set_autoupdate('bluehost-wordpress-plugin/bluehost-wordpress-plugin.php', false); From 038b60fd312e4de910529036a7bface0bd59f406 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 15:03:59 -0800 Subject: [PATCH 17/27] Add default paths so it runs without parameters --- phpcs.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phpcs.xml b/phpcs.xml index e1bf8e0..b074744 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -3,4 +3,8 @@ + + + ./includes + ./upgrades From 67f252a538c985e6436a0612572d91354713e60a Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 15:05:35 -0800 Subject: [PATCH 18/27] Phive install `brianhenryie/php-diff-test` --- .phive/phars.xml | 4 ++++ tools/php-diff-test | 1 + 2 files changed, 5 insertions(+) create mode 100644 .phive/phars.xml create mode 120000 tools/php-diff-test diff --git a/.phive/phars.xml b/.phive/phars.xml new file mode 100644 index 0000000..6869f4f --- /dev/null +++ b/.phive/phars.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tools/php-diff-test b/tools/php-diff-test new file mode 120000 index 0000000..7b0621b --- /dev/null +++ b/tools/php-diff-test @@ -0,0 +1 @@ +/Users/brian.henry/.phive/phars/brianhenryie/php-diff-test-0.7.1.phar \ No newline at end of file From 0f89d2eb3ca46cb0c014d4949158c0f144c305ab Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Fri, 15 Nov 2024 15:44:21 -0800 Subject: [PATCH 19/27] Revert "Phive install `brianhenryie/php-diff-test`" This reverts commit 67f252a538c985e6436a0612572d91354713e60a. --- .phive/phars.xml | 4 ---- tools/php-diff-test | 1 - 2 files changed, 5 deletions(-) delete mode 100644 .phive/phars.xml delete mode 120000 tools/php-diff-test diff --git a/.phive/phars.xml b/.phive/phars.xml deleted file mode 100644 index 6869f4f..0000000 --- a/.phive/phars.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/tools/php-diff-test b/tools/php-diff-test deleted file mode 120000 index 7b0621b..0000000 --- a/tools/php-diff-test +++ /dev/null @@ -1 +0,0 @@ -/Users/brian.henry/.phive/phars/brianhenryie/php-diff-test-0.7.1.phar \ No newline at end of file From 1af8eb2c76f897fbb8f870a81eecb380b97b38b2 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Mon, 18 Nov 2024 09:29:08 -0800 Subject: [PATCH 20/27] Allow injecting `Helpers/Plugin` --- includes/Listeners/Plugin.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/includes/Listeners/Plugin.php b/includes/Listeners/Plugin.php index 82f7e37..1bbc4c4 100644 --- a/includes/Listeners/Plugin.php +++ b/includes/Listeners/Plugin.php @@ -21,11 +21,15 @@ class Plugin extends Listener { /** * Constructor * - * @param EventManager $manager Event manager instance + * @param EventManager $manager Event manager instance + * @param ?PluginHelper $plugin_helper Class used to fetch plugin data. */ - public function __construct( EventManager $manager ) { + public function __construct( + EventManager $manager, + ?PluginHelper $plugin_helper = null + ) { parent::__construct( $manager ); - $this->plugin_helper = new PluginHelper(); + $this->plugin_helper = $plugin_helper ?? new PluginHelper(); } /** From 3626318c312dc29f881d1d9a5e77cc7d41a2f691 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Mon, 18 Nov 2024 09:53:50 -0800 Subject: [PATCH 21/27] Use Mockery instead of Patchwork. --- .../phpunit/includes/Listeners/PluginTest.php | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/tests/phpunit/includes/Listeners/PluginTest.php b/tests/phpunit/includes/Listeners/PluginTest.php index 95f5599..cabe175 100644 --- a/tests/phpunit/includes/Listeners/PluginTest.php +++ b/tests/phpunit/includes/Listeners/PluginTest.php @@ -4,6 +4,7 @@ use Mockery; use NewfoldLabs\WP\Module\Data\EventManager; +use NewfoldLabs\WP\Module\Data\Helpers\Plugin as Plugin_Helper; use WP_Mock; /** @@ -17,8 +18,6 @@ class PluginTest extends \WP_Mock\Tools\TestCase { public function tearDown(): void { parent::tearDown(); - \Patchwork\restoreAll(); - unset( $_SERVER['REMOTE_ADDR'] ); unset( $_SERVER['REQUEST_URI'] ); } @@ -33,16 +32,18 @@ public function tearDown(): void { public function upgrader_process_complete_data_provider(): array { return array( array( - 'plugins' => array( + 'plugins' => array( 'bluehost-wordpress-plugin/bluehost-wordpress-plugin.php', ), - 'expect_push_times' => 1, + 'expected_count_collect' => 1, + 'expect_push_times' => 1, ), array( - 'plugins' => array( + 'plugins' => array( '', ), - 'expect_push_times' => 0, + 'expected_count_collect' => 0, + 'expect_push_times' => 0, ), ); } @@ -63,7 +64,7 @@ public function upgrader_process_complete_data_provider(): array { * @param array $plugins The plugins value sent to the `upgrader_process_complete` action. * @param int $expect_push_times The number of times the `push` method should be called. I.e. 0 when there is no plugin. */ - public function test_upgrader_process_complete_fired( array $plugins, int $expect_push_times ): void { + public function test_upgrader_process_complete_fired( array $plugins, int $expected_count_collect, int $expect_push_times ): void { /** * It is difficult to mock the `Plugin_Upgrader` class, so we will just pass `null` for now. @@ -79,10 +80,8 @@ public function test_upgrader_process_complete_fired( array $plugins, int $expec 'plugins' => $plugins, ); - $event_manager = Mockery::mock( EventManager::class ); - $event_manager->expects( 'push' )->times( $expect_push_times ); - - $sut = new Plugin( $event_manager ); + $event_manager_mock = Mockery::mock( EventManager::class ); + $event_manager_mock->expects( 'push' )->times( $expect_push_times ); /** * This will only be called if the plugin is not empty, meaning we don't test with the current problematic @@ -100,13 +99,13 @@ public function test_upgrader_process_complete_fired( array $plugins, int $expec 'auto_updates' => true, ); - \Patchwork\redefine( - array( \NewfoldLabs\WP\Module\Data\Helpers\Plugin::class, 'collect' ), - function () use ( $plugin_collected ) { - return $plugin_collected; - } - ); + $plugin_helper_mock = Mockery::mock( Plugin_Helper::class )->makePartial(); + $plugin_helper_mock->shouldReceive( 'collect' ) + ->times( $expected_count_collect ) + ->with( 'bluehost-wordpress-plugin/bluehost-wordpress-plugin.php' ) + ->andReturn( $plugin_collected ); + $sut = new Plugin( $event_manager_mock, $plugin_helper_mock ); /** * The Event constructor calls a lot of WordPress functions to determine the environment. * From d10b59b4dd22ddc67a8a3b659776cb234862423f Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Mon, 18 Nov 2024 12:19:38 -0800 Subject: [PATCH 22/27] Update deprecated diff filter config --- .github/workflows/lint.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a9f738e..63b695c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -34,7 +34,7 @@ jobs: - uses: technote-space/get-diff-action@v6 # repo is archived. with: - SUFFIX_FILTER: .php + PATTERNS: ./**/*.php - name: Get Composer cache directory id: composer-cache @@ -68,5 +68,5 @@ jobs: GITHUB_TOKEN: "${{ github.token }}" - name: Detecting PHP Code Standards Violations - run: vendor/bin/phpcs --standard=phpcs.xml -s ${{ env.GIT_DIFF }} --report=checkstyle | cs2pr - if: "!! env.GIT_DIFF" + run: vendor/bin/phpcs --standard=phpcs.xml -s ${{ env.GIT_DIFF_FILTERED }} --report=checkstyle | cs2pr + if: "!! env.GIT_DIFF_FILTERED" From 6436c2b10cd2228fa79abb6a1a2f147f98688f24 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Mon, 18 Nov 2024 12:32:45 -0800 Subject: [PATCH 23/27] Use diff in `compose cs-changes` script --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1b573dc..84255c0 100644 --- a/composer.json +++ b/composer.json @@ -71,7 +71,7 @@ "vendor/bin/phpcbf . --standard=phpcs.xml" ], "cs-changes": [ - "updated_files=$( git status | grep '\\(new file\\|modified\\):\\s.*.php$' | cut -c14- | awk '{ printf(\"%s \", $0) }' ); echo \"\\nChecking\"$(git status | grep '\\(new file\\|modified\\):\\s.*.php$' | tail -n+2 | wc -l)\" files\"; phpcbf $(echo $updated_files); phpcs $(echo $updated_files);" + "updated_files=$(echo $(git diff --name-only `git merge-base origin/main HEAD` | grep php)); if [ -n \"$updated_files\" ]; then phpcbf $(echo $updated_files); phpcs $(echo $updated_files); else echo \"No modified .php files for PHPCS.\"; fi;" ], "lint": [ "vendor/bin/phpcs . --standard=phpcs.xml -s" From dda58c884f57f1fee47106a9c035c09baa96d4cc Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Mon, 18 Nov 2024 12:32:59 -0800 Subject: [PATCH 24/27] Show progress and sniff codes in all reports --- phpcs.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phpcs.xml b/phpcs.xml index 1c6f8e2..8d5883c 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -7,4 +7,7 @@ includes upgrades + + + From 85c4630d7a53993c69f5d402d9eea3db7db273a8 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Mon, 18 Nov 2024 12:33:20 -0800 Subject: [PATCH 25/27] =?UTF-8?q?Remove=20TODO=20=E2=80=93=20covered=20by?= =?UTF-8?q?=20a=20broad=20Jira=20ticket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- includes/HiiveConnection.php | 1 - 1 file changed, 1 deletion(-) diff --git a/includes/HiiveConnection.php b/includes/HiiveConnection.php index 576f524..4d6e0d4 100644 --- a/includes/HiiveConnection.php +++ b/includes/HiiveConnection.php @@ -260,7 +260,6 @@ public function send_event( Event $event ) { $hiive_response = $this->hiive_request( 'sites/v1/events', $payload ); if ( is_wp_error( $hiive_response ) ) { - // TODO: enqueue failed event for later. Should this function call go via EventManager? return $hiive_response; } From 0db708466ec373f13a7051b88727e96ff3567ab3 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Mon, 18 Nov 2024 12:33:37 -0800 Subject: [PATCH 26/27] `phpcs:ignore` the verify token, which is a nonce --- includes/HiiveConnection.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/includes/HiiveConnection.php b/includes/HiiveConnection.php index 4d6e0d4..abb2ecb 100644 --- a/includes/HiiveConnection.php +++ b/includes/HiiveConnection.php @@ -78,17 +78,23 @@ public function rest_api_init(): void { * * Hiive will first attempt to verify using the REST API, and fallback to this AJAX endpoint on error. * + * Token is generated in {@see self::connect()} using {@see md5()}. + * * @hooked wp_ajax_nopriv_nfd-hiive-verify * * @return never */ public function ajax_verify() { - $valid = $this->verify_token( $_REQUEST['token'] ); - $status = ( $valid ) ? 200 : 400; + // PHPCS: Ignore the nonce verification here – the token _is_ a nonce. + // @phpcs:ignore WordPress.Security.NonceVerification.Recommended + $token = $_REQUEST['token']; + + $is_valid = $this->verify_token( $token ); + $status = ( $is_valid ) ? 200 : 400; $data = array( - 'token' => $_REQUEST['token'], - 'valid' => $valid, + 'token' => $token, + 'valid' => $is_valid, ); \wp_send_json( $data, $status ); } @@ -96,6 +102,8 @@ public function ajax_verify() { /** * Confirm whether verification token is valid * + * Token is generated in {@see self::connect()} using {@see md5()}. + * * @param string $token Token to verify */ public function verify_token( string $token ): bool { From 5ec6f299f16a1fc23689c452fd7cbe64dffc0521 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Mon, 18 Nov 2024 12:35:07 -0800 Subject: [PATCH 27/27] Rename `codecoverage-main` to `unit-tests` --- .github/workflows/unit-tests-and-coverage-report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests-and-coverage-report.yml b/.github/workflows/unit-tests-and-coverage-report.yml index ef254c0..66493ff 100644 --- a/.github/workflows/unit-tests-and-coverage-report.yml +++ b/.github/workflows/unit-tests-and-coverage-report.yml @@ -15,7 +15,7 @@ on: jobs: - codecoverage-main: + unit-tests: runs-on: ubuntu-latest services: