Test Failed
Pull Request — master (#238)
by Jonathan
02:43
created

Object_Sync_Sf_WordPress   F

Complexity

Total Complexity 289

Size/Duplication

Total Lines 2487
Duplicated Lines 26.7 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 289
lcom 1
cbo 2
dl 664
loc 2487
rs 0.8
c 0
b 0
f 0

33 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 23 2
A get_object_types() 0 35 2
C get_wordpress_table_structure() 50 167 10
B get_wordpress_object_fields() 0 48 5
B get_wordpress_object_data() 0 55 10
A cache_get() 0 11 2
A cache_set() 0 15 3
A cache_expiration() 0 4 1
B object_fields() 0 61 9
B object_create() 21 49 9
C object_upsert() 0 65 10
B object_update() 24 52 9
B object_delete() 21 53 9
C user_create() 32 93 9
F user_upsert() 7 121 19
B user_update() 6 44 6
A user_delete() 0 6 1
D post_create() 29 77 13
F post_upsert() 113 149 21
B post_update() 35 55 10
A post_delete() 0 4 1
B attachment_create() 17 64 8
F attachment_upsert() 113 144 20
C attachment_update() 22 79 11
A attachment_delete() 0 4 1
C term_create() 35 70 11
F term_upsert() 51 123 21
B term_update() 41 61 8
A term_delete() 0 7 2
F comment_create() 27 77 12
F comment_upsert() 7 156 26
B comment_update() 13 59 7
A comment_delete() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Object_Sync_Sf_WordPress often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Object_Sync_Sf_WordPress, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Class file for Object_Sync_Sf_WordPress.
4
 *
5
 * @file
6
 */
7
8
if ( ! class_exists( 'Object_Sync_Salesforce' ) ) {
9
	die();
10
}
11
12
/**
13
 * Work with the WordPress $wpdb object. This class can make read and write calls to the WordPress database, and also cache the responses.
14
 */
15
class Object_Sync_Sf_WordPress {
16
17
	protected $wpdb;
18
	protected $version;
19
	protected $slug;
20
	protected $mappings;
21
	protected $logging;
22
	protected $option_prefix;
23
24
	/**
25
	 * Constructor which discovers objects in WordPress
26
	 *
27
	 * @param object $wpdb A wpdb object.
28
	 * @param string $version The plugin version.
29
	 * @param string $slug The plugin slug.
30
	 * @param object $mappings Mapping objects.
31
	 * @param object $logging a Object_Sync_Sf_Logging instance.
32
	 * @param string $option_prefix The plugin's option prefix
33
	 * @throws \Exception
34
	 */
35
	public function __construct( $wpdb, $version, $slug, $mappings, $logging, $option_prefix = '' ) {
36
		$this->wpdb          = $wpdb;
37
		$this->version       = $version;
38
		$this->slug          = $slug;
39
		$this->option_prefix = isset( $option_prefix ) ? $option_prefix : 'object_sync_for_salesforce_';
40
		$this->mappings      = $mappings;
41
		$this->logging       = $logging;
42
43
		add_action( 'admin_init', function() {
44
			$this->wordpress_objects = $this->get_object_types();
45
		} );
46
47
		$this->options = array(
48
			'cache'            => true,
49
			'cache_expiration' => $this->cache_expiration( 'wordpress_data_cache', 86400 ),
50
			'type'             => 'read',
51
		);
52
53
		$this->sfwp_transients = new Object_Sync_Sf_WordPress_Transient( 'sfwp_transients' );
54
55
		$this->debug = get_option( $this->option_prefix . 'debug_mode', false );
56
57
	}
58
59
	/**
60
	 * Get WordPress object types
61
	 *
62
	 * @return array $wordpress_objects
63
	 */
64
	public function get_object_types() {
65
		/*
66
		 * Allow developers to specify, especially non-post, content types that should be included or ignored.
67
		 * Here's an example of filters to add/remove types:
68
		 *
69
			add_filter( 'object_sync_for_salesforce_add_more_wordpress_types', 'add_more_types', 10, 1 );
70
			function add_more_types( $wordpress_object_types ) {
71
				$wordpress_object_types[] = 'foo'; // this will add to the existing types.
72
				return $wordpress_object_types;
73
			}
74
75
			add_filter( 'object_sync_for_salesforce_remove_wordpress_types', 'wordpress_object_types', 10, 1 );
76
			function remove_types( $types_to_remove ) {
77
				$types_to_remove[] = 'revision'; // this adds to the array of types to ignore
78
				return $types_to_remove;
79
			}
80
		*/
81
82
		// this should include the available object types and send them to the hook
83
		$wordpress_types_not_posts_include = array( 'user', 'comment', 'category', 'tag' );
84
		$wordpress_objects                 = array_merge( get_post_types(), $wordpress_types_not_posts_include );
85
		// this should be all the objects
86
		$wordpress_objects = apply_filters( $this->option_prefix . 'add_more_wordpress_types', $wordpress_objects );
87
88
		// by default, only remove the log type we use in this plugin
89
		$types_to_remove = apply_filters( $this->option_prefix . 'remove_wordpress_types', array( 'wp_log' ) );
90
91
		// if the hook filters out any types, remove them from the visible list
92
		if ( ! empty( $types_to_remove ) ) {
93
			$wordpress_objects = array_diff( $wordpress_objects, $types_to_remove );
94
		}
95
96
		sort( $wordpress_objects );
97
		return $wordpress_objects;
98
	}
99
100
	/**
101
	 * Get WordPress table structure for an object
102
	 *
103
	 * @param string $object_type The type of object.
104
	 * @return array $object_table_structure The table structure.
105
	 */
106
	public function get_wordpress_table_structure( $object_type ) {
107
		if ( 'attachment' === $object_type ) {
108
			$object_table_structure = array(
109
				'object_name'     => 'post',
110
				'content_methods' => array(
111
					'create' => 'wp_insert_attachment',
112
					'read'   => 'get_posts',
113
					'update' => 'wp_insert_attachment',
114
					'delete' => 'wp_delete_attachment',
115
					'match'  => 'get_posts',
116
				),
117
				'meta_methods'    => array(
118
					'create' => 'wp_generate_attachment_metadata',
119
					'read'   => 'wp_get_attachment_metadata',
120
					'update' => 'wp_update_attachment_metadata',
121
					'delete' => '',
122
					'match'  => 'WP_Query',
123
				),
124
				'content_table'   => $this->wpdb->prefix . 'posts',
125
				'id_field'        => 'ID',
126
				'meta_table'      => $this->wpdb->prefix . 'postmeta',
127
				'meta_join_field' => 'post_id',
128
				'where'           => 'AND ' . $this->wpdb->prefix . 'posts.post_type = "' . $object_type . '"',
129
				'ignore_keys'     => array(),
130
			);
131
		} elseif ( 'user' === $object_type ) {
132
			// User meta fields need to use update_user_meta for create as well, otherwise it'll just get created twice because apparently when the post is created it's already there.
133
134
			// if the user is on WordPress VIP, the meta method is get_user_attribute
135
			if ( ( defined( 'WPCOM_IS_VIP_ENV' ) && WPCOM_IS_VIP_ENV ) ) {
136
				$user_meta_methods = array(
137
					'create' => 'update_user_attribute',
138
					'read'   => 'get_user_attribute',
139
					'update' => 'update_user_attribute',
140
					'delete' => 'delete_user_attribute',
141
				);
142
			} else {
143
				$user_meta_methods = array(
144
					'create' => 'update_user_meta',
145
					'read'   => 'get_user_meta',
146
					'update' => 'update_user_meta',
147
					'delete' => 'delete_user_meta',
148
				);
149
			}
150
151
			$object_table_structure = array(
152
				'object_name'     => 'user',
153
				'content_methods' => array(
154
					'create' => 'wp_insert_user',
155
					'read'   => 'get_user_by',
156
					'update' => 'wp_update_user',
157
					'delete' => 'wp_delete_user',
158
					'match'  => 'get_user_by',
159
				),
160
				'meta_methods'    => $user_meta_methods,
161
				'content_table'   => $this->wpdb->prefix . 'users',
162
				'id_field'        => 'ID',
163
				'meta_table'      => $this->wpdb->prefix . 'usermeta',
164
				'meta_join_field' => 'user_id',
165
				'where'           => '',
166
				'ignore_keys'     => array( // Keep it simple and avoid security risks.
167
					'user_pass',
168
					'user_activation_key',
169
					'session_tokens',
170
				),
171
			);
172 View Code Duplication
		} elseif ( 'post' === $object_type ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
			$object_table_structure = array(
174
				'object_name'     => 'post',
175
				'content_methods' => array(
176
					'create' => 'wp_insert_post',
177
					'read'   => 'get_posts',
178
					'update' => 'wp_update_post',
179
					'delete' => 'wp_delete_post',
180
					'match'  => 'get_posts',
181
				),
182
				'meta_methods'    => array(
183
					'create' => 'add_post_meta',
184
					'read'   => 'get_post_meta',
185
					'update' => 'update_post_meta',
186
					'delete' => 'delete_post_meta',
187
					'match'  => 'WP_Query',
188
				),
189
				'content_table'   => $this->wpdb->prefix . 'posts',
190
				'id_field'        => 'ID',
191
				'meta_table'      => $this->wpdb->prefix . 'postmeta',
192
				'meta_join_field' => 'post_id',
193
				'where'           => 'AND ' . $this->wpdb->prefix . 'posts.post_type = "' . $object_type . '"',
194
				'ignore_keys'     => array(),
195
			);
196
		} elseif ( 'category' === $object_type || 'tag' === $object_type || 'post_tag' === $object_type ) {
197
			// I am unsure why post_tag wasn't here for so long, but i figure it probably needs to be there.
198
			$object_table_structure = array(
199
				'object_name'     => 'term',
200
				'content_methods' => array(
201
					'create' => 'wp_insert_term',
202
					'read'   => 'get_term_by',
203
					'update' => 'wp_update_term',
204
					'delete' => 'wp_delete_term',
205
					'match'  => 'get_term_by',
206
				),
207
				'meta_methods'    => array(
208
					'create' => 'add_term_meta',
209
					'read'   => 'get_term_meta',
210
					'update' => 'update_term_meta',
211
					'delete' => 'delete_metadata',
212
					'match'  => 'WP_Term_Query',
213
				),
214
				'content_table'   => $this->wpdb->prefix . 'terms',
215
				'id_field'        => 'term_id',
216
				'meta_table'      => array( $this->wpdb->prefix . 'termmeta', $this->wpdb->prefix . 'term_taxonomy' ),
217
				'meta_join_field' => 'term_id',
218
				'where'           => '',
219
				'ignore_keys'     => array(),
220
			);
221
		} elseif ( 'comment' === $object_type ) {
222
			$object_table_structure = array(
223
				'object_name'     => 'comment',
224
				'content_methods' => array(
225
					'create' => 'wp_new_comment',
226
					'read'   => 'get_comments',
227
					'update' => 'wp_update_comment',
228
					'delete' => 'wp_delete_comment',
229
					'match'  => 'get_comments',
230
				),
231
				'meta_methods'    => array(
232
					'create' => 'add_comment_meta',
233
					'read'   => 'get_comment_meta',
234
					'update' => 'update_comment_meta',
235
					'delete' => 'delete_comment_metadata',
236
					'match'  => 'WP_Comment_Query',
237
				),
238
				'content_table'   => $this->wpdb->prefix . 'comments',
239
				'id_field'        => 'comment_ID',
240
				'meta_table'      => $this->wpdb->prefix . 'commentmeta',
241
				'meta_join_field' => 'comment_id',
242
				'where'           => '',
243
				'ignore_keys'     => array(),
244
			);
245 View Code Duplication
		} else { // This is for custom post types.
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
246
			$object_table_structure = array(
247
				'object_name'     => 'post',
248
				'content_methods' => array(
249
					'create' => 'wp_insert_post',
250
					'read'   => 'get_posts',
251
					'update' => 'wp_update_post',
252
					'delete' => 'wp_delete_post',
253
					'match'  => 'get_posts',
254
				),
255
				'meta_methods'    => array(
256
					'create' => 'add_post_meta',
257
					'read'   => 'get_post_meta',
258
					'update' => 'update_post_meta',
259
					'delete' => 'delete_post_meta',
260
					'match'  => 'WP_Query',
261
				),
262
				'content_table'   => $this->wpdb->prefix . 'posts',
263
				'id_field'        => 'ID',
264
				'meta_table'      => $this->wpdb->prefix . 'postmeta',
265
				'meta_join_field' => 'post_id',
266
				'where'           => 'AND ' . $this->wpdb->prefix . 'posts.post_type = "' . $object_type . '"',
267
				'ignore_keys'     => array(),
268
			);
269
		} // End if().
270
271
		return $object_table_structure;
272
	}
273
274
	/**
275
	 * Get WordPress fields for an object
276
	 *
277
	 * @param string $wordpress_object The type of WordPress object.
278
	 * @param string $id_field The field of that object that corresponds with its ID in the database.
279
	 * @return array $object_fields
280
	 */
281
	public function get_wordpress_object_fields( $wordpress_object, $id_field = 'ID' ) {
0 ignored issues
show
Unused Code introduced by
The parameter $id_field is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
282
283
		$object_table_structure = $this->get_wordpress_table_structure( $wordpress_object );
284
285
		$meta_table      = $object_table_structure['meta_table'];
286
		$meta_methods    = maybe_unserialize( $object_table_structure['meta_methods'] );
287
		$content_table   = $object_table_structure['content_table'];
288
		$content_methods = maybe_unserialize( $object_table_structure['content_methods'] );
289
		$id_field        = $object_table_structure['id_field'];
290
		$object_name     = $object_table_structure['object_name'];
291
		$where           = $object_table_structure['where'];
292
		$ignore_keys     = $object_table_structure['ignore_keys'];
293
294
		$object_fields = array();
295
296
		// Try to find the object fields in cache before acquiring it from other source.
297
		if ( true === $this->options['cache'] && 'write' !== $this->options['cache'] ) {
298
			$cached = $this->cache_get( $wordpress_object, array( 'data', 'meta' ) );
299
			if ( is_array( $cached ) ) {
300
				$object_fields['data']       = $cached;
301
				$object_fields['from_cache'] = true;
302
				$object_fields['cached']     = true;
303
			} else {
304
				$object_fields['data'] = $this->object_fields( $object_name, $id_field, $content_table, $content_methods, $meta_table, $meta_methods, $where, $ignore_keys );
0 ignored issues
show
Bug introduced by
It seems like $meta_table defined by $object_table_structure['meta_table'] on line 285 can also be of type array<integer,string,{"0":"string","1":"string"}>; however, Object_Sync_Sf_WordPress::object_fields() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
305
				if ( ! empty( $object_fields['data'] ) ) {
306
					$object_fields['cached'] = $this->cache_set( $wordpress_object, array( 'data', 'meta' ), $object_fields['data'], $this->options['cache_expiration'] );
307
				} else {
308
					$object_fields['cached'] = false;
309
				}
310
				$object_fields['from_cache'] = false;
311
			}
312
		} else {
313
			$object_fields['data']       = $this->object_fields( $object_name, $id_field, $content_table, $content_methods, $meta_table, $meta_methods, $where, $ignore_keys );
0 ignored issues
show
Bug introduced by
It seems like $meta_table defined by $object_table_structure['meta_table'] on line 285 can also be of type array<integer,string,{"0":"string","1":"string"}>; however, Object_Sync_Sf_WordPress::object_fields() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
314
			$object_fields['from_cache'] = false;
315
			$object_fields['cached']     = false;
316
		}
317
318
		/*
319
		 * Developers can use this hook to change the WordPress object field array.
320
		 * The returned $object_fields needs to be an array like is described earlier in this method:
321
		 *     $object_fields = array( 'data' => array(), 'from_cache' => bool, 'cached' => bool );
322
		 * This is useful for custom objects that do not use the normal metadata table structure.
323
		 */
324
		$object_fields = apply_filters( $this->option_prefix . 'wordpress_object_fields', $object_fields, $wordpress_object );
325
326
		return $object_fields['data'];
327
328
	}
329
330
	/**
331
	 * Get WordPress data based on what object it is
332
	 *
333
	 * @param string $object_type The type of object.
334
	 * @param string $object_id The ID of the object.
335
	 * @param bool $is_deleted Whether the WordPress object has been deleted
336
	 * @return array $wordpress_object
337
	 */
338
	public function get_wordpress_object_data( $object_type, $object_id, $is_deleted = false ) {
339
		$wordpress_object       = array();
340
		$object_table_structure = $this->get_wordpress_table_structure( $object_type );
341
342
		$meta_table      = $object_table_structure['meta_table'];
0 ignored issues
show
Unused Code introduced by
$meta_table is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
343
		$meta_methods    = maybe_unserialize( $object_table_structure['meta_methods'] );
0 ignored issues
show
Unused Code introduced by
$meta_methods is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
344
		$content_table   = $object_table_structure['content_table'];
0 ignored issues
show
Unused Code introduced by
$content_table is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
345
		$content_methods = maybe_unserialize( $object_table_structure['content_methods'] );
0 ignored issues
show
Unused Code introduced by
$content_methods is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
346
		$id_field        = $object_table_structure['id_field'];
347
		$object_name     = $object_table_structure['object_name'];
0 ignored issues
show
Unused Code introduced by
$object_name is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
348
		$where           = $object_table_structure['where'];
0 ignored issues
show
Unused Code introduced by
$where is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
349
		$ignore_keys     = $object_table_structure['ignore_keys'];
0 ignored issues
show
Unused Code introduced by
$ignore_keys is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
350
351
		if ( true === $is_deleted ) {
352
			$wordpress_object              = array();
353
			$wordpress_object[ $id_field ] = $object_id;
354
			return $wordpress_object;
355
		}
356
357
		if ( 'user' === $object_type ) {
358
			$data = get_userdata( $object_id );
359
		} elseif ( 'post' === $object_type || 'attachment' === $object_type ) {
360
			$data = get_post( $object_id );
361
		} elseif ( 'category' === $object_type || 'tag' === $object_type || 'post_tag' === $object_type ) {
362
			$data = get_term( $object_id );
363
		} elseif ( 'comment' === $object_type ) {
364
			$data = get_comment( $object_id );
365
		} else { // This is for custom post types.
366
			$data = get_post( $object_id );
367
		}
368
369
		$fields = $this->get_wordpress_object_fields( $object_type );
370
		foreach ( $fields as $key => $value ) {
371
			$field                      = $value['key'];
372
			$wordpress_object[ $field ] = $data->{$field};
373
		}
374
375
		/*
376
		 * Allow developers to change the WordPress object, including any formatting that needs to happen to the data.
377
		 * The returned $wordpress_object needs to be an array like described above.
378
		 * This is useful for custom objects, hidden fields, or custom formatting.
379
		 * Here's an example of filters to add/modify data:
380
		 *
381
			add_filter( 'object_sync_for_salesforce_wordpress_object_data', 'modify_data', 10, 1 );
382
			function modify_data( $wordpress_object ) {
383
				$wordpress_object['field_a'] = 'i am a field value that salesforce wants to store but WordPress does not care about';
384
				return $wordpress_object;
385
			}
386
		*/
387
388
		$wordpress_object = apply_filters( $this->option_prefix . 'wordpress_object_data', $wordpress_object );
389
390
		return $wordpress_object;
391
392
	}
393
394
	/**
395
	 * Check to see if this API call exists in the cache
396
	 * if it does, return the transient for that key
397
	 *
398
	 * @param string $url The API call we'd like to make.
399
	 * @param array  $args The arguents of the API call.
400
	 * @return $this->sfwp_transients->get $cachekey
0 ignored issues
show
Documentation introduced by
The doc-type $this->sfwp_transients->get could not be parsed: Unknown type name "$this-" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
401
	 */
402
	public function cache_get( $url, $args ) {
403
		if ( is_array( $args ) ) {
404
			$args[] = $url;
405
			array_multisort( $args );
406
		} else {
407
			$args .= $url;
408
		}
409
410
		$cachekey = md5( wp_json_encode( $args ) );
411
		return $this->sfwp_transients->get( $cachekey );
412
	}
413
414
	/**
415
	 * Create a cache entry for the current result, with the url and args as the key
416
	 *
417
	 * @param string $url The API query URL.
418
	 * @param array  $args The arguments passed on the API query.
419
	 * @param array  $data The data received.
420
	 * @param string $cache_expiration How long to keep the cache result around for.
421
	 * @return Bool whether or not the value was set
422
	 * @link https://wordpress.stackexchange.com/questions/174330/transient-storage-location-database-xcache-w3total-cache
423
	 */
424
	public function cache_set( $url, $args, $data, $cache_expiration = '' ) {
425
		if ( is_array( $args ) ) {
426
			$args[] = $url;
427
			array_multisort( $args );
428
		} else {
429
			$args .= $url;
430
		}
431
		$cachekey = md5( wp_json_encode( $args ) );
432
		// Cache_expiration is how long it should be stored in the cache.
433
		// If we didn't give a custom one, use the default.
434
		if ( '' === $cache_expiration ) {
435
			$cache_expiration = $this->options['cache_expiration'];
436
		}
437
		return $this->sfwp_transients->set( $cachekey, $data, $cache_expiration );
438
	}
439
440
	/**
441
	 * If there is a WordPress setting for how long to keep this specific cache, return it and set the object property
442
	 * Otherwise, return seconds in 24 hours
443
	 *
444
	 * @param string $option_key The cache item to keep around.
445
	 * @param int    $expire The default time after which to expire the cache.
446
	 * @return The cache expiration saved in the database.
447
	 */
448
	public function cache_expiration( $option_key, $expire ) {
449
		$cache_expiration = get_option( $option_key, $expire );
450
		return $cache_expiration;
451
	}
452
453
	/**
454
	 * Get all the fields for an object
455
	 * The important thing here is returning the fields as an array:
456
	 * $all_fields = array( 'key' => 'key name', 'table' => 'table name', 'methods' => array( 'create' => '', 'read' => '', 'update' => '', 'delete' => '' ) );
457
	 * if there's a better way to do this than the mess of queries below, we should switch to that when we can
458
	 * we just need to make sure we get all applicable fields for the object itself, as well as its meta fields
459
	 *
460
	 * @param string $object_name THe name of the object type.
461
	 * @param string $id_field The database filed that contains its ID.
462
	 * @param string $content_table The table that normally contains such objects.
463
	 * @param array  $content_methods Unused, but included as part of the return.
464
	 * @param string $meta_table The table where meta values for this object type are contained.
465
	 * @param array  $meta_methods Unused, but included as part of the return.
466
	 * @param string $where SQL query.
467
	 * @param array  $ignore_keys Fields to ignore from the database.
468
	 * @return array $all_fields The fields for the object.
469
	 */
470
	private function object_fields( $object_name, $id_field, $content_table, $content_methods, $meta_table, $meta_methods, $where, $ignore_keys ) {
471
		// These two queries load all the fields from the specified object unless they have been specified as ignore fields.
472
		// They also load the fields that are meta_keys from the specified object's meta table.
473
		// Maybe a box for a custom query, since custom fields get done in so many ways.
474
		// Eventually this would be the kind of thing we could use fields api for, if it ever gets done.
475
		$data_fields      = $this->wpdb->get_col( "DESC {$content_table}", 0 );
476
		$data_field_types = $this->wpdb->get_col( "DESC {$content_table}", 1 ); // get the database field types
477
478
		if ( is_array( $meta_table ) ) {
479
			$tax_table  = $meta_table[1];
480
			$meta_table = $meta_table[0];
481
		}
482
		$select_meta = '
483
		SELECT DISTINCT ' . $meta_table . '.meta_key
484
		FROM ' . $content_table . '
485
		LEFT JOIN ' . $meta_table . '
486
		ON ' . $content_table . '.' . $id_field . ' = ' . $meta_table . '.' . $object_name . '_id
487
		WHERE ' . $meta_table . '.meta_key != ""
488
		' . $where . '
489
		';
490
		$meta_fields = $this->wpdb->get_results( $select_meta );
491
		$all_fields  = array();
492
493
		foreach ( $data_fields as $key => $value ) {
494
			if ( ! in_array( $value, $ignore_keys, true ) ) {
495
				$all_fields[] = array(
496
					'key'     => $value,
497
					'table'   => $content_table,
498
					'methods' => serialize( $content_methods ),
499
					'type'    => $data_field_types[ $key ],
500
				);
501
			}
502
		}
503
504
		foreach ( $meta_fields as $key => $value ) {
505
			if ( ! in_array( $value->meta_key, $ignore_keys, true ) ) {
506
				$all_fields[] = array(
507
					'key'     => $value->meta_key,
508
					'table'   => $meta_table,
509
					'methods' => serialize( $meta_methods ),
510
				);
511
			}
512
		}
513
514
		if ( 'term' === $object_name ) {
515
			$taxonomy = $this->wpdb->get_col( "DESC {$tax_table}", 0 );
516
			foreach ( $taxonomy as $key => $value ) {
517
				$exists = array_search( $value, array_column( $all_fields, 'key' ), true );
518
				if ( 0 !== $exists ) {
519
					$all_fields[] = array(
520
						'key'     => $value,
521
						'table'   => $tax_table,
522
						'methods' => serialize( $content_methods ),
523
					);
524
				}
525
			}
526
		}
527
528
		return $all_fields;
529
530
	}
531
532
	/**
533
	 * Create a new object of a given type.
534
	 *
535
	 * @param string $name Object type name, E.g., user, post, comment.
536
	 * @param array  $params Values of the fields to set for the object.
537
	 *
538
	 * @return array
539
	 *   data:
540
	 *     id : 123,
541
	 *     success : true
542
	 *   errors : [ ],
543
	 *   from_cache:
544
	 *   cached:
545
	 *   is_redo:
546
	 *
547
	 * part of CRUD for WordPress objects
548
	 */
549
	public function object_create( $name, $params ) {
550
551
		$structure = $this->get_wordpress_table_structure( $name );
552
		$id_field  = $structure['id_field'];
553
554
		switch ( $name ) {
555
			case 'user':
556
				$result = $this->user_create( $params, $id_field );
557
				break;
558
			case 'post':
559
				$result = $this->post_create( $params, $id_field );
560
				break;
561
			case 'attachment':
562
				$result = $this->attachment_create( $params, $id_field );
563
				break;
564
			case 'category':
565
			case 'tag':
566
			case 'post_tag':
567
				$result = $this->term_create( $params, $name, $id_field );
568
				break;
569
			case 'comment':
570
				$result = $this->comment_create( $params, $id_field );
571
				break;
572 View Code Duplication
			default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
573
				/*
574
				 * Developers can use this hook to create objects with their own methods.
575
				 * The returned $result needs to be an array like this.
576
				 * $id_field should be the database key; i.e. 'ID' and the value should be the new item's id, or whatever WordPress returns from the method (sometimes this can be an error)
577
				 * $success should be a boolean value
578
					$result = array( 'data' => array( $id_field => $post_id, 'success' => $success ), 'errors' => $errors );
579
				 * use hook like: add_filter( 'object_sync_for_salesforce_create_custom_wordpress_item', add_object, 10, 1 );
580
				 * the one param is: array( 'name' => objecttype, 'params' => array_of_params, 'id_field' => idfield )
581
				 */
582
				// Check to see if someone is calling the filter, and apply it if so.
583
				if ( ! has_filter( $this->option_prefix . 'create_custom_wordpress_item' ) ) {
584
					$result = $this->post_create( $params, $id_field, $name );
585
				} else {
586
					$result = apply_filters( $this->option_prefix . 'create_custom_wordpress_item', array(
587
						'params'   => $params,
588
						'name'     => $name,
589
						'id_field' => $id_field,
590
					) );
591
				}
592
				break;
593
		} // End switch().
594
595
		return $result;
596
597
	}
598
599
600
	/**
601
	 * Create new records or update existing records.
602
	 *
603
	 * The new records or updated records are based on the value of the specified
604
	 * field.  If the value is not unique, REST API returns a 300 response with
605
	 * the list of matching records.
606
	 *
607
	 * @param string $name Object type name, E.g., user, post, comment.
608
	 * @param string $key The field to check if this record should be created or updated.
609
	 * @param string $value The value for this record of the field specified for $key.
610
	 * @param array  $methods What WordPress methods do we use to get the data, if there are any. otherwise, maybe will have to do a wpdb query.
611
	 * @param array  $params Values of the fields to set for the object.
612
	 * @param bool   $pull_to_drafts Whether to save to WordPress drafts when pulling from Salesforce.
613
	 * @param bool   $check_only Allows this method to only check for matching records, instead of making any data changes.
614
	 *
615
	 * @return array
616
	 *   data:
617
	 *     "id" : 123,
618
	 *     "success" : true
619
	 *   "errors" : [ ],
620
	 *   from_cache:
621
	 *   cached:
622
	 *   is_redo:
623
	 *
624
	 * part of CRUD for WordPress objects
625
	 */
626
	public function object_upsert( $name, $key, $value, $methods = array(), $params, $pull_to_drafts = false, $check_only = false ) {
627
628
		$structure = $this->get_wordpress_table_structure( $name );
629
		$id_field  = $structure['id_field'];
630
631
		// If key is set, remove from $params to avoid SQL errors.
632
		if ( isset( $params[ $key ] ) ) {
633
			unset( $params[ $key ] );
634
		}
635
636
		// Allow developers to change both the key and value by which objects should be matched.
637
		$key   = apply_filters( $this->option_prefix . 'modify_upsert_key', $key );
638
		$value = apply_filters( $this->option_prefix . 'modify_upsert_value', $value );
639
640
		switch ( $name ) {
641
			case 'user':
642
				$result = $this->user_upsert( $key, $value, $methods, $params, $id_field, $pull_to_drafts, $check_only );
643
				break;
644
			case 'post':
645
				$result = $this->post_upsert( $key, $value, $methods, $params, $id_field, $pull_to_drafts, $name, $check_only );
646
				break;
647
			case 'attachment':
648
				$result = $this->attachment_upsert( $key, $value, $methods, $params, $id_field, $check_only );
649
				break;
650
			case 'category':
651
			case 'tag':
652
			case 'post_tag':
653
				$result = $this->term_upsert( $key, $value, $methods, $params, $name, $id_field, $check_only );
654
				break;
655
			case 'comment':
656
				$result = $this->comment_upsert( $key, $value, $methods, $params, $id_field, $pull_to_drafts, $check_only );
657
				break;
658
			default:
659
				/*
660
				 * Developers can use this hook to upsert objects with their own methods.
661
				 * The returned $result needs to be an array like this:
662
				 * $id_field should be the database key; i.e. 'ID' and the value should be the item's id, or whatever WordPress returns from the method (sometimes this can be an error)
663
				 * $success should be a boolean value
664
				 *     $result = array( 'data' => array( $id_field => $post_id, 'success' => $success ), 'errors' => $errors );
665
				 * Use hook like this:
666
				 *     add_filter( 'object_sync_for_salesforce_upsert_custom_wordpress_item', upsert_object, 10, 1 );
667
				 * The one param is:
668
				 *     array( 'key' => key, 'value' => value, 'methods' => methods, 'params' => array_of_params, 'id_field' => idfield, 'pull_to_drafts' => pulltodrafts, 'name' => name, 'check_only' => $check_only )
669
				*/
670
				// Check to see if someone is calling the filter, and apply it if so.
671
				if ( ! has_filter( $this->option_prefix . 'upsert_custom_wordpress_item' ) ) {
672
					$result = $this->post_upsert( $key, $value, $methods, $params, $id_field, $pull_to_drafts, $name, $check_only );
673
				} else {
674
					$result = apply_filters( $this->option_prefix . 'upsert_custom_wordpress_item', array(
675
						'key'            => $key,
676
						'value'          => $value,
677
						'methods'        => $methods,
678
						'params'         => $params,
679
						'id_field'       => $id_field,
680
						'pull_to_drafts' => $pull_to_drafts,
681
						'name'           => $name,
682
						'check_only'     => $check_only,
683
					) );
684
				}
685
				break;
686
		} // End switch().
687
688
		return $result;
689
690
	}
691
692
	/**
693
	 * Update an existing object.
694
	 *
695
	 * @param string $name Object type name, E.g., user, post, comment.
696
	 * @param string $id WordPress id of the object.
697
	 * @param array  $params Values of the fields to set for the object.
698
	 *
699
	 * part of CRUD for WordPress objects
700
	 *
701
	 * @return array
702
	 *   data:
703
	 *     success: 1
704
	 *   "errors" : [ ],
705
	 *   from_cache:
706
	 *   cached:
707
	 *   is_redo:
708
	 */
709
	public function object_update( $name, $id, $params ) {
710
711
		$structure = $this->get_wordpress_table_structure( $name );
712
		$id_field  = $structure['id_field'];
713
714
		switch ( $name ) {
715
			case 'user':
716
				// User id does not come through by default, but we need it to pass to wp method.
717
				$result = $this->user_update( $id, $params, $id_field );
718
				break;
719
			case 'post':
720
				$result = $this->post_update( $id, $params, $id_field );
721
				break;
722
			case 'attachment':
723
				$result = $this->attachment_update( $id, $params, $id_field );
724
				break;
725
			case 'category':
726
			case 'tag':
727
			case 'post_tag':
728
				$result = $this->term_update( $id, $params, $name, $id_field );
729
				break;
730
			case 'comment':
731
				$result = $this->comment_update( $id, $params, $id_field );
732
				break;
733 View Code Duplication
			default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
734
				/*
735
				 * Developers can use this hook to update objects with their own methods.
736
				 * The returned $result needs to be an array like this:
737
				 *     $id_field should be the database key; i.e. 'ID' and the value should be the updated item's id, or whatever WordPress returns from the method (sometimes this can be an error)
738
				 * $success should be a boolean value
739
				 *     $result = array( 'data' => array( $id_field => $post_id, 'success' => $success ), 'errors' => $errors );
740
				 * Use hook like this:
741
				 *     add_filter( 'object_sync_for_salesforce_update_custom_wordpress_item', update_object, 10, 1 );
742
				 * The one param is:
743
				 *     array( 'id' => id, 'params' => array_of_params, 'name' => objecttype, 'id_field' => idfield )
744
				 */
745
				// Check to see if someone is calling the filter, and apply it if so.
746
				if ( ! has_filter( $this->option_prefix . 'update_custom_wordpress_item' ) ) {
747
					$result = $this->post_update( $id, $params, $id_field, $name );
748
				} else {
749
					$result = apply_filters( $this->option_prefix . 'update_custom_wordpress_item', array(
750
						'id'       => $id,
751
						'params'   => $params,
752
						'name'     => $name,
753
						'id_field' => $id_field,
754
					) );
755
				}
756
				break;
757
		} // End switch().
758
759
		return $result;
760
	}
761
762
	/**
763
	 * Delete a WordPress object.
764
	 *
765
	 * @param string $name Object type name, E.g., user, post, comment.
766
	 * @param string $id WordPress id of the object.
767
	 *
768
	 * @return array
769
	 *   data:
770
	 *     success: 1
771
	 *   "errors" : [ ],
772
	 *
773
	 * part of CRUD for WordPress objects
774
	 */
775
	public function object_delete( $name, $id ) {
776
		$structure = $this->get_wordpress_table_structure( $name );
777
		$id_field  = $structure['id_field'];
0 ignored issues
show
Unused Code introduced by
$id_field is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
778
779
		switch ( $name ) {
780
			case 'user':
781
				$success = $this->user_delete( $id );
782
				break;
783
			case 'post':
784
				$success = $this->post_delete( $id );
785
				break;
786
			case 'attachment':
787
				$success = $this->attachment_delete( $id );
788
				break;
789
			case 'category':
790
			case 'tag':
791
			case 'post_tag':
792
				$success = $this->term_delete( $id, $name );
793
				break;
794
			case 'comment':
795
				$success = $this->comment_delete( $id );
796
				break;
797 View Code Duplication
			default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
798
				/*
799
				 * Developers can use this hook to delete objects with their own methods.
800
				 * The returned $success is an object of the correct type, or a FALSE
801
				 * Use hook like:
802
				 *     add_filter( 'object_sync_for_salesforce_delete_custom_wordpress_item', delete_object, 10, 1 );
803
				 * The one param is:
804
				 *     array( 'id' => id, 'name' => objecttype )
805
				 */
806
				// Check to see if someone is calling the filter, and apply it if so.
807
				if ( ! has_filter( $this->option_prefix . 'delete_custom_wordpress_item' ) ) {
808
					$success = $this->post_delete( $id );
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
809
				} else {
810
					$success = apply_filters( $this->option_prefix . 'delete_custom_wordpress_item', array(
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
811
						'id'   => $id,
812
						'name' => $name,
813
					) );
814
				}
815
816
				$success = $this->post_delete( $id );
817
				break;
818
		} // End switch().
819
820
		$result = array(
821
			'data'   => array(
822
				'success' => $success,
823
			),
824
			'errors' => array(),
825
		);
826
		return $result;
827
	}
828
829
	/**
830
	 * Create a new WordPress user.
831
	 *
832
	 * @param array  $params array of user data params.
833
	 * @param string $id_field The column in the DB that holdes the user ID.
834
	 *
835
	 * @return array
836
	 *   data:
837
	 *     ID : 123,
838
	 *     success: 1
839
	 *   "errors" : [ ],
840
	 */
841
	private function user_create( $params, $id_field = 'ID' ) {
842
843
		// Allow username to be email address or username.
844
		// The username could be autogenerated before this point for the sake of URLs.
845
		$username      = $params['user_email']['value'];
846
		$email_address = $params['user_email']['value'];
0 ignored issues
show
Unused Code introduced by
$email_address is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
847
		if ( isset( $params['user_login']['value'] ) ) { // User_login is used by username_exists.
848
			$username = $params['user_login']['value'];
849
		} else {
850
			$params['user_login'] = array(
851
				'value'         => $username,
852
				'method_modify' => 'wp_insert_user',
853
				'method_read'   => 'get_user_by',
854
			);
855
		}
856
857
		// This is a new user.
858
		if ( false === username_exists( $username ) ) {
859
860
			// Create the user
861
			// WordPress sends a password reset link so this password doesn't get used, but it does exist in the database, which is helpful to prevent access before the user uses their password reset email.
862
			$params['user_pass'] = array(
863
				'value'         => wp_generate_password( 12, false ),
864
				'method_modify' => 'wp_insert_user',
865
				'method_read'   => 'get_user_by',
866
			);
867
			// Load all params with a method_modify of the object structure's content_method into $content
868
			$content   = array();
869
			$structure = $this->get_wordpress_table_structure( 'user' );
870
			foreach ( $params as $key => $value ) {
871
				if ( in_array( $value['method_modify'], $structure['content_methods'] ) ) {
872
					$content[ $key ] = $value['value'];
873
					unset( $params[ $key ] );
874
				}
875
			}
876
877
			$user_id = wp_insert_user( $content );
878
879 View Code Duplication
			if ( is_wp_error( $user_id ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
880
				$success = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
881
				$errors  = $user_id;
0 ignored issues
show
Unused Code introduced by
$errors is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
882
			} else {
883
				$success = true;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
884
				$errors  = array();
885
				foreach ( $params as $key => $value ) {
886
					$method = $value['method_modify'];
887
					// we need to provide a way for passing the values in a custom order here
888
					$meta_id = $method( $user_id, $key, $value['value'] );
889
					if ( false === $meta_id ) {
890
						$success  = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
891
						$errors[] = array(
892
							'message' => sprintf(
893
								// translators: %1$s is a method name.
894
								esc_html__( 'Tried to upsert meta with method %1$s.', 'object-sync-for-salesforce' ),
895
								esc_html( $method )
896
							),
897
							'key'     => $key,
898
							'value'   => $value,
899
						);
900
					}
901
				}
902
903
				// Developers can use this hook to set any other user data - permissions, etc.
904
				do_action( $this->option_prefix . 'set_more_user_data', $user_id, $params, 'create' );
905
906
				// Send notification of new user.
907
				// todo: Figure out what permissions ought to get notifications for this and make sure it works the right way.
908
				wp_new_user_notification( $user_id, null, 'both' );
909
910
			}
911
		} else {
912
			$user_id = username_exists( $username );
913
		} // End if().
914
915
		if ( is_wp_error( $user_id ) ) {
916
			$success = false;
917
			$errors  = $user_id;
918
		} else {
919
			$success = true;
920
			$errors  = array();
921
		}
922
923
		$result = array(
924
			'data'   => array(
925
				$id_field => $user_id,
926
				'success' => $success,
927
			),
928
			'errors' => $errors,
929
		);
930
931
		return $result;
932
933
	}
934
935
	/**
936
	 * Create a new WordPress user or update it if a match is found.
937
	 *
938
	 * @param string $key What key we are looking at for possible matches.
939
	 * @param string $value What value we are looking at for possible matches.
940
	 * @param array  $methods What WordPress methods do we use to get the data, if there are any. otherwise, maybe will have to do a wpdb query.
941
	 * @param array  $params Array of user data params. This is generated by Object_Sync_Sf_Mapping::map_params().
942
	 * @param string $id_field Optional string of what the ID field is, if it is ever not ID.
943
	 * @param bool   $pull_to_drafts Whether to save to WordPress drafts when pulling from Salesforce.
944
	 * @param bool   $check_only Allows this method to only check for matching records, instead of making any data changes.
945
	 *
946
	 * @return array
947
	 *   data:
948
	 *     ID : 123,
949
	 *     success: 1
950
	 *   "errors" : [ ],
951
	 */
952
	private function user_upsert( $key, $value, $methods = array(), $params, $id_field = 'ID', $pull_to_drafts = false, $check_only = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $pull_to_drafts is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
953
954
		// If the key is user_email, we need to make it just email because that is how the WordPress method reads it.
955
		$method = $methods['method_match'];
956
		if ( '' !== $method ) {
957
			// These methods should give us the user object if we are matching for one.
958
			// if we are trying to match to a meta field, the method is an object
959
			if ( class_exists( $method ) ) {
960
				$args        = array(
961
					'meta_query' => array(
0 ignored issues
show
introduced by
Detected usage of meta_query, possible slow query.
Loading history...
962
						array(
963
							'key'   => $key,
964
							'value' => $value,
965
						),
966
					),
967
				);
968
				$match_query = new $method( $args );
969
				$users       = $match_query->get_results();
970
				if ( ! empty( $users ) ) {
971
					$user = $users[0];
972
				}
973
			} else {
974
				$user = $method( str_replace( 'user_', '', $key ), $value );
975
			}
976
977
			if ( isset( $user ) && isset( $user->{$id_field} ) ) {
978
				// User does exist after checking the matching value. we want its id.
979
				$user_id = $user->{$id_field};
980
981
				if ( true === $check_only ) {
982
					// We are just checking to see if there is a match.
983
					return $user_id;
984
				}
985
986
				// On the prematch fields, we specify the method_update param.
987
				if ( isset( $methods['method_update'] ) ) {
988
					$method = $methods['method_update'];
989
				} else {
990
					$method = $methods['method_modify'];
991
				}
992
				$params[ $key ] = array(
993
					'value'         => $value,
994
					'method_modify' => $method,
995
					'method_read'   => $methods['method_read'],
996
				);
997
			} elseif ( false === $check_only ) {
998
				// User does not exist after checking the matching value. create it.
999
				// On the prematch fields, we specify the method_create param.
1000
				if ( isset( $methods['method_create'] ) ) {
1001
					$method = $methods['method_create'];
1002
				} else {
1003
					$method = $methods['method_modify'];
1004
				}
1005
				$params[ $key ] = array(
1006
					'value'         => $value,
1007
					'method_modify' => $method,
1008
					'method_read'   => $methods['method_read'],
1009
				);
1010
				$result         = $this->user_create( $params );
1011
				return $result;
1012
			} else {
1013
				// Check only is true but there's not a user yet.
1014
				return null;
1015
			} // End if().
1016
		} else {
1017
			// There is no method by which to check the user. we can check other ways here.
1018
			$params[ $key ] = array(
1019
				'value'         => $value,
1020
				'method_modify' => $methods['method_modify'],
1021
				'method_read'   => $methods['method_read'],
1022
			);
1023
1024
			// Allow username to be email address or username.
1025
			// The username could be autogenerated before this point for the sake of URLs.
1026
			if ( isset( $params['user_email']['value'] ) ) {
1027
				$username      = $params['user_email']['value'];
1028
				$email_address = $params['user_email']['value'];
0 ignored issues
show
Unused Code introduced by
$email_address is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1029
			}
1030
			if ( isset( $params['user_login']['value'] ) ) { // user_login is used by username_exists.
1031
				$username = $params['user_login']['value'];
1032
			}
1033
1034
			$existing_id = username_exists( $username ); // Returns an id if there is a result.
1035
1036
			// User does not exist after more checking. we want to create it.
1037
			if ( false === $existing_id && false === $check_only ) {
1038
				$result = $this->user_create( $params );
1039
				return $result;
1040
			} elseif ( true === $check_only ) {
1041
				// We are just checking to see if there is a match.
1042
				return $existing_id;
1043
			} else {
1044
				// User does exist based on username, and we aren't doing a check only. we want to update the wp user here.
1045
				$user_id = $existing_id;
1046
			}
1047
		} // End if().
1048
1049 View Code Duplication
		if ( isset( $user_id ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1050
			foreach ( $params as $key => $value ) {
1051
				$params[ $key ]['method_modify'] = $methods['method_update'];
1052
			}
1053
			$result = $this->user_update( $user_id, $params );
1054
			return $result;
1055
		}
1056
1057
		// Create log entry for lack of a user id.
1058
		if ( isset( $this->logging ) ) {
1059
			$logging = $this->logging;
1060
		} elseif ( class_exists( 'Object_Sync_Sf_Logging' ) ) {
1061
			$logging = new Object_Sync_Sf_Logging( $this->wpdb, $this->version );
1062
		}
1063
		$logging->setup(
1064
			// todo: can we get any more specific about this?
1065
			esc_html__( 'Error: Users: Tried to run user_upsert, and ended up without a user id', 'object-sync-for-salesforce' ),
1066
			'',
1067
			0,
1068
			0,
1069
			'error'
1070
		);
1071
1072
	}
1073
1074
	/**
1075
	 * Update a WordPress user.
1076
	 *
1077
	 * @param string $user_id The ID for the user to be updated. This value needs to be in the array that is sent to wp_update_user.
1078
	 * @param array  $params Array of user data params.
1079
	 * @param string $id_field Optional string of what the ID field is, if it is ever not ID.
1080
	 *
1081
	 * @return array
1082
	 *   data:
1083
	 *     success: 1
1084
	 *   "errors" : [ ],
1085
	 */
1086
	private function user_update( $user_id, $params, $id_field = 'ID' ) {
1087
		$content              = array();
1088
		$content[ $id_field ] = $user_id;
1089 View Code Duplication
		foreach ( $params as $key => $value ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1090
			if ( 'wp_update_user' === $value['method_modify'] ) {
1091
				$content[ $key ] = $value['value'];
1092
				unset( $params[ $key ] );
1093
			}
1094
		}
1095
1096
		$user_id = wp_update_user( $content );
1097
1098
		if ( is_wp_error( $user_id ) ) {
1099
			$success = false;
1100
			$errors  = $user_id;
1101
		} else {
1102
			$success = true;
1103
			$errors  = array();
1104
			foreach ( $params as $key => $value ) {
1105
				$method  = $value['method_modify'];
1106
				$meta_id = $method( $user_id, $key, $value['value'] );
1107
				if ( false === $meta_id ) {
1108
					$success  = false;
1109
					$errors[] = array(
1110
						'key'   => $key,
1111
						'value' => $value,
1112
					);
1113
				}
1114
			}
1115
1116
			// Developers can use this hook to set any other user data - permissions, etc.
1117
			do_action( $this->option_prefix . 'set_more_user_data', $user_id, $params, 'update' );
1118
1119
		}
1120
1121
		$result = array(
1122
			'data'   => array(
1123
				$id_field => $user_id,
1124
				'success' => $success,
1125
			),
1126
			'errors' => $errors,
1127
		);
1128
		return $result;
1129
	}
1130
1131
	/**
1132
	 * Delete a WordPress user.
1133
	 *
1134
	 * @param int $id User ID.
1135
	 * @param int $reassign If we should reassign any posts to other users. We don't change this from NULL anywhere in this plugin.
1136
	 *
1137
	 * @return boolean true if successful
1138
	 */
1139
	private function user_delete( $id, $reassign = null ) {
1140
		// According to https://codex.wordpress.org/Function_Reference/wp_delete_user we have to include user.php first; otherwise it throws undefined error.
1141
		require_once( './wp-admin/includes/user.php' );
1142
		$result = wp_delete_user( $id, $reassign );
1143
		return $result;
1144
	}
1145
1146
	/**
1147
	 * Create a new WordPress post.
1148
	 *
1149
	 * @param array  $params Array of post data params.
1150
	 * @param string $id_field Optional string of what the ID field is, if it is ever not ID.
1151
	 * @param string $post_type Optional string for custom post type, if applicable.
1152
	 *
1153
	 * @return array
1154
	 *   data:
1155
	 *     ID : 123,
1156
	 *     success: 1
1157
	 *   "errors" : [ ],
1158
	 */
1159
	private function post_create( $params, $id_field = 'ID', $post_type = 'post' ) {
1160
		// Load all params with a method_modify of the object structure's content_method into $content
1161
		$content   = array();
1162
		$structure = $this->get_wordpress_table_structure( $post_type );
1163
		foreach ( $params as $key => $value ) {
1164
			if ( in_array( $value['method_modify'], $structure['content_methods'] ) ) {
1165
				$content[ $key ] = $value['value'];
1166
				unset( $params[ $key ] );
1167
			}
1168
		}
1169
1170
		if ( '' !== $post_type ) {
1171
			$content['post_type'] = $post_type;
1172
		}
1173
1174
		// WordPress post creation will fail with an object of 0 if there is no title or content
1175
		// I think we should allow this to happen and not make users' data decisions, so
1176
		// if we're receiving nothing for either of these, create a blank one so it doesn't fail
1177
		// here we have to use $content because $params has already been unset
1178
		if ( ! isset( $content['post_title'] ) ) {
1179
			$content['post_title'] = ' ';
1180
		}
1181
		if ( ! isset( $content['post_content'] ) ) {
1182
			$content['post_content'] = ' ';
1183
		}
1184
1185
		$post_id = wp_insert_post( $content, true ); // return an error instead of a 0 id
1186
1187 View Code Duplication
		if ( is_wp_error( $post_id ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1188
			$success = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1189
			$errors  = $post_id;
0 ignored issues
show
Unused Code introduced by
$errors is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1190
		} else {
1191
			$success = true;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1192
			$errors  = array();
1193
			// If it's a custom post type, fix the methods.
1194
			if ( isset( $params['RecordTypeId']['value'] ) ) {
1195
				$params['RecordTypeId']['method_modify'] = 'update_post_meta';
1196
				$params['RecordTypeId']['method_read']   = 'get_post_meta';
1197
			}
1198
			if ( is_array( $params ) && ! empty( $params ) ) {
1199
				foreach ( $params as $key => $value ) {
1200
					$method  = $value['method_modify'];
1201
					$meta_id = $method( $post_id, $key, $value['value'] );
1202
					if ( false === $meta_id ) {
1203
						$success  = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1204
						$errors[] = array(
1205
							'key'   => $key,
1206
							'value' => $value,
1207
						);
1208
					}
1209
				}
1210
			}
1211
1212
			// Developers can use this hook to set any other post data.
1213
			do_action( $this->option_prefix . 'set_more_post_data', $post_id, $params, 'create' );
1214
1215
		}
1216
1217
		if ( is_wp_error( $post_id ) ) {
1218
			$success = false;
1219
			$errors  = $post_id;
1220
		} else {
1221
			$success = true;
1222
			$errors  = array();
1223
		}
1224
1225
		$result = array(
1226
			'data'   => array(
1227
				$id_field => $post_id,
1228
				'success' => $success,
1229
			),
1230
			'errors' => $errors,
1231
		);
1232
1233
		return $result;
1234
1235
	}
1236
1237
	/**
1238
	 * Create a new WordPress post or update it if a match is found.
1239
	 *
1240
	 * @param string $key What key we are looking at for possible matches.
1241
	 * @param string $value What value we are looking at for possible matches.
1242
	 * @param array  $methods What WordPress methods do we use to get the data, if there are any. otherwise, maybe will have to do a wpdb query.
1243
	 * @param array  $params Array of post data params.
1244
	 * @param string $id_field optional string of what the ID field is, if it is ever not ID.
1245
	 * @param bool   $pull_to_drafts Whether to save to WordPress drafts when pulling from Salesforce.
1246
	 * @param string $post_type Optional string for custom post type, if applicable.
1247
	 * @param bool   $check_only Allows this method to only check for matching records, instead of making any data changes.
1248
	 *
1249
	 * @return array
1250
	 *   data:
1251
	 *     ID : 123,
1252
	 *     success: 1
1253
	 *   "errors" : [ ],
1254
	 */
1255
	private function post_upsert( $key, $value, $methods = array(), $params, $id_field = 'ID', $pull_to_drafts = false, $post_type = 'post', $check_only = false ) {
1256
1257
		$method = $methods['method_match'];
1258
1259
		if ( '' !== $method ) {
1260
			// By default, posts use get_posts as the method. args can be like this.
1261
			// The args don't really make sense, and are inconsistently documented.
1262
			// These methods should give us the post object.
1263
			$args = array();
1264 View Code Duplication
			if ( 'post_title' === $key ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1265
				$params['post_title'] = array(
1266
					'value'         => $value,
1267
					'method_modify' => $method,
1268
					'method_read'   => $methods['method_read'],
1269
				);
1270
				$args['name']         = sanitize_title( $value );
1271
			} else {
1272
				$args[ $key ] = $value;
1273
			}
1274
			$args['post_type'] = $post_type;
1275
			$post_statuses     = array( 'publish' );
1276
1277
			if ( true === filter_var( $pull_to_drafts, FILTER_VALIDATE_BOOLEAN ) ) {
1278
				$post_statuses[] = 'draft';
1279
			}
1280
			$args['post_status'] = $post_statuses;
1281
1282
			// if we are trying to match to a meta field, the method is an object
1283 View Code Duplication
			if ( class_exists( $method ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1284
				unset( $args[ $key ] );
1285
				$args['meta_query'] = array(
0 ignored issues
show
introduced by
Detected usage of meta_query, possible slow query.
Loading history...
1286
					array(
1287
						'key'   => $key,
1288
						'value' => $value,
1289
					),
1290
				);
1291
				$match_query        = new $method( $args );
1292
				$posts              = $match_query->get_results();
1293
			} else {
1294
				$posts = $method( $args );
1295
			}
1296
1297 View Code Duplication
			if ( isset( $posts ) && isset( $posts[0]->{$id_field} ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1298
				// Post does exist after checking the matching value. We want its id.
1299
				$post_id = $posts[0]->{$id_field};
1300
1301
				if ( true === $check_only ) {
1302
					// We are just checking to see if there is a match.
1303
					return $post_id;
1304
				}
1305
1306
				// On the prematch fields, we specify the method_update param.
1307
				if ( isset( $methods['method_update'] ) ) {
1308
					$method = $methods['method_update'];
1309
				} else {
1310
					$method = $methods['method_modify'];
1311
				}
1312
				$params[ $key ] = array(
1313
					'value'         => $value,
1314
					'method_modify' => $method,
1315
					'method_read'   => $methods['method_read'],
1316
				);
1317
			} elseif ( false === $check_only ) {
1318
				// Post does not exist after checking the matching value. create it.
1319
				// On the prematch fields, we specify the method_create param.
1320
				if ( isset( $methods['method_create'] ) ) {
1321
					$method = $methods['method_create'];
1322
				} else {
1323
					$method = $methods['method_modify'];
1324
				}
1325
				$params[ $key ] = array(
1326
					'value'         => $value,
1327
					'method_modify' => $method,
1328
					'method_read'   => $methods['method_read'],
1329
				);
1330
				$result         = $this->post_create( $params, $id_field, $post_type );
1331
				return $result;
1332
			} else {
1333
				// Check only is true but there's not a post yet.
1334
				return null;
1335
			} // End if().
1336 View Code Duplication
		} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1337
			// There is no method by which to check the post. we can check other ways here.
1338
			$params[ $key ] = array(
1339
				'value'         => $value,
1340
				'method_modify' => $methods['method_modify'],
1341
				'method_read'   => $methods['method_read'],
1342
			);
1343
1344
			// If we have a title, use it to check for existing post.
1345
			if ( isset( $params['post_title']['value'] ) ) {
1346
				$title = $params['post_title']['value'];
1347
			}
1348
1349
			// If we have content, use it to check for existing post.
1350
			if ( isset( $params['post_content']['value'] ) ) {
1351
				$content = $params['post_content']['value'];
1352
			} else {
1353
				$content = '';
1354
			}
1355
1356
			// If we have a date, use it to check for existing post.
1357
			if ( isset( $params['post_date']['value'] ) ) {
1358
				$date = $params['post_date']['value'];
1359
			} else {
1360
				$date = '';
1361
			}
1362
1363
			$existing_id = post_exists( $title, $content, $date ); // Returns an id if there is a result. Returns 0 if not.
1364
1365
			// Post does not exist after more checking. maybe we want to create it.
1366
			if ( 0 === $existing_id && false === $check_only ) {
1367
				$result = $this->post_create( $params, $id_field, $post_type );
1368
				return $result;
1369
			} elseif ( true === $check_only ) {
1370
				// We are just checking to see if there is a match.
1371
				return $existing_id;
1372
			} else {
1373
				// Post does exist based on fields, and we aren't doing a check only. we want to update the wp post here.
1374
				$post_id = $existing_id;
0 ignored issues
show
Unused Code introduced by
$post_id is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1375
			}
1376
1377
			return $result;
1378
1379
		} // End if().
1380
1381 View Code Duplication
		if ( isset( $post_id ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1382
			foreach ( $params as $key => $value ) {
1383
				$params[ $key ]['method_modify'] = $methods['method_update'];
1384
			}
1385
			$result = $this->post_update( $post_id, $params, $id_field, $post_type );
1386
			return $result;
1387
		}
1388
		// Create log entry for lack of a post id.
1389
		if ( isset( $this->logging ) ) {
1390
			$logging = $this->logging;
1391
		} elseif ( class_exists( 'Object_Sync_Sf_Logging' ) ) {
1392
			$logging = new Object_Sync_Sf_Logging( $this->wpdb, $this->version );
1393
		}
1394
		$logging->setup(
1395
			// todo: can we be more explicit here about what post upsert failed?
1396
			esc_html__( 'Error: Posts: Tried to run post_upsert, and ended up without a post id', 'object-sync-for-salesforce' ),
1397
			'',
1398
			0,
1399
			0,
1400
			'error'
1401
		);
1402
1403
	}
1404
1405
	/**
1406
	 * Update a WordPress post.
1407
	 *
1408
	 * @param string $post_id The ID for the post to be updated. This value needs to be in the array that is sent to wp_update_post.
1409
	 * @param array  $params Array of post data params.
1410
	 * @param string $id_field Optional string of what the ID field is, if it is ever not ID.
1411
	 * @param string $post_type Optional string for custom post type, if applicable.
1412
	 *
1413
	 * @return array
1414
	 *   data:
1415
	 *     success: 1
1416
	 *   "errors" : [ ],
1417
	 */
1418
	private function post_update( $post_id, $params, $id_field = 'ID', $post_type = '' ) {
1419
		$content              = array();
1420
		$content[ $id_field ] = $post_id;
1421 View Code Duplication
		foreach ( $params as $key => $value ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1422
			if ( 'wp_update_post' === $value['method_modify'] ) {
1423
				$content[ $key ] = $value['value'];
1424
				unset( $params[ $key ] );
1425
			}
1426
		}
1427
1428
		if ( '' !== $post_type ) {
1429
			$content['post_type'] = $post_type;
1430
		}
1431
1432
		$post_id = wp_update_post( $content, true ); // return an error instead of a 0 id
1433
1434 View Code Duplication
		if ( is_wp_error( $post_id ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1435
			$success = false;
1436
			$errors  = $post_id;
1437
		} else {
1438
			$success = true;
1439
			$errors  = array();
1440
			// If it's a custom post type, fix the methods.
1441
			if ( isset( $params['RecordTypeId']['value'] ) ) {
1442
				$params['RecordTypeId']['method_modify'] = 'update_post_meta';
1443
				$params['RecordTypeId']['method_read']   = 'get_post_meta';
1444
			}
1445
			if ( is_array( $params ) && ! empty( $params ) ) {
1446
				foreach ( $params as $key => $value ) {
1447
					$method  = $value['method_modify'];
1448
					$meta_id = $method( $post_id, $key, $value['value'] );
1449
					if ( false === $meta_id ) {
1450
						$success  = false;
1451
						$errors[] = array(
1452
							'key'   => $key,
1453
							'value' => $value,
1454
						);
1455
					}
1456
				}
1457
			}
1458
1459
			// Developers can use this hook to set any other post data.
1460
			do_action( $this->option_prefix . 'set_more_post_data', $post_id, $params, 'update' );
1461
1462
		}
1463
1464
		$result = array(
1465
			'data'   => array(
1466
				$id_field => $post_id,
1467
				'success' => $success,
1468
			),
1469
			'errors' => $errors,
1470
		);
1471
		return $result;
1472
	}
1473
1474
	/**
1475
	 * Delete a WordPress post.
1476
	 *
1477
	 * @param int  $id Post ID.
1478
	 * @param bool $force_delete If we should bypass the trash. We don't change this from FALSE anywhere in this plugin.
1479
	 *
1480
	 * @return mixed post object if successful, false if failed
1481
	 */
1482
	private function post_delete( $id, $force_delete = false ) {
1483
		$result = wp_delete_post( $id, $force_delete );
1484
		return $result;
1485
	}
1486
1487
	/**
1488
	 * Create a new WordPress attachment.
1489
	 *
1490
	 * @param array  $params Array of attachment data params.
1491
	 * @param string $id_field Optional string of what the ID field is, if it is ever not ID.
1492
	 *
1493
	 * @return array
1494
	 *   data:
1495
	 *     ID : 123,
1496
	 *     success: 1
1497
	 *   "errors" : [ ],
1498
	 */
1499
	private function attachment_create( $params, $id_field = 'ID' ) {
1500
		// Load all params with a method_modify of the object structure's content_method into $content
1501
		$content   = array();
1502
		$structure = $this->get_wordpress_table_structure( 'attachment' );
1503
		// WP requires post_title, post_content (can be empty), post_status, and post_mime_type to create an attachment.
1504
		foreach ( $params as $key => $value ) {
1505
			if ( in_array( $value['method_modify'], $structure['content_methods'] ) ) {
1506
				$content[ $key ] = $value['value'];
1507
				unset( $params[ $key ] );
1508
			}
1509
		}
1510
1511
		// Developers can use this hook to pass filename and parent data for the attachment.
1512
		$params = apply_filters( $this->option_prefix . 'set_initial_attachment_data', $params );
1513
1514 View Code Duplication
		if ( isset( $params['filename']['value'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1515
			$filename = $params['filename']['value'];
1516
		} else {
1517
			$filename = false;
1518
		}
1519
1520 View Code Duplication
		if ( isset( $params['parent']['value'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1521
			$parent = $params['parent']['value'];
1522
		} else {
1523
			$parent = 0;
1524
		}
1525
1526
		$attachment_id = wp_insert_attachment( $content, $filename, $parent );
1527
1528
		if ( is_wp_error( $attachment_id ) ) {
1529
			$success = false;
1530
			$errors  = $attachment_id;
1531
		} else {
1532
			$success = true;
1533
			$errors  = array();
1534
1535 View Code Duplication
			if ( false !== $filename ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1536
				// According to https://codex.wordpress.org/Function_Reference/wp_insert_attachment we need this file.
1537
				require_once( ABSPATH . 'wp-admin/includes/image.php' );
1538
				// Generate metadata for the attachment.
1539
				$attach_data = wp_generate_attachment_metadata( $attachment_id, $filename );
1540
				wp_update_attachment_metadata( $attachment_id, $attach_data );
1541
			}
1542
1543
			if ( 0 !== $parent ) {
1544
				set_post_thumbnail( $parent_post_id, $attachment_id );
1545
			}
1546
1547
			// Developers can use this hook to set any other attachment data.
1548
			do_action( $this->option_prefix . 'set_more_attachment_data', $attachment_id, $params, 'create' );
1549
1550
		}
1551
1552
		$result = array(
1553
			'data'   => array(
1554
				$id_field => $attachment_id,
1555
				'success' => $success,
1556
			),
1557
			'errors' => $errors,
1558
		);
1559
1560
		return $result;
1561
1562
	}
1563
1564
	/**
1565
	 * Create a new WordPress attachment or update it if a match is found.
1566
	 *
1567
	 * @param string $key What key we are looking at for possible matches.
1568
	 * @param string $value What value we are looking at for possible matches.
1569
	 * @param array  $methods What WordPress methods do we use to get the data, if there are any. otherwise, maybe will have to do a wpdb query.
1570
	 * @param array  $params Array of attachment data params.
1571
	 * @param string $id_field Optional string of what the ID field is, if it is ever not ID.
1572
	 * @param bool   $check_only Allows this method to only check for matching records, instead of making any data changes.
1573
	 *
1574
	 * @return array
1575
	 *   data:
1576
	 *     ID : 123,
1577
	 *     success: 1
1578
	 *   "errors" : [ ],
1579
	 */
1580
	private function attachment_upsert( $key, $value, $methods = array(), $params, $id_field = 'ID', $check_only = false ) {
1581
1582
		$method = $methods['method_match'];
1583
1584
		if ( '' !== $method ) {
1585
			// Get_posts is more helpful here, so that is the method attachment uses for 'read'.
1586
			// By default, posts use get_posts as the method. args can be like this.
1587
			// The args don't really make sense, and are inconsistently documented.
1588
			// These methods should give us the post object.
1589
			$args = array();
1590 View Code Duplication
			if ( 'post_title' === $key ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1591
				$params['post_title'] = array(
1592
					'value'         => $value,
1593
					'method_modify' => $method,
1594
					'method_read'   => $methods['method_read'],
1595
				);
1596
				$args['name']         = sanitize_title( $value );
1597
			} else {
1598
				$args[ $key ] = $value;
1599
			}
1600
			$args['post_type'] = 'attachment';
1601
1602
			// if we are trying to match to a meta field, the method is an object
1603 View Code Duplication
			if ( class_exists( $method ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1604
				unset( $args[ $key ] );
1605
				$args['meta_query'] = array(
0 ignored issues
show
introduced by
Detected usage of meta_query, possible slow query.
Loading history...
1606
					array(
1607
						'key'   => $key,
1608
						'value' => $value,
1609
					),
1610
				);
1611
				$match_query        = new $method( $args );
1612
				$posts              = $match_query->get_results();
1613
			} else {
1614
				$posts = $method( $args );
1615
			}
1616
1617 View Code Duplication
			if ( isset( $posts ) && isset( $posts[0]->{$id_field} ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1618
				// Attachment does exist after checking the matching value. we want its id.
1619
				$attachment_id = $posts[0]->{$id_field};
1620
1621
				if ( true === $check_only ) {
1622
					// We are just checking to see if there is a match.
1623
					return $attachment_id;
1624
				}
1625
1626
				// On the prematch fields, we specify the method_update param.
1627
				if ( isset( $methods['method_update'] ) ) {
1628
					$method = $methods['method_update'];
1629
				} else {
1630
					$method = $methods['method_modify'];
1631
				}
1632
				$params[ $key ] = array(
1633
					'value'         => $value,
1634
					'method_modify' => $method,
1635
					'method_read'   => $methods['method_read'],
1636
				);
1637
			} elseif ( false === $check_only ) {
1638
				// Attachment does not exist after checking the matching value. create it.
1639
				// On the prematch fields, we specify the method_create param.
1640
				if ( isset( $methods['method_create'] ) ) {
1641
					$method = $methods['method_create'];
1642
				} else {
1643
					$method = $methods['method_modify'];
1644
				}
1645
				$params[ $key ] = array(
1646
					'value'         => $value,
1647
					'method_modify' => $method,
1648
					'method_read'   => $methods['method_read'],
1649
				);
1650
				$result         = $this->attachment_create( $params );
1651
				return $result;
1652
			} else {
1653
				// Check only is true but there's not an attachment yet.
1654
				return null;
1655
			} // End if().
1656 View Code Duplication
		} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1657
			// There is no method by which to check the post. we can check other ways here.
1658
			$params[ $key ] = array(
1659
				'value'         => $value,
1660
				'method_modify' => $methods['method_modify'],
1661
				'method_read'   => $methods['method_read'],
1662
			);
1663
1664
			// If we have a title, use it to check for existing post.
1665
			if ( isset( $params['post_title']['value'] ) ) {
1666
				$title = $params['post_title']['value'];
1667
			}
1668
1669
			// If we have content, use it to check for existing post.
1670
			if ( isset( $params['post_content']['value'] ) ) {
1671
				$content = $params['post_content']['value'];
1672
			} else {
1673
				$content = '';
1674
			}
1675
1676
			// If we have a date, use it to check for existing post.
1677
			if ( isset( $params['post_date']['value'] ) ) {
1678
				$date = $params['post_date']['value'];
1679
			} else {
1680
				$date = '';
1681
			}
1682
1683
			$existing_id = post_exists( $title, $content, $date ); // Returns an id if there is a result. Returns 0 if not.
1684
1685
			// Attachment does not exist after more checking. maybe we want to create it.
1686
			if ( 0 === $existing_id && false === $check_only ) {
1687
				$result = $this->attachment_create( $params );
1688
				return $result;
1689
			} elseif ( true === $check_only ) {
1690
				// We are just checking to see if there is a match.
1691
				return $existing_id;
1692
			} else {
1693
				// Attachment does exist based on fields, and we aren't doing a check only. we want to update the wp attachment here.
1694
				$attachment_id = $existing_id;
0 ignored issues
show
Unused Code introduced by
$attachment_id is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1695
			}
1696
1697
			return $result;
1698
1699
		} // End if().
1700
1701 View Code Duplication
		if ( isset( $attachment_id ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1702
			foreach ( $params as $key => $value ) {
1703
				$params[ $key ]['method_modify'] = $methods['method_update'];
1704
			}
1705
			$result = $this->attachment_update( $attachment_id, $params );
1706
			return $result;
1707
		}
1708
1709
		// Create log entry for lack of an attachment id.
1710
		if ( isset( $this->logging ) ) {
1711
			$logging = $this->logging;
1712
		} elseif ( class_exists( 'Object_Sync_Sf_Logging' ) ) {
1713
			$logging = new Object_Sync_Sf_Logging( $this->wpdb, $this->version );
1714
		}
1715
		$logging->setup(
1716
			esc_html__( 'Error: Attachment: Tried to run attachment_upsert, and ended up without an attachment id', 'object-sync-for-salesforce' ),
1717
			'',
1718
			0,
1719
			0,
1720
			'error'
1721
		);
1722
1723
	}
1724
1725
	/**
1726
	 * Update a WordPress attachment.
1727
	 *
1728
	 * @param string $attachment_id The ID for the attachment to be updated. This value needs to be in the array that is sent to the update methods.
1729
	 * @param array  $params Array of attachment data params.
1730
	 * @param string $id_field Optional string of what the ID field is, if it is ever not ID.
1731
	 *
1732
	 * @return array
1733
	 *   data:
1734
	 *     success: 1
1735
	 *   "errors" : [ ],
1736
	 *
1737
	 * Note: this method uses wp_insert_attachment for core content fields as there isn't a corresponding method for updating these rows
1738
	 * it does use wp_update_attachment_metadata for the meta fields, though.
1739
	 * Developers should use hooks to change this, if it does not meet their needs.
1740
	 */
1741
	private function attachment_update( $attachment_id, $params, $id_field = 'ID' ) {
1742
		$content              = array();
1743
		$content[ $id_field ] = $attachment_id;
1744 View Code Duplication
		foreach ( $params as $key => $value ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1745
			if ( 'wp_insert_attachment' === $value['method_modify'] ) { // Should also be insert attachment maybe.
1746
				$content[ $key ] = $value['value'];
1747
				unset( $params[ $key ] );
1748
			}
1749
		}
1750
1751 View Code Duplication
		if ( isset( $params['filename']['value'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1752
			$filename = $params['filename']['value'];
1753
		} else {
1754
			$filename = false;
1755
		}
1756
1757 View Code Duplication
		if ( isset( $params['parent']['value'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1758
			$parent = $params['parent']['value'];
1759
		} else {
1760
			$parent = 0;
1761
		}
1762
1763
		$attachment_id = wp_insert_attachment( $content, $filename, $parent );
1764
1765
		if ( is_wp_error( $attachment_id ) ) {
1766
			$success = false;
1767
			$errors  = $attachment_id;
1768
		} else {
1769
			$success = true;
1770
			$errors  = array();
1771
1772 View Code Duplication
			if ( false !== $filename ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1773
				// According to https://codex.wordpress.org/Function_Reference/wp_insert_attachment we need this file.
1774
				require_once( ABSPATH . 'wp-admin/includes/image.php' );
1775
				// Generate metadata for the attachment.
1776
				$attach_data = wp_generate_attachment_metadata( $attachment_id, $filename );
1777
			}
1778
1779
			// Put the data from salesforce into the meta array.
1780
			$attach_new_data = array();
1781
			foreach ( $params as $key => $value ) {
1782
				$method                  = $value['method_modify'];
0 ignored issues
show
Unused Code introduced by
$method is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1783
				$attach_new_data[ $key ] = $value['value'];
1784
			}
1785
1786
			if ( isset( $attach_data ) ) {
1787
				$attach_data = array_merge( $attach_data, $attach_new_data );
1788
			} else {
1789
				$attach_data = $attach_new_data;
1790
			}
1791
1792
			$meta_updated = wp_update_attachment_metadata( $attachment_id, $attach_data );
1793
1794
			if ( false === $meta_updated ) {
1795
				$success  = false;
1796
				$errors[] = array(
1797
					'key'   => $key,
1798
					'value' => $value,
1799
				);
1800
			}
1801
1802
			if ( 0 !== $parent ) {
1803
				set_post_thumbnail( $parent_post_id, $attachment_id );
1804
			}
1805
1806
			// Developers can use this hook to set any other attachment data.
1807
			do_action( $this->option_prefix . 'set_more_attachment_data', $attachment_id, $params, 'update' );
1808
1809
		} // End if().
1810
1811
		$result = array(
1812
			'data'   => array(
1813
				$id_field => $attachment_id,
1814
				'success' => $success,
1815
			),
1816
			'errors' => $errors,
1817
		);
1818
		return $result;
1819
	}
1820
1821
	/**
1822
	 * Delete a WordPress attachment.
1823
	 *
1824
	 * @param int  $id Attachment ID.
1825
	 * @param bool $force_delete If we should bypass the trash. We don't change this from FALSE anywhere in this plugin.
1826
	 *
1827
	 * @return mixed
1828
	 *   attachment object if successful, false if failed
1829
	 */
1830
	private function attachment_delete( $id, $force_delete = false ) {
1831
		$result = wp_delete_attachment( $id, $force_delete );
1832
		return $result;
1833
	}
1834
1835
	/**
1836
	 * Create a new WordPress term.
1837
	 *
1838
	 * @param array  $params Array of term data params.
1839
	 * @param string $taxonomy The taxonomy to which to add the term. this is required.
1840
	 * @param string $id_field Optional string of what the ID field is, if it is ever not ID.
1841
	 *
1842
	 * @return array
1843
	 *   data:
1844
	 *     ID : 123,
1845
	 *     success: 1
1846
	 *   "errors" : [ ],
1847
	 */
1848
	private function term_create( $params, $taxonomy, $id_field = 'ID' ) {
1849
		if ( 'tag' === $taxonomy ) {
1850
			$taxonomy = 'post_tag';
1851
		}
1852
		// Load all params with a method_modify of the object structure's content_method into $content
1853
		$content   = array();
0 ignored issues
show
Unused Code introduced by
$content is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1854
		$structure = $this->get_wordpress_table_structure( $taxonomy );
1855
		$args      = array();
1856
		foreach ( $params as $key => $value ) {
1857
			if ( 'name' === $key ) {
1858
				$name = $value['value'];
1859
				unset( $params[ $key ] );
1860
			}
1861
			if ( in_array( $value['method_modify'], $structure['content_methods'] ) && 'name' !== $key ) {
1862
				$args[ $key ] = $value['value'];
1863
				unset( $params[ $key ] );
1864
			}
1865
		}
1866
		if ( isset( $name ) ) {
1867
			$term = wp_insert_term( $name, $taxonomy, $args );
1868
		}
1869
1870 View Code Duplication
		if ( is_wp_error( $term ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1871
			$success = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1872
			$errors  = $term;
0 ignored issues
show
Unused Code introduced by
$errors is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1873
		} else {
1874
			$term_id = $term[ "$id_field" ];
1875
			$success = true;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1876
			$errors  = array();
1877
			foreach ( $params as $key => $value ) {
1878
				$method  = $value['method_modify'];
1879
				$meta_id = $method( $term_id, $key, $value['value'] );
1880
				if ( false === $meta_id ) {
1881
					$success  = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1882
					$errors[] = array(
1883
						'message' => sprintf(
1884
							// translators: %1$s is a method name.
1885
							esc_html__( 'Tried to upsert meta with method %1$s.', 'object-sync-for-salesforce' ),
1886
							esc_html( $method )
1887
						),
1888
						'key'     => $key,
1889
						'value'   => $value,
1890
					);
1891
				}
1892
			}
1893
1894
			// Developers can use this hook to set any other term data.
1895
			do_action( $this->option_prefix . 'set_more_term_data', $term_id, $params, 'create' );
1896
1897
		}
1898
1899 View Code Duplication
		if ( is_wp_error( $term ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1900
			$success = false;
1901
			$errors  = $term;
1902
		} else {
1903
			$success = true;
1904
			$errors  = array();
1905
		}
1906
1907
		$result = array(
1908
			'data'   => array(
1909
				$id_field => $term_id,
1910
				'success' => $success,
1911
			),
1912
			'errors' => $errors,
1913
		);
1914
1915
		return $result;
1916
1917
	}
1918
1919
	/**
1920
	 * Create a new WordPress term or update it if a match is found.
1921
	 *
1922
	 * @param string $key What key we are looking at for possible matches.
1923
	 * @param string $value What value we are looking at for possible matches.
1924
	 * @param array  $methods What WordPress methods do we use to get the data, if there are any. otherwise, maybe will have to do a wpdb query.
1925
	 * @param array  $params Array of term data params.
1926
	 * @param string $taxonomy The taxonomy to which to add the term. this is required..
1927
	 * @param string $id_field Optional string of what the ID field is, if it is ever not ID.
1928
	 * @param bool   $pull_to_drafts Whether to save to WordPress drafts when pulling from Salesforce.
1929
	 * @param bool   $check_only Allows this method to only check for matching records, instead of making any data changes.
1930
	 *
1931
	 * @return array
1932
	 *   data:
1933
	 *     ID : 123,
1934
	 *     success: 1
1935
	 *   "errors" : [ ],
1936
	 */
1937
	private function term_upsert( $key, $value, $methods = array(), $params, $taxonomy, $id_field = 'ID', $pull_to_drafts = false, $check_only = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $pull_to_drafts is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1938
		if ( 'tag' === $taxonomy ) {
1939
			$taxonomy = 'post_tag';
1940
		}
1941
		$method = $methods['method_match'];
1942
		if ( '' !== $method ) {
1943
			// These methods should give us the term object if we are matching for one.
1944
			// if we are trying to match to a meta field, the method is an object
1945
			if ( class_exists( $method ) ) {
1946
				$args        = array(
1947
					'taxonomy'   => $taxonomy,
1948
					'meta_key'   => $key,
0 ignored issues
show
introduced by
Detected usage of meta_key, possible slow query.
Loading history...
1949
					'meta_value' => $value,
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
1950
				);
1951
				$match_query = new $method( $args );
1952
				$terms       = $match_query->get_terms();
1953
				if ( ! empty( $terms ) ) {
1954
					$term = $terms[0];
1955
				}
1956
			} else {
1957
				$term = $method( $key, $value, $taxonomy ); // We need to put the taxonomy in there probably.
1958
			}
1959
1960 View Code Duplication
			if ( isset( $term ) && isset( $term->{$id_field} ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1961
				// Term does exist after checking the matching value. we want its id.
1962
				$term_id = $term->{$id_field};
1963
1964
				if ( true === $check_only ) {
1965
					// We are just checking to see if there is a match.
1966
					return $term_id;
1967
				}
1968
1969
				// On the prematch fields, we specify the method_update param.
1970
				if ( isset( $methods['method_update'] ) ) {
1971
					$method = $methods['method_update'];
1972
				} else {
1973
					$method = $methods['method_modify'];
1974
				}
1975
				$params[ $key ] = array(
1976
					'value'         => $value,
1977
					'method_modify' => $method,
1978
					'method_read'   => $methods['method_read'],
1979
				);
1980
			} elseif ( false === $check_only ) {
1981
				// Term does not exist after checking the matching value. Create it.
1982
				// On the prematch fields, we specify the method_create param.
1983
				if ( isset( $methods['method_create'] ) ) {
1984
					$method = $methods['method_create'];
1985
				} else {
1986
					$method = $methods['method_modify'];
1987
				}
1988
				$params[ $key ] = array(
1989
					'value'         => $value,
1990
					'method_modify' => $method,
1991
					'method_read'   => $methods['method_read'],
1992
				);
1993
				$result         = $this->term_create( $params, $taxonomy, $id_field );
1994
				return $result;
1995
			} else {
1996
				// Check only is true but there's not a term yet.
1997
				return null;
1998
			} // End if().
1999
		} else {
2000
			// There is no method by which to check the term. we can check other ways here.
2001
			$params[ $key ] = array(
2002
				'value'         => $value,
2003
				'method_modify' => $methods['method_modify'],
2004
				'method_read'   => $methods['method_read'],
2005
			);
2006
2007
			if ( isset( $params['name']['value'] ) ) {
2008
				$term = $params['name']['value'];
2009
			}
2010
2011 View Code Duplication
			if ( isset( $params['parent']['value'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2012
				$parent = $params['parent']['value'];
2013
			} else {
2014
				$parent = 0;
2015
			}
2016
2017
			// Returns an id if there is a result. Returns null if it does not exist.
2018
			// wpcom_vip_term_exists is cached, and therefore preferred.
2019
			if ( function_exists( 'wpcom_vip_term_exists' ) ) {
2020
				$existing_id = wpcom_vip_term_exists( $term, $taxonomy, $parent );
2021
			} else {
2022
				$existing_id = term_exists( $term, $taxonomy, $parent );
2023
			}
2024
2025
			// Term does not exist after more checking. maybe we want to create it.
2026
			if ( null === $existing_id && false === $check_only ) {
2027
				$result = $this->term_create( $params, $taxonomy, $id_field );
2028
				return $result;
2029
			} elseif ( true === $check_only ) {
2030
				// We are just checking to see if there is a match.
2031
				return $existing_id;
2032
			} else {
2033
				// Term does exist based on criteria, and we aren't doing a check only. we want to update the wp term here.
2034
				$term_id = $existing_id;
2035
			}
2036
		} // End if().
2037
2038 View Code Duplication
		if ( isset( $term_id ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2039
			foreach ( $params as $key => $value ) {
2040
				$params[ $key ]['method_modify'] = $methods['method_update'];
2041
			}
2042
			$result = $this->term_update( $term_id, $params, $taxonomy, $id_field );
2043
			return $result;
2044
		}
2045
		// Create log entry for lack of a term id.
2046
		if ( isset( $this->logging ) ) {
2047
			$logging = $this->logging;
2048
		} elseif ( class_exists( 'Object_Sync_Sf_Logging' ) ) {
2049
			$logging = new Object_Sync_Sf_Logging( $this->wpdb, $this->version );
2050
		}
2051
		$logging->setup(
2052
			esc_html__( 'Error: Terms: Tried to run term_upsert, and ended up without a term id', 'object-sync-for-salesforce' ),
2053
			'',
2054
			0,
2055
			0,
2056
			'error'
2057
		);
2058
2059
	}
2060
2061
	/**
2062
	 * Update a WordPress term.
2063
	 *
2064
	 * @param string $term_id The ID for the term to be updated. This value needs to be in the array that is sent to wp_update_term.
2065
	 * @param array  $params Array of term data params.
2066
	 * @param string $taxonomy The taxonomy to which to add the term. this is required.
2067
	 * @param string $id_field Optional string of what the ID field is, if it is ever not ID.
2068
	 *
2069
	 * @return array
2070
	 *   data:
2071
	 *     success: 1
2072
	 *   "errors" : [ ],
2073
	 */
2074
	private function term_update( $term_id, $params, $taxonomy, $id_field = 'ID' ) {
2075
		if ( 'tag' === $taxonomy ) {
2076
			$taxonomy = 'post_tag';
2077
		}
2078
		$args = array();
2079 View Code Duplication
		foreach ( $params as $key => $value ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2080
			if ( 'wp_update_term' === $value['method_modify'] ) {
2081
				$args[ $key ] = $value['value'];
2082
				unset( $params[ $key ] );
2083
			}
2084
		}
2085
		$term = wp_update_term( $term_id, $taxonomy, $args );
2086
2087 View Code Duplication
		if ( is_wp_error( $term ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2088
			$success = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2089
			$errors  = $term;
0 ignored issues
show
Unused Code introduced by
$errors is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2090
		} else {
2091
			$term_id = $term[ "$id_field" ];
2092
			$success = true;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2093
			$errors  = array();
2094
			foreach ( $params as $key => $value ) {
2095
				$method  = $value['method_modify'];
2096
				$meta_id = $method( $term_id, $key, $value['value'] );
2097
				if ( false === $meta_id ) {
2098
					$success  = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2099
					$errors[] = array(
2100
						'message' => sprintf(
2101
							// translators: %1$s is a method name.
2102
							esc_html__( 'Tried to update meta with method %1$s.', 'object-sync-for-salesforce' ),
2103
							esc_html( $method )
2104
						),
2105
						'key'     => $key,
2106
						'value'   => $value,
2107
					);
2108
				}
2109
			}
2110
2111
			// Developers can use this hook to set any other term data.
2112
			do_action( $this->option_prefix . 'set_more_term_data', $term_id, $params, 'update' );
2113
2114
		}
2115
2116 View Code Duplication
		if ( is_wp_error( $term ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2117
			$success = false;
2118
			$errors  = $term;
2119
		} else {
2120
			$success = true;
2121
			$errors  = array();
2122
		}
2123
2124
		$result = array(
2125
			'data'   => array(
2126
				$id_field => $term_id,
2127
				'success' => $success,
2128
			),
2129
			'errors' => $errors,
2130
		);
2131
2132
		return $result;
2133
2134
	}
2135
2136
	/**
2137
	 * Delete a WordPress term.
2138
	 *
2139
	 * @param string $term_id The ID for the term to be updated. This value needs to be in the array that is sent to wp_update_term.
2140
	 * @param string $taxonomy The taxonomy from which to delete the term. this is required.
2141
	 *
2142
	 * @return bool True if successful, false if failed.
2143
	 */
2144
	private function term_delete( $term_id, $taxonomy ) {
2145
		if ( 'tag' === $taxonomy ) {
2146
			$taxonomy = 'post_tag';
2147
		}
2148
		$result = wp_delete_term( $term_id, $taxonomy );
2149
		return $result;
2150
	}
2151
2152
	/**
2153
	 * Create a new WordPress comment.
2154
	 *
2155
	 * @param array  $params Array of comment data params.
2156
	 * @param string $id_field Optional string of what the ID field is, if it is ever not comment_ID.
2157
	 *
2158
	 * @return array
2159
	 *   data:
2160
	 *     ID : 123,
2161
	 *     success: 1
2162
	 *   "errors" : [ ],
2163
	 */
2164
	private function comment_create( $params, $id_field = 'comment_ID' ) {
2165
		// Load all params with a method_modify of the object structure's content_method into $content
2166
		$content   = array();
2167
		$structure = $this->get_wordpress_table_structure( 'comment' );
2168
		foreach ( $params as $key => $value ) {
2169
			if ( in_array( $value['method_modify'], $structure['content_methods'] ) ) {
2170
				$content[ $key ] = $value['value'];
2171
				unset( $params[ $key ] );
2172
			}
2173
		}
2174
2175
		// Fields that are required for comments, even if they are empty values.
2176
		if ( ! isset( $content['comment_author'] ) ) {
2177
			$content['comment_author'] = '';
2178
		}
2179
		if ( ! isset( $content['comment_author_IP'] ) ) {
2180
			$content['comment_author_IP'] = '';
2181
		}
2182
		if ( ! isset( $content['comment_author_email'] ) ) {
2183
			$content['comment_author_email'] = '';
2184
		}
2185
		if ( ! isset( $content['comment_author_url'] ) ) {
2186
			$content['comment_author_url'] = '';
2187
		}
2188
		if ( ! isset( $content['comment_type'] ) ) {
2189
			$content['comment_type'] = '';
2190
		}
2191
2192
		$comment_id = wp_new_comment( $content );
2193
2194 View Code Duplication
		if ( is_wp_error( $comment_id ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2195
			$success = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2196
			$errors  = $comment_id;
0 ignored issues
show
Unused Code introduced by
$errors is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2197
		} else {
2198
			$success = true;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2199
			$errors  = array();
2200
			foreach ( $params as $key => $value ) {
2201
				$method  = $value['method_modify'];
2202
				$meta_id = $method( $comment_id, $key, $value['value'] );
2203
				if ( false === $meta_id ) {
2204
					$success  = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2205
					$errors[] = array(
2206
						'message' => sprintf(
2207
							// translators: %1$s is a method name.
2208
							esc_html__( 'Tried to add meta with method %1$s.', 'object-sync-for-salesforce' ),
2209
							esc_html( $method )
2210
						),
2211
						'key'     => $key,
2212
						'value'   => $value,
2213
					);
2214
				}
2215
			}
2216
2217
			// Developers can use this hook to set any other comment data.
2218
			do_action( $this->option_prefix . 'set_more_comment_data', $comment_id, $params, 'create' );
2219
2220
		}
2221
2222
		if ( is_wp_error( $comment_id ) ) {
2223
			$success = false;
2224
			$errors  = $comment_id;
2225
		} else {
2226
			$success = true;
2227
			$errors  = array();
2228
		}
2229
2230
		$result = array(
2231
			'data'   => array(
2232
				$id_field => $comment_id,
2233
				'success' => $success,
2234
			),
2235
			'errors' => $errors,
2236
		);
2237
2238
		return $result;
2239
2240
	}
2241
2242
	/**
2243
	 * Create a new WordPress comment or update it if a match is found.
2244
	 *
2245
	 * @param string $key What key we are looking at for possible matches.
2246
	 * @param string $value What value we are looking at for possible matches.
2247
	 * @param array  $methods What WordPress methods do we use to get the data, if there are any. otherwise, maybe will have to do a wpdb query.
2248
	 * @param array  $params Array of comment data params.
2249
	 * @param string $id_field Optional string of what the ID field is, if it is ever not comment_ID.
2250
	 * @param bool   $pull_to_drafts Whether to save to WordPress drafts when pulling from Salesforce.
2251
	 * @param bool   $check_only Allows this method to only check for matching records, instead of making any data changes.
2252
	 *
2253
	 * @return array
2254
	 *   data:
2255
	 *     ID : 123,
2256
	 *     success: 1
2257
	 *   "errors" : [ ],
2258
	 */
2259
	private function comment_upsert( $key, $value, $methods, $params, $id_field = 'comment_ID', $pull_to_drafts = false, $check_only = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $pull_to_drafts is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2260
		$method = $methods['method_match'];
2261
		if ( 'get_comment' === $method ) {
2262
			$method = 'get_comments';
2263
		}
2264
		if ( '' !== $method ) {
2265
2266
			// These methods should give us the comment object if we are matching for one.
2267
			// if we are trying to match to a meta field, the method is an object
2268
			if ( class_exists( $method ) ) {
2269
				$args        = array(
2270
					'meta_query' => array(
0 ignored issues
show
introduced by
Detected usage of meta_query, possible slow query.
Loading history...
2271
						array(
2272
							'key'   => $key,
2273
							'value' => $value,
2274
						),
2275
					),
2276
				);
2277
				$match_query = new $method( $args );
2278
				$comments    = $match_query->get_comments();
2279
				if ( ! empty( $comments ) ) {
2280
					$comment = $users[0];
0 ignored issues
show
Unused Code introduced by
$comment is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2281
				}
2282
			} else {
2283
				$match = array();
2284
				if ( 'comment_author' === $key ) {
2285
					$match['author__in'] = array( $value );
2286
				} else {
2287
					$key           = str_replace( 'comment_', '', $key );
2288
					$match[ $key ] = $value;
2289
				}
2290
				$comments = $method( $match );
2291
			}
2292
2293
			if ( 1 === count( $comments ) && isset( $comments ) && isset( $comments[0]->{$id_field} ) ) {
2294
				$comment = $comments[0];
2295
				// Comment does exist after checking the matching value. we want its id.
2296
				$comment_id = $comment->{$id_field};
2297
2298
				if ( true === $check_only ) {
2299
					// We are just checking to see if there is a match.
2300
					return $comment_id;
2301
				}
2302
2303
				// On the prematch fields, we specify the method_update param.
2304
				if ( isset( $methods['method_update'] ) ) {
2305
					$method = $methods['method_update'];
2306
				} else {
2307
					$method = $methods['method_modify'];
2308
				}
2309
				$params[ $key ] = array(
2310
					'value'         => $value,
2311
					'method_modify' => $method,
2312
					'method_read'   => $methods['method_read'],
2313
				);
2314
			} elseif ( count( $comments ) > 1 ) {
2315
				$status = 'error';
2316
				// Create log entry for multiple matches.
2317
				if ( isset( $this->logging ) ) {
2318
					$logging = $this->logging;
2319
				} elseif ( class_exists( 'Object_Sync_Sf_Logging' ) ) {
2320
					$logging = new Object_Sync_Sf_Logging( $this->wpdb, $this->version );
2321
				}
2322
				$logging->setup(
2323
					sprintf(
2324
						// translators: %1$s is a number. %2$s is a key. %3$s is the value of that key. %4$s is a var_export'd array of comments.
2325
						esc_html__( 'Error: Comments: there are %1$s comment matches for the Salesforce key %2$s with the value of %3$s. Here they are: %4$s', 'object-sync-for-salesforce' ),
2326
						absint( count( $comments ) ),
2327
						esc_html( $key ),
2328
						esc_html( $value ),
2329
						esc_html( var_export( $comments ) ) // Debugging code in production because having useful error messages is good.
2330
					),
2331
					'',
2332
					0,
2333
					0,
2334
					$status
2335
				);
2336
			} elseif ( false === $check_only ) {
2337
				// Comment does not exist after checking the matching value. Create it.
2338
				// On the prematch fields, we specify the method_create param.
2339
				if ( isset( $methods['method_create'] ) ) {
2340
					$method = $methods['method_create'];
2341
				} else {
2342
					$method = $methods['method_modify'];
2343
				}
2344
				$params[ $key ] = array(
2345
					'value'         => $value,
2346
					'method_modify' => $method,
2347
					'method_read'   => $methods['method_read'],
2348
				);
2349
				$result         = $this->comment_create( $params, $id_field );
2350
				return $result;
2351
			} else {
2352
				// Check only is true but there's not a comment yet.
2353
				return null;
2354
			} // End if().
2355
		} else {
2356
			// There is no method by which to check the comment. We can check other ways here.
2357
			$params[ $key ] = array(
2358
				'value'         => $value,
2359
				'method_modify' => $methods['method_modify'],
2360
				'method_read'   => $methods['method_read'],
2361
			);
2362
2363
			if ( isset( $params['comment_author']['value'] ) ) {
2364
				$comment_author = $params['comment_author']['value'];
2365
			}
2366
2367
			if ( isset( $params['comment_date']['value'] ) ) {
2368
				$comment_date = $params['comment_date']['value'];
2369
			}
2370
2371
			if ( isset( $params['timezone']['value'] ) ) {
2372
				$timezone = $params['timezone']['value'];
2373
			} else {
2374
				$timezone = 'blog';
2375
			}
2376
2377
			$existing_id = comment_exists( $comment_author, $comment_date, $timezone ); // Returns an id if there is a result. Uses $wpdb->get_var, so it returns null if there is no value
2378
2379
			// Comment does not exist after more checking. We want to create it.
2380
			if ( null === $existing_id && false === $check_only ) {
2381
				$result = $this->comment_create( $params, $id_field );
2382
				return $result;
2383
			} elseif ( true === $check_only ) {
2384
				// We are just checking to see if there is a match.
2385
				return $existing_id;
2386
			} else {
2387
				// Comment does exist based on username, and we aren't doing a check only. we want to update the wp user here.
2388
				$comment_id = $existing_id;
2389
			}
2390
		} // End if() that sets up the parameters in the $params array.
2391
2392 View Code Duplication
		if ( isset( $comment_id ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2393
			foreach ( $params as $key => $value ) {
2394
				$params[ $key ]['method_modify'] = $methods['method_update'];
2395
			}
2396
			$result = $this->comment_update( $comment_id, $params, $id_field );
2397
			return $result;
2398
		}
2399
2400
		// Create log entry for lack of a comment id.
2401
		if ( isset( $this->logging ) ) {
2402
			$logging = $this->logging;
2403
		} elseif ( class_exists( 'Object_Sync_Sf_Logging' ) ) {
2404
			$logging = new Object_Sync_Sf_Logging( $this->wpdb, $this->version );
2405
		}
2406
		$logging->setup(
2407
			esc_html__( 'Error: Comments: Tried to run comment_upsert, and ended up without a comment id', 'object-sync-for-salesforce' ),
2408
			'',
2409
			0,
2410
			0,
2411
			'error'
2412
		);
2413
2414
	}
2415
2416
	/**
2417
	 * Update a WordPress comment.
2418
	 *
2419
	 * @param string $comment_id The ID for the comment to be updated. This value needs to be in the array that is sent to wp_update_comment.
2420
	 * @param array  $params Array of comment data params.
2421
	 * @param string $id_field Optional string of what the ID field is, if it is ever not ID.
2422
	 *
2423
	 * @return array
2424
	 *   data:
2425
	 *     success: 1
2426
	 *   "errors" : [ ],
2427
	 */
2428
	private function comment_update( $comment_id, $params, $id_field = 'comment_ID' ) {
2429
		$content              = array();
2430
		$content[ $id_field ] = $comment_id;
2431 View Code Duplication
		foreach ( $params as $key => $value ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2432
			if ( 'wp_update_comment' === $value['method_modify'] ) {
2433
				$content[ $key ] = $value['value'];
2434
				unset( $params[ $key ] );
2435
			}
2436
		}
2437
2438
		$updated = wp_update_comment( $content );
2439
2440
		if ( 0 === $updated ) {
2441
			$success = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2442
			$errors  = $updated;
0 ignored issues
show
Unused Code introduced by
$errors is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2443
		} else {
2444
			$success = true;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2445
			$errors  = array();
2446
			foreach ( $params as $key => $value ) {
2447
				$method  = $value['method_modify'];
2448
				$meta_id = $method( $comment_id, $key, $value['value'] );
2449
				if ( false === $meta_id ) {
2450
					$success  = false;
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2451
					$errors[] = array(
2452
						'message' => sprintf(
2453
							// Translators: %1$s is a method name.
2454
							esc_html__( 'Tried to update meta with method %1$s.', 'object-sync-for-salesforce' ),
2455
							esc_html( $method )
2456
						),
2457
						'key'     => $key,
2458
						'value'   => $value,
2459
					);
2460
				}
2461
			}
2462
2463
			// Developers can use this hook to set any other comment data.
2464
			do_action( $this->option_prefix . 'set_more_comment_data', $comment_id, $params, 'update' );
2465
2466
		}
2467
2468 View Code Duplication
		if ( is_wp_error( $updated ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2469
			$success = false;
2470
			$errors  = $updated;
2471
		} else {
2472
			$success = true;
2473
			$errors  = array();
2474
		}
2475
2476
		$result = array(
2477
			'data'   => array(
2478
				$id_field => $comment_id,
2479
				'success' => $success,
2480
			),
2481
			'errors' => $errors,
2482
		);
2483
2484
		return $result;
2485
2486
	}
2487
2488
	/**
2489
	 * Delete a WordPress comment.
2490
	 *
2491
	 * @param int  $id Comment ID.
2492
	 * @param bool $force_delete If we should bypass the trash. We don't change this from FALSE anywhere in this plugin.
2493
	 *
2494
	 * @return boolean true if successful, false if failed.
2495
	 */
2496
	private function comment_delete( $id, $force_delete = false ) {
2497
		$result = wp_delete_comment( $id, $force_delete );
2498
		return $result;
2499
	}
2500
2501
}
2502
2503
/**
2504
 * WordpressException is a placeholder class in the event that we want to modify Exception for our own purposes.
2505
 */
2506
class WordpressException extends Exception {
2507
}
2508
2509
/**
2510
 * Class to store all theme/plugin transients as an array in one WordPress transient
2511
 **/
2512
class Object_Sync_Sf_WordPress_Transient {
2513
2514
	protected $name;
2515
2516
	/**
2517
	 * Constructor which sets cache options and the name of the field that lists this plugin's cache keys.
2518
	 *
2519
	 * @param string $name The name of the field that lists all cache keys.
2520
	 */
2521
	public function __construct( $name ) {
2522
		$this->name         = $name;
2523
		$this->cache_prefix = esc_sql( 'sfwp_' );
2524
	}
2525
2526
	/**
2527
	 * Get the transient that lists all the other transients for this plugin.
2528
	 *
2529
	 * @return mixed value of transient. False of empty, otherwise array.
2530
	 */
2531
	public function all_keys() {
2532
		return get_transient( $this->name );
2533
	}
2534
2535
	/**
2536
	 * Set individual transient, and add its key to the list of this plugin's transients.
2537
	 *
2538
	 * @param string $cachekey the key for this cache item
2539
	 * @param mixed $value the value of the cache item
2540
	 * @param int $cache_expiration. How long the plugin key cache, and this individual item cache, should last before expiring.
0 ignored issues
show
Documentation introduced by
There is no parameter named $cache_expiration.. Did you maybe mean $cache_expiration?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
2541
	 * @return mixed value of transient. False of empty, otherwise array.
2542
	 */
2543
	public function set( $cachekey, $value, $cache_expiration = 0 ) {
2544
2545
		$prefix   = $this->cache_prefix;
2546
		$cachekey = $prefix . $cachekey;
2547
2548
		$keys   = $this->all_keys();
2549
		$keys[] = $cachekey;
2550
		set_transient( $this->name, $keys, $cache_expiration );
2551
2552
		return set_transient( $cachekey, $value, $cache_expiration );
2553
	}
2554
2555
	/**
2556
	 * Get the individual cache value
2557
	 *
2558
	 * @param string $cachekey the key for this cache item
2559
	 * @return mixed value of transient. False of empty, otherwise array.
2560
	 */
2561
	public function get( $cachekey ) {
2562
		$prefix   = $this->cache_prefix;
2563
		$cachekey = $prefix . $cachekey;
2564
		return get_transient( $cachekey );
2565
	}
2566
2567
	/**
2568
	 * Delete the individual cache value
2569
	 *
2570
	 * @param string $cachekey the key for this cache item
2571
	 * @return bool True if successful, false otherwise.
2572
	 */
2573
	public function delete( $cachekey ) {
2574
		$prefix   = $this->cache_prefix;
2575
		$cachekey = $prefix . $cachekey;
2576
		return delete_transient( $cachekey );
2577
	}
2578
2579
	/**
2580
	 * Delete the entire cache for this plugin
2581
	 *
2582
	 * @return bool True if successful, false otherwise.
2583
	 */
2584
	public function flush() {
2585
		$keys   = $this->all_keys();
2586
		$result = true;
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2587
		if ( ! empty( $keys ) ) {
2588
			foreach ( $keys as $key ) {
2589
				$result = delete_transient( $key );
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2590
			}
2591
		}
2592
		$result = delete_transient( $this->name );
2593
		return $result;
2594
	}
2595
2596
}
2597