form-post.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. <?php
  2. if ( ! defined( 'ABSPATH' ) ) {
  3. exit; // Exit if accessed directly
  4. }
  5. if ( ! class_exists( 'ACF_Form_Post' ) ) :
  6. class ACF_Form_Post {
  7. /** @var string The first field groups style CSS. */
  8. var $style = '';
  9. /**
  10. * __construct
  11. *
  12. * Sets up the class functionality.
  13. *
  14. * @date 5/03/2014
  15. * @since 5.0.0
  16. *
  17. * @param void
  18. * @return void
  19. */
  20. function __construct() {
  21. // initialize on post edit screens
  22. add_action( 'load-post.php', array( $this, 'initialize' ) );
  23. add_action( 'load-post-new.php', array( $this, 'initialize' ) );
  24. // save
  25. add_filter( 'wp_insert_post_empty_content', array( $this, 'wp_insert_post_empty_content' ), 10, 2 );
  26. add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
  27. }
  28. /**
  29. * initialize
  30. *
  31. * Sets up Form functionality.
  32. *
  33. * @date 19/9/18
  34. * @since 5.7.6
  35. *
  36. * @param void
  37. * @return void
  38. */
  39. function initialize() {
  40. // globals
  41. global $typenow;
  42. remove_meta_box( 'submitdiv', 'acf-field-group', 'side' );
  43. // restrict specific post types
  44. $restricted = array( 'acf-field-group', 'attachment' );
  45. if ( in_array( $typenow, $restricted ) ) {
  46. return;
  47. }
  48. // enqueue scripts
  49. acf_enqueue_scripts(
  50. array(
  51. 'uploader' => true,
  52. )
  53. );
  54. // actions
  55. add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 10, 2 );
  56. }
  57. /**
  58. * add_meta_boxes
  59. *
  60. * Adds ACF metaboxes for the given $post_type and $post.
  61. *
  62. * @date 19/9/18
  63. * @since 5.7.6
  64. *
  65. * @param string $post_type The post type.
  66. * @param WP_Post $post The post being edited.
  67. * @return void
  68. */
  69. function add_meta_boxes( $post_type, $post ) {
  70. // Storage for localized postboxes.
  71. $postboxes = array();
  72. // Get field groups for this screen.
  73. $field_groups = acf_get_field_groups(
  74. array(
  75. 'post_id' => $post->ID,
  76. 'post_type' => $post_type,
  77. )
  78. );
  79. // Loop over field groups.
  80. if ( $field_groups ) {
  81. foreach ( $field_groups as $field_group ) {
  82. // vars
  83. $id = "acf-{$field_group['key']}"; // acf-group_123
  84. $title = $field_group['title']; // Group 1
  85. $context = $field_group['position']; // normal, side, acf_after_title
  86. $priority = 'high'; // high, core, default, low
  87. // Reduce priority for sidebar metaboxes for best position.
  88. if ( $context == 'side' ) {
  89. $priority = 'core';
  90. }
  91. /**
  92. * Filters the metabox priority.
  93. *
  94. * @date 23/06/12
  95. * @since 3.1.8
  96. *
  97. * @param string $priority The metabox priority (high, core, default, low).
  98. * @param array $field_group The field group array.
  99. */
  100. $priority = apply_filters( 'acf/input/meta_box_priority', $priority, $field_group );
  101. // Localize data
  102. $postboxes[] = array(
  103. 'id' => $id,
  104. 'key' => $field_group['key'],
  105. 'style' => $field_group['style'],
  106. 'label' => $field_group['label_placement'],
  107. 'edit' => acf_get_field_group_edit_link( $field_group['ID'] ),
  108. );
  109. // Add the meta box.
  110. add_meta_box( $id, acf_esc_html( $title ), array( $this, 'render_meta_box' ), $post_type, $context, $priority, array( 'field_group' => $field_group ) );
  111. }
  112. // Set style from first field group.
  113. $this->style = acf_get_field_group_style( $field_groups[0] );
  114. // Localize postboxes.
  115. acf_localize_data(
  116. array(
  117. 'postboxes' => $postboxes,
  118. )
  119. );
  120. }
  121. // remove postcustom metabox (removes expensive SQL query)
  122. if ( acf_get_setting( 'remove_wp_meta_box' ) ) {
  123. remove_meta_box( 'postcustom', false, 'normal' );
  124. }
  125. // Add hidden input fields.
  126. add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ) );
  127. /**
  128. * Fires after metaboxes have been added.
  129. *
  130. * @date 13/12/18
  131. * @since 5.8.0
  132. *
  133. * @param string $post_type The post type.
  134. * @param WP_Post $post The post being edited.
  135. * @param array $field_groups The field groups added.
  136. */
  137. do_action( 'acf/add_meta_boxes', $post_type, $post, $field_groups );
  138. }
  139. /**
  140. * edit_form_after_title
  141. *
  142. * Called after the title adn before the content editor.
  143. *
  144. * @date 19/9/18
  145. * @since 5.7.6
  146. *
  147. * @param void
  148. * @return void
  149. */
  150. function edit_form_after_title() {
  151. // globals
  152. global $post, $wp_meta_boxes;
  153. // render post data
  154. acf_form_data(
  155. array(
  156. 'screen' => 'post',
  157. 'post_id' => $post->ID,
  158. )
  159. );
  160. // render 'acf_after_title' metaboxes
  161. do_meta_boxes( get_current_screen(), 'acf_after_title', $post );
  162. // render dynamic field group style
  163. echo '<style type="text/css" id="acf-style">' . $this->style . '</style>';
  164. }
  165. /**
  166. * render_meta_box
  167. *
  168. * Renders the ACF metabox HTML.
  169. *
  170. * @date 19/9/18
  171. * @since 5.7.6
  172. *
  173. * @param WP_Post $post The post being edited.
  174. * @param array metabox The add_meta_box() args.
  175. * @return void
  176. */
  177. function render_meta_box( $post, $metabox ) {
  178. // vars
  179. $id = $metabox['id'];
  180. $field_group = $metabox['args']['field_group'];
  181. // Render fields.
  182. $fields = acf_get_fields( $field_group );
  183. acf_render_fields( $fields, $post->ID, 'div', $field_group['instruction_placement'] );
  184. }
  185. /**
  186. * wp_insert_post_empty_content
  187. *
  188. * Allows WP to insert a new post without title or post_content if ACF data exists.
  189. *
  190. * @date 16/07/2014
  191. * @since 5.0.1
  192. *
  193. * @param bool $maybe_empty Whether the post should be considered "empty".
  194. * @param array $postarr Array of post data.
  195. * @return bool
  196. */
  197. function wp_insert_post_empty_content( $maybe_empty, $postarr ) {
  198. // return false and allow insert if '_acf_changed' exists
  199. if ( $maybe_empty && acf_maybe_get_POST( '_acf_changed' ) ) {
  200. return false;
  201. }
  202. // return
  203. return $maybe_empty;
  204. }
  205. /*
  206. * allow_save_post
  207. *
  208. * Checks if the $post is allowed to be saved.
  209. * Used to avoid triggering "acf/save_post" on dynamically created posts during save.
  210. *
  211. * @type function
  212. * @date 26/06/2016
  213. * @since 5.3.8
  214. *
  215. * @param WP_Post $post The post to check.
  216. * @return bool
  217. */
  218. function allow_save_post( $post ) {
  219. // vars
  220. $allow = true;
  221. // restrict post types
  222. $restrict = array( 'auto-draft', 'revision', 'acf-field', 'acf-field-group' );
  223. if ( in_array( $post->post_type, $restrict ) ) {
  224. $allow = false;
  225. }
  226. // disallow if the $_POST ID value does not match the $post->ID
  227. $form_post_id = (int) acf_maybe_get_POST( 'post_ID' );
  228. if ( $form_post_id && $form_post_id !== $post->ID ) {
  229. $allow = false;
  230. }
  231. // revision (preview)
  232. if ( $post->post_type == 'revision' ) {
  233. // allow if doing preview and this $post is a child of the $_POST ID
  234. if ( acf_maybe_get_POST( 'wp-preview' ) == 'dopreview' && $form_post_id === $post->post_parent ) {
  235. $allow = true;
  236. }
  237. }
  238. // return
  239. return $allow;
  240. }
  241. /*
  242. * save_post
  243. *
  244. * Triggers during the 'save_post' action to save the $_POST data.
  245. *
  246. * @type function
  247. * @date 23/06/12
  248. * @since 1.0.0
  249. *
  250. * @param int $post_id The post ID
  251. * @param WP_POST $post the post object.
  252. * @return int
  253. */
  254. function save_post( $post_id, $post ) {
  255. // bail early if no allowed to save this post type
  256. if ( ! $this->allow_save_post( $post ) ) {
  257. return $post_id;
  258. }
  259. // verify nonce
  260. if ( ! acf_verify_nonce( 'post' ) ) {
  261. return $post_id;
  262. }
  263. // validate for published post (allow draft to save without validation)
  264. if ( $post->post_status == 'publish' ) {
  265. // bail early if validation fails
  266. if ( ! acf_validate_save_post() ) {
  267. return;
  268. }
  269. }
  270. // save
  271. acf_save_post( $post_id );
  272. // save revision
  273. if ( post_type_supports( $post->post_type, 'revisions' ) ) {
  274. acf_save_post_revision( $post_id );
  275. }
  276. // return
  277. return $post_id;
  278. }
  279. }
  280. acf_new_instance( 'ACF_Form_Post' );
  281. endif;