Completed
Push — development ( 5ed9d2...646735 )
by
unknown
04:14
created

Post_Meta_Container::is_valid_save()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
nc 4
nop 0
dl 0
loc 18
rs 9.3554
c 0
b 0
f 0
ccs 0
cts 11
cp 0
crap 30
1
<?php
2
3
namespace Carbon_Fields\Container;
4
5
use Carbon_Fields\Helper\Helper;
6
use Carbon_Fields\Datastore\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
		'meta_box_context' => 'normal',
31
		'meta_box_priority' => 'high',
32
	);
33
34
	/**
35
	 * {@inheritDoc}
36
	 */
37 View Code Duplication
	public function __construct( $id, $title, $type, $condition_collection, $condition_translator ) {
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...
38
		parent::__construct( $id, $title, $type, $condition_collection, $condition_translator );
39
40
		if ( ! $this->get_datastore() ) {
41
			$this->set_datastore( Datastore::make( 'post_meta' ), $this->has_default_datastore() );
42
		}
43
	}
44
45
	/**
46
	 * Create DataStore instance, set post ID to operate with (if such exists).
47
	 * Bind attach() and save() to the appropriate WordPress actions.
48
	 */
49
	public function init() {
50
		$input = stripslashes_deep( $_GET );
51
		$request_post_id = isset( $input['post'] ) ? intval( $input['post'] ) : 0;
52
		if ( $request_post_id > 0 ) {
53
			$this->set_post_id( $request_post_id );
54
		}
55
56
		add_action( 'admin_init', array( $this, '_attach' ) );
57
		add_action( 'save_post', array( $this, '_save' ) );
58
59
		// support for attachments
60
		add_action( 'add_attachment', array( $this, '_save' ) );
61
		add_action( 'edit_attachment', array( $this, '_save' ) );
62
	}
63
64
	/**
65
	 * Checks whether the current save request is valid
66
	 * Possible errors are triggering save() for autosave requests
67
	 * or performing post save outside of the post edit page (like Quick Edit)
68
	 *
69
	 * @return bool
70
	 */
71
	public function is_valid_save() {
72
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
73
			return false;
74
		}
75
76
		if ( ! $this->verified_nonce_in_request() ) {
77
			return false;
78
		}
79
80
		$params = func_get_args();
81
		$post_id = $params[0];
82
		$post_type = get_post_type( $post_id );
83
		if ( $post_type === 'revision' ) {
84
			return false;
85
		}
86
87
		return $this->is_valid_attach_for_object( $post_id );
88
	}
89
90
	/**
91
	 * Perform save operation after successful is_valid_save() check.
92
	 * The call is propagated to all fields in the container.
93
	 *
94
	 * @param int $post_id ID of the post against which save() is ran
95
	 */
96 View Code Duplication
	public function save( $post_id = null ) {
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...
97
		// Unhook action to garantee single save
98
		remove_action( 'save_post', array( $this, '_save' ) );
99
100
		$this->set_post_id( $post_id );
101
102
		foreach ( $this->fields as $field ) {
103
			$field->set_value_from_input( Helper::input() );
104
			$field->save();
105
		}
106
107
		do_action( 'carbon_fields_post_meta_container_saved', $post_id, $this );
108
	}
109
110
	/**
111
	 * Get environment array for page request (in admin)
112
	 *
113
	 * @return array
114
	 */
115
	protected function get_environment_for_request() {
116
		global $pagenow;
117
118
		$input = stripslashes_deep( $_GET );
119
		$request_post_type = isset( $input['post_type'] ) ? $input['post_type'] : '';
120
		$post_type = '';
121
122
		if ( $this->post_id ) {
123
			$post_type = get_post_type( $this->post_id );
124
		} elseif ( ! empty( $request_post_type ) ) {
125
			$post_type = $request_post_type;
126
		} elseif ( $pagenow === 'post-new.php' ) {
127
			$post_type = 'post';
128
		}
129
130
		$post = get_post( $this->post_id );
131
		$post = $post ? $post : null;
132
		$environment = array(
133
			'post_id' => $post ? $post->ID : 0,
134
			'post_type' => $post ? $post->post_type : $post_type,
135
			'post' => $post,
136
		);
137
		return $environment;
138
	}
139
140
	/**
141
	 * Perform checks whether the container should be attached during the current request
142
	 *
143
	 * @return bool True if the container is allowed to be attached
144
	 */
