PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / trunk
Secure Custom Fields vtrunk
6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / includes / forms / form-post.php
secure-custom-fields / includes / forms Last commit date
WC_Order.php 10 hours ago form-attachment.php 1 year ago form-comment.php 7 months ago form-customizer.php 10 months ago form-front.php 3 weeks ago form-gutenberg.php 1 year ago form-nav-menu.php 7 months ago form-post.php 1 month ago form-taxonomy.php 2 weeks ago form-user.php 7 months ago form-widget.php 10 months ago index.php 1 year ago
form-post.php
386 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit; // Exit if accessed directly
5 }
6
7 if ( ! class_exists( 'ACF_Form_Post' ) ) :
8
9 /**
10 * Class ACF_Form_Post
11 *
12 * Handles the functionality for adding custom fields to post edit screens.
13 *
14 * @package ACF
15 * @since ACF 5.0.0
16 */
17 class ACF_Form_Post {
18
19 /**
20 * Style.
21 *
22 * @var string The first field groups style CSS.
23 */
24 public $style = '';
25
26 /**
27 * __construct
28 *
29 * Sets up the class functionality.
30 *
31 * @date 5/03/2014
32 * @since ACF 5.0.0.0.0
33 *
34 * @return void
35 */
36 public function __construct() {
37
38 // initialize on post edit screens
39 add_action( 'load-post.php', array( $this, 'initialize' ) );
40 add_action( 'load-post-new.php', array( $this, 'initialize' ) );
41
42 // save
43 add_filter( 'wp_insert_post_empty_content', array( $this, 'wp_insert_post_empty_content' ), 10, 1 );
44 add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
45 }
46
47
48 /**
49 * Initialize.
50 *
51 * Sets up Form functionality.
52 *
53 * @date 19/9/18
54 * @since ACF 5.7.6.7.6
55 *
56 * @return void
57 */
58 public function initialize() {
59
60 // globals
61 global $typenow;
62
63 $acf_post_types = acf_get_internal_post_types();
64
65 foreach ( $acf_post_types as $post_type ) {
66 remove_meta_box( 'submitdiv', $post_type, 'side' );
67 }
68
69 // restrict specific post types
70 $restricted = array_merge( $acf_post_types, array( 'acf-taxonomy', 'attachment' ) );
71 if ( in_array( $typenow, $restricted ) ) {
72 return;
73 }
74
75 // enqueue scripts
76 acf_enqueue_scripts(
77 array(
78 'uploader' => true,
79 )
80 );
81
82 // actions
83 add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 10, 2 );
84 }
85
86 /**
87 * Checks if a field group is assigned to blocks.
88 *
89 * Block field groups should not be rendered as metaboxes because:
90 * 1. They are managed by the block editor (blocks v3)
91 * 2. They have their own validation system via AJAX
92 * 3. Rendering them as metaboxes causes duplicate validation on post save
93 *
94 * @since SCF 6.6.0
95 *
96 * @param array $field_group The field group array.
97 * @return bool True if field group is for blocks, false otherwise.
98 */
99 public function is_block_field_group( $field_group ) {
100 if ( empty( $field_group['location'] ) ) {
101 return false;
102 }
103
104 // Check each location group
105 foreach ( $field_group['location'] as $location_group ) {
106 foreach ( $location_group as $rule ) {
107 if ( isset( $rule['param'] ) && 'block' === $rule['param'] ) {
108 return true;
109 }
110 }
111 }
112
113 return false;
114 }
115
116 /**
117 *
118 * Adds ACF metaboxes for the given $post_type and $post.
119 *
120 * @date 19/9/18
121 * @since ACF 5.7.6.7.6
122 *
123 * @param string $post_type The post type.
124 * @param WP_Post $post The post being edited.
125 * @return void
126 */
127 public function add_meta_boxes( $post_type, $post ) {
128
129 // Storage for localized postboxes.
130 $postboxes = array();
131
132 // Get field groups for this screen.
133 $field_groups = acf_get_field_groups(
134 array(
135 'post_id' => $post->ID,
136 'post_type' => $post_type,
137 )
138 );
139
140 // Loop over field groups.
141 if ( $field_groups ) {
142 foreach ( $field_groups as $field_group ) {
143 // Skip block field groups - they are managed by the block editor
144 if ( $this->is_block_field_group( $field_group ) ) {
145 continue;
146 }
147
148 $id = esc_attr( "acf-{$field_group['key']}" );
149 $context = esc_attr( $field_group['position'] );
150 $priority = 'high';
151
152 // Reduce priority for sidebar metaboxes for best position.
153 if ( 'side' === $context ) {
154 $priority = 'core';
155 }
156
157 /**
158 * Filters the metabox priority.
159 *
160 * @date 23/06/12
161 * @since ACF 3.1.8.1.8
162 *
163 * @param string $priority The metabox priority (high, core, default, low).
164 * @param array $field_group The field group array.
165 */
166 $priority = apply_filters( 'acf/input/meta_box_priority', $priority, $field_group );
167
168 // Localize data
169 $postboxes[] = array(
170 'id' => $id,
171 'key' => esc_attr( $field_group['key'] ),
172 'style' => esc_attr( $field_group['style'] ),
173 'label' => esc_attr( $field_group['label_placement'] ),
174 'edit' => esc_url( acf_get_field_group_edit_link( $field_group['ID'] ) ),
175 );
176
177 // Add the meta box.
178 add_meta_box(
179 $id,
180 acf_esc_html( acf_get_field_group_title( $field_group ) ),
181 array( $this, 'render_meta_box' ),
182 $post_type,
183 $context,
184 $priority,
185 array( 'field_group' => $field_group )
186 );
187 }
188
189 // Set style from first field group.
190 $this->style = acf_get_field_group_style( $field_groups[0] );
191
192 // Localize postboxes.
193 acf_localize_data(
194 array(
195 'postboxes' => $postboxes,
196 )
197 );
198 }
199
200 // remove postcustom metabox (removes expensive SQL query)
201 if ( acf_get_setting( 'remove_wp_meta_box' ) ) {
202 remove_meta_box( 'postcustom', false, 'normal' );
203 }
204
205 // Add hidden input fields.
206 add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ) );
207
208 /**
209 * Fires after metaboxes have been added.
210 *
211 * @date 13/12/18
212 * @since ACF 5.8.0.8.0
213 *
214 * @param string $post_type The post type.
215 * @param WP_Post $post The post being edited.
216 * @param array $field_groups The field groups added.
217 */
218 do_action( 'acf/add_meta_boxes', $post_type, $post, $field_groups );
219 }
220
221 /**
222 * Called after the title and before the content editor to render the after title metaboxes.
223 * Also renders the CSS required to hide the "hide-on-screen" elements on the page based on the field group settings.
224 *
225 * @since ACF 5.7.6.7.6
226 */
227 public function edit_form_after_title() {
228
229 // globals
230 global $post;
231
232 // render post data
233 acf_form_data(
234 array(
235 'screen' => 'post',
236 'post_id' => $post->ID,
237 )
238 );
239
240 // render 'acf_after_title' metaboxes
241 do_meta_boxes( get_current_screen(), 'acf_after_title', $post );
242
243 $style = '';
244 if ( is_string( $this->style ) ) {
245 $style = $this->style;
246 }
247
248 // Render dynamic field group style, using wp_strip_all_tags as this is filterable, but should only contain valid styles and no html.
249 echo '<style type="text/css" id="acf-style">' . wp_strip_all_tags( $style ) . '</style>'; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSS only, escaped by wp_strip_all_tags.
250 }
251
252 /**
253 * Renders the ACF metabox HTML.
254 *
255 * @date 19/9/18
256 * @since ACF 5.7.6.7.6
257 *
258 * @param WP_Post $post The post being edited.
259 * @param array $metabox The add_meta_box() args.
260 * @return void
261 */
262 public function render_meta_box( $post, $metabox ) {
263
264 // vars
265 $id = $metabox['id'];
266 $field_group = $metabox['args']['field_group'];
267
268 // Render fields.
269 $fields = acf_get_fields( $field_group );
270 acf_render_fields( $fields, $post->ID, 'div', $field_group['instruction_placement'] );
271 }
272
273 /**
274 *
275 * Allows WP to insert a new post without title or post_content if ACF data exists.
276 *
277 * @date 16/07/2014
278 * @since ACF 5.0.1.0.1
279 *
280 * @param boolean $maybe_empty Whether the post should be considered "empty".
281 * @return boolean
282 */
283 public function wp_insert_post_empty_content( $maybe_empty ) {
284
285 // Return false and allow insert if '_acf_changed' exists.
286 if ( $maybe_empty && acf_maybe_get_POST( '_acf_changed' ) ) {
287 return false;
288 }
289 return $maybe_empty;
290 }
291
292 /**
293 * Checks if the $post is allowed to be saved.
294 * Used to avoid triggering "acf/save_post" on dynamically created posts during save.
295 *
296 * @type function
297 * @date 26/06/2016
298 * @since ACF 5.3.8.3.8
299 *
300 * @param WP_Post $post The post to check.
301 * @return boolean
302 */
303 public function allow_save_post( $post ) {
304
305 $allow = true;
306
307 // Restricted post types.
308 $restrict = array( 'auto-draft', 'revision', 'acf-field', 'acf-field-group' );
309 if ( in_array( $post->post_type, $restrict, true ) ) {
310 $allow = false;
311 }
312
313 // Disallow if the $_POST ID value does not match the $post->ID.
314 $form_post_id = (int) acf_maybe_get_POST( 'post_ID' );
315 if ( $form_post_id && $form_post_id !== $post->ID ) {
316 $allow = false;
317 }
318
319 // Revision (preview).
320 if ( 'revision' === $post->post_type ) {
321
322 // allow if doing preview and this $post is a child of the $_POST ID
323 if ( 'dopreview' === acf_maybe_get_POST( 'wp-preview' ) && $form_post_id === $post->post_parent ) {
324 $allow = true;
325 }
326 }
327
328 return $allow;
329 }
330
331 /**
332 * Triggers during the 'save_post' action to save the $_POST data.
333 *
334 * @since ACF 1.0.0.0.0
335 *
336 * @param integer $post_id The post ID.
337 * @param WP_Post $post The post object.
338 * @return void
339 */
340 public function save_post( $post_id, $post ) {
341 // Bail early if not allowed to save this post type.
342 if ( ! $this->allow_save_post( $post ) ) {
343 return;
344 }
345
346 /**
347 * Filters whether ACF_Form_Post::save_post() should bail without
348 * verifying the nonce or running acf_save_post(). Allows extensions
349 * to short-circuit the save when another handler is responsible for
350 * persisting field values for the current request.
351 *
352 * @since ACF 6.8.1
353 *
354 * @param boolean $skip Whether to skip the save.
355 * @param integer $post_id The post ID being saved.
356 * @param WP_Post $post The post being saved.
357 */
358 if ( apply_filters( 'acf/form-post/skip_save', false, $post_id, $post ) ) {
359 return $post_id;
360 }
361
362 // Verify nonce.
363 if ( ! acf_verify_nonce( 'post' ) ) {
364 return $post_id;
365 }
366
367 // Validate for published post (allow draft to save without validation).
368 if ( 'publish' === $post->post_status ) {
369 // Bail early if validation fails.
370 if ( ! acf_validate_save_post() ) {
371 return;
372 }
373 }
374
375 acf_save_post( $post_id );
376
377 // We handle revisions differently on WP 6.4+.
378 if ( version_compare( get_bloginfo( 'version' ), '6.4', '<' ) && post_type_supports( $post->post_type, 'revisions' ) ) {
379 acf_save_post_revision( $post_id );
380 }
381 }
382 }
383
384 acf_new_instance( 'ACF_Form_Post' );
385 endif;
386