PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.9
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.9
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 / actions / importing / aioseo / aioseo-validate-data-action.php

aioseo-validate-data-action.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 18.9, at src/actions/importing/aioseo/aioseo-validate-data-action.php

259 lines 8.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Given it's a very specific case.
4 namespace Yoast\WP\SEO\Actions\Importing\Aioseo;
5
6 use wpdb;
7 use Yoast\WP\SEO\Helpers\Options_Helper;
8 use Yoast\WP\SEO\Exceptions\Importing\Aioseo_Validation_Exception;
9 use Yoast\WP\SEO\Actions\Importing\Abstract_Aioseo_Importing_Action;
10
11 /**
12 * Importing action for validating AIOSEO data before the import occurs.
13 *
14 * @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
15 */
16 class Aioseo_Validate_Data_Action extends Abstract_Aioseo_Importing_Action {
17
18 /**
19 * The plugin of the action.
20 */
21 const PLUGIN = 'aioseo';
22
23 /**
24 * The type of the action.
25 */
26 const TYPE = 'validate_data';
27
28 /**
29 * The WordPress database instance.
30 *
31 * @var wpdb
32 */
33 protected $wpdb;
34
35 /**
36 * The Post Importing action.
37 *
38 * @var Aioseo_Posts_Importing_Action
39 */
40 protected $post_importing_action;
41
42 /**
43 * The settings importing actions.
44 *
45 * @var array
46 */
47 protected $settings_importing_actions;
48
49 /**
50 * Class constructor.
51 *
52 * @param wpdb $wpdb The WordPress database instance.
53 * @param Options_Helper $options The options helper.
54 * @param Aioseo_Custom_Archive_Settings_Importing_Action $custom_archive_action The Custom Archive Settings importing action.
55 * @param Aioseo_Default_Archive_Settings_Importing_Action $default_archive_action The Default Archive Settings importing action.
56 * @param Aioseo_General_Settings_Importing_Action $general_settings_action The General Settings importing action.
57 * @param Aioseo_Posttype_Defaults_Settings_Importing_Action $posttype_defaults_settings_action The Posttype Defaults Settings importing action.
58 * @param Aioseo_Taxonomy_Settings_Importing_Action $taxonomy_settings_action The Taxonomy Settings importing action.
59 * @param Aioseo_Posts_Importing_Action $post_importing_action The Post importing action.
60 */
61 public function __construct(
62 wpdb $wpdb,
63 Options_Helper $options,
64 Aioseo_Custom_Archive_Settings_Importing_Action $custom_archive_action,
65 Aioseo_Default_Archive_Settings_Importing_Action $default_archive_action,
66 Aioseo_General_Settings_Importing_Action $general_settings_action,
67 Aioseo_Posttype_Defaults_Settings_Importing_Action $posttype_defaults_settings_action,
68 Aioseo_Taxonomy_Settings_Importing_Action $taxonomy_settings_action,
69 Aioseo_Posts_Importing_Action $post_importing_action
70 ) {
71 $this->wpdb = $wpdb;
72 $this->options = $options;
73 $this->post_importing_action = $post_importing_action;
74 $this->settings_importing_actions = [
75 $custom_archive_action,
76 $default_archive_action,
77 $general_settings_action,
78 $posttype_defaults_settings_action,
79 $taxonomy_settings_action,
80 ];
81 }
82
83 /**
84 * Just checks if the action has been completed in the past.
85 *
86 * @return int 1 if it hasn't been completed in the past, 0 if it has.
87 */
88 public function get_total_unindexed() {
89 return ( ! $this->get_completed() ) ? 1 : 0;
90 }
91
92 /**
93 * Just checks if the action has been completed in the past.
94 *
95 * @param int $limit The maximum number of unimported objects to be returned. Not used, exists to comply with the interface.
96 *
97 * @return int 1 if it hasn't been completed in the past, 0 if it has.
98 */
99 public function get_limited_unindexed_count( $limit ) {
100 return ( ! $this->get_completed() ) ? 1 : 0;
101 }
102
103 /**
104 * Validates AIOSEO data.
105 *
106 * @return array|false An array of validated data or false if aioseo data did not pass validation.
107 *
108 * @throws Aioseo_Validation_Exception If the validation fails.
109 */
110 public function index() {
111 if ( $this->get_completed() ) {
112 return [];
113 }
114
115 $validated_aioseo_table = $this->validate_aioseo_table();
116 $validated_aioseo_settings = $this->validate_aioseo_settings();
117 $validated_robot_settings = $this->validate_robot_settings();
118
119
120 if ( $validated_aioseo_table === false || $validated_aioseo_settings === false || $validated_robot_settings === false ) {
121 throw new Aioseo_Validation_Exception();
122 }
123
124 $this->set_completed( true );
125
126 return [
127 'validated_aioseo_table' => $validated_aioseo_table,
128 'validated_aioseo_settings' => $validated_aioseo_settings,
129 'validated_robot_settings' => $validated_robot_settings,
130 ];
131 }
132
133 /**
134 * Validates the AIOSEO indexable table.
135 *
136 * @return bool Whether the AIOSEO table exists and has the structure we expect.
137 */
138 public function validate_aioseo_table() {
139 if ( ! $this->aioseo_helper->aioseo_exists() ) {
140 return false;
141 }
142
143 $table = $this->aioseo_helper->get_table();
144 $needed_data = $this->post_importing_action->get_needed_data();
145
146 $aioseo_columns = $this->wpdb->get_col(
147 "SHOW COLUMNS FROM {$table}", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: There is no unescaped user input.
148 0
149 );
150
151 return $needed_data === \array_intersect( $needed_data, $aioseo_columns );
152 }
153
154 /**
155 * Validates the AIOSEO settings from the options table.
156 *
157 * @return bool Whether the AIOSEO settings from the options table exist and have the structure we expect.
158 */
159 public function validate_aioseo_settings() {
160 foreach ( $this->settings_importing_actions as $settings_import_action ) {
161 $aioseo_settings = \json_decode( \get_option( $settings_import_action->get_source_option_name(), '' ), true );
162
163 if ( ! $settings_import_action->isset_settings_tab( $aioseo_settings ) ) {
164 return false;
165 }
166 }
167
168 return true;
169 }
170
171 /**
172 * Validates the AIOSEO robots settings from the options table.
173 *
174 * @return bool Whether the AIOSEO robots settings from the options table exist and have the structure we expect.
175 */
176 public function validate_robot_settings() {
177 if ( $this->validate_post_robot_settings() && $this->validate_default_robot_settings() ) {
178 return true;
179 }
180
181 return false;
182 }
183
184 /**
185 * Validates the post AIOSEO robots settings from the options table.
186 *
187 * @return bool Whether the post AIOSEO robots settings from the options table exist and have the structure we expect.
188 */
189 public function validate_post_robot_settings() {
190 $post_robot_mapping = $this->post_importing_action->enhance_mapping();
191 // We're gonna validate against posttype robot settings only for posts, assuming the robot settings stay the same for other post types.
192 $post_robot_mapping['subtype'] = 'post';
193
194 // Let's get both the aioseo_options and the aioseo_options_dynamic options.
195 $aioseo_global_settings = $this->aioseo_helper->get_global_option();
196 $aioseo_posts_settings = \json_decode( \get_option( $post_robot_mapping['option_name'], '' ), true );
197
198 $needed_robots_data = $this->post_importing_action->get_needed_robot_data();
199 \array_push( $needed_robots_data, 'default', 'noindex' );
200
201 foreach ( $needed_robots_data as $robot_setting ) {
202 // Validate against global settings.
203 if ( ! isset( $aioseo_global_settings['searchAppearance']['advanced']['globalRobotsMeta'][ $robot_setting ] ) ) {
204 return false;
205 }
206
207 // Validate against posttype settings.
208 if ( ! isset( $aioseo_posts_settings['searchAppearance'][ $post_robot_mapping['type'] ][ $post_robot_mapping['subtype'] ]['advanced']['robotsMeta'][ $robot_setting ] ) ) {
209 return false;
210 }
211 }
212
213 return true;
214 }
215
216 /**
217 * Validates the default AIOSEO robots settings for search appearance settings from the options table.
218 *
219 * @return bool Whether the AIOSEO robots settings for search appearance settings from the options table exist and have the structure we expect.
220 */
221 public function validate_default_robot_settings() {
222
223 foreach ( $this->settings_importing_actions as $settings_import_action ) {
224 $robot_setting_map = $settings_import_action->pluck_robot_setting_from_mapping();
225
226 // Some actions return empty robot settings, let's not validate against those.
227 if ( ! empty( $robot_setting_map ) ) {
228 $aioseo_settings = \json_decode( \get_option( $robot_setting_map['option_name'], '' ), true );
229
230 if ( ! isset( $aioseo_settings['searchAppearance'][ $robot_setting_map['type'] ][ $robot_setting_map['subtype'] ]['advanced']['robotsMeta']['default'] ) ) {
231 return false;
232 }
233 }
234 }
235
236 return true;
237 }
238
239 /**
240 * Used nowhere. Exists to comply with the interface.
241 *
242 * @return int The limit.
243 */
244 public function get_limit() {
245 /**
246 * Filter 'wpseo_aioseo_cleanup_limit' - Allow filtering the number of validations during each action pass.
247 *
248 * @api int The maximum number of validations.
249 */
250 $limit = \apply_filters( 'wpseo_aioseo_validation_limit', 25 );
251
252 if ( ! \is_int( $limit ) || $limit < 1 ) {
253 $limit = 25;
254 }
255
256 return $limit;
257 }
258 }
259