145
	public function is_valid_attach_for_request() {
146
		global $pagenow;
147
148
		if ( $pagenow !== 'post.php' && $pagenow !== 'post-new.php' ) {
149
			return false;
150
		}
151
152
		$environment = $this->get_environment_for_request();
153
		if ( ! $environment['post_type'] ) {
154
			return false;
155
		}
156
157
		return $this->static_conditions_pass();
158
	}
159
160
	/**
161
	 * Get environment array for object id
162
	 *
163
	 * @return array
164
	 */
165
	protected function get_environment_for_object( $object_id ) {
166
		$post = get_post( intval( $object_id ) );
167
168
		$environment = array(
169
			'post_id' => $post->ID,
170
			'post' => $post,
171
			'post_type' => get_post_type( $post->ID ),
172
		);
173
		return $environment;
174
	}
175
176
	/**
177
	 * Check container attachment rules against object id
178
	 *
179
	 * @param int $object_id
180
	 * @return bool
181
	 */
182 View Code Duplication
	public function is_valid_attach_for_object( $object_id = null ) {
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...
183
		$post = get_post( intval( $object_id ) );
184
185
		if ( ! $post ) {
186
			return false;
187
		}
188
189
		return $this->all_conditions_pass( intval( $post->ID ) );
190
	}
191
192
	/**
193
	 * Add meta box for each of the container post types
194
	 */
195
	public function attach() {
196
		$this->post_types = $this->get_post_type_visibility();
197
198
		foreach ( $this->post_types as $post_type ) {
199
			add_meta_box(
200
				$this->get_id(),
201
				$this->title,
202
				array( $this, 'render' ),
203
				$post_type,
204
				$this->settings['meta_box_context'],
205
				$this->settings['meta_box_priority']
206
			);
207
208
			$container_id = $this->get_id();
209
			add_filter( "postbox_classes_{$post_type}_{$container_id}", array( $this, 'add_postbox_classes' ) );
210
		}
211
	}
212
213
	/**
214
	 * Classes to add to the post meta box
215
	 */
216
	public function add_postbox_classes( $classes ) {
217
		$classes[] = 'carbon-box';
218
		return $classes;
219
	}
220
221
	/**
222
	 * Output the container markup
223
	 */
224
	public function render() {
225
		include \Carbon_Fields\DIR . '/templates/Container/post_meta.php';
226
	}
227
228
	/**
229
	 * Set the post ID the container will operate with.
230
	 *
231
	 * @param int $post_id
232
	 */
233 View Code Duplication
	protected function set_post_id( $post_id ) {
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...
234
		$this->post_id = $post_id;
235
		$this->get_datastore()->set_object_id( $post_id );
236
237
		foreach ( $this->fields as $field ) {
238
			$datastore = $field->get_datastore();
239
			if ( $datastore->get_object_id() === 0 ) {
240
				$datastore->set_object_id( $post_id );
241
			}
242
		}
243
	}
244
245
	/**
246
	 * Get array of post types this container can appear on conditionally
247
	 *
248
	 * @return array<string>
249
	 */
250 View Code Duplication
	public function get_post_type_visibility() {
251
		$all_post_types = get_post_types();
252
		$evaluated_collection = $this->condition_collection->evaluate( array( 'post_type' ), true, array(), true );
253
254
		$shown_on = array();
255
		foreach ( $all_post_types as $post_type ) {
256
			$environment = array(
257
				'post_type' => $post_type,
258
			);
259
			if ( $evaluated_collection->is_fulfilled( $environment ) ) {
260
				$shown_on[] = $post_type;
261
			}
262
		}
263
		return $shown_on;
264
	}
265
266
	/**
267
	 * COMMON USAGE METHODS
268
	 */
269
270
	/**
271
	 * Show the container only on particular page referenced by its path.
272
	 *
273
	 * @deprecated
274
	 * @param int|string $page page ID or page path
275
	 * @return object $this
276
	 */
277
	public function show_on_page( $page ) {
278
		$page_id = absint( $page );
279
280
		if ( $page_id && $page_id == $page ) {
281
			$page_obj = get_post( $page_id );
282
		} else {
283
			$page_obj = get_page_by_path( $page );
284
		}
285
		$page_id = ( $page_obj ) ? $page_obj->ID : -1;
286
287
		$this->where( 'post_id', '=', $page_id );
288
289
		return $this;
290
	}
291
292
	/**
293
	 * Show the container only on pages whose parent is referenced by $parent_page_path.
294
	 *
295
	 * @deprecated
296
	 * @param string $parent_page_path
297
	 * @return object $this
298
	 */
