Completed
Push — fix/gulp-env ( ec4107...cf0b47 )
by
unknown
133:51 queued 124:05
created

Jetpack_Sync_WP_Replicastore::upsert_user()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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();
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $post. This often makes code more readable.
Loading history...
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 );
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $post. This often makes code more readable.
Loading history...
106
107
		$post = sanitize_post( $post, 'db' );
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $post. This often makes code more readable.
Loading history...
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;
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $comment. This often makes code more readable.
Loading history...
193
		} else {
194
			// WP 4.4 introduced the WP_Comment Class
195
			$comment = $comment->to_array();
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $comment. This often makes code more readable.
Loading history...
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 options_checksum() {
262
		global $wpdb;
263
264
		$options_whitelist = "'" . implode( "', '", Jetpack_Sync_Defaults::$default_options_whitelist ) . "'";
0 ignored issues
show
Bug introduced by
The property default_options_whitelist cannot be accessed from this context as it is declared private in class Jetpack_Sync_Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
265
		$query = <<<ENDSQL
266
			SELECT CONV(BIT_XOR(CRC32(CONCAT(option_name,option_value))), 10, 16) FROM $wpdb->options WHERE option_name IN ( $options_whitelist ) 
267
ENDSQL;
268
269
		return $wpdb->get_var( $query );
270
	}
271
	
272
273
	public function update_option( $option, $value ) {
274
		return update_option( $option, $value );
275
	}
276
277
	public function get_option( $option, $default = false ) {
278
		return get_option( $option, $default );
279
	}
280
281
	public function delete_option( $option ) {
282
		return delete_option( $option );
283
	}
284
285
	public function set_theme_support( $theme_support ) {
286
		// noop
287
	}
288
289
	public function current_theme_supports( $feature ) {
290
		return current_theme_supports( $feature );
291
	}
292
293
	public function get_metadata( $type, $object_id, $meta_key = '', $single = false ) {
294
		return get_metadata( $type, $object_id, $meta_key, $single );
295
	}
296
297
	/**
298
	 *
299
	 * Stores remote meta key/values alongside an ID mapping key
300
	 *
301
	 * @param $type
302
	 * @param $object_id
303
	 * @param $meta_key
304
	 * @param $meta_value
305
	 * @param $meta_id
306
	 *
307
	 * @return bool
308
	 */
309
	public function upsert_metadata( $type, $object_id, $meta_key, $meta_value, $meta_id ) {
310
311
		$table = _get_meta_table( $type );
312
		if ( ! $table ) {
313
			return false;
314
		}
315
316
		global $wpdb;
317
318
		$exists = $wpdb->get_var( $wpdb->prepare(
319
			"SELECT EXISTS( SELECT 1 FROM $table WHERE meta_id = %d )",
320
			$meta_id
321
		) );
322
323
		if ( $exists ) {
324
			$wpdb->update( $table, array( 'meta_key'   => $meta_key,
325
			                              'meta_value' => serialize( $meta_value )
326
			), array( 'meta_id' => $meta_id ) );
327
		} else {
328
			$object_id_field = $type . '_id';
329
			$wpdb->insert( $table, array( 'meta_id'        => $meta_id,
330
			                              $object_id_field => $object_id,
331
			                              'meta_key'       => $meta_key,
332
			                              'meta_value'     => serialize( $meta_value )
333
			) );
334
		}
335
336
		wp_cache_delete( $object_id, $type . '_meta' );
337
338
		return true;
339
	}
340
341
	public function delete_metadata( $type, $object_id, $meta_ids ) {
342
		global $wpdb;
343
344
		$table = _get_meta_table( $type );
345
		if ( ! $table ) {
346
			return false;
347
		}
348
349
		foreach ( $meta_ids as $meta_id ) {
350
			$wpdb->query( $wpdb->prepare( "DELETE FROM $table WHERE meta_id = %d", $meta_id ) );
351
		}
352
353
		// if we don't have an object ID what do we do - invalidate ALL meta?
354
		if ( $object_id ) {
355
			wp_cache_delete( $object_id, $type . '_meta' );
356
		}
357
	}
358
359
	// constants
360
	public function get_constant( $constant ) {
361
		$value = get_option( 'jetpack_constant_' . $constant );
362
363
		if ( $value ) {
364
			return $value;
365
		}
366
367
		return null;
368
	}
369
370
	public function set_constant( $constant, $value ) {
371
		update_option( 'jetpack_constant_' . $constant, $value );
372
	}
373
374
	public function get_updates( $type ) {
375
		$all_updates = get_option( 'jetpack_updates', array() );
376
377
		if ( isset( $all_updates[ $type ] ) ) {
378
			return $all_updates[ $type ];
379
		} else {
380
			return null;
381
		}
382
	}
383
384
	public function set_updates( $type, $updates ) {
385
		$all_updates          = get_option( 'jetpack_updates', array() );
386
		$all_updates[ $type ] = $updates;
387
		update_option( 'jetpack_updates', $all_updates );
388
	}
389
390
	// functions
391
	public function get_callable( $name ) {
392
		$value = get_option( 'jetpack_' . $name );
393
394
		if ( $value ) {
395
			return $value;
396
		}
397
398
		return null;
399
	}
400
401
	public function set_callable( $name, $value ) {
402
		update_option( 'jetpack_' . $name, $value );
403
	}
404
405
	// network options
406
	public function get_site_option( $option ) {
407
		return get_option( 'jetpack_network_' . $option );
408
	}
409
410
	public function update_site_option( $option, $value ) {
411
		return update_option( 'jetpack_network_' . $option, $value );
412
	}
413
414
	public function delete_site_option( $option ) {
415
		return delete_option( 'jetpack_network_' . $option );
416
	}
417
418
	// terms
419
	// terms
420
	public function get_terms( $taxonomy ) {
421
		return get_terms( $taxonomy );
422
	}
423
424
	public function get_term( $taxonomy, $term_id, $is_term_id = true ) {
425
		$t = $this->ensure_taxonomy( $taxonomy );
426
		if ( ! $t || is_wp_error( $t ) ) {
427
			return $t;
428
		}
429
430
		return get_term( $term_id, $taxonomy );
431
	}
432
433
	private function ensure_taxonomy( $taxonomy ) {
434
		if ( ! taxonomy_exists( $taxonomy ) ) {
435
			// try re-registering synced taxonomies
436
			$taxonomies = $this->get_callable( 'taxonomies' );
437
			if ( ! isset( $taxonomies[ $taxonomy ] ) ) {
438
				// doesn't exist, or somehow hasn't been synced
439
				return new WP_Error( 'invalid_taxonomy', "The taxonomy '$taxonomy' doesn't exist" );
440
			}
441
			$t = $taxonomies[ $taxonomy ];
442
443
			return register_taxonomy(
444
				$taxonomy,
445
				$t->object_type,
446
				(array) $t
447
			);
448
		}
449
450
		return true;
451
	}
452
453
	public function get_the_terms( $object_id, $taxonomy ) {
454
		return get_the_terms( $object_id, $taxonomy );
455
	}
456
457
	public function update_term( $term_object ) {
458
		$taxonomy = $term_object->taxonomy;
459
		global $wpdb;
460
		$exists = $wpdb->get_var( $wpdb->prepare(
461
			"SELECT EXISTS( SELECT 1 FROM $wpdb->terms WHERE term_id = %d )",
462
			$term_object->term_id
463
		) );
464
		if ( ! $exists ) {
465
			$term_object   = sanitize_term( clone( $term_object ), $taxonomy, 'db' );
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $term_object. This often makes code more readable.
Loading history...
466
			$term          = array(
467
				'term_id'    => $term_object->term_id,
468
				'name'       => $term_object->name,
469
				'slug'       => $term_object->slug,
470
				'term_group' => $term_object->term_group,
471
			);
472
			$term_taxonomy = array(
473
				'term_taxonomy_id' => $term_object->term_taxonomy_id,
474
				'term_id'          => $term_object->term_id,
475
				'taxonomy'         => $term_object->taxonomy,
476
				'description'      => $term_object->description,
477
				'parent'           => (int) $term_object->parent,
478
				'count'            => (int) $term_object->count,
479
			);
480
			$wpdb->insert( $wpdb->terms, $term );
481
			$wpdb->insert( $wpdb->term_taxonomy, $term_taxonomy );
482
483
//			clean_term_cache( $term_object->term_id, $taxonomy );
484
485
			return true;
486
		}
487
488
		return wp_update_term( $term_object->term_id, $taxonomy, (array) $term_object );
489
	}
490
491
	public function delete_term( $term_id, $taxonomy ) {
492
		return wp_delete_term( $term_id, $taxonomy );
493
	}
494
495
	public function update_object_terms( $object_id, $taxonomy, $terms, $append ) {
496
		wp_set_object_terms( $object_id, $terms, $taxonomy, $append );
497
	}
498
499
	public function delete_object_terms( $object_id, $tt_ids ) {
500
		global $wpdb;
501
502
		if ( is_array( $tt_ids ) && ! empty( $tt_ids ) ) {
503
			$taxonomies = array();
504
			foreach ( $tt_ids as $tt_id ) {
505
				$term                            = get_term_by( 'term_taxonomy_id', $tt_id );
506
				$taxonomies[ $term->taxonomy ][] = $tt_id;
507
			}
508
			$in_tt_ids = "'" . implode( "', '", $tt_ids ) . "'";
509
510
			/**
511
			 * Fires immediately before 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( 'delete_term_relationships', $object_id, $tt_ids );
519
			$deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) );
520
			foreach ( $taxonomies as $taxonomy => $taxonomy_tt_ids ) {
521
				wp_cache_delete( $object_id, $taxonomy . '_relationships' );
522
				/**
523
				 * Fires immediately after an object-term relationship is deleted.
524
				 *
525
				 * @since 2.9.0
526
				 *
527
				 * @param int $object_id Object ID.
528
				 * @param array $tt_ids An array of term taxonomy IDs.
529
				 */
530
				do_action( 'deleted_term_relationships', $object_id, $taxonomy_tt_ids );
531
				wp_update_term_count( $taxonomy_tt_ids, $taxonomy );
532
			}
533
534
			return (bool) $deleted;
535
		}
536
537
		return false;
538
	}
539
540
	// users
541
	public function user_count() {
542
543
	}
544
545
	public function get_user( $user_id ) {
546
		return WP_User::get_instance( $user_id );
547
	}
548
549
	public function upsert_user( $user ) {
550
		$this->invalid_call();
551
	}
552
553
	public function delete_user( $user_id ) {
554
		$this->invalid_call();
555
	}
556
557
	public function get_allowed_mime_types( $user_id ) {
558
559
	}
560
561
	public function checksum_all() {
562
		return array(
563
			'posts'    => $this->posts_checksum(),
564
			'comments' => $this->comments_checksum(),
565
			'options' => $this->options_checksum(),
566
		);
567
	}
568
569
	private function invalid_call() {
570
		$backtrace = debug_backtrace();
571
		$caller    = $backtrace[1]['function'];
572
		throw new Exception( "This function $caller is not supported on the WP Replicastore" );
573
	}
574
}
575