Completed
Pull Request — master (#146)
by
unknown
02:15
created

Post_Meta_Container::set_priority()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
ccs 0
cts 3
cp 0
crap 2
1
<?php
2
3
namespace Carbon_Fields\Container;
4
5
use Carbon_Fields\Datastore\Meta_Datastore;
6
use Carbon_Fields\Datastore\Post_Meta_Datastore;
7
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
8
9
/**
10
 * Field container designed to extend WordPress custom fields functionality,
11
 * providing easier user interface to add, edit and delete text, media files,
12
 * location information and more.
13
 */
14
class Post_Meta_Container extends Container {
15
	/**
16
	 * ID of the post the container is working with
17
	 *
18
	 * @see init()
19
	 * @var int
20
	 */
21
	protected $post_id;
22
23
	/**
24
	 * List of default container settings
25
	 *
26
	 * @see init()
27
	 * @var array
28
	 */
29
	public $settings = array(
30
		'post_type' => array( 'post' ),
31
		'panel_context' => 'normal',
32
		'panel_priority' => 'high',
33
		'show_on' => array(
34
			'category' => null,
35
			'template_names' => array(),
36
			'not_in_template_names' => array(),
37
			'post_formats' => array(),
38
			'level_limit' => null,
39
			'tax_term_id' => null,
40
			'page_id' => null,
41
			'parent_page_id' => null,
42
			'post_path' => null,
43
		),
44
	);
45
46
	/**
47
	 * Create a new post meta fields container
48
	 *
49
	 * @param string $title Unique title of the container
50
	 **/
51
	public function __construct( $title ) {
52
		parent::__construct( $title );
53
54
		if ( ! $this->get_datastore() ) {
55
			$this->set_datastore( new Post_Meta_Datastore() );
56
		}
57
	}
58
59
	/**
60
	 * Check if all required container settings have been specified
61
	 *
62
	 * @param array $settings Container settings
63
	 **/
64
	public function check_setup_settings( &$settings = array() ) {
65
		if ( isset( $settings['show_on'] ) ) {
66
			$invalid_settings = array_diff_key( $settings['show_on'], $this->settings['show_on'] );
67
			if ( ! empty( $invalid_settings ) ) {
68
				Incorrect_Syntax_Exception::raise( 'Invalid show_on settings supplied to setup(): "' . implode( '", "', array_keys( $invalid_settings ) ) . '"' );
69
			}
70
		}
71
72
		if ( isset( $settings['show_on']['post_formats'] ) ) {
73
			$settings['show_on']['post_formats'] = (array) $settings['show_on']['post_formats'];
74
		}
75
76
		if ( isset( $settings['show_on']['post_path'] ) ) {
77
			$page = get_page_by_path( $settings['show_on']['post_path'] );
78
79
			if ( $page ) {
80
				$settings['show_on']['page_id'] = $page->ID;
81
			} else {
82
				$settings['show_on']['page_id'] = -1;
83
			}
84
		}
85
86
		// Transform category slug to taxonomy + term slug + term id
87
		if ( isset( $settings['show_on']['category'] ) ) {
88
			$term = get_term_by( 'slug', $settings['show_on']['category'], 'category' );
89
90
			if ( $term ) {
91
				$settings['show_on']['tax_slug'] = $term->taxonomy;
92
				$settings['show_on']['tax_term'] = $term->slug;
93
				$settings['show_on']['tax_term_id'] = $term->term_id;
94
			}
95
		}
96
97
		return parent::check_setup_settings( $settings );
98
	}
99
100
	/**
101
	 * Create DataStore instance, set post ID to operate with (if such exists).
102
	 * Bind attach() and save() to the appropriate WordPress actions.
103
	 **/
104
	public function init() {
105
		if ( isset( $_GET['post'] ) ) {
1 ignored issue
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
106
			$this->set_post_id( $_GET['post'] );
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
107
		}
108
109
		// force post_type to be array
110
		if ( ! is_array( $this->settings['post_type'] ) ) {
111
			$this->settings['post_type'] = array( $this->settings['post_type'] );
112
		}
113
114
		add_action( 'admin_init', array( $this, '_attach' ) );
115
		add_action( 'save_post', array( $this, '_save' ) );
116
117
		// support for attachments
118
		add_action( 'add_attachment', array( $this, '_save' ) );
119
		add_action( 'edit_attachment', array( $this, '_save' ) );
120
	}
121
122
	/**
123
	 * Perform save operation after successful is_valid_save() check.
124
	 * The call is propagated to all fields in the container.
125
	 *
126
	 * @param int $post_id ID of the post against which save() is ran
127
	 **/
128 View Code Duplication
	public function save( $post_id ) {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in 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...
129
		// Unhook action to garantee single save
130
		remove_action( 'save_post', array( $this, '_save' ) );
131
132
		$this->set_post_id( $post_id );
133
134
		foreach ( $this->fields as $field ) {
135
			$field->set_value_from_input();
136
			$field->save();
137
		}
138
139
		do_action( 'carbon_after_save_custom_fields', $post_id );
140
		do_action( 'carbon_after_save_post_meta', $post_id );
141
	}
142
143
	/**
144
	 * Perform checks whether the current save() request is valid
145
	 * Possible errors are triggering save() for autosave requests
146
	 * or performing post save outside of the post edit page (like Quick Edit)
147
	 *
148
	 * @see is_valid_save_conditions()
149
	 * @param int $post_id ID of the post against which save() is ran
150
	 * @return bool
151
	 **/
152
	public function is_valid_save( $post_id = 0 ) {
153
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
154
			return false;
155
		} else if ( ! isset( $_REQUEST[ $this->get_nonce_name() ] ) || ! wp_verify_nonce( $_REQUEST[ $this->get_nonce_name() ], $this->get_nonce_name() ) ) { // Input var okay.
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
156
			return false;
157
		} else if ( $post_id < 1 ) {
158
			return false;
159
		}
160
161
		return $this->is_valid_save_conditions( $post_id );
162
	}
163
164
	/**
165
	 * Perform checks whether the current save() request is valid
166
	 * Possible errors are triggering save() for autosave requests
167
	 * or performing post save outside of the post edit page (like Quick Edit)
168
	 *
169
	 * @param int $post_id ID of the post against which save() is ran
170
	 * @return bool
171
	 **/
172
	public function is_valid_save_conditions( $post_id ) {
173
		$valid = true;
174
		$post = get_post( $post_id );
175
176
		// Check post type
177
		if ( ! in_array( $post->post_type, $this->settings['post_type'] ) ) {
178
			return false;
179
		}
180
181
		// Check show on conditions
182
		foreach ( $this->settings['show_on'] as $condition => $value ) {
183
			if ( is_null( $value ) ) {
184
				continue;
185
			}
186
187
			switch ( $condition ) {
188
				// show_on_post_format
189
				case 'post_formats':
190
					if ( empty( $value ) || $post->post_type != 'post' ) {
191
						break;
192
					}
193
194
					$current_format = get_post_format( $post_id );
195
					if ( ! in_array( $current_format, $value ) ) {
196
						$valid = false;
197
						break 2;
198
					}
199
200
					break;
201
202
				// show_on_taxonomy_term or show_on_category
203
				case 'category':
204
					$this->show_on_category( $value );
205
206
					/* fall-through intended */
207
				case 'tax_term_id':
208
					$current_terms = wp_get_object_terms( $post_id, $this->settings['show_on']['tax_slug'], array( 'fields' => 'ids' ) );
209
210
					if ( ! is_array( $current_terms ) || ! in_array( $this->settings['show_on']['tax_term_id'], $current_terms ) ) {
211
						$valid = false;
212
						break 2;
213
					}
214
215
					break;
216
217
				// show_on_level
218
				case 'level_limit':
219
					$post_level = count( get_post_ancestors( $post_id ) ) + 1;
220
221
					if ( $post_level != $value ) {
222
						$valid = false;
223
						break 2;
224
					}
225
226
					break;
227
228
				// show_on_page
229
				case 'page_id':
230
					if ( $post_id != $value ) {
231
						$valid = false;
232
						break 2;
233
					}
234
235
					break;
236
237
				// show_on_page_children
238
				case 'parent_page_id':
239
					if ( $post->post_parent != $value ) {
240
						$valid = false;
241
						break 2;
242
					}
243
244
					break;
245
246
				// show_on_template
247 View Code Duplication
				case 'template_names':
1 ignored issue
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...
248
					if ( empty( $value ) || $post->post_type != 'page' ) {
249
						break;
250
					}
251
					$current_template = get_post_meta( $post_id, '_wp_page_template', 1 );
252
253
					if ( ! in_array( $current_template, $value ) ) {
254
						$valid = false;
255
						break 2;
256
					}
257
258
					break;
259
260
				// hide_on_template
261 View Code Duplication
				case 'not_in_template_names':
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...
262
					if ( empty( $value ) || $post->post_type != 'page' ) {
263
						break;
264
					}
265
					$current_template = get_post_meta( $post_id, '_wp_page_template', 1 );
266
267
					if ( in_array( $current_template, $value ) ) {
268
						$valid = false;
269
						break 2;
270
					}
271
272
					break;
273
			}
274
		}
275
276
		return $valid;
277
	}
278
279
	/**
280
	 * Add meta box for each of the container post types
281
	 **/
282
	public function attach() {
283
		foreach ( $this->settings['post_type'] as $post_type ) {
284
			add_meta_box(
285
				$this->id,
286
				$this->title,
287
				array( $this, 'render' ),
288
				$post_type,
289
				$this->settings['panel_context'],
290
				$this->settings['panel_priority']
291
			);
292
		}
293
294
		foreach ( $this->settings['post_type'] as $post_type ) {
295
			add_filter( "postbox_classes_{$post_type}_{$this->id}", array( $this, 'postbox_classes' ) );
296
		}
297
	}
298
299
	/**
300
	 * Classes to add to the post meta box
301
	 */
302
	public function postbox_classes( $classes ) {
303
		$classes[] = 'carbon-box';
304
		return $classes;
305
	}
306
307
	/**
308
	 * Perform checks whether the container should be attached during the current request
309
	 *
310
	 * @return bool True if the container is allowed to be attached
311
	 **/
312
	public function is_valid_attach() {
313
		global $pagenow;
314
315
		if ( $pagenow !== 'post.php' && $pagenow !== 'post-new.php' ) {
316
			return false;
317
		}
318
319
		// Post types check
320
		if ( ! empty( $this->settings['post_type'] ) ) {
321
			$post_type = '';
322
323
			if ( $this->post_id ) {
324
				$post_type = get_post_type( $this->post_id );
325
			} elseif ( ! empty( $_GET['post_type'] ) ) {
326
				$post_type = $_GET['post_type'];
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
327
			} elseif ( $pagenow === 'post-new.php' ) {
328
				$post_type = 'post';
329
			}
330
331
			if ( ! $post_type || ! in_array( $post_type, $this->settings['post_type'] ) ) {
332
				return false;
333
			}
334
		}
335
336
		// Check show on conditions
337
		foreach ( $this->settings['show_on'] as $condition => $value ) {
338
			if ( is_null( $value ) ) {
339
				continue;
340
			}
341
342
			switch ( $condition ) {
343
				case 'page_id':
344
					if ( $value < 1 || $this->post_id != $value ) {
345
						return false;
346
					}
347
					break;
348
				case 'parent_page_id':
349
					// Check if such page exists
350
					if ( $value < 1 ) {
351
						return false;
352
					}
353
					break;
354
			}
355
		}
356
357
		return true;
358
	}
359
360
	/**
361
	 * Revert the result of attach()
362
	 **/
363 View Code Duplication
	public function detach() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
364
		parent::detach();
365
366
		remove_action( 'admin_init', array( $this, '_attach' ) );
367
		remove_action( 'save_post', array( $this, '_save' ) );
368
369
		// unregister field names
370
		foreach ( $this->fields as $field ) {
371
			$this->drop_unique_field_name( $field->get_name() );
372
		}
373
	}
