Completed
Push — branch-4.2 ( 1c7f7d...820ca9 )
by Jeremy
14:43 queued 04:22
created

Jetpack_Sync_WP_Replicastore::upsert_plugins()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 2
Metric Value
cc 1
eloc 1
c 2
b 0
f 2
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
require_once 'interface.jetpack-sync-replicastore.php';
4
5
/**
6
 * An implementation of iJetpack_Sync_Replicastore which returns data stored in a WordPress.org DB.
7
 * This is useful to compare values in the local WP DB to values in the synced replica store
8
 */
9
class Jetpack_Sync_WP_Replicastore implements iJetpack_Sync_Replicastore {
10
	
11
12
	public function reset() {
13
		global $wpdb;
14
15
		$wpdb->query( "DELETE FROM $wpdb->posts" );
16
		$wpdb->query( "DELETE FROM $wpdb->comments" );
17
18
		// also need to delete terms from cache
19
		$term_ids = $wpdb->get_col( "SELECT term_id FROM $wpdb->terms" );
20
		foreach ( $term_ids as $term_id ) {
21
			wp_cache_delete( $term_id, 'terms' );
22
		}
23
24
		$wpdb->query( "DELETE FROM $wpdb->terms" );
25
26
		$wpdb->query( "DELETE FROM $wpdb->term_taxonomy" );
27
		$wpdb->query( "DELETE FROM $wpdb->term_relationships" );
28
29
		// callables and constants
30
		$wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE 'jetpack_%'" );
31
		$wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key NOT LIKE '\_%'" );
32
	}
33
34
	function full_sync_start() {
35
		$this->reset();
36
	}
37
38
	function full_sync_end( $checksum ) {
39
		// noop right now
40
	}
41
42
	public function post_count( $status = null ) {
43
		return count( $this->get_posts( $status ) );
44
	}
45
46
	public function get_posts( $status = null ) {
47
		$args = array( 'orderby' => 'ID' );
48
49
		if ( $status ) {
50
			$args['post_status'] = $status;
51
		} else {
52
			$args['post_status'] = 'any';
53
		}
54
55
		return get_posts( $args );
56
	}
57
58
	public function get_post( $id ) {
59
		return get_post( $id );
60
	}
61
62
	public function upsert_post( $post, $silent = false ) {
63
		global $wpdb;
64
65
		// reject the post if it's not a WP_Post
66
		if ( ! $post instanceof WP_Post ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
67
			return;
68
		}
69
70
		$post = $post->to_array();
71
72
		// reject posts without an ID
73
		if ( ! isset( $post['ID'] ) ) {
74
			return;
75
		}
76
77
		$now     = current_time( 'mysql' );
78
		$now_gmt = get_gmt_from_date( $now );
79
80
		$defaults = array(
81
			'ID'                    => 0,
82
			'post_author'           => '0',
83
			'post_content'          => '',
84
			'post_content_filtered' => '',
85
			'post_title'            => '',
86
			'post_name'             => '',
87
			'post_excerpt'          => '',
88
			'post_status'           => 'draft',
89
			'post_type'             => 'post',
90
			'comment_status'        => 'closed',
91
			'comment_count'         => '0',
92
			'ping_status'           => '',
93
			'post_password'         => '',
94
			'to_ping'               => '',
95
			'pinged'                => '',
96
			'post_parent'           => 0,
97
			'menu_order'            => 0,
98
			'guid'                  => '',
99
			'post_date'             => $now,
100
			'post_date_gmt'         => $now_gmt,
101
			'post_modified'         => $now,
102
			'post_modified_gmt'     => $now_gmt,
103
		);
104
105
		$post = array_intersect_key( $post, $defaults );
106
107
		$post = sanitize_post( $post, 'db' );
108
109
		unset( $post['filter'] );
110
111
		$exists = $wpdb->get_var( $wpdb->prepare( "SELECT EXISTS( SELECT 1 FROM $wpdb->posts WHERE ID = %d )", $post['ID'] ) );
112
113
		if ( $exists ) {
114
			$wpdb->update( $wpdb->posts, $post, array( 'ID' => $post['ID'] ) );
115
		} else {
116
			$wpdb->insert( $wpdb->posts, $post );
117
		}
118
119
		clean_post_cache( $post['ID'] );
120
	}
121
122
	public function delete_post( $post_id ) {
123
		wp_delete_post( $post_id, true );
124
	}
125
126
	public function posts_checksum() {
127
		global $wpdb;
128
129
		$post_type_sql = Jetpack_Sync_Defaults::get_blacklisted_post_types_sql();
130
131
		$query = <<<ENDSQL
132
			SELECT CONV(BIT_XOR(CRC32(CONCAT(ID,post_modified))), 10, 16) 
133
				FROM $wpdb->posts
134
				WHERE $post_type_sql
135
ENDSQL;
136
137
		return $wpdb->get_var( $query );
138
	}
139
140
	public function comment_count( $status = null ) {
141
		global $wpdb;
142
143
		$comment_approved = $this->comment_status_to_approval_value( $status );
144
145
		if ( $comment_approved !== false ) {
146
			return $wpdb->get_var( $wpdb->prepare(
147
				"SELECT COUNT(*) FROM $wpdb->comments WHERE comment_approved = %s",
148
				$comment_approved
149
			) );
150
		} else {
151
			return $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->comments" );
152
		}
153
	}
154
155
	private function comment_status_to_approval_value( $status ) {
156
		switch ( $status ) {
157
			case 'approve':
158
				return "1";
159
			case 'hold':
160
				return "0";
161
			case 'spam':
162
				return 'spam';
163
			case 'trash':
164
				return 'trash';
165
			case 'any':
166
				return false;
167
			case 'all':
168
				return false;
169
			default:
170
				return false;
171
		}
172
	}
173
174
	public function get_comments( $status = null ) {
175
		$args = array( 'orderby' => 'ID', 'status' => 'all' );
176
177
		if ( $status ) {
178
			$args['status'] = $status;
179
		}
180
181
		return get_comments( $args );
182
	}
183
184
	public function get_comment( $id ) {
185
		return WP_Comment::get_instance( $id );
186
	}
187
188
	public function upsert_comment( $comment ) {
189
		global $wpdb, $wp_version;
190
191
		if ( version_compare( $wp_version, '4.4', '<' ) ) {
192
			$comment = (array) $comment;
193
		} else {
194
			// WP 4.4 introduced the WP_Comment Class
195
			$comment = $comment->to_array();
196
		}
197
198
		// filter by fields on comment table
199
		$comment_fields_whitelist = array(
200
			'comment_ID',
201
			'comment_post_ID',
202
			'comment_author',
203
			'comment_author_email',
204
			'comment_author_url',
205
			'comment_author_IP',
206
			'comment_date',
207
			'comment_date_gmt',
208
			'comment_content',
209
			'comment_karma',
210
			'comment_approved',
211
			'comment_agent',
212
			'comment_type',
213
			'comment_parent',
214
			'user_id'
215
		);
216
217
		foreach ( $comment as $key => $value ) {
218
			if ( ! in_array( $key, $comment_fields_whitelist ) ) {
219
				unset( $comment[ $key ] );
220
			}
221
		}
222
223
		$exists = $wpdb->get_var(
224
			$wpdb->prepare(
225
				"SELECT EXISTS( SELECT 1 FROM $wpdb->comments WHERE comment_ID = %d )",
226
				$comment['comment_ID']
227
			)
228
		);
229
230
		if ( $exists ) {
231
			$wpdb->update( $wpdb->comments, $comment, array( 'comment_ID' => $comment['comment_ID'] ) );
232
		} else {
233
			$wpdb->insert( $wpdb->comments, $comment );
234
		}
235
236
		wp_update_comment_count( $comment['comment_post_ID'] );
237
	}
238
239
	public function trash_comment( $comment_id ) {
240
		wp_delete_comment( $comment_id );
241
	}
242
243
	public function delete_comment( $comment_id ) {
244
		wp_delete_comment( $comment_id, true );
245
	}
246
247
	public function spam_comment( $comment_id ) {
248
		wp_spam_comment( $comment_id );
249
	}
250
251
	public function comments_checksum() {
252
		global $wpdb;
253
254
		$query = <<<ENDSQL
255
			SELECT CONV(BIT_XOR(CRC32(CONCAT(comment_ID,comment_content))), 10, 16) FROM $wpdb->comments
256
ENDSQL;
257
258
		return $wpdb->get_var( $query );
259
	}
260
261
	public function update_option( $option, $value ) {
262
		return update_option( $option, $value );
263
	}
264
265
	public function get_option( $option, $default = false ) {
266
		return get_option( $option, $default );
267
	}
268
269
	public function delete_option( $option ) {
270
		return delete_option( $option );
271
	}
272
273
	public function set_theme_support( $theme_support ) {
274
		// noop
275
	}
276
277
	public function current_theme_supports( $feature ) {
278
		return current_theme_supports( $feature );
279
	}
280
281
	public function get_metadata( $type, $object_id, $meta_key = '', $single = false ) {
282
		return get_metadata( $type, $object_id, $meta_key, $single );
283
	}
284
285
	/**
286
	 *
287
	 * Stores remote meta key/values alongside an ID mapping key
288
	 *
289
	 * @param $type
290
	 * @param $object_id
291
	 * @param $meta_key
292
	 * @param $meta_value
293
	 * @param $meta_id
294
	 *
295
	 * @return bool
296
	 */
297
	public function upsert_metadata( $type, $object_id, $meta_key, $meta_value, $meta_id ) {
298
299
		$table = _get_meta_table( $type );
300
		if ( ! $table ) {
301
			return false;
302
		}
303
304
		global $wpdb;
305
306
		$exists = $wpdb->get_var( $wpdb->prepare(
307
			"SELECT EXISTS( SELECT 1 FROM $table WHERE meta_id = %d )",
308
			$meta_id
309
		) );
310
311
		if ( $exists ) {
312
			$wpdb->update( $table, array( 'meta_key'   => $meta_key,
313
			                              'meta_value' => serialize( $meta_value )
314
			), array( 'meta_id' => $meta_id ) );
315
		} else {
316
			$object_id_field = $type . '_id';
317
			$wpdb->insert( $table, array( 'meta_id'        => $meta_id,
318
			                              $object_id_field => $object_id,
319
			                              'meta_key'       => $meta_key,
320
			                              'meta_value'     => serialize( $meta_value )
321
			) );
322
		}
323
324
		wp_cache_delete( $object_id, $type . '_meta' );
325
326
		return true;
327
	}
328
329
	public function delete_metadata( $type, $object_id, $meta_ids ) {
330
		global $wpdb;
331
332
		$table = _get_meta_table( $type );
333
		if ( ! $table ) {
334
			return false;
335
		}
336
337
		foreach ( $meta_ids as $meta_id ) {
338
			$wpdb->query( $wpdb->prepare( "DELETE FROM $table WHERE meta_id = %d", $meta_id ) );
339
		}
340
341
		// if we don't have an object ID what do we do - invalidate ALL meta?
342
		if ( $object_id ) {
343
			wp_cache_delete( $object_id, $type . '_meta' );
344
		}
345
	}
346
347
	// constants
348
	public function get_constant( $constant ) {
349
		$value = get_option( 'jetpack_constant_' . $constant );
350
351
		if ( $value ) {
352
			return $value;
353
		}
354
355
		return null;
356
	}
357
358
	public function set_constant( $constant, $value ) {
359
		update_option( 'jetpack_constant_' . $constant, $value );
360
	}
361
362
	public function get_updates( $type ) {
363
		$all_updates = get_option( 'jetpack_updates', array() );
364
365
		if ( isset( $all_updates[ $type ] ) ) {
366
			return $all_updates[ $type ];
367
		} else {
368
			return null;
369
		}
370
	}
371
372
	public function set_updates( $type, $updates ) {
373
		$all_updates          = get_option( 'jetpack_updates', array() );
374
		$all_updates[ $type ] = $updates;
375
		update_option( 'jetpack_updates', $all_updates );
376
	}
377
378
	// functions
379
	public function get_callable( $name ) {
380
		$value = get_option( 'jetpack_' . $name );
381
382
		if ( $value ) {
383
			return $value;
384
		}
385
386
		return null;
387
	}
388
389
	public function set_callable( $name, $value ) {
390
		update_option( 'jetpack_' . $name, $value );
391
	}
392
393
	// network options
394
	public function get_site_option( $option ) {
395
		return get_option( 'jetpack_network_' . $option );
396
	}
397
398
	public function update_site_option( $option, $value ) {
399
		return update_option( 'jetpack_network_' . $option, $value );
400
	}
401
402
	public function delete_site_option( $option ) {
403
		return delete_option( 'jetpack_network_' . $option );
404
	}
405
406
	// terms
407
	// terms
408
	public function get_terms( $taxonomy ) {
409
		return get_terms( $taxonomy );
410
	}
411
412
	public function get_term( $taxonomy, $term_id, $is_term_id = true ) {
413
		$t = $this->ensure_taxonomy( $taxonomy );
414
		if ( ! $t || is_wp_error( $t ) ) {
415
			return $t;
416
		}
417
418
		return get_term( $term_id, $taxonomy );
419
	}
420
421
	private function ensure_taxonomy( $taxonomy ) {
422
		if ( ! taxonomy_exists( $taxonomy ) ) {
423
			// try re-registering synced taxonomies
424
			$taxonomies = $this->get_callable( 'taxonomies' );
425
			if ( ! isset( $taxonomies[ $taxonomy ] ) ) {
426
				// doesn't exist, or somehow hasn't been synced
427
				return new WP_Error( 'invalid_taxonomy', "The taxonomy '$taxonomy' doesn't exist" );
428
			}
429
			$t = $taxonomies[ $taxonomy ];
430
431
			return register_taxonomy(
432
				$taxonomy,
433
				$t->object_type,
434
				(array) $t
435
			);
436
		}
437
438
		return true;
439
	}
440
441
	public function get_the_terms( $object_id, $taxonomy ) {
442
		return get_the_terms( $object_id, $taxonomy );
443
	}
444
445
	public function update_term( $term_object ) {
446
		$taxonomy = $term_object->taxonomy;
447
		global $wpdb;
448
		$exists = $wpdb->get_var( $wpdb->prepare(
449
			"SELECT EXISTS( SELECT 1 FROM $wpdb->terms WHERE term_id = %d )",
450
			$term_object->term_id
451
		) );
452
		if ( ! $exists ) {
453
			$term_object   = sanitize_term( clone( $term_object ), $taxonomy, 'db' );
454
			$term          = array(
455
				'term_id'    => $term_object->term_id,
456
				'name'       => $term_object->name,
457
				'slug'       => $term_object->slug,
458
				'term_group' => $term_object->term_group,
459
			);
460
			$term_taxonomy = array(
461
				'term_taxonomy_id' => $term_object->term_taxonomy_id,
462
				'term_id'          => $term_object->term_id,
463
				'taxonomy'         => $term_object->taxonomy,
464
				'description'      => $term_object->description,
465
				'parent'           => (int) $term_object->parent,
466
				'count'            => (int) $term_object->count,
467
			);
468
			$wpdb->insert( $wpdb->terms, $term );
469
			$wpdb->insert( $wpdb->term_taxonomy, $term_taxonomy );
470
471
//			clean_term_cache( $term_object->term_id, $taxonomy );
472
473
			return true;
474
		}
475
476
		return wp_update_term( $term_object->term_id, $taxonomy, (array) $term_object );
477
	}
478
479
	public function delete_term( $term_id, $taxonomy ) {
480
		return wp_delete_term( $term_id, $taxonomy );
481
	}
482
483
	public function update_object_terms( $object_id, $taxonomy, $terms, $append ) {
484
		wp_set_object_terms( $object_id, $terms, $taxonomy, $append );
485
	}
486
487
	public function delete_object_terms( $object_id, $tt_ids ) {
488
		global $wpdb;
489
490
		if ( is_array( $tt_ids ) && ! empty( $tt_ids ) ) {
491
			$taxonomies = array();
492
			foreach ( $tt_ids as $tt_id ) {
493
				$term                            = get_term_by( 'term_taxonomy_id', $tt_id );
494
				$taxonomies[ $term->taxonomy ][] = $tt_id;
495
			}
496
			$in_tt_ids = "'" . implode( "', '", $tt_ids ) . "'";
497
498
			/**
499
			 * Fires immediately before an object-term relationship is deleted.
500
			 *
501
			 * @since 2.9.0
502
			 *
503
			 * @param int $object_id Object ID.
504
			 * @param array $tt_ids An array of term taxonomy IDs.
505
			 */
506
			do_action( 'delete_term_relationships', $object_id, $tt_ids );
507
			$deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) );
508
			foreach ( $taxonomies as $taxonomy => $taxonomy_tt_ids ) {
509
				wp_cache_delete( $object_id, $taxonomy . '_relationships' );
510
				/**
511
				 * Fires immediately after an object-term relationship is deleted.
512
				 *
513
				 * @since 2.9.0
514
				 *
515
				 * @param int $object_id Object ID.
516
				 * @param array $tt_ids An array of term taxonomy IDs.
517
				 */
518
				do_action( 'deleted_term_relationships', $object_id, $taxonomy_tt_ids );
519
				wp_update_term_count( $taxonomy_tt_ids, $taxonomy );
520
			}
521
522
			return (bool) $deleted;
523
		}
524
525
		return false;
526
	}
527
528
	// users
529
	public function user_count() {
530
531
	}
532
533
	public function get_user( $user_id ) {
534
		return WP_User::get_instance( $user_id );
535
	}
536
537
	public function upsert_user( $user ) {
538
		$this->invalid_call();
539
	}
540
541
	public function delete_user( $user_id ) {
542
		$this->invalid_call();
543
	}
544
	
545
	// plugins
546
	public function get_plugins() {
547
		// TODO: Implement get_plugins() method.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
548
	}
549
550
	public function upsert_plugins( $plugins ) {
551
		// TODO: Implement upsert_plugins() method.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
552
	}
553
554
	public function checksum_all() {
555
		return array(
556
			'posts'    => $this->posts_checksum(),
557
			'comments' => $this->comments_checksum()
558
		);
559
	}
560
561
	private function invalid_call() {
562
		$backtrace = debug_backtrace();
563
		$caller    = $backtrace[1]['function'];
564
		throw new Exception( "This function $caller is not supported on the WP Replicastore" );
565
	}
566
}
567