Post   B
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 409
Duplicated Lines 3.18 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 13
loc 409
rs 8.3999
c 0
b 0
f 0
wmc 38
lcom 1
cbo 5

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B create_objects() 0 29 4
C create_test_object() 13 71 11
A get_cpt_supports() 0 12 1
B assign_terms() 0 41 6
A delete_all() 0 18 3
B delete_associated_media() 0 27 5
C delete() 0 73 7

How to fix   Duplicated Code   

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:

1
<?php
2
namespace DummyPress\Types;
3
use DummyPress as Main;
4
use DummyPress\TestContent as TestContent;
5
use DummyPress\Delete as Delete;
6
use DummyPress\Abstracts as Abs;
7
8
9
/**
10
 * Class to build test data for custom post types.
11
 *
12
 * @package    WordPress
13
 * @subpackage Evans
14
 * @author     Mike Selander
15
 */
16
class Post extends Abs\Type {
17
18
	/**
19
	 * metabox_types
20
	 * Easy access for the MetaboxTypes class.
21
	 *
22
	 * @var object
23
	 * @access private
24
	 */
25
	private $metabox_types;
26
27
	/**
28
	 * metabox_values
29
	 * Easy access for the MetaboxValues class.
30
	 *
31
	 * @var object
32
	 * @access private
33
	 */
34
	private $metabox_values;
35
36
	/**
37
	 * type
38
	 * Defines type slug for use elsewhere in the plugin
39
	 *
40
	 * @var string
41
	 * @access protected
42
	 */
43
	protected $type = 'post';
44
45
	/**
46
	 * Constructor to load in the Metaboxes class.
47
	 *
48
	 * @see MetaboxTypes, MetaboxValues
49
	 */
50
	public function __construct() {
51
52
		$this->metabox_types = new Main\MetaboxTypes;
53
		$this->metabox_values = new Main\MetaboxValues;
54
55
	}
56
57
	/**
58
	 * Create test data posts.
59
	 *
60
	 * This is where the magic begins. We accept a cpt id (slug) and potntially
61
	 * a number of posts to create. We then fetch the supports & metaboxes
62
	 * for that cpt and feed them into a function to create each post individually.
63
	 *
64
	 * @access private
65
	 *
66
	 * @see $this->get_cpt_supports, $this->get_metaboxes, $this->create_test_object
67
	 *
68
	 * @param string $slug a custom post type ID.
69
	 * @param boolean $connection Whether or not we're connected to the Internet.
70
	 * @param int $num Optional. Number of posts to create.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $num not be string|integer?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
71
	 */
72
	public function create_objects( $slug, $connection, $num = '' ) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
73
74
		// If we're missing a custom post type id - don't do anything
75
		if ( empty( $slug ) ) {
76
			return;
77
		}
78
79
		// Gather the necessary data to create the posts
80
		$supports 	= $this->get_cpt_supports( $slug );
81
		$metaboxes	= $this->metabox_types->get_metaboxes( $slug );
82
83
		// Set our connection status for the rest of the methods
84
		$this->connected = $connection;
85
86
		// If we forgot to put in a quantity, make one for us
87
		if ( empty( $num ) ) {
88
			$num = rand( 5, 30 );
89
		}
90
91
		// Create test posts
92
		for( $i = 0; $i < $num; $i++ ) {
0 ignored issues
show
Unused Code introduced by
$i++; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
93
94
			$return = $this->create_test_object( $slug, $supports, $metaboxes );
95
96
			return $return;
97
98
		}
99
100
	}
101
102
103
	/**
104
	 * Creates the individual test data post.
105
	 *
106
	 * Create individual posts for testing with. Gathers basic information such
107
	 * as title, content, thumbnail, etc. and inserts them with the post. Also
108
	 * adds metaboxes if applicable .
109
	 *
110
	 * @access private
111
	 *
112
	 * @see TestContent, wp_insert_post, add_post_meta, update_post_meta, $this->get_values
113
	 *
114
	 * @param string $slug a custom post type ID.
115
	 * @param array $supports Features that the post type supports.
116
	 * @param array $supports All CMB2 metaboxes attached to the post type.
117
	 */
118
	private function create_test_object( $slug, $supports, $metaboxes ) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
119
		$return = '';
120
121
		// Get a random title
122
		$title = apply_filters( "tc_{$slug}_post_title", TestContent::title() );
123
124
		// First, insert our post
125
		$post = array(
126
		  'post_name'      => sanitize_title( $title ),
127
		  'post_status'    => 'publish',
128
		  'post_type'      => $slug,
129
		  'ping_status'    => 'closed',
130
		  'comment_status' => 'closed',
131
		);
132
133
		// Add title if supported
134
		if ( $supports['title'] === true ) {
135
			$post['post_title'] = $title;
136
		}
137
138
		// Add main content if supported
139
		if ( $supports['editor'] === true ) {
140
			$post['post_content'] = apply_filters( "tc_{$slug}_post_content", TestContent::paragraphs() );
141
		}
142
143
		// Add excerpt content if supported
144
		if ( $supports['excerpt'] === true ) {
145
			$post['post_excerpt'] = apply_filters( "tc_{$slug}_post_excerpt", TestContent::plain_text() );
146
		}
147
148
		// Insert then post object
149
		$post_id = wp_insert_post( apply_filters( "tc_{$slug}_post_arguments", $post ) );
150
151
		// Then, set a test content flag on the new post for later deletion
152
		add_post_meta( $post_id, 'dummypress_test_data', '__test__', true );
153
154
		// Add thumbnail if supported
155
		if ( $this->connected == true && ( $supports['thumbnail'] === true || in_array( $slug, array( 'post', 'page' ) ) ) ) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
156
			 update_post_meta( $post_id, '_thumbnail_id', TestContent::image( $post_id ) );
157
		}
158
159
		$taxonomies = get_object_taxonomies( $slug );
160
161
		// Assign the post to terms
162
		if ( ! empty( $taxonomies ) ) {
163
			$return .= $this->assign_terms( $post_id, $taxonomies );
164
		}
165
166
		// Spin up metaboxes
167
		if ( ! empty( $metaboxes ) ) {
168
			foreach ( $metaboxes as $cmb ) :
169
				$return .= $this->metabox_values->get_values( $post_id, $cmb, $this->connected );
170
			endforeach;
171
		}
172
173
		// Check if we have errors and return them or created message
174 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...
175
			error_log( $post_id->get_error_message() );
176
			return $post_id;
177
		} else {
178
			return array(
179
				'action'	=> 'created',
180
				'object'	=> 'post',
181
				'oid'		=> $post_id,
182
				'type'		=> get_post_type( $post_id ),
183
				'link_edit'	=> admin_url( '/post.php?post='.$post_id.'&action=edit' ),
184
				'link_view'	=> get_permalink( $post_id ),
185
			);
186
		}
187
188
	}
189
190
191
	/**
192
	 * Assemble supports statements for a particular post type.
193
	 *
194
	 * @access private
195
	 *
196
	 * @see post_type_supports
197
	 *
198
	 * @param string $slug a custom post type ID.
199
	 * @return array Array of necessary supports booleans.
200
	 */
201
	private function get_cpt_supports( $slug ) {
202
203
		$supports = array(
204
			'title'		=> post_type_supports( $slug, 'title' ),
205
			'editor'	=> post_type_supports( $slug, 'editor' ),
206
			'excerpt'	=> post_type_supports( $slug, 'excerpt' ),
207
			'thumbnail'	=> post_type_supports( $slug, 'thumbnail' ),
208
		);
209
210
		return $supports;
211
212
	}
213
214
215
	/**
216
	 * Assigns taxonomies to the new post.
217
	 *
218
	 * Loop through every taxonomy type associated with a custom post type &
219
	 * assign the post to a random item out of each taxonomy. Taxonomies must
220
	 * have at least one term in them for this to work.
221
	 *
222
	 * @access private
223
	 *
224
	 * @param int $post_id a custom post type ID.
225
	 * @param array $taxonomies taxonomies assigned to this cpt.
226
	 * @return object WP Error if there is one.
227
	 */
228
	private function assign_terms( $post_id, $taxonomies ) {
229
230
		// Make sure it's an array & has items
231
		if ( empty( $taxonomies ) || ! is_array( $taxonomies ) ) {
232
			return;
233
		}
234
235
		foreach ( $taxonomies as $tax ) {
236
237
			// Get the individual terms already existing
238
			$terms = get_terms( $tax, array( 'hide_empty'	=> false ) );
239
			$count = count( $terms ) - 1;
240
241
			// If there are no terms, skip to the next taxonomy
242
			if ( empty( $terms ) ) {
243
				continue;
244
			}
245
246
			// Get a random index to use
247
			$index = rand( 0, $count );
248
249
			// Initialize our array
250
			$post_data = array(
251
				'ID'	=> $post_id
252
			);
253
254
			// Set the term data to update
255
			$post_data['tax_input'][ $tax ] = array( $terms[$index]->term_id );
256
257
			// Update the post with the taxonomy info
258
			$return = wp_update_post( $post_data );
259
260
			// Return the error if it exists
261
			if ( is_wp_error( $return ) ) {
262
				error_log( $return->get_error_messages() );
263
				return $return->get_error_messages();
264
			}
265
266
		}
267
268
	}
269
270
271
	/**
272
	 * Delete all test data, regardless of type, within posts.
273
	 *
274
	 * @see Delete
275
	 */
276
	public function delete_all() {
277
278
		$delete =  new Delete;
279
280
		// Make sure that the current user is logged in & has full permissions.
281
		if ( ! $delete->user_can_delete() ) {
282
			return;
283
		}
284
285
		// Loop through all post types and remove any test data
286
		$post_types = get_post_types( array( 'public' => true ), 'objects' );
287
		foreach ( $post_types as $post_type ) :
288
289
		    return $this->delete( $post_type->name );
290
291
		endforeach;
292
293
	}
294
295
296
	/**
297
	 * Delete test data posts.
298
	 *
299
	 * This function will search for all posts of a particular post type ($slug)
300
	 * and delete them all using a particular cmb flag that we set when creating
301
	 * the posts. Validates the user first.
302
	 *
303
	 * @see WP_Query, wp_delete_post
304
	 *
305
	 * @param string $slug a custom post type ID.
306
	 */
307
	public function delete( $slug ) {
308
309
		$delete =  new Delete;
310
311
		// Make sure that the current user is logged in & has full permissions.
312
		if ( ! $delete->user_can_delete() ) {
313
			return;
314
		}
315
316
		// Check that $cptslg has a string.
317
		if ( empty( $slug ) ) {
318
			return;
319
		}
320
321
		// Find our test data by the unique flag we set when we created the data
322
		$query = array(
323
			'post_type' 		=> $slug,
324
			'posts_per_page'	=> 500,
325
			'meta_query' 		=> array(
326
				'relation'		=> 'OR',
327
		        array(
328
		           'key'       => 'dummypress_test_data',
329
		           'value'     => '__test__',
330
		           'compare'   => '='
331
			   ),
332
			   array(
333
				  'key'       => 'evans_test_content',
334
				  'value'     => '__test__',
335
				  'compare'   => '='
336
			  ),
337
			),
338
		);
339
340
		$objects = new \WP_Query( $query );
341
342
		if ( $objects->have_posts() ) {
343
344
			$events = array();
345
346
			while ( $objects->have_posts() ) : $objects->the_post();
347
348
				// Find any media associated with the test post and delete it as well
349
				$this->delete_associated_media( get_the_id() );
350
351
				// Double check our set user meta value
352
				if ( '__test__' != get_post_meta( get_the_id(), 'dummypress_test_data', true ) && '__test__' != get_post_meta( get_the_id(), 'evans_test_content', true ) ) {
353
					continue;
354
				}
355
356
				$events[] = array(
357
					'action'	=> 'deleted',
358
					'oid'		=> get_the_id(),
359
					'type'		=> get_post_type( get_the_id() ),
360
					'link'		=> ''
361
				);
362
363
				// Force delete the post
364
				wp_delete_post( get_the_id(), true );
365
366
			endwhile;
367
368
			$obj = get_post_type_object( $slug );
369
370
			$events[] = array(
371
				'action'	=> 'general',
372
				'message'	=> __( 'Deleted', 'dummybot' ) . ' ' . $obj->labels->all_items
373
			);
374
375
			return $events;
376
377
		}
378
379
	}
380
381
382
	/**
383
	 * Find and delete attachments associated with a post ID.
384
	 *
385
	 * This function finds each attachment that is associated with a post ID
386
	 * and deletes it completely from the site. This is to prevent leftover
387
	 * random images from sitting on the site forever.
388
	 *
389
	 * @access private
390
	 *
391
	 * @see get_attached_media, wp_delete_attachment
392
	 *
393
	 * @param int $pid a custom post type ID.
394
	 */
395
	private function delete_associated_media( $pid ) {
396
397
		$delete =  new Delete;
398
399
		// Make sure that the current user is logged in & has full permissions.
400
		if ( ! $delete->user_can_delete() ) {
401
			return;
402
		}
403
404
		// Make sure $pid is, in fact, an ID
405
		if ( ! is_int( $pid ) ) {
406
			return;
407
		}
408
409
		// Get our images
410
		$media = get_attached_media( 'image', $pid );
411
412
		if ( ! empty( $media ) ) {
413
414
			// Loop through the media & delete each one
415
			foreach ( $media as $attachment ) {
416
				wp_delete_attachment( $attachment->ID, true );
417
			}
418
419
		}
420
421
	}
422
423
424
}
425