374
375
	/**
376
	 * Output the container markup
377
	 **/
378
	public function render() {
379
		include \Carbon_Fields\DIR . '/templates/Container/post_meta.php';
380
	}
381
382
	/**
383
	 * Set the post ID the container will operate with.
384
	 *
385
	 * @param int $post_id
386
	 **/
387
	public function set_post_id( $post_id ) {
388
		$this->post_id = $post_id;
389
		$this->store->set_id( $post_id );
390
	}
391
392
	/**
393
	 * Show the container only on pages whose parent is referenced by $parent_page_path.
394
	 *
395
	 * @param string $parent_page_path
396
	 * @return object $this
397
	 **/
398 1
	public function show_on_page_children( $parent_page_path ) {
399 1
		$page = get_page_by_path( $parent_page_path );
400
401 1
		$this->show_on_post_type( 'page' );
402
403 1
		if ( $page ) {
404 1
			$this->settings['show_on']['parent_page_id'] = $page->ID;
405 1
		} else {
406
			$this->settings['show_on']['parent_page_id'] = -1;
407
		}
408
409 1
		return $this;
410
	}
411
412
	/**
413
	 * Show the container only on particular page referenced by it's path.
414
	 *
415
	 * @param int|string $page page ID or page path
416
	 * @return object $this
417
	 **/
