• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / b05d07fc5b184095141e8ead75857d0154e04580

23 Jul 2024 07:52AM UTC coverage: 48.579% (-5.4%) from 53.976%
b05d07fc5b184095141e8ead75857d0154e04580

push

github

YoastBot
Bump version to 23.1

7399 of 13400 branches covered (55.22%)

Branch coverage included in aggregate %.

25129 of 53559 relevant lines covered (46.92%)

41942.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/admin/import/plugins/class-abstract-plugin-importer.php
1
<?php
2
/**
3
 * This file holds the abstract class for dealing with imports from other plugins.
4
 *
5
 * @package WPSEO\Admin\Import\Plugins
6
 */
7

8
/**
9
 * Class WPSEO_Plugin_Importer.
10
 *
11
 * Class with functionality to import meta data from other plugins.
12
 */
13
abstract class WPSEO_Plugin_Importer {
14

15
        /**
16
         * Holds the import status object.
17
         *
18
         * @var WPSEO_Import_Status
19
         */
20
        protected $status;
21

22
        /**
23
         * The plugin name.
24
         *
25
         * @var string
26
         */
27
        protected $plugin_name;
28

29
        /**
30
         * Meta key, used in SQL LIKE clause for delete query.
31
         *
32
         * @var string
33
         */
34
        protected $meta_key;
35

36
        /**
37
         * Array of meta keys to detect and import.
38
         *
39
         * @var array
40
         */
41
        protected $clone_keys;
42

43
        /**
44
         * Class constructor.
45
         */
46
        public function __construct() {}
47

48
        /**
49
         * Returns the string for the plugin we're importing from.
50
         *
51
         * @return string Plugin name.
52
         */
53
        public function get_plugin_name() {
×
54
                return $this->plugin_name;
×
55
        }
56

57
        /**
58
         * Imports the settings and post meta data from another SEO plugin.
59
         *
60
         * @return WPSEO_Import_Status Import status object.
61
         */
62
        public function run_import() {
×
63
                $this->status = new WPSEO_Import_Status( 'import', false );
×
64

65
                if ( ! $this->detect() ) {
×
66
                        return $this->status;
×
67
                }
68

69
                $this->status->set_status( $this->import() );
×
70

71
                // Flush the entire cache, as we no longer know what's valid and what's not.
72
                wp_cache_flush();
×
73

74
                return $this->status;
×
75
        }
76

77
        /**
78
         * Handles post meta data to import.
79
         *
80
         * @return bool Import success status.
81
         */
82
        protected function import() {
×
83
                return $this->meta_keys_clone( $this->clone_keys );
×
84
        }
85

86
        /**
87
         * Removes the plugin data from the database.
88
         *
89
         * @return WPSEO_Import_Status Import status object.
90
         */
91
        public function run_cleanup() {
×
92
                $this->status = new WPSEO_Import_Status( 'cleanup', false );
×
93

94
                if ( ! $this->detect() ) {
×
95
                        return $this->status;
×
96
                }
97

98
                return $this->status->set_status( $this->cleanup() );
×
99
        }
100

101
        /**
102
         * Removes the plugin data from the database.
103
         *
104
         * @return bool Cleanup status.
105
         */
106
        protected function cleanup() {
×
107
                global $wpdb;
×
108
                if ( empty( $this->meta_key ) ) {
×
109
                        return true;
×
110
                }
111
                $wpdb->query(
×
112
                        $wpdb->prepare(
×
113
                                "DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE %s",
×
114
                                $this->meta_key
×
115
                        )
116
                );
117
                $result = $wpdb->__get( 'result' );
×
118
                if ( ! $result ) {
×
119
                        $this->cleanup_error_msg();
×
120
                }
121

122
                return $result;
×
123
        }
124

125
        /**
126
         * Sets the status message for when a cleanup has gone bad.
127
         *
128
         * @return void
129
         */
130
        protected function cleanup_error_msg() {
×
131
                /* translators: %s is replaced with the plugin's name. */
132
                $this->status->set_msg( sprintf( __( 'Cleanup of %s data failed.', 'wordpress-seo' ), $this->plugin_name ) );
×
133
        }
134

135
        /**
136
         * Detects whether an import for this plugin is needed.
137
         *
138
         * @return WPSEO_Import_Status Import status object.
139
         */
140
        public function run_detect() {
×
141
                $this->status = new WPSEO_Import_Status( 'detect', false );
×
142

143
                if ( ! $this->detect() ) {
×
144
                        return $this->status;
×
145
                }
146

147
                return $this->status->set_status( true );
×
148
        }
149

150
        /**
151
         * Detects whether there is post meta data to import.
152
         *
153
         * @return bool Boolean indicating whether there is something to import.
154
         */
155
        protected function detect() {
×
156
                global $wpdb;
×
157

158
                $meta_keys = wp_list_pluck( $this->clone_keys, 'old_key' );
×
159
                $result    = $wpdb->get_var(
×
160
                        $wpdb->prepare(
×
161
                                "SELECT COUNT(*) AS `count`
162
                                        FROM {$wpdb->postmeta}
×
163
                                        WHERE meta_key IN ( " . implode( ', ', array_fill( 0, count( $meta_keys ), '%s' ) ) . ' )',
×
164
                                $meta_keys
×
165
                        )
166
                );
167

168
                if ( $result === '0' ) {
×
169
                        return false;
×
170
                }
171

172
                return true;
×
173
        }
174

175
        /**
176
         * Helper function to clone meta keys and (optionally) change their values in bulk.
177
         *
178
         * @param string $old_key        The existing meta key.
179
         * @param string $new_key        The new meta key.
180
         * @param array  $replace_values An array, keys old value, values new values.
181
         *
182
         * @return bool Clone status.
183
         */
184
        protected function meta_key_clone( $old_key, $new_key, $replace_values = [] ) {
×
185
                global $wpdb;
×
186

187
                // First we create a temp table with all the values for meta_key.
188
                $result = $wpdb->query(
×
189
                        $wpdb->prepare(
×
190
                                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange -- This is intentional + temporary.
191
                                "CREATE TEMPORARY TABLE tmp_meta_table SELECT * FROM {$wpdb->postmeta} WHERE meta_key = %s",
×
192
                                $old_key
×
193
                        )
194
                );
195
                if ( $result === false ) {
×
196
                        $this->set_missing_db_rights_status();
×
197
                        return false;
×
198
                }
199

200
                // Delete all the values in our temp table for posts that already have data for $new_key.
201
                $wpdb->query(
×
202
                        $wpdb->prepare(
×
203
                                "DELETE FROM tmp_meta_table WHERE post_id IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s )",
×
204
                                WPSEO_Meta::$meta_prefix . $new_key
×
205
                        )
206
                );
207

208
                /*
209
                 * We set meta_id to NULL so on re-insert into the postmeta table, MYSQL can set
210
                 * new meta_id's and we don't get duplicates.
211
                 */
212
                $wpdb->query( 'UPDATE tmp_meta_table SET meta_id = NULL' );
×
213

214
                // Now we rename the meta_key.
215
                $wpdb->query(
×
216
                        $wpdb->prepare(
×
217
                                'UPDATE tmp_meta_table SET meta_key = %s',
×
218
                                WPSEO_Meta::$meta_prefix . $new_key
×
219
                        )
220
                );
221

222
                $this->meta_key_clone_replace( $replace_values );
×
223

224
                // With everything done, we insert all our newly cloned lines into the postmeta table.
225
                $wpdb->query( "INSERT INTO {$wpdb->postmeta} SELECT * FROM tmp_meta_table" );
×
226

227
                // Now we drop our temporary table.
228
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange -- This is intentional + a temporary table.
229
                $wpdb->query( 'DROP TEMPORARY TABLE IF EXISTS tmp_meta_table' );
×
230

231
                return true;
×
232
        }
233

234
        /**
235
         * Clones multiple meta keys.
236
         *
237
         * @param array $clone_keys The keys to clone.
238
         *
239
         * @return bool Success status.
240
         */
241
        protected function meta_keys_clone( $clone_keys ) {
×
242
                foreach ( $clone_keys as $clone_key ) {
×
243
                        $result = $this->meta_key_clone( $clone_key['old_key'], $clone_key['new_key'], ( $clone_key['convert'] ?? [] ) );
×
244
                        if ( ! $result ) {
×
245
                                return false;
×
246
                        }
247
                }
248
                return true;
×
249
        }
250

251
        /**
252
         * Sets the import status to false and returns a message about why it failed.
253
         *
254
         * @return void
255
         */
256
        protected function set_missing_db_rights_status() {
×
257
                $this->status->set_status( false );
×
258
                /* translators: %s is replaced with Yoast SEO. */
259
                $this->status->set_msg( sprintf( __( 'The %s importer functionality uses temporary database tables. It seems your WordPress install does not have the capability to do this, please consult your hosting provider.', 'wordpress-seo' ), 'Yoast SEO' ) );
×
260
        }
261

262
        /**
263
         * Helper function to search for a key in an array and maybe save it as a meta field.
264
         *
265
         * @param string $plugin_key The key in the $data array to check.
266
         * @param string $yoast_key  The identifier we use in our meta settings.
267
         * @param array  $data       The array of data for this post to sift through.
268
         * @param int    $post_id    The post ID.
269
         *
270
         * @return void
271
         */
272
        protected function import_meta_helper( $plugin_key, $yoast_key, $data, $post_id ) {
×
273
                if ( ! empty( $data[ $plugin_key ] ) ) {
×
274
                        $this->maybe_save_post_meta( $yoast_key, $data[ $plugin_key ], $post_id );
×
275
                }
276
        }
277

278
        /**
279
         * Saves a post meta value if it doesn't already exist.
280
         *
281
         * @param string $new_key The key to save.
282
         * @param mixed  $value   The value to set the key to.
283
         * @param int    $post_id The Post to save the meta for.
284
         *
285
         * @return void
286
         */
287
        protected function maybe_save_post_meta( $new_key, $value, $post_id ) {
×
288
                // Big. Fat. Sigh. Mostly used for _yst_is_cornerstone, but might be useful for other hidden meta's.
289
                $key        = WPSEO_Meta::$meta_prefix . $new_key;
×
290
                $wpseo_meta = true;
×
291
                if ( substr( $new_key, 0, 1 ) === '_' ) {
×
292
                        $key        = $new_key;
×
293
                        $wpseo_meta = false;
×
294
                }
295

296
                $existing_value = get_post_meta( $post_id, $key, true );
×
297
                if ( empty( $existing_value ) ) {
×
298
                        if ( $wpseo_meta ) {
×
299
                                WPSEO_Meta::set_value( $new_key, $value, $post_id );
×
300
                                return;
×
301
                        }
302
                        update_post_meta( $post_id, $new_key, $value );
×
303
                }
304
        }
305

306
        /**
307
         * Replaces values in our temporary table according to our settings.
308
         *
309
         * @param array $replace_values Key value pair of values to replace with other values.
310
         *
311
         * @return void
312
         */
313
        protected function meta_key_clone_replace( $replace_values ) {
×
314
                global $wpdb;
×
315

316
                // Now we replace values if needed.
317
                if ( is_array( $replace_values ) && $replace_values !== [] ) {
×
318
                        foreach ( $replace_values as $old_value => $new_value ) {
×
319
                                $wpdb->query(
×
320
                                        $wpdb->prepare(
×
321
                                                'UPDATE tmp_meta_table SET meta_value = %s WHERE meta_value = %s',
×
322
                                                $new_value,
×
323
                                                $old_value
×
324
                                        )
325
                                );
326
                        }
327
                }
328
        }
329
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc