Passed
Push — master ( c00ab5...5ed1e2 )
by litefeel
03:01
created

Writing_On_GitHub_Database::delete_post()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 25
Code Lines 13

Duplication

Lines 15
Ratio 60 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 15
loc 25
ccs 0
cts 15
cp 0
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 13
nc 3
nop 1
crap 20
1
<?php
2
/**
3
 * Database interface.
4
 * @package Writing_On_GitHub
5
 */
6
7
/**
8
 * Class Writing_On_GitHub_Database
9
 */
10
class Writing_On_GitHub_Database {
11
12
	/**
13
	 * Application container.
14
	 *
15
	 * @var Writing_On_GitHub
16
	 */
17
	protected $app;
18
19
	/**
20
	 * Currently whitelisted post types.
21
	 *
22
	 * @var array
23
	 */
24
	protected $whitelisted_post_types = array( 'post', 'page' );
25
26
	/**
27
	 * Currently whitelisted post statuses.
28
	 *
29
	 * @var array
30
	 */
31
	protected $whitelisted_post_statuses = array( 'publish' );
32
33
	/**
34
	 * Instantiates a new Database object.
35
	 *
36
	 * @param Writing_On_GitHub $app Application container.
37
	 */
38
	public function __construct( Writing_On_GitHub $app ) {
39
		$this->app = $app;
40
	}
41
42
	/**
43
	 * Queries the database for all of the supported posts.
44
	 *
45
     * @param  bool $force
46
     *
47
     * @return Writing_On_GitHub_Post[]|WP_Error
48
     */
49
	public function fetch_all_supported( $force = false ) {
50
		$args  = array(
51
			'post_type'   => $this->get_whitelisted_post_types(),
52
			'post_status' => $this->get_whitelisted_post_statuses(),
53
			'nopaging'    => true,
0 ignored issues
show
introduced by
Disabling pagination is prohibited in VIP context, do not set nopaging to true ever.
Loading history...
54
			'fields'      => 'ids',
55
		);
56
57
		$query = new WP_Query( apply_filters( 'wogh_pre_fetch_all_supported', $args ) );
58
59
		$post_ids = $query->get_posts();
60
61
		if ( ! $post_ids ) {
62
			return new WP_Error(
63
				'no_results',
64
				__( 'Querying for supported posts returned no results.', 'writing-on-github' )
65
			);
66
		}
67
68
        /* @var Writing_On_GitHub_Post[] $results */
69
		$results = array();
70
		foreach ( $post_ids as $post_id ) {
71
			// Do not export posts that have already been exported
72
			if ( $force || ! get_post_meta( $post_id, '_wogh_sha', true ) ||
73
				 ! get_post_meta( $post_id, '_wogh_github_path', true ) ) {
74
75
				$results[] = new Writing_On_GitHub_Post( $post_id, $this->app->api() );
76
			}
77
		}
78
79
		return $results;
80
	}
81
82
	/**
83
	 * Queries a post and returns it if it's supported.
84
	 *
85
	 * @param int $post_id Post ID to fetch.
86
	 *
87
	 * @return WP_Error|Writing_On_GitHub_Post
88
	 */
89
	public function fetch_by_id( $post_id ) {
90
		$post = new Writing_On_GitHub_Post( $post_id, $this->app->api() );
91
92
		if ( ! $this->is_post_supported( $post ) ) {
93
			return new WP_Error(
94
				'unsupported_post',
95
				sprintf(
96
					__(
97
						'Post ID %s is not supported by WOGH. See wiki to find out how to add support.',
98
						'writing-on-github'
99
					),
100
					$post_id
101
				)
102
			);
103
		}
104
105
		return $post;
106
	}
107
108
	/**
109
	 * Saves an array of Post objects to the database
110
	 * and associates their author as well as their latest
111
	 *
112
	 * @param Writing_On_GitHub_Post[] $posts Array of Posts to save.
113
	 *
114
	 * @return string|WP_Error
115
	 */
116
	public function save_posts( array $posts ) {
0 ignored issues
show
Complexity introduced by
This operation has 322 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

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

Loading history...
117
118
		/**
119
		 * Whether an error has occurred.
120
		 *
121
		 * @var WP_Error|false $error
122
		 */
123
		$error = false;
124
125
		foreach ( $posts as $post ) {
126
			$args = apply_filters( 'wogh_pre_import_args', $this->post_args( $post ), $post );
127
128
			remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
129
			$post_id = $post->is_new() ?
130
				wp_insert_post( $args, true ) :
131
				wp_update_post( $args, true );
132
			add_filter( 'content_save_pre', 'wp_filter_post_kses' );
133
134
			if ( is_wp_error( $post_id ) ) {
135
                /* @var WP_Error $post_id */
136
                $error = wogh_append_error( $error, $post_id );
137
138
				// Abort saving if updating the post fails.
139
				continue;
140
			}
141
142
			if ( $post->is_new() ) {
143
				$author = false;
144
				$meta = $post->get_meta();
145
				if ( ! empty( $meta ) && ! empty( $meta['author'] ) ) {
146
					$author = $meta['author'];
147
				}
148
				$user    = $this->fetch_commit_user( $author );
149
				$user_id = is_wp_error( $user ) ? 0 : $user->ID;
150
				$this->set_post_author( $post_id, $user_id );
151
			}
152
153
			$post->set_post( get_post( $post_id ) );
154
155
			$meta = apply_filters( 'wogh_pre_import_meta', $post->get_meta(), $post );
156
157
			// unset( $meta['tags'] );
158
			// unset( $meta['categories'] );
159
			// unset( $meta['author'] );
160
			// unset( $meta['post_date'] );
161
			// unset( $meta['post_excerpt'] );
162
			// unset( $meta['permalink'] );
163
			// unset( $meta['link'] );
164
165
			// foreach ( $meta as $key => $value ) {
166
			// 	update_post_meta( $post_id, $key, $value );
167
			// }
168
		}
169
170
		if ( $error ) {
171
			return $error;
172
		}
173
174
		return __( 'Successfully saved posts.', 'writing-on-github' );
175
	}
176
177
	protected function post_args( $post ) {
178
		$args = $post->get_args();
179
		$meta = $post->get_meta();
180
181
		// prevent backslash loss
182
		$args['post_content'] = addslashes( $args['post_content'] );
183
184
		// update tags
185
		if ( ! empty( $meta['tags'] ) ) {
186
		    $args['tags_input'] = $meta['tags'];
187
		}
188
189
		// update categories
190
		if ( ! empty( $meta['categories'] ) ) {
191
		    $categories = $meta['categories'];
192
		    if ( ! is_array( $categories ) ) {
193
		        $categories = array( $categories );
194
		    }
195
		    $terms = get_terms( array(
196
		        'taxonomy' => 'category',
197
		        'fields' => 'id=>name',
198
		        'hide_empty' => 0,
199
		        'name' => $categories
0 ignored issues
show
introduced by
Each line in an array declaration must end in a comma
Loading history...
200
		        )
201
		    );
202
		    $map = array();
203
		    foreach ( $categories as $name ) {
204
		        $map[$name] = 1;
0 ignored issues
show
introduced by
Array keys should be surrounded by spaces unless they contain a string or an integer.
Loading history...
205
		    }
206
207
		    $ids = array();
208
		    if ( ! empty( $terms ) ) {
209
		        foreach ( $terms as $id => $name ) {
210
		            $ids[] = $id;
211
		            unset( $map[$name] );
0 ignored issues
show
introduced by
Array keys should be surrounded by spaces unless they contain a string or an integer.
Loading history...
212
		        }
213
		    }
214
215
		    // create new terms
216
		    if ( ! empty( $map ) ) {
217
		        foreach ( $map as $name => $value ) {
218
		            $term = wp_insert_term( $name, 'category', array( 'parent' => 0 ) );
219
		            // array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
220
		            $ids[] = $term['term_id'];
221
		        }
222
		    }
223
224
		    $args['post_category'] = $ids;
225
		}
226
227
		return $args;
228
	}
229
230
    private function get_post_id_by_filename( $filename, $pattern  ) {
231
        preg_match( $pattern , $filename, $matches );
232
        $title = $matches[4];
233
234
        $query = new WP_Query( array(
235
            'name'     => $title,
236
            'posts_per_page' => 1,
237
            'post_type' => $this->get_whitelisted_post_types(),
238
            'fields'         => 'ids',
239
        ) );
240
241
        $post_id = $query->get_posts();
242
        $post_id = array_pop( $post_id );
243
        return $post_id;
244
    }
245
246
	/**
247
	 * Deletes a post from the database based on its GitHub path.
248
	 *
249
	 * @param string $path Path of Post to delete.
250
	 *
251
	 * @return string|WP_Error
252
	 */
253
	public function delete_post_by_path( $path ) {
254
		$query = new WP_Query( array(
255
			'meta_key'       => '_wogh_github_path',
0 ignored issues
show
introduced by
Detected usage of meta_key, possible slow query.
Loading history...
256
			'meta_value'     => $path,
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
257
			'meta_compare'   => '=',
258
			'posts_per_page' => 1,
259
			'fields'         => 'ids',
260
		) );
261
262
		$post_id = $query->get_posts();
263
		$post_id = array_pop( $post_id );
264
265
		if ( ! $post_id ) {
266
			$parts     = explode( '/', $path );
267
			$filename  = array_pop( $parts );
268
			$directory = $parts ? array_shift( $parts ) : '';
269
270
			if ( false !== strpos( $directory, 'post' ) ) {
271
                $post_id = get_post_id_by_filename( $filename, '/([0-9]{4})-([0-9]{2})-([0-9]{2})-(.*)\.md/' );
272
			}
273
274
			if ( ! $post_id ) {
275
                $post_id = get_post_id_by_filename( $filename, '/(.*)\.md/' );
276
			}
277
		}
278
279
		if ( ! $post_id ) {
280
			return new WP_Error(
281
				'path_not_found',
282
				sprintf(
283
					__( 'Post not found for path %s.', 'writing-on-github' ),
284
					$path
285
				)
286
			);
287
		}
288
289
		$result = wp_delete_post( $post_id );
290
291
		// If deleting fails...
292 View Code Duplication
		if ( false === $result ) {
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...
293
			$post = get_post( $post_id );
294
295
			// ...and the post both exists and isn't in the trash...
296
			if ( $post && 'trash' !== $post->post_status ) {
297
				// ... then something went wrong.
298
				return new WP_Error(
299
					'db_error',
300
					sprintf(
301
						__( 'Failed to delete post ID %d.', 'writing-on-github' ),
302
						$post_id
303
					)
304
				);
305
			}
306
		}
307
308
		return sprintf(
309
			__( 'Successfully deleted post ID %d.', 'writing-on-github' ),
310
			$post_id
311
		);
312
	}
313
314
	public function delete_post( $post_id ) {
315
		$result = wp_delete_post( $post_id );
316
317
		// If deleting fails...
318 View Code Duplication
		if ( false === $result ) {
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...
319
			$post = get_post( $post_id );
320
321
			// ...and the post both exists and isn't in the trash...
322
			if ( $post && 'trash' !== $post->post_status ) {
323
				// ... then something went wrong.
324
				return new WP_Error(
325
					'db_error',
326
					sprintf(
327
						__( 'Failed to delete post ID %d.', 'writing-on-github' ),
328
						$post_id
329
					)
330
				);
331
			}
332
		}
333
334
		return sprintf(
335
			__( 'Successfully deleted post ID %d.', 'writing-on-github' ),
336
			$post_id
337
		);
338
	}
339
340
	/**
341
	 * Returns the list of post type permitted.
342
	 *
343
	 * @return array
344
	 */
345
	protected function get_whitelisted_post_types() {
346
		return apply_filters( 'wogh_whitelisted_post_types', $this->whitelisted_post_types );
347
	}
348
349
	/**
350
	 * Returns the list of post status permitted.
351
	 *
352
	 * @return array
353
	 */
354
	protected function get_whitelisted_post_statuses() {
355
		return apply_filters( 'wogh_whitelisted_post_statuses', $this->whitelisted_post_statuses );
356
	}
357
358
	/**
359
	 * Formats a whitelist array for a query.
360
	 *
361
	 * @param array $whitelist Whitelisted posts to format into query.
362
	 *
363
	 * @return string Whitelist formatted for query
364
	 */
365
	protected function format_for_query( $whitelist ) {
366
		foreach ( $whitelist as $key => $value ) {
367
			$whitelist[ $key ] = "'$value'";
368
		}
369
370
		return implode( ', ', $whitelist );
371
	}
372
373
	/**
374
	 * Verifies that both the post's status & type
375
	 * are currently whitelisted
376
	 *
377
	 * @param  Writing_On_GitHub_Post $post Post to verify.
378
	 *
379
	 * @return boolean                          True if supported, false if not.
380
	 */
381
	protected function is_post_supported( Writing_On_GitHub_Post $post ) {
382
		if ( wp_is_post_revision( $post->id ) ) {
383
			return false;
384
		}
385
386
		// We need to allow trashed posts to be queried, but they are not whitelisted for export.
387
		if ( ! in_array( $post->status(), $this->get_whitelisted_post_statuses() ) && 'trash' !== $post->status() ) {
388
			return false;
389
		}
390
391
		if ( ! in_array( $post->type(), $this->get_whitelisted_post_types() ) ) {
392
			return false;
393
		}
394
395
		if ( $post->has_password() ) {
396
			return false;
397
		}
398
399
		return apply_filters( 'wogh_is_post_supported', true, $post );
400
	}
401
402
	/**
403
	 * Retrieves the commit user for a provided display name
404
	 *
405
	 * Searches for a user with provided display name or returns
406
	 * the default user saved in the database.
407
	 *
408
	 * @param string $display_name User display name to search for.
409
	 *
410
	 * @return WP_Error|WP_User
411
	 */
412
	protected function fetch_commit_user( $display_name ) {
413
		// If we can't find a user and a default hasn't been set,
414
		// we're just going to set the revision author to 0.
415
		$user = false;
416
417
		if ( ! empty( $display_name ) ) {
418
			$search_string = esc_attr( $display_name );
419
			$query = new WP_User_Query( array(
420
			    'search'         => "{$search_string}",
421
			    'search_columns' => array(
422
			        'display_name',
423
			        'user_nicename',
424
			        'user_login',
425
			    )
426
			) );
427
			$users = $query->get_results();
428
			$user = empty($users) ? false : $users[0];
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
429
		}
430
431
		if ( ! $user ) {
432
			// Use the default user.
433
			$user = get_user_by( 'id', (int) get_option( 'wogh_default_user' ) );
434
		}
435
436
		if ( ! $user ) {
437
			return new WP_Error(
438
				'user_not_found',
439
				sprintf(
440
					__( 'Commit user not found for email %s', 'writing-on-github' ),
441
					$email
442
				)
443
			);
444
		}
445
446
		return $user;
447
	}
448
449
	// /**
450
	//  * Sets the author latest revision
451
	//  * of the provided post ID to the provided user.
452
	//  *
453
	//  * @param int $post_id Post ID to update revision author.
454
	//  * @param int $user_id User ID for revision author.
455
	//  *
456
	//  * @return string|WP_Error
457
	//  */
458
	// protected function set_revision_author( $post_id, $user_id ) {
459
	// 	$revision = wp_get_post_revisions( $post_id );
460
461
	// 	if ( ! $revision ) {
462
	// 		$new_revision = wp_save_post_revision( $post_id );
463
464
	// 		if ( ! $new_revision || is_wp_error( $new_revision ) ) {
465
	// 			return new WP_Error( 'db_error', 'There was a problem saving a new revision.' );
466
	// 		}
467
468
	// 		// `wp_save_post_revision` returns the ID, whereas `get_post_revision` returns the whole object
469
	// 		// in order to be consistent, let's make sure we have the whole object before continuing.
470
	// 		$revision = get_post( $new_revision );
471
472
	// 		if ( ! $revision ) {
473
	// 			return new WP_Error( 'db_error', 'There was a problem retrieving the newly recreated revision.' );
474
	// 		}
475
	// 	} else {
476
	// 		$revision = array_shift( $revision );
477
	// 	}
478
479
	// 	return $this->set_post_author( $revision->ID, $user_id );
480
	// }
481
482
	/**
483
	 * Updates the user ID for the provided post ID.
484
	 *
485
	 * Bypassing triggering any hooks, including creating new revisions.
486
	 *
487
	 * @param int $post_id Post ID to update.
488
	 * @param int $user_id User ID to update to.
489
	 *
490
	 * @return string|WP_Error
491
	 */
492
	protected function set_post_author( $post_id, $user_id ) {
493
		global $wpdb;
494
495
		$result = $wpdb->update(
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
496
			$wpdb->posts,
497
			array(
498
				'post_author' => (int) $user_id,
499
			),
500
			array(
501
				'ID' => (int) $post_id,
502
			),
503
			array( '%d' ),
504
			array( '%d' )
505
		);
506
507
		if ( false === $result ) {
508
			return new WP_Error( 'db_error', $wpdb->last_error );
509
		}
510
511
		if ( 0 === $result ) {
512
			return sprintf(
513
				__( 'No change for post ID %d.', 'writing-on-github' ),
514
				$post_id
515
			);
516
		}
517
518
		clean_post_cache( $post_id );
519
520
		return sprintf(
521
			__( 'Successfully updated post ID %d.', 'writing-on-github' ),
522
			$post_id
523
		);
524
	}
525
526
	// *
527
	//  * Update the provided post's blob sha.
528
	//  *
529
	//  * @param Writing_On_GitHub_Post $post Post to update.
530
	//  * @param string                     $sha Sha to update to.
531
	//  *
532
	//  * @return bool|int
533
534
	// public function set_post_sha( $post, $sha ) {
535
	// 	return update_post_meta( $post->id, '_wogh_sha', $sha );
536
	// }
537
}
538