418 4
	public function show_on_page( $page ) {
419 4
		$page_id = absint( $page );
420
421 4
		if ( $page_id && $page_id == $page ) {
422 2
			$page_obj = get_post( $page_id );
423 2
		} else {
424 2
			$page_obj = get_page_by_path( $page );
425
		}
426
427 4
		$this->show_on_post_type( 'page' );
428
429 4
		if ( $page_obj ) {
430 4
			$this->settings['show_on']['page_id'] = $page_obj->ID;
431 4
		} else {
432
			$this->settings['show_on']['page_id'] = -1;
433
		}
434
435 4
		return $this;
436
	}
437
438
	/**
439
	 * Show the container only on posts from the specified category.
440
	 *
441
	 * @see show_on_taxonomy_term()
442
	 *
443
	 * @param string $category_slug
444
	 * @return object $this
445
	 **/
446
	public function show_on_category( $category_slug ) {
447
		$this->settings['show_on']['category'] = $category_slug;
448
449
		return $this->show_on_taxonomy_term( $category_slug, 'category' );
450
	}
451
452
	/**
453
	 * Show the container only on pages whose template has filename $template_path.
454
	 *
455
	 * @param string|array $template_path
456
	 * @return object $this
457
	 **/
458 2 View Code Duplication
	public function show_on_template( $template_path ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
459 2
		if ( is_array( $template_path ) ) {
460 1
			foreach ( $template_path as $path ) {
461 1
				$this->show_on_template( $path );
462 1
			}
463
464 1
			return $this;
465
		}
466
467 2
		$this->settings['show_on']['template_names'][] = $template_path;
468
469 2
		return $this;
470
	}