299
	public function show_on_page_children( $parent_page_path ) {
300
		$page = get_page_by_path( $parent_page_path );
301
		$page_id = ( $page ) ? $page->ID : -1;
302
		$this->where( 'post_parent_id', '=', $page_id );
303
		return $this;
304
	}
305
306
	/**
307
	 * Show the container only on pages whose template has filename $template_path.
308
	 *
309
	 * @deprecated
310
	 * @param string|array $template_path
311
	 * @return object $this
312
	 */
313
	public function show_on_template( $template_path ) {
314
		// Backwards compatibility where only pages support templates
315
		if ( version_compare( get_bloginfo( 'version' ), '4.7', '<' ) ) {
316
			$this->show_on_post_type( 'page' );
317
		}
318
319
		$template_paths = is_array( $template_path ) ? $template_path : array( $template_path );
320
		$this->where( 'post_template', 'IN', $template_paths );
321
		return $this;
322
	}
323
324
	/**
325
	 * Hide the container from pages whose template has filename $template_path.
326
	 *
327
	 * @deprecated
328
	 * @param string|array $template_path
329
	 * @return object $this
330
	 */
331
	public function hide_on_template( $template_path ) {
332
		$template_paths = is_array( $template_path ) ? $template_path : array( $template_path );
333
		$this->where( 'post_template', 'NOT IN', $template_paths );
334
		return $this;
335
	}
336
337
	/**
338
	 * Show the container only on hierarchical posts of level $level.
339
	 * Levels start from 1 (top level post)
340
	 *
341
	 * @deprecated
342
	 * @param int $level
343
	 * @return object $this
344
	 */
345
	public function show_on_level( $level ) {
346
		$this->where( 'post_level', '=', intval( $level ) );
347
		return $this;
348
	}
349
350
	/**
351
	 * Show the container only on posts from the specified format.
352
	 * Learn more about {@link http://codex.wordpress.org/Post_Formats Post Formats (Codex)}
353
	 *
354
	 * @deprecated
355
	 * @param string|array $post_format Name of the format as listed on Codex
356
	 * @return object $this
357
	 */
358
	public function show_on_post_format( $post_format ) {
359
		$post_formats = is_array( $post_format ) ? $post_format : array( $post_format );
360
		$this->where( 'post_format', 'IN', $post_formats );
361
		return $this;
362
	}
363
364
	/**
365
	 * Show the container only on posts from the specified type(s).
366
	 *
367
	 * @deprecated
368
	 * @param string|array $post_types
369
	 * @return object $this
370
	 */
371
	public function show_on_post_type( $post_types ) {
372
		$post_types = is_array( $post_types ) ? $post_types : array( $post_types );
373
		$this->where( 'post_type', 'IN', $post_types );
374
		return $this;
375
	}
376
377
	/**
378
	 * Show the container only on posts from the specified category.
379
	 *
380
	 * @see show_on_taxonomy_term()
381
	 *
382
	 * @deprecated
383
	 * @param string $category_slug
384
	 * @return object $this
385
	 */
386
	public function show_on_category( $category_slug ) {
387
		$this->where( 'post_term', '=', array(
388
			'value' => $category_slug,
389
			'field' => 'slug',
390
			'taxonomy' => 'category',
391
		) );
392
		return $this;
393
	}
394
395
	/**
396
	 * Show the container only on posts which have term $term_slug from the $taxonomy_slug taxonomy.
397
	 *
398
	 * @deprecated
399
	 * @param string $taxonomy_slug
400
	 * @param string $term_slug
401
	 * @return object $this
402
	 */
403
	public function show_on_taxonomy_term( $term_slug, $taxonomy_slug ) {
404
		$this->where( 'post_term', '=', array(
405
			'value' => $term_slug,
406
			'field' => 'slug',
407
			'taxonomy' => $taxonomy_slug,
408
		) );
409
		return $this;
410
	}
411
412
	/**
413
	 * Sets the meta box container context
414
	 *
415
	 * @see https://codex.wordpress.org/Function_Reference/add_meta_box
416
	 * @param string $context ('normal', 'advanced', 'side' or the custom `carbon_fields_after_title`)
417
	 */
418
	public function set_context( $context ) {
419
		$this->settings['meta_box_context'] = $context;
420
		return $this;
421
	}
422
423
	/**
424
	 * Sets the meta box container priority
425
	 *
426
	 * @see https://codex.wordpress.org/Function_Reference/add_meta_box
427
	 * @param string $priority ('high', 'core', 'default' or 'low')
428
	 */
429
	public function set_priority( $priority ) {
430
		$this->settings['meta_box_priority'] = $priority;
431
		return $this;
432
	}
433
}
434