Post::create_objects()   B
last analyzed

Complexity

Conditions 4
Paths 5

Size

Total Lines 29
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 4
eloc 11
c 2
b 1
f 0
nc 5
nop 3
dl 0
loc 29
rs 8.5806
1
<?php
2
namespace testContent\Types;
3
use testContent as Main;
4
use testContent\TestContent as TestContent;
5
use testContent\Delete as Delete;
6
use testContent\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     Old Town Media
15
 */
16
class Post extends Abs\Type{
17
18
	/**
19
	 * metaboxes
20
	 * Easy access for the Metaboxes class.
21
	 *
22
	 * @var string
23
	 * @access private
24
	 */
25
	private $metaboxes;
26
27
	/**
28
	 * type
29
	 * Defines type slug for use elsewhere in the plugin
30
	 *
31
	 * @var string
32
	 * @access protected
33
	 */
34
	protected $type = 'post';
35
36
	/**
37
	 * Constructor to load in the Metaboxes class.
38
	 *
39
	 * @see object
40
	 */
41
	public function __construct(){
42
43
		$this->metaboxes = new Main\Metaboxes;
0 ignored issues
show
Documentation Bug introduced by
It seems like new \testContent\Metaboxes() of type object<testContent\Metaboxes> is incompatible with the declared type string of property $metaboxes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
44
45
	}
46
47
	/**
48
	 * Create test data posts.
49
	 *
50
	 * This is where the magic begins. We accept a cpt id (slug) and potntially
51
	 * a number of posts to create. We then fetch the supports & metaboxes
52
	 * for that cpt and feed them into a function to create each post individually.
53
	 *
54
	 * @access private
55
	 *
56
	 * @see $this->get_cpt_supports, $this->get_metaboxes, $this->create_test_object
57
	 *
58
	 * @param string $slug a custom post type ID.
59
	 * @param boolean $connection Whether or not we're connected to the Internet.
60
	 * @param int $num Optional. Number of posts to create.
61
	 */
62
	public function create_objects( $slug, $connection, $num = '' ){
63
64
		// If we're missing a custom post type id - don't do anything
65
		if ( empty( $slug ) ){
66
			return;
67
		}
68
69
		// Gather the necessary data to create the posts
70
		$supports 	= $this->get_cpt_supports( $slug );
71
		$metaboxes	= $this->metaboxes->get_metaboxes( $slug );
0 ignored issues
show
Bug introduced by
The method get_metaboxes cannot be called on $this->metaboxes (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
72
73
		// Set our connection status for the rest of the methods
74
		$this->connected = $connection;
75
76
		// If we forgot to put in a quantity, make one for us
77
		if ( empty( $num ) ){
78
			$num = rand( 5, 30 );
79
		}
80
81
		// Create test posts
82
		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...
83
84
			$return = $this->create_test_object( $slug, $supports, $metaboxes );
85
86
			return $return;
87
88
		}
89
90
	}
91
92
93
	/**
94
	 * Creates the individual test data post.
95
	 *
96
	 * Create individual posts for testing with. Gathers basic information such
97
	 * as title, content, thumbnail, etc. and inserts them with the post. Also
98
	 * adds metaboxes if applicable .
99
	 *
100
	 * @access private
101
	 *
102
	 * @see TestContent, wp_insert_post, add_post_meta, update_post_meta, $this->random_metabox_content
103
	 *
104
	 * @param string $slug a custom post type ID.
105
	 * @param array $supports Features that the post type supports.
106
	 * @param array $supports All CMB2 metaboxes attached to the post type.
107
	 */
108
	private function create_test_object( $slug, $supports, $metaboxes ){
109
		$return = '';
110
111
		// Get a random title
112
		$title = apply_filters( "tc_{$slug}_post_title", TestContent::title() );
113
114
		// First, insert our post
115
		$post = array(
116
		  'post_name'      => sanitize_title( $title ),
117
		  'post_status'    => 'publish',
118
		  'post_type'      => $slug,
119
		  'ping_status'    => 'closed',
120
		  'comment_status' => 'closed',
121
		);
122
123
		// Add title if supported
124
		if ( $supports['title'] === true ){
125
			$post['post_title'] = $title;
126
		}
127
128
		// Add main content if supported
129
		if ( $supports['editor'] === true ){
130
			$post['post_content'] = apply_filters( "tc_{$slug}_post_content", TestContent::paragraphs() );
131
		}
132
133
		// Add excerpt content if supported
134
		if ( $supports['excerpt'] === true ){
135
			$post['post_excerpt'] = apply_filters( "tc_{$slug}_post_excerpt", TestContent::plain_text() );
136
		}
137
138
		// Insert then post object
139
		$post_id = wp_insert_post( apply_filters( "tc_{$slug}_post_arguments", $post ) );
140
141
		// Then, set a test content flag on the new post for later deletion
142
		add_post_meta( $post_id, 'evans_test_content', '__test__', true );
143
144
		// Add thumbnail if supported
145
		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...
146
			 update_post_meta( $post_id, '_thumbnail_id', TestContent::image( $post_id ) );
147
		}
148
149
		$taxonomies = get_object_taxonomies( $slug );
150
151
		// Assign the post to terms
152
		if ( !empty( $taxonomies ) ){
153
			$return .= $this->assign_terms( $post_id, $taxonomies );
154
		}
155
156
		// Spin up metaboxes
157
		if ( !empty( $metaboxes ) ){
158
			foreach ( $metaboxes as $cmb ) :
159
				$return .= $this->metaboxes->random_metabox_content( $post_id, $cmb, $this->connected );
0 ignored issues
show
Bug introduced by
The method random_metabox_content cannot be called on $this->metaboxes (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

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