← All changes
|
jetpack_vendor/automattic/jetpack-sync/src/class-replicastore.php
+78
-62
13.0.2
→
16.3-beta
View file →
| @@ -12,8 +12,12 @@ | ||
| 12 | 12 | use Automattic\Jetpack\Sync\Replicastore\Table_Checksum_Users; |
| 13 | 13 | use Exception; |
| 14 | 14 | use WP_Error; |
| 15 | 15 | |
| 16 | +if ( ! defined( 'ABSPATH' ) ) { | |
| 17 | + exit( 0 ); | |
| 18 | +} | |
| 19 | + | |
| 16 | 20 | /** |
| 17 | 21 | * An implementation of Replicastore Interface which returns data stored in a WordPress.org DB. |
| 18 | 22 | * This is useful to compare values in the local WP DB to values in the synced replica store |
| 19 | 23 | */ |
| @@ -81,9 +85,10 @@ | ||
| 81 | 85 | * @return int Number of terms. |
| 82 | 86 | */ |
| 83 | 87 | public function term_count() { |
| 84 | 88 | global $wpdb; |
| 85 | - return $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->terms" ); | |
| 89 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 90 | + return (int) $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->terms" ); | |
| 86 | 91 | } |
| 87 | 92 | |
| 88 | 93 | /** |
| 89 | 94 | * Retrieve the number of rows in the `term_taxonomy` table. |
| @@ -93,9 +98,10 @@ | ||
| 93 | 98 | * @return int Number of terms. |
| 94 | 99 | */ |
| 95 | 100 | public function term_taxonomy_count() { |
| 96 | 101 | global $wpdb; |
| 97 | - return $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->term_taxonomy" ); | |
| 102 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 103 | + return (int) $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->term_taxonomy" ); | |
| 98 | 104 | } |
| 99 | 105 | |
| 100 | 106 | /** |
| 101 | 107 | * Retrieve the number of term relationships. |
| @@ -105,9 +111,10 @@ | ||
| 105 | 111 | * @return int Number of rows in the term relationships table. |
| 106 | 112 | */ |
| 107 | 113 | public function term_relationship_count() { |
| 108 | 114 | global $wpdb; |
| 109 | - return $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->term_relationships" ); | |
| 115 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 116 | + return (int) $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->term_relationships" ); | |
| 110 | 117 | } |
| 111 | 118 | |
| 112 | 119 | /** |
| 113 | 120 | * Retrieve the number of posts with a particular post status within a certain range. |
| @@ -139,10 +146,10 @@ | ||
| 139 | 146 | if ( ! empty( $max_id ) ) { |
| 140 | 147 | $where .= ' AND ID <= ' . (int) $max_id; |
| 141 | 148 | } |
| 142 | 149 | |
| 143 | - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 144 | - return $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts WHERE $where" ); | |
| 150 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 151 | + return (int) $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts WHERE $where" ); | |
| 145 | 152 | } |
| 146 | 153 | |
| 147 | 154 | /** |
| 148 | 155 | * Retrieve the posts with a particular post status. |
| @@ -318,10 +325,10 @@ | ||
| 318 | 325 | if ( ! empty( $max_id ) ) { |
| 319 | 326 | $where .= ' AND comment_ID <= ' . (int) $max_id; |
| 320 | 327 | } |
| 321 | 328 | |
| 322 | - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 323 | - return $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->comments WHERE $where" ); | |
| 329 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 330 | + return (int) $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->comments WHERE $where" ); | |
| 324 | 331 | } |
| 325 | 332 | |
| 326 | 333 | /** |
| 327 | 334 | * Translate a comment status to a value of the comment_approved field. |
| @@ -719,8 +726,47 @@ | ||
| 719 | 726 | } |
| 720 | 727 | } |
| 721 | 728 | |
| 722 | 729 | /** |
| 730 | + * Delete metadata with a certain key and value for all objects. | |
| 731 | + * | |
| 732 | + * @access public | |
| 733 | + * | |
| 734 | + * @param string $type Meta type. | |
| 735 | + * @param string $meta_key Meta key. | |
| 736 | + * @param mixed $meta_value Meta value to match. | |
| 737 | + */ | |
| 738 | + public function delete_metadata_by_key_value( $type, $meta_key, $meta_value ) { | |
| 739 | + global $wpdb; | |
| 740 | + | |
| 741 | + $table = _get_meta_table( $type ); | |
| 742 | + if ( ! $table ) { | |
| 743 | + return false; | |
| 744 | + } | |
| 745 | + | |
| 746 | + if ( '' === $meta_value || null === $meta_value || false === $meta_value ) { | |
| 747 | + return false; | |
| 748 | + } | |
| 749 | + | |
| 750 | + $column = sanitize_key( $type . '_id' ); | |
| 751 | + $meta_value = maybe_serialize( $meta_value ); | |
| 752 | + | |
| 753 | + $object_ids = $wpdb->get_col( $wpdb->prepare( 'SELECT DISTINCT %i FROM %i WHERE meta_key = %s AND meta_value = %s', $column, $table, $meta_key, $meta_value ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Direct replica query is needed to identify caches invalidated below. | |
| 754 | + $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Direct replica mutation. | |
| 755 | + $table, | |
| 756 | + array( | |
| 757 | + 'meta_key' => $meta_key, | |
| 758 | + 'meta_value' => $meta_value, | |
| 759 | + ), | |
| 760 | + array( '%s', '%s' ) | |
| 761 | + ); | |
| 762 | + | |
| 763 | + foreach ( $object_ids as $object_id ) { | |
| 764 | + wp_cache_delete( $object_id, $type . '_meta' ); | |
| 765 | + } | |
| 766 | + } | |
| 767 | + | |
| 768 | + /** | |
| 723 | 769 | * Retrieve value of a constant based on the constant name. |
| 724 | 770 | * |
| 725 | 771 | * We explicitly return null instead of false if the constant doesn't exist. |
| 726 | 772 | * |
| @@ -873,11 +919,11 @@ | ||
| 873 | 919 | * Retrieve a particular term. |
| 874 | 920 | * |
| 875 | 921 | * @access public |
| 876 | 922 | * |
| 877 | - * @param string $taxonomy Taxonomy slug. | |
| 878 | - * @param int $term_id ID of the term. | |
| 879 | - * @param string $term_key ID Field `term_id` or `term_taxonomy_id`. | |
| 923 | + * @param string|false $taxonomy Taxonomy slug. | |
| 924 | + * @param int $term_id ID of the term. | |
| 925 | + * @param string $term_key ID Field `term_id` or `term_taxonomy_id`. | |
| 880 | 926 | * |
| 881 | 927 | * @return \WP_Term|WP_Error Term object on success, \WP_Error object on failure. |
| 882 | 928 | */ |
| 883 | 929 | public function get_term( $taxonomy, $term_id, $term_key = 'term_id' ) { |
| @@ -1085,12 +1131,13 @@ | ||
| 1085 | 1131 | * |
| 1086 | 1132 | * @access public |
| 1087 | 1133 | * |
| 1088 | 1134 | * @param int $user_id User ID. |
| 1089 | - * @return \WP_User User object. | |
| 1135 | + * @return \WP_User|null User object, or `null` if user invalid/not found. | |
| 1090 | 1136 | */ |
| 1091 | 1137 | public function get_user( $user_id ) { |
| 1092 | - return \WP_User::get_instance( $user_id ); | |
| 1138 | + $user = get_user_by( 'id', $user_id ); | |
| 1139 | + return $user instanceof \WP_User ? $user : null; | |
| 1093 | 1140 | } |
| 1094 | 1141 | |
| 1095 | 1142 | /** |
| 1096 | 1143 | * Insert or update a user. |
| @@ -1170,9 +1217,8 @@ | ||
| 1170 | 1217 | } |
| 1171 | 1218 | |
| 1172 | 1219 | /** |
| 1173 | 1220 | * Retrieve all the checksums we are interested in. |
| 1174 | - * Currently that is posts, comments, post meta and comment meta. | |
| 1175 | 1221 | * |
| 1176 | 1222 | * @access public |
| 1177 | 1223 | * |
| 1178 | 1224 | * @param boolean $perform_text_conversion If text fields should be latin1 converted. |
| @@ -1179,62 +1225,28 @@ | ||
| 1179 | 1225 | * |
| 1180 | 1226 | * @return array Checksums. |
| 1181 | 1227 | */ |
| 1182 | 1228 | public function checksum_all( $perform_text_conversion = false ) { |
| 1183 | - $post_checksum = $this->checksum_histogram( 'posts', null, null, null, null, true, '', false, false, $perform_text_conversion ); | |
| 1184 | - $comments_checksum = $this->checksum_histogram( 'comments', null, null, null, null, true, '', false, false, $perform_text_conversion ); | |
| 1185 | - $post_meta_checksum = $this->checksum_histogram( 'postmeta', null, null, null, null, true, '', false, false, $perform_text_conversion ); | |
| 1186 | - $comment_meta_checksum = $this->checksum_histogram( 'commentmeta', null, null, null, null, true, '', false, false, $perform_text_conversion ); | |
| 1187 | - $terms_checksum = $this->checksum_histogram( 'terms', null, null, null, null, true, '', false, false, $perform_text_conversion ); | |
| 1188 | - $term_relationships_checksum = $this->checksum_histogram( 'term_relationships', null, null, null, null, true, '', false, false, $perform_text_conversion ); | |
| 1189 | - $term_taxonomy_checksum = $this->checksum_histogram( 'term_taxonomy', null, null, null, null, true, '', false, false, $perform_text_conversion ); | |
| 1229 | + $all_checksum_tables = Table_Checksum::get_allowed_tables(); | |
| 1190 | 1230 | |
| 1191 | - $result = array( | |
| 1192 | - 'posts' => $this->summarize_checksum_histogram( $post_checksum ), | |
| 1193 | - 'comments' => $this->summarize_checksum_histogram( $comments_checksum ), | |
| 1194 | - 'post_meta' => $this->summarize_checksum_histogram( $post_meta_checksum ), | |
| 1195 | - 'comment_meta' => $this->summarize_checksum_histogram( $comment_meta_checksum ), | |
| 1196 | - 'terms' => $this->summarize_checksum_histogram( $terms_checksum ), | |
| 1197 | - 'term_relationships' => $this->summarize_checksum_histogram( $term_relationships_checksum ), | |
| 1198 | - 'term_taxonomy' => $this->summarize_checksum_histogram( $term_taxonomy_checksum ), | |
| 1199 | - ); | |
| 1231 | + unset( $all_checksum_tables['users'] ); // Handled separately - TODO. | |
| 1232 | + unset( $all_checksum_tables['usermeta'] ); // Handled separately - TODO. | |
| 1233 | + unset( $all_checksum_tables['termmeta'] ); // Handled separately - TODO. | |
| 1234 | + unset( $all_checksum_tables['links'] ); // Not supported yet. Consider removing from default config. | |
| 1235 | + unset( $all_checksum_tables['options'] ); // Not supported yet. Consider removing from default config. | |
| 1200 | 1236 | |
| 1201 | - /** | |
| 1202 | - * WooCommerce tables | |
| 1203 | - */ | |
| 1237 | + $all_checksum_tables = array_unique( array_keys( $all_checksum_tables ) ); | |
| 1204 | 1238 | |
| 1205 | - /** | |
| 1206 | - * On WordPress.com, we can't directly check if the site has support for WooCommerce. | |
| 1207 | - * Having the option to override the functionality here helps with syncing WooCommerce tables. | |
| 1208 | - * | |
| 1209 | - * @since 10.1 | |
| 1210 | - * | |
| 1211 | - * @param bool If we should we force-enable WooCommerce tables support. | |
| 1212 | - */ | |
| 1213 | - $force_woocommerce_support = apply_filters( 'jetpack_table_checksum_force_enable_woocommerce', false ); | |
| 1239 | + $result = array(); | |
| 1214 | 1240 | |
| 1215 | - if ( $force_woocommerce_support || class_exists( 'WooCommerce' ) ) { | |
| 1216 | - /** | |
| 1217 | - * Guard in Try/Catch as it's possible for the WooCommerce class to exist, but | |
| 1218 | - * the tables to not. If we don't do this, the response will be just the exception, without | |
| 1219 | - * returning any valid data. This will prevent us from ever performing a checksum/fix | |
| 1220 | - * for sites like this. | |
| 1221 | - * It's better to just skip the tables in the response, instead of completely failing. | |
| 1222 | - */ | |
| 1223 | - | |
| 1241 | + foreach ( $all_checksum_tables as $table ) { | |
| 1242 | + $result_key = in_array( $table, array( 'postmeta', 'commentmeta' ), true ) ? str_replace( 'meta', '_meta', $table ) : $table; | |
| 1224 | 1243 | try { |
| 1225 | - $woocommerce_order_items_checksum = $this->checksum_histogram( 'woocommerce_order_items' ); | |
| 1226 | - $result['woocommerce_order_items'] = $this->summarize_checksum_histogram( $woocommerce_order_items_checksum ); | |
| 1244 | + $checksum = $this->checksum_histogram( $table, null, null, null, null, true, '', false, false, $perform_text_conversion ); | |
| 1245 | + $result[ $result_key ] = $this->summarize_checksum_histogram( $checksum ); | |
| 1227 | 1246 | } catch ( Exception $ex ) { |
| 1228 | - $result['woocommerce_order_items'] = null; | |
| 1247 | + $result[ $result_key ] = null; | |
| 1229 | 1248 | } |
| 1230 | - | |
| 1231 | - try { | |
| 1232 | - $woocommerce_order_itemmeta_checksum = $this->checksum_histogram( 'woocommerce_order_itemmeta' ); | |
| 1233 | - $result['woocommerce_order_itemmeta'] = $this->summarize_checksum_histogram( $woocommerce_order_itemmeta_checksum ); | |
| 1234 | - } catch ( Exception $ex ) { | |
| 1235 | - $result['woocommerce_order_itemmeta'] = null; | |
| 1236 | - } | |
| 1237 | 1249 | } |
| 1238 | 1250 | |
| 1239 | 1251 | return $result; |
| 1240 | 1252 | } |
| @@ -1319,9 +1331,9 @@ | ||
| 1319 | 1331 | |
| 1320 | 1332 | try { |
| 1321 | 1333 | $range_edges = $checksum_table->get_range_edges( $start_id, $end_id ); |
| 1322 | 1334 | } catch ( Exception $ex ) { |
| 1323 | - return new WP_Error( 'invalid_range_edges', '[' . $start_id . '-' . $end_id . ']: ' . $ex->getMessage() ); | |
| 1335 | + return new WP_Error( 'invalid_range_edges', '[' . ( $start_id ?? 'null' ) . '-' . ( $end_id ?? 'null' ) . ']: ' . $ex->getMessage() ); | |
| 1324 | 1336 | } |
| 1325 | 1337 | |
| 1326 | 1338 | if ( $only_range_edges ) { |
| 1327 | 1339 | return $range_edges; |
| @@ -1365,9 +1377,12 @@ | ||
| 1365 | 1377 | $histogram[ $ids_range['min_range'] ] = $batch_checksum; |
| 1366 | 1378 | } else { |
| 1367 | 1379 | $histogram[ "{$ids_range[ 'min_range' ]}-{$ids_range[ 'max_range' ]}" ] = $batch_checksum; |
| 1368 | 1380 | } |
| 1369 | - | |
| 1381 | + // If ids_range['max_range'] is PHP_INT_MAX, we've reached the end of the table. Edge case causing the loop to never end. | |
| 1382 | + if ( PHP_INT_MAX === (int) $ids_range['max_range'] ) { | |
| 1383 | + break; | |
| 1384 | + } | |
| 1370 | 1385 | $previous_max_id = $ids_range['max_range'] + 1; |
| 1371 | 1386 | // If we've reached the max_range lets bail out. |
| 1372 | 1387 | if ( $previous_max_id > $range_edges['max_range'] ) { |
| 1373 | 1388 | break; |
| @@ -1391,8 +1406,9 @@ | ||
| 1391 | 1406 | /** |
| 1392 | 1407 | * Used in methods that are not implemented and shouldn't be invoked. |
| 1393 | 1408 | * |
| 1394 | 1409 | * @access private |
| 1410 | + * @return never | |
| 1395 | 1411 | * @throws Exception If this method is invoked. |
| 1396 | 1412 | */ |
| 1397 | 1413 | private function invalid_call() { |
| 1398 | 1414 | // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace |