PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.2
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.2
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / src / integrations / watchers / addon-update-watcher.php

addon-update-watcher.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 18.2, at src/integrations/watchers/addon-update-watcher.php

222 lines 7.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Yoast\WP\SEO\Integrations\Watchers;
4
5 use Yoast\WP\SEO\Conditionals\Admin_Conditional;
6 use Yoast\WP\SEO\Integrations\Integration_Interface;
7
8 /**
9 * Enables Yoast add-on auto updates when Yoast SEO is enabled and the other way around.
10 *
11 * Also removes the auto-update toggles from the Yoast SEO add-ons.
12 */
13 class Addon_Update_Watcher implements Integration_Interface {
14
15 /**
16 * ID string used by WordPress to identify the free plugin.
17 *
18 * @var string
19 */
20 const WPSEO_FREE_PLUGIN_ID = 'wordpress-seo/wp-seo.php';
21
22 /**
23 * A list of Yoast add-on identifiers.
24 *
25 * @var string[]
26 */
27 const ADD_ON_PLUGIN_FILES = [
28 'wordpress-seo-premium/wp-seo-premium.php',
29 'wpseo-video/video-seo.php',
30 'wpseo-local/local-seo.php', // When installing Local through a released zip, the path is different from the path on a dev environment.
31 'wpseo-woocommerce/wpseo-woocommerce.php',
32 'wpseo-news/wpseo-news.php',
33 'acf-content-analysis-for-yoast-seo/yoast-acf-analysis.php', // When installing ACF for Yoast through a released zip, the path is different from the path on a dev environment.
34 ];
35
36 /**
37 * Registers the hooks.
38 */
39 public function register_hooks() {
40 \add_action( 'add_site_option_auto_update_plugins', [ $this, 'call_toggle_auto_updates_with_empty_array' ], 10, 2 );
41 \add_action( 'update_site_option_auto_update_plugins', [ $this, 'toggle_auto_updates_for_add_ons' ], 10, 3 );
42 \add_filter( 'plugin_auto_update_setting_html', [ $this, 'replace_auto_update_toggles_of_addons' ], 10, 2 );
43 \add_action( 'activated_plugin', [ $this, 'maybe_toggle_auto_updates_for_new_install' ] );
44 }
45
46 /**
47 * Returns the conditionals based on which this loadable should be active.
48 *
49 * @return string[] The conditionals.
50 */
51 public static function get_conditionals() {
52 return [ Admin_Conditional::class ];
53 }
54
55 /**
56 * Replaces the auto-update toggle links for the Yoast add-ons
57 * with a text explaining that toggling the Yoast SEO auto-update setting
58 * automatically toggles the one for the setting for the add-ons as well.
59 *
60 * @param string $old_html The old HTML.
61 * @param string $plugin The plugin.
62 *
63 * @return string The new HTML, with the auto-update toggle link replaced.
64 */
65 public function replace_auto_update_toggles_of_addons( $old_html, $plugin ) {
66 if ( ! \is_string( $old_html ) ) {
67 return $old_html;
68 }
69
70 $not_a_yoast_addon = ! \in_array( $plugin, self::ADD_ON_PLUGIN_FILES, true );
71
72 if ( $not_a_yoast_addon ) {
73 return $old_html;
74 }
75
76 $auto_updated_plugins = \get_site_option( 'auto_update_plugins' );
77
78 if ( $this->are_auto_updates_enabled( self::WPSEO_FREE_PLUGIN_ID, $auto_updated_plugins ) ) {
79 return \sprintf(
80 '<em>%s</em>',
81 \sprintf(
82 /* Translators: %1$s resolves to Yoast SEO. */
83 \esc_html__( 'Auto-updates are enabled based on this setting for %1$s.', 'wordpress-seo' ),
84 'Yoast SEO'
85 )
86 );
87 }
88
89 return \sprintf(
90 '<em>%s</em>',
91 \sprintf(
92 /* Translators: %1$s resolves to Yoast SEO. */
93 \esc_html__( 'Auto-updates are disabled based on this setting for %1$s.', 'wordpress-seo' ),
94 'Yoast SEO'
95 )
96 );
97 }
98
99 /**
100 * Handles the situation where the auto_update_plugins option did not previously exist.
101 *
102 * @param string $option The name of the option that is being created.
103 * @param array|mixed $value The new (and first) value of the option that is being created.
104 */
105 public function call_toggle_auto_updates_with_empty_array( $option, $value ) {
106 if ( $option !== 'auto_update_plugins' ) {
107 return;
108 }
109
110 $this->toggle_auto_updates_for_add_ons( $option, $value, [] );
111 }
112
113 /**
114 * Enables premium auto updates when free are enabled and the other way around.
115 *
116 * @param string $option The name of the option that has been updated.
117 * @param array $new_value The new value of the `auto_update_plugins` option.
118 * @param array $old_value The old value of the `auto_update_plugins` option.
119 *
120 * @return void
121 */
122 public function toggle_auto_updates_for_add_ons( $option, $new_value, $old_value ) {
123 if ( $option !== 'auto_update_plugins' ) {
124 // If future versions of WordPress change this filter's behavior, our behavior should stay consistent.
125 return;
126 }
127
128 if ( ! \is_array( $old_value ) || ! \is_array( $new_value ) ) {
129 return;
130 }
131
132 $auto_updates_are_enabled = $this->are_auto_updates_enabled( self::WPSEO_FREE_PLUGIN_ID, $new_value );
133 $auto_updates_were_enabled = $this->are_auto_updates_enabled( self::WPSEO_FREE_PLUGIN_ID, $old_value );
134
135 if ( $auto_updates_are_enabled === $auto_updates_were_enabled ) {
136 // Auto-updates for Yoast SEO have stayed the same, so have neither been enabled or disabled.
137 return;
138 }
139
140 $auto_updates_have_been_enabled = $auto_updates_are_enabled && ! $auto_updates_were_enabled;
141
142 if ( $auto_updates_have_been_enabled ) {
143 $this->enable_auto_updates_for_addons( $new_value );
144 return;
145 }
146 else {
147 $this->disable_auto_updates_for_addons( $new_value );
148 return;
149 }
150
151 if ( ! $auto_updates_are_enabled ) {
152 return;
153 }
154
155 $auto_updates_have_been_removed = false;
156 foreach ( self::ADD_ON_PLUGIN_FILES as $addon ) {
157 if ( ! $this->are_auto_updates_enabled( $addon, $new_value ) ) {
158 $auto_updates_have_been_removed = true;
159 break;
160 }
161 }
162
163 if ( $auto_updates_have_been_removed ) {
164 $this->enable_auto_updates_for_addons( $new_value );
165 }
166 }
167
168 /**
169 * Trigger a change in the auto update detection whenever a new Yoast addon is activated.
170 *
171 * @param string $plugin The plugin that is activated.
172 *
173 * @return void
174 */
175 public function maybe_toggle_auto_updates_for_new_install( $plugin ) {
176 $not_a_yoast_addon = ! \in_array( $plugin, self::ADD_ON_PLUGIN_FILES, true );
177
178 if ( $not_a_yoast_addon ) {
179 return;
180 }
181
182 $enabled_auto_updates = \get_site_option( 'auto_update_plugins' );
183 $this->toggle_auto_updates_for_add_ons( 'auto_update_plugins', $enabled_auto_updates, [] );
184 }
185
186 /**
187 * Enables auto-updates for all addons.
188 *
189 * @param string[] $auto_updated_plugins The current list of auto-updated plugins.
190 */
191 protected function enable_auto_updates_for_addons( $auto_updated_plugins ) {
192 $plugins = \array_unique( \array_merge( $auto_updated_plugins, self::ADD_ON_PLUGIN_FILES ) );
193 \update_site_option( 'auto_update_plugins', $plugins );
194 }
195
196 /**
197 * Disables auto-updates for all addons.
198 *
199 * @param string[] $auto_updated_plugins The current list of auto-updated plugins.
200 */
201 protected function disable_auto_updates_for_addons( $auto_updated_plugins ) {
202 $plugins = \array_values( \array_diff( $auto_updated_plugins, self::ADD_ON_PLUGIN_FILES ) );
203 \update_site_option( 'auto_update_plugins', $plugins );
204 }
205
206 /**
207 * Checks whether auto updates for a plugin are enabled.
208 *
209 * @param string $plugin_id The plugin ID.
210 * @param array $auto_updated_plugins The array of auto updated plugins.
211 *
212 * @return bool Whether auto updates for a plugin are enabled.
213 */
214 protected function are_auto_updates_enabled( $plugin_id, $auto_updated_plugins ) {
215 if ( $auto_updated_plugins === false || ! \is_array( $auto_updated_plugins ) ) {
216 return false;
217 }
218
219 return \in_array( $plugin_id, $auto_updated_plugins, true );
220 }
221 }
222