/wp-content/plugins/wordpress-seo/admin/import/plugins/class-abstract-plugin-importer.php

https://bitbucket.org/carloskikea/helpet · PHP · 318 lines · 151 code · 40 blank · 127 comment · 14 complexity · 0dc7962dd3116de2dacf2c4fcf516657 MD5 · raw file

  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. * Class WPSEO_Plugin_Importer
  9. *
  10. * Class with functionality to import meta data from other plugins.
  11. */
  12. abstract class WPSEO_Plugin_Importer {
  13. /**
  14. * Holds the import status object.
  15. *
  16. * @var WPSEO_Import_Status
  17. */
  18. protected $status;
  19. /**
  20. * The plugin name.
  21. *
  22. * @var string
  23. */
  24. protected $plugin_name;
  25. /**
  26. * Meta key, used in SQL LIKE clause for delete query.
  27. *
  28. * @var string
  29. */
  30. protected $meta_key;
  31. /**
  32. * Array of meta keys to detect and import.
  33. *
  34. * @var array
  35. */
  36. protected $clone_keys;
  37. /**
  38. * Class constructor.
  39. */
  40. public function __construct() {
  41. }
  42. /**
  43. * Returns the string for the plugin we're importing from.
  44. *
  45. * @return string Plugin name.
  46. */
  47. public function get_plugin_name() {
  48. return $this->plugin_name;
  49. }
  50. /**
  51. * Imports the settings and post meta data from another SEO plugin.
  52. *
  53. * @return WPSEO_Import_Status Import status object.
  54. */
  55. public function run_import() {
  56. $this->status = new WPSEO_Import_Status( 'import', false );
  57. if ( ! $this->detect() ) {
  58. return $this->status;
  59. }
  60. $this->status->set_status( $this->import() );
  61. // Flush the entire cache, as we no longer know what's valid and what's not.
  62. wp_cache_flush();
  63. return $this->status;
  64. }
  65. /**
  66. * Handles post meta data to import.
  67. *
  68. * @return bool Import success status.
  69. */
  70. protected function import() {
  71. return $this->meta_keys_clone( $this->clone_keys );
  72. }
  73. /**
  74. * Removes the plugin data from the database.
  75. *
  76. * @return WPSEO_Import_Status Import status object.
  77. */
  78. public function run_cleanup() {
  79. $this->status = new WPSEO_Import_Status( 'cleanup', false );
  80. if ( ! $this->detect() ) {
  81. return $this->status;
  82. }
  83. return $this->status->set_status( $this->cleanup() );
  84. }
  85. /**
  86. * Removes the plugin data from the database.
  87. *
  88. * @return bool Cleanup status.
  89. */
  90. protected function cleanup() {
  91. global $wpdb;
  92. if ( empty( $this->meta_key ) ) {
  93. return true;
  94. }
  95. $wpdb->query(
  96. $wpdb->prepare(
  97. "DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE %s",
  98. $this->meta_key
  99. )
  100. );
  101. $result = $wpdb->__get( 'result' );
  102. if ( ! $result ) {
  103. $this->cleanup_error_msg();
  104. }
  105. return $result;
  106. }
  107. /**
  108. * Sets the status message for when a cleanup has gone bad.
  109. *
  110. * @return void
  111. */
  112. protected function cleanup_error_msg() {
  113. /* translators: %s is replaced with the plugin's name. */
  114. $this->status->set_msg( sprintf( __( 'Cleanup of %s data failed.', 'wordpress-seo' ), $this->plugin_name ) );
  115. }
  116. /**
  117. * Detects whether an import for this plugin is needed.
  118. *
  119. * @return WPSEO_Import_Status Import status object.
  120. */
  121. public function run_detect() {
  122. $this->status = new WPSEO_Import_Status( 'detect', false );
  123. if ( ! $this->detect() ) {
  124. return $this->status;
  125. }
  126. return $this->status->set_status( true );
  127. }
  128. /**
  129. * Detects whether there is post meta data to import.
  130. *
  131. * @return bool Boolean indicating whether there is something to import.
  132. */
  133. protected function detect() {
  134. global $wpdb;
  135. $meta_keys = wp_list_pluck( $this->clone_keys, 'old_key' );
  136. $placeholders = implode( ', ', array_fill( 0, count( $meta_keys ), '%s' ) );
  137. $result = $wpdb->get_var(
  138. $wpdb->prepare(
  139. "SELECT COUNT(*) AS `count` FROM {$wpdb->postmeta} WHERE meta_key IN ( $placeholders )",
  140. $meta_keys
  141. )
  142. );
  143. if ( $result === '0' ) {
  144. return false;
  145. }
  146. return true;
  147. }
  148. /**
  149. * Helper function to clone meta keys and (optionally) change their values in bulk.
  150. *
  151. * @param string $old_key The existing meta key.
  152. * @param string $new_key The new meta key.
  153. * @param array $replace_values An array, keys old value, values new values.
  154. *
  155. * @return bool Clone status.
  156. */
  157. protected function meta_key_clone( $old_key, $new_key, $replace_values = array() ) {
  158. global $wpdb;
  159. // First we create a temp table with all the values for meta_key.
  160. $result = $wpdb->query(
  161. $wpdb->prepare(
  162. "CREATE TEMPORARY TABLE tmp_meta_table SELECT * FROM {$wpdb->postmeta} WHERE meta_key = %s",
  163. $old_key
  164. )
  165. );
  166. if ( $result === false ) {
  167. $this->set_missing_db_rights_status();
  168. return false;
  169. }
  170. // Delete all the values in our temp table for posts that already have data for $new_key.
  171. $wpdb->query(
  172. $wpdb->prepare(
  173. "DELETE FROM tmp_meta_table WHERE post_id IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s )",
  174. WPSEO_Meta::$meta_prefix . $new_key
  175. )
  176. );
  177. // We set meta_id to NULL so on re-insert into the postmeta table, MYSQL can set new meta_id's and we don't get duplicates.
  178. $wpdb->query( 'UPDATE tmp_meta_table SET meta_id = NULL' );
  179. // Now we rename the meta_key.
  180. $wpdb->query(
  181. $wpdb->prepare(
  182. 'UPDATE tmp_meta_table SET meta_key = %s',
  183. WPSEO_Meta::$meta_prefix . $new_key
  184. )
  185. );
  186. $this->meta_key_clone_replace( $replace_values );
  187. // With everything done, we insert all our newly cloned lines into the postmeta table.
  188. $wpdb->query( "INSERT INTO {$wpdb->postmeta} SELECT * FROM tmp_meta_table" );
  189. // Now we drop our temporary table.
  190. $wpdb->query( 'DROP TEMPORARY TABLE IF EXISTS tmp_meta_table' );
  191. return true;
  192. }
  193. /**
  194. * Clones multiple meta keys.
  195. *
  196. * @param array $clone_keys The keys to clone.
  197. *
  198. * @return bool Success status.
  199. */
  200. protected function meta_keys_clone( $clone_keys ) {
  201. foreach ( $clone_keys as $clone_key ) {
  202. $result = $this->meta_key_clone( $clone_key['old_key'], $clone_key['new_key'], isset( $clone_key['convert'] ) ? $clone_key['convert'] : array() );
  203. if ( ! $result ) {
  204. return false;
  205. }
  206. }
  207. return true;
  208. }
  209. /**
  210. * Sets the import status to false and returns a message about why it failed.
  211. */
  212. protected function set_missing_db_rights_status() {
  213. $this->status->set_status( false );
  214. /* translators: %s is replaced with Yoast SEO. */
  215. $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' ) );
  216. }
  217. /**
  218. * Helper function to search for a key in an array and maybe save it as a meta field.
  219. *
  220. * @param string $plugin_key The key in the $data array to check.
  221. * @param string $yoast_key The identifier we use in our meta settings.
  222. * @param array $data The array of data for this post to sift through.
  223. * @param int $post_id The post ID.
  224. *
  225. * @return void
  226. */
  227. protected function import_meta_helper( $plugin_key, $yoast_key, $data, $post_id ) {
  228. if ( ! empty( $data[ $plugin_key ] ) ) {
  229. $this->maybe_save_post_meta( $yoast_key, $data[ $plugin_key ], $post_id );
  230. }
  231. }
  232. /**
  233. * Saves a post meta value if it doesn't already exist.
  234. *
  235. * @param string $new_key The key to save.
  236. * @param mixed $value The value to set the key to.
  237. * @param int $post_id The Post to save the meta for.
  238. */
  239. protected function maybe_save_post_meta( $new_key, $value, $post_id ) {
  240. // Big. Fat. Sigh. Mostly used for _yst_is_cornerstone, but might be useful for other hidden meta's.
  241. $key = WPSEO_Meta::$meta_prefix . $new_key;
  242. $wpseo_meta = true;
  243. if ( substr( $new_key, 0, 1 ) === '_' ) {
  244. $key = $new_key;
  245. $wpseo_meta = false;
  246. }
  247. $existing_value = get_post_meta( $post_id, $key, true );
  248. if ( empty( $existing_value ) ) {
  249. if ( $wpseo_meta ) {
  250. WPSEO_Meta::set_value( $new_key, $value, $post_id );
  251. return;
  252. }
  253. update_post_meta( $post_id, $new_key, $value );
  254. }
  255. }
  256. /**
  257. * Replaces values in our temporary table according to our settings.
  258. *
  259. * @param array $replace_values Key value pair of values to replace with other values.
  260. *
  261. * @return void
  262. */
  263. protected function meta_key_clone_replace( $replace_values ) {
  264. global $wpdb;
  265. // Now we replace values if needed.
  266. if ( is_array( $replace_values ) && $replace_values !== array() ) {
  267. foreach ( $replace_values as $old_value => $new_value ) {
  268. $wpdb->query(
  269. $wpdb->prepare(
  270. 'UPDATE tmp_meta_table SET meta_value = %s WHERE meta_value = %s',
  271. $new_value,
  272. $old_value
  273. )
  274. );
  275. }
  276. }
  277. }
  278. }