471
472
	/**
473
	 * Hide the container from pages whose template has filename $template_path.
474
	 *
475
	 * @param string|array $template_path
476
	 * @return object $this
477
	 **/
478 View Code Duplication
	public function hide_on_template( $template_path ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
479
		if ( is_array( $template_path ) ) {
480
			foreach ( $template_path as $path ) {
481
				$this->hide_on_template( $path );
482
			}
483
			return $this;
484
		}
485
486
		$this->settings['show_on']['not_in_template_names'][] = $template_path;
487
488
		return $this;
489
	}
490
491
	/**
492
	 * Show the container only on hierarchical posts of level $level.
493
	 * Levels start from 1 (top level post)
494
	 *
495
	 * @param int $level
496
	 * @return object $this
497
	 **/
498
	public function show_on_level( $level ) {
499
		if ( $level < 0 ) {
500
			Incorrect_Syntax_Exception::raise( 'Invalid level limitation (' . $level . ')' );
501
		}
502
503
		$this->settings['show_on']['level_limit'] = $level;
504
505
		return $this;
506
	}
507
508
	/**
509
	 * Show the container only on posts which have term $term_slug from the $taxonomy_slug taxonomy.
510
	 *
511
	 * @param string $taxonomy_slug
512
	 * @param string $term_slug
513
	 * @return object $this
514
	 **/
515
	public function show_on_taxonomy_term( $term_slug, $taxonomy_slug ) {
516
		$term = get_term_by( 'slug', $term_slug, $taxonomy_slug );
517
518
		$this->settings['show_on']['tax_slug'] = $taxonomy_slug;
519
		$this->settings['show_on']['tax_term'] = $term_slug;
520
		$this->settings['show_on']['tax_term_id'] = $term ? $term->term_id : null;
521
522
		return $this;
523
	}
524
525
	/**
526
	 * Show the container only on posts from the specified format.
527
	 * Learn more about {@link http://codex.wordpress.org/Post_Formats Post Formats (Codex)}
528
	 *
529
	 * @param string|array $post_format Name of the format as listed on Codex
530
	 * @return object $this
531
	 **/
532
	public function show_on_post_format( $post_format ) {
533
		if ( is_array( $post_format ) ) {
534
			foreach ( $post_format as $format ) {
535
				$this->show_on_post_format( $format );
536
			}
537
			return $this;
538
		}
539
540
		if ( $post_format === 'standard' ) {
541
			$post_format = 0;
542
		}
543
544
		$this->settings['show_on']['post_formats'][] = strtolower( $post_format );
545
546
		return $this;
547
	}
548
549
	/**
550
	 * Show the container only on posts from the specified type(s).
551
	 *
552
	 * @param string|array $post_types
553
	 * @return object $this
554
	 **/
555
	public function show_on_post_type( $post_types ) {
556
		$post_types = (array) $post_types;
557
558
		$this->settings['post_type'] = $post_types;
559
560
		return $this;
561
	}
562
563
	/**
564
	 * Sets the meta box container context
565
	 *
566
	 * @see https://codex.wordpress.org/Function_Reference/add_meta_box
567
	 * @param string $context ('normal', 'advanced' or 'side')
568
	 */
569
	public function set_context( $context ) {
570
		$this->settings['panel_context'] = $context;
571
572
		return $this;
573
	}
574
575
	/**
576
	 * Sets the meta box container priority
577
	 *
578
	 * @see https://codex.wordpress.org/Function_Reference/add_meta_box
579
	 * @param string $priority ('high', 'core', 'default' or 'low')
580
	 */
581
	public function set_priority( $priority ) {
582
		$this->settings['panel_priority'] = $priority;
583
584
		return $this;
585
	}
586
} // END Post_Meta_Container
587