acf-field-group-functions.php 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144
  1. <?php
  2. // Register store.
  3. acf_register_store( 'field-groups' )->prop( 'multisite', true );
  4. /**
  5. * acf_get_field_group
  6. *
  7. * Retrieves a field group for the given identifier.
  8. *
  9. * @date 30/09/13
  10. * @since 5.0.0
  11. *
  12. * @param (int|string) $id The field group ID, key or name.
  13. * @return (array|false) The field group array.
  14. */
  15. function acf_get_field_group( $id = 0 ) {
  16. // Allow WP_Post to be passed.
  17. if ( is_object( $id ) ) {
  18. $id = $id->ID;
  19. }
  20. // Check store.
  21. $store = acf_get_store( 'field-groups' );
  22. if ( $store->has( $id ) ) {
  23. return $store->get( $id );
  24. }
  25. // Check local fields first.
  26. if ( acf_is_local_field_group( $id ) ) {
  27. $field_group = acf_get_local_field_group( $id );
  28. // Then check database.
  29. } else {
  30. $field_group = acf_get_raw_field_group( $id );
  31. }
  32. // Bail early if no field group.
  33. if ( ! $field_group ) {
  34. return false;
  35. }
  36. // Validate field group.
  37. $field_group = acf_validate_field_group( $field_group );
  38. /**
  39. * Filters the $field_group array after it has been loaded.
  40. *
  41. * @date 12/02/2014
  42. * @since 5.0.0
  43. *
  44. * @param array The field_group array.
  45. */
  46. $field_group = apply_filters( 'acf/load_field_group', $field_group );
  47. // Store field group using aliasses to also find via key, ID and name.
  48. $store->set( $field_group['key'], $field_group );
  49. $store->alias( $field_group['key'], $field_group['ID'] );
  50. // Return.
  51. return $field_group;
  52. }
  53. /**
  54. * acf_get_raw_field_group
  55. *
  56. * Retrieves raw field group data for the given identifier.
  57. *
  58. * @date 18/1/19
  59. * @since 5.7.10
  60. *
  61. * @param (int|string) $id The field ID, key or name.
  62. * @return (array|false) The field group array.
  63. */
  64. function acf_get_raw_field_group( $id = 0 ) {
  65. // Get raw field group from database.
  66. $post = acf_get_field_group_post( $id );
  67. if ( ! $post ) {
  68. return false;
  69. }
  70. // Bail early if incorrect post type.
  71. if ( $post->post_type !== 'acf-field-group' ) {
  72. return false;
  73. }
  74. // Unserialize post_content.
  75. $field_group = (array) maybe_unserialize( $post->post_content );
  76. // update attributes
  77. $field_group['ID'] = $post->ID;
  78. $field_group['title'] = $post->post_title;
  79. $field_group['key'] = $post->post_name;
  80. $field_group['menu_order'] = $post->menu_order;
  81. $field_group['active'] = in_array( $post->post_status, array( 'publish', 'auto-draft' ) );
  82. // Return field.
  83. return $field_group;
  84. }
  85. /**
  86. * acf_get_field_group_post
  87. *
  88. * Retrieves the field group's WP_Post object.
  89. *
  90. * @date 18/1/19
  91. * @since 5.7.10
  92. *
  93. * @param (int|string) $id The field group's ID, key or name.
  94. * @return (array|false) The field group's array.
  95. */
  96. function acf_get_field_group_post( $id = 0 ) {
  97. // Get post if numeric.
  98. if ( is_numeric( $id ) ) {
  99. return get_post( $id );
  100. // Search posts if is string.
  101. } elseif ( is_string( $id ) ) {
  102. // Try cache.
  103. $cache_key = acf_cache_key( "acf_get_field_group_post:key:$id" );
  104. $post_id = wp_cache_get( $cache_key, 'acf' );
  105. if ( $post_id === false ) {
  106. // Query posts.
  107. $posts = get_posts(
  108. array(
  109. 'posts_per_page' => 1,
  110. 'post_type' => 'acf-field-group',
  111. 'post_status' => array( 'publish', 'acf-disabled', 'trash' ),
  112. 'orderby' => 'menu_order title',
  113. 'order' => 'ASC',
  114. 'suppress_filters' => false,
  115. 'cache_results' => true,
  116. 'update_post_meta_cache' => false,
  117. 'update_post_term_cache' => false,
  118. 'acf_group_key' => $id,
  119. )
  120. );
  121. // Update $post_id with a non false value.
  122. $post_id = $posts ? $posts[0]->ID : 0;
  123. // Update cache.
  124. wp_cache_set( $cache_key, $post_id, 'acf' );
  125. }
  126. // Check $post_id and return the post when possible.
  127. if ( $post_id ) {
  128. return get_post( $post_id );
  129. }
  130. }
  131. // Return false by default.
  132. return false;
  133. }
  134. /**
  135. * acf_is_field_group_key
  136. *
  137. * Returns true if the given identifier is a field group key.
  138. *
  139. * @date 6/12/2013
  140. * @since 5.0.0
  141. *
  142. * @param string $id The identifier.
  143. * @return bool
  144. */
  145. function acf_is_field_group_key( $id = '' ) {
  146. // Check if $id is a string starting with "group_".
  147. if ( is_string( $id ) && substr( $id, 0, 6 ) === 'group_' ) {
  148. return true;
  149. }
  150. /**
  151. * Filters whether the $id is a field group key.
  152. *
  153. * @date 23/1/19
  154. * @since 5.7.10
  155. *
  156. * @param bool $bool The result.
  157. * @param string $id The identifier.
  158. */
  159. return apply_filters( 'acf/is_field_group_key', false, $id );
  160. }
  161. /**
  162. * acf_validate_field_group
  163. *
  164. * Ensures the given field group is valid.
  165. *
  166. * @date 18/1/19
  167. * @since 5.7.10
  168. *
  169. * @param array $field The field group array.
  170. * @return array
  171. */
  172. function acf_validate_field_group( $field_group = array() ) {
  173. // Bail early if already valid.
  174. if ( is_array( $field_group ) && ! empty( $field_group['_valid'] ) ) {
  175. return $field_group;
  176. }
  177. // Apply defaults.
  178. $field_group = wp_parse_args(
  179. $field_group,
  180. array(
  181. 'ID' => 0,
  182. 'key' => '',
  183. 'title' => '',
  184. 'fields' => array(),
  185. 'location' => array(),
  186. 'menu_order' => 0,
  187. 'position' => 'normal',
  188. 'style' => 'default',
  189. 'label_placement' => 'top',
  190. 'instruction_placement' => 'label',
  191. 'hide_on_screen' => array(),
  192. 'active' => true,
  193. 'description' => '',
  194. 'show_in_rest' => false,
  195. )
  196. );
  197. // Convert types.
  198. $field_group['ID'] = (int) $field_group['ID'];
  199. $field_group['menu_order'] = (int) $field_group['menu_order'];
  200. $field_group['active'] = (bool) $field_group['active'];
  201. // Field group is now valid.
  202. $field_group['_valid'] = true;
  203. /**
  204. * Filters the $field_group array to validate settings.
  205. *
  206. * @date 12/02/2014
  207. * @since 5.0.0
  208. *
  209. * @param array $field_group The field group array.
  210. */
  211. $field_group = apply_filters( 'acf/validate_field_group', $field_group );
  212. // return
  213. return $field_group;
  214. }
  215. /**
  216. * acf_get_valid_field_group
  217. *
  218. * Ensures the given field group is valid.
  219. *
  220. * @date 28/09/13
  221. * @since 5.0.0
  222. *
  223. * @param array $field_group The field group array.
  224. * @return array
  225. */
  226. function acf_get_valid_field_group( $field_group = false ) {
  227. return acf_validate_field_group( $field_group );
  228. }
  229. /**
  230. * acf_translate_field_group
  231. *
  232. * Translates a field group's settings.
  233. *
  234. * @date 8/03/2016
  235. * @since 5.3.2
  236. *
  237. * @param array $field_group The field group array.
  238. * @return array
  239. */
  240. function acf_translate_field_group( $field_group = array() ) {
  241. // Get settings.
  242. $l10n = acf_get_setting( 'l10n' );
  243. $l10n_textdomain = acf_get_setting( 'l10n_textdomain' );
  244. // Translate field settings if textdomain is set.
  245. if ( $l10n && $l10n_textdomain ) {
  246. $field_group['title'] = acf_translate( $field_group['title'] );
  247. /**
  248. * Filters the $field group array to translate strings.
  249. *
  250. * @date 12/02/2014
  251. * @since 5.0.0
  252. *
  253. * @param array $field_group The field group array.
  254. */
  255. $field_group = apply_filters( 'acf/translate_field_group', $field_group );
  256. }
  257. // Return field.
  258. return $field_group;
  259. }
  260. // Translate field groups passing through validation.
  261. add_action( 'acf/validate_field_group', 'acf_translate_field_group' );
  262. /**
  263. * acf_get_field_groups
  264. *
  265. * Returns and array of field_groups for the given $filter.
  266. *
  267. * @date 30/09/13
  268. * @since 5.0.0
  269. *
  270. * @param array $filter An array of args to filter results by.
  271. * @return array
  272. */
  273. function acf_get_field_groups( $filter = array() ) {
  274. // Vars.
  275. $field_groups = array();
  276. // Check database.
  277. $raw_field_groups = acf_get_raw_field_groups();
  278. if ( $raw_field_groups ) {
  279. foreach ( $raw_field_groups as $raw_field_group ) {
  280. $field_groups[] = acf_get_field_group( $raw_field_group['ID'] );
  281. }
  282. }
  283. /**
  284. * Filters the $field_groups array.
  285. *
  286. * @date 12/02/2014
  287. * @since 5.0.0
  288. *
  289. * @param array $field_groups The array of field_groups.
  290. */
  291. $field_groups = apply_filters( 'acf/load_field_groups', $field_groups );
  292. // Filter results.
  293. if ( $filter ) {
  294. return acf_filter_field_groups( $field_groups, $filter );
  295. }
  296. // Return field groups.
  297. return $field_groups;
  298. }
  299. /**
  300. * acf_get_raw_field_groups
  301. *
  302. * Returns and array of raw field_group data.
  303. *
  304. * @date 18/1/19
  305. * @since 5.7.10
  306. *
  307. * @param void
  308. * @return array
  309. */
  310. function acf_get_raw_field_groups() {
  311. // Try cache.
  312. $cache_key = acf_cache_key( 'acf_get_field_group_posts' );
  313. $post_ids = wp_cache_get( $cache_key, 'acf' );
  314. if ( $post_ids === false ) {
  315. // Query posts.
  316. $posts = get_posts(
  317. array(
  318. 'posts_per_page' => -1,
  319. 'post_type' => 'acf-field-group',
  320. 'orderby' => 'menu_order title',
  321. 'order' => 'ASC',
  322. 'suppress_filters' => false, // Allow WPML to modify the query
  323. 'cache_results' => true,
  324. 'update_post_meta_cache' => false,
  325. 'update_post_term_cache' => false,
  326. 'post_status' => array( 'publish', 'acf-disabled' ),
  327. )
  328. );
  329. // Update $post_ids with a non false value.
  330. $post_ids = array();
  331. foreach ( $posts as $post ) {
  332. $post_ids[] = $post->ID;
  333. }
  334. // Update cache.
  335. wp_cache_set( $cache_key, $post_ids, 'acf' );
  336. }
  337. // Loop over ids and populate array of field groups.
  338. $field_groups = array();
  339. foreach ( $post_ids as $post_id ) {
  340. $field_groups[] = acf_get_raw_field_group( $post_id );
  341. }
  342. // Return field groups.
  343. return $field_groups;
  344. }
  345. /**
  346. * acf_filter_field_groups
  347. *
  348. * Returns a filtered aray of field groups based on the given $args.
  349. *
  350. * @date 29/11/2013
  351. * @since 5.0.0
  352. *
  353. * @param array $field_groups An array of field groups.
  354. * @param array $args An array of location args.
  355. * @return array
  356. */
  357. function acf_filter_field_groups( $field_groups, $args = array() ) {
  358. // Loop over field groups and check visibility.
  359. $filtered = array();
  360. if ( $field_groups ) {
  361. foreach ( $field_groups as $field_group ) {
  362. if ( acf_get_field_group_visibility( $field_group, $args ) ) {
  363. $filtered[] = $field_group;
  364. }
  365. }
  366. }
  367. // Return filtered.
  368. return $filtered;
  369. }
  370. /**
  371. * acf_get_field_group_visibility
  372. *
  373. * Returns true if the given field group's location rules match the given $args.
  374. *
  375. * @date 7/10/13
  376. * @since 5.0.0
  377. *
  378. * @param array $field_groups An array of field groups.
  379. * @param array $args An array of location args.
  380. * @return bool
  381. */
  382. function acf_get_field_group_visibility( $field_group, $args = array() ) {
  383. // Check if active.
  384. if ( ! $field_group['active'] ) {
  385. return false;
  386. }
  387. // Check if location rules exist
  388. if ( $field_group['location'] ) {
  389. // Get the current screen.
  390. $screen = acf_get_location_screen( $args );
  391. // Loop through location groups.
  392. foreach ( $field_group['location'] as $group ) {
  393. // ignore group if no rules.
  394. if ( empty( $group ) ) {
  395. continue;
  396. }
  397. // Loop over rules and determine if all rules match.
  398. $match_group = true;
  399. foreach ( $group as $rule ) {
  400. if ( ! acf_match_location_rule( $rule, $screen, $field_group ) ) {
  401. $match_group = false;
  402. break;
  403. }
  404. }
  405. // If this group matches, show the field group.
  406. if ( $match_group ) {
  407. return true;
  408. }
  409. }
  410. }
  411. // Return default.
  412. return false;
  413. }
  414. /**
  415. * acf_update_field_group
  416. *
  417. * Updates a field group in the database.
  418. *
  419. * @date 21/1/19
  420. * @since 5.7.10
  421. *
  422. * @param array $field_group The field group array.
  423. * @return array
  424. */
  425. function acf_update_field_group( $field_group ) {
  426. // Validate field group.
  427. $field_group = acf_get_valid_field_group( $field_group );
  428. // May have been posted. Remove slashes.
  429. $field_group = wp_unslash( $field_group );
  430. // Parse types (converts string '0' to int 0).
  431. $field_group = acf_parse_types( $field_group );
  432. // Clean up location keys.
  433. if ( $field_group['location'] ) {
  434. // Remove empty values and convert to associated array.
  435. $field_group['location'] = array_filter( $field_group['location'] );
  436. $field_group['location'] = array_values( $field_group['location'] );
  437. $field_group['location'] = array_map( 'array_filter', $field_group['location'] );
  438. $field_group['location'] = array_map( 'array_values', $field_group['location'] );
  439. }
  440. // Make a backup of field group data and remove some args.
  441. $_field_group = $field_group;
  442. acf_extract_vars( $_field_group, array( 'ID', 'key', 'title', 'menu_order', 'fields', 'active', '_valid' ) );
  443. // Create array of data to save.
  444. $save = array(
  445. 'ID' => $field_group['ID'],
  446. 'post_status' => $field_group['active'] ? 'publish' : 'acf-disabled',
  447. 'post_type' => 'acf-field-group',
  448. 'post_title' => $field_group['title'],
  449. 'post_name' => $field_group['key'],
  450. 'post_excerpt' => sanitize_title( $field_group['title'] ),
  451. 'post_content' => maybe_serialize( $_field_group ),
  452. 'menu_order' => $field_group['menu_order'],
  453. 'comment_status' => 'closed',
  454. 'ping_status' => 'closed',
  455. );
  456. // Unhook wp_targeted_link_rel() filter from WP 5.1 corrupting serialized data.
  457. remove_filter( 'content_save_pre', 'wp_targeted_link_rel' );
  458. // Slash data.
  459. // WP expects all data to be slashed and will unslash it (fixes '\' character issues).
  460. $save = wp_slash( $save );
  461. // Update or Insert.
  462. if ( $field_group['ID'] ) {
  463. wp_update_post( $save );
  464. } else {
  465. $field_group['ID'] = wp_insert_post( $save );
  466. }
  467. // Flush field group cache.
  468. acf_flush_field_group_cache( $field_group );
  469. /**
  470. * Fires immediately after a field group has been updated.
  471. *
  472. * @date 12/02/2014
  473. * @since 5.0.0
  474. *
  475. * @param array $field_group The field group array.
  476. */
  477. do_action( 'acf/update_field_group', $field_group );
  478. // Return field group.
  479. return $field_group;
  480. }
  481. /**
  482. * _acf_apply_unique_field_group_slug
  483. *
  484. * Allows full control over 'acf-field-group' slugs.
  485. *
  486. * @date 21/1/19
  487. * @since 5.7.10
  488. *
  489. * @param string $slug The post slug.
  490. * @param int $post_ID Post ID.
  491. * @param string $post_status The post status.
  492. * @param string $post_type Post type.
  493. * @param int $post_parent Post parent ID
  494. * @param string $original_slug The original post slug.
  495. */
  496. function _acf_apply_unique_field_group_slug( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
  497. // Check post type and reset to original value.
  498. if ( $post_type === 'acf-field-group' ) {
  499. return $original_slug;
  500. }
  501. // Return slug.
  502. return $slug;
  503. }
  504. // Hook into filter.
  505. add_filter( 'wp_unique_post_slug', '_acf_apply_unique_field_group_slug', 999, 6 );
  506. /**
  507. * acf_flush_field_group_cache
  508. *
  509. * Deletes all caches for this field group.
  510. *
  511. * @date 22/1/19
  512. * @since 5.7.10
  513. *
  514. * @param array $field_group The field group array.
  515. * @return void
  516. */
  517. function acf_flush_field_group_cache( $field_group ) {
  518. // Delete stored data.
  519. acf_get_store( 'field-groups' )->remove( $field_group['key'] );
  520. // Flush cached post_id for this field group's key.
  521. wp_cache_delete( acf_cache_key( "acf_get_field_group_post:key:{$field_group['key']}" ), 'acf' );
  522. // Flush cached array of post_ids for collection of field groups.
  523. wp_cache_delete( acf_cache_key( 'acf_get_field_group_posts' ), 'acf' );
  524. }
  525. /**
  526. * acf_delete_field_group
  527. *
  528. * Deletes a field group from the database.
  529. *
  530. * @date 21/1/19
  531. * @since 5.7.10
  532. *
  533. * @param (int|string) $id The field group ID, key or name.
  534. * @return bool True if field group was deleted.
  535. */
  536. function acf_delete_field_group( $id = 0 ) {
  537. // Disable filters to ensure ACF loads data from DB.
  538. acf_disable_filters();
  539. // Get the field_group.
  540. $field_group = acf_get_field_group( $id );
  541. // Bail early if field group was not found.
  542. if ( ! $field_group || ! $field_group['ID'] ) {
  543. return false;
  544. }
  545. // Delete fields.
  546. $fields = acf_get_fields( $field_group );
  547. if ( $fields ) {
  548. foreach ( $fields as $field ) {
  549. acf_delete_field( $field['ID'] );
  550. }
  551. }
  552. // Delete post.
  553. wp_delete_post( $field_group['ID'], true );
  554. // Flush field group cache.
  555. acf_flush_field_group_cache( $field_group );
  556. /**
  557. * Fires immediately after a field group has been deleted.
  558. *
  559. * @date 12/02/2014
  560. * @since 5.0.0
  561. *
  562. * @param array $field_group The field group array.
  563. */
  564. do_action( 'acf/delete_field_group', $field_group );
  565. // Return true.
  566. return true;
  567. }
  568. /**
  569. * acf_trash_field_group
  570. *
  571. * Trashes a field group from the database.
  572. *
  573. * @date 2/10/13
  574. * @since 5.0.0
  575. *
  576. * @param (int|string) $id The field group ID, key or name.
  577. * @return bool True if field group was trashed.
  578. */
  579. function acf_trash_field_group( $id = 0 ) {
  580. // Disable filters to ensure ACF loads data from DB.
  581. acf_disable_filters();
  582. // Get the field_group.
  583. $field_group = acf_get_field_group( $id );
  584. // Bail early if field_group was not found.
  585. if ( ! $field_group || ! $field_group['ID'] ) {
  586. return false;
  587. }
  588. // Trash fields.
  589. $fields = acf_get_fields( $field_group );
  590. if ( $fields ) {
  591. foreach ( $fields as $field ) {
  592. acf_trash_field( $field['ID'] );
  593. }
  594. }
  595. // Trash post.
  596. wp_trash_post( $field_group['ID'], true );
  597. // Flush field group cache.
  598. acf_flush_field_group_cache( $field_group );
  599. /**
  600. * Fires immediately after a field_group has been trashed.
  601. *
  602. * @date 12/02/2014
  603. * @since 5.0.0
  604. *
  605. * @param array $field_group The field_group array.
  606. */
  607. do_action( 'acf/trash_field_group', $field_group );
  608. // Return true.
  609. return true;
  610. }
  611. /**
  612. * acf_untrash_field_group
  613. *
  614. * Restores a field_group from the trash.
  615. *
  616. * @date 2/10/13
  617. * @since 5.0.0
  618. *
  619. * @param (int|string) $id The field_group ID, key or name.
  620. * @return bool True if field_group was trashed.
  621. */
  622. function acf_untrash_field_group( $id = 0 ) {
  623. // Disable filters to ensure ACF loads data from DB.
  624. acf_disable_filters();
  625. // Get the field_group.
  626. $field_group = acf_get_field_group( $id );
  627. // Bail early if field_group was not found.
  628. if ( ! $field_group || ! $field_group['ID'] ) {
  629. return false;
  630. }
  631. // Untrash fields.
  632. $fields = acf_get_fields( $field_group );
  633. if ( $fields ) {
  634. foreach ( $fields as $field ) {
  635. acf_untrash_field( $field['ID'] );
  636. }
  637. }
  638. // Untrash post.
  639. wp_untrash_post( $field_group['ID'], true );
  640. // Flush field group cache.
  641. acf_flush_field_group_cache( $field_group );
  642. /**
  643. * Fires immediately after a field_group has been trashed.
  644. *
  645. * @date 12/02/2014
  646. * @since 5.0.0
  647. *
  648. * @param array $field_group The field_group array.
  649. */
  650. do_action( 'acf/untrash_field_group', $field_group );
  651. // Return true.
  652. return true;
  653. }
  654. /**
  655. * Filter callback which returns the previous post_status instead of "draft" for the "acf-field-group" post type.
  656. *
  657. * Prior to WordPress 5.6.0, this filter was not needed as restored posts were always assigned their original status.
  658. *
  659. * @since 5.9.5
  660. *
  661. * @param string $new_status The new status of the post being restored.
  662. * @param int $post_id The ID of the post being restored.
  663. * @param string $previous_status The status of the post at the point where it was trashed.
  664. * @return string.
  665. */
  666. function _acf_untrash_field_group_post_status( $new_status, $post_id, $previous_status ) {
  667. return ( get_post_type( $post_id ) === 'acf-field-group' ) ? $previous_status : $new_status;
  668. }
  669. add_action( 'wp_untrash_post_status', '_acf_untrash_field_group_post_status', 10, 3 );
  670. /**
  671. * acf_is_field_group
  672. *
  673. * Returns true if the given params match a field group.
  674. *
  675. * @date 21/1/19
  676. * @since 5.7.10
  677. *
  678. * @param array $field_group The field group array.
  679. * @param mixed $id An optional identifier to search for.
  680. * @return bool
  681. */
  682. function acf_is_field_group( $field_group = false ) {
  683. return (
  684. is_array( $field_group )
  685. && isset( $field_group['key'] )
  686. && isset( $field_group['title'] )
  687. );
  688. }
  689. /**
  690. * acf_duplicate_field_group
  691. *
  692. * Duplicates a field group.
  693. *
  694. * @date 16/06/2014
  695. * @since 5.0.0
  696. *
  697. * @param (int|string) $id The field_group ID, key or name.
  698. * @param int $new_post_id Optional post ID to override.
  699. * @return array The new field group.
  700. */
  701. function acf_duplicate_field_group( $id = 0, $new_post_id = 0 ) {
  702. // Disable filters to ensure ACF loads data from DB.
  703. acf_disable_filters();
  704. // Get the field_group.
  705. $field_group = acf_get_field_group( $id );
  706. // Bail early if field_group was not found.
  707. if ( ! $field_group || ! $field_group['ID'] ) {
  708. return false;
  709. }
  710. // Get fields.
  711. $fields = acf_get_fields( $field_group );
  712. // Update attributes.
  713. $field_group['ID'] = $new_post_id;
  714. $field_group['key'] = uniqid( 'group_' );
  715. // Add (copy) to title when apropriate.
  716. if ( ! $new_post_id ) {
  717. $field_group['title'] .= ' (' . __( 'copy', 'acf' ) . ')';
  718. }
  719. // When importing a new field group, insert a temporary post and set the field group's ID.
  720. // This allows fields to be updated before the field group (field group ID is needed for field parent setting).
  721. if ( ! $field_group['ID'] ) {
  722. $field_group['ID'] = wp_insert_post( array( 'post_title' => $field_group['key'] ) );
  723. }
  724. // Duplicate fields.
  725. $duplicates = acf_duplicate_fields( $fields, $field_group['ID'] );
  726. // Save field group.
  727. $field_group = acf_update_field_group( $field_group );
  728. /**
  729. * Fires immediately after a field_group has been duplicated.
  730. *
  731. * @date 12/02/2014
  732. * @since 5.0.0
  733. *
  734. * @param array $field_group The field_group array.
  735. */
  736. do_action( 'acf/duplicate_field_group', $field_group );
  737. // return
  738. return $field_group;
  739. }
  740. /**
  741. * Activates or deactivates a field group.
  742. *
  743. * @param int|string $id The field_group ID, key or name.
  744. * @return bool
  745. */
  746. function acf_update_field_group_active_status( $id, $activate = true ) {
  747. // Disable filters to ensure ACF loads data from DB.
  748. acf_disable_filters();
  749. $field_group = acf_get_field_group( $id );
  750. if ( ! $field_group || ! $field_group['ID'] ) {
  751. return false;
  752. }
  753. $field_group['active'] = (bool) $activate;
  754. $updated_field_group = acf_update_field_group( $field_group );
  755. /**
  756. * Fires immediately after a field_group has been made active/inactive.
  757. *
  758. * @since 6.0.0
  759. *
  760. * @param array $field_group The updated field group array.
  761. */
  762. do_action( 'acf/update_field_group_active_status', $updated_field_group );
  763. if ( ! isset( $updated_field_group['active'] ) || $activate !== $updated_field_group['active'] ) {
  764. return false;
  765. }
  766. return true;
  767. }
  768. /**
  769. * acf_get_field_group_style
  770. *
  771. * Returns the CSS styles generated from field group settings.
  772. *
  773. * @date 20/10/13
  774. * @since 5.0.0
  775. *
  776. * @param array $field_group The field group array.
  777. * @return string.
  778. */
  779. function acf_get_field_group_style( $field_group ) {
  780. // Vars.
  781. $style = '';
  782. $elements = array(
  783. 'permalink' => '#edit-slug-box',
  784. 'the_content' => '#postdivrich',
  785. 'excerpt' => '#postexcerpt',
  786. 'custom_fields' => '#postcustom',
  787. 'discussion' => '#commentstatusdiv',
  788. 'comments' => '#commentsdiv',
  789. 'slug' => '#slugdiv',
  790. 'author' => '#authordiv',
  791. 'format' => '#formatdiv',
  792. 'page_attributes' => '#pageparentdiv',
  793. 'featured_image' => '#postimagediv',
  794. 'revisions' => '#revisionsdiv',
  795. 'categories' => '#categorydiv',
  796. 'tags' => '#tagsdiv-post_tag',
  797. 'send-trackbacks' => '#trackbacksdiv',
  798. );
  799. // Loop over field group settings and generate list of selectors to hide.
  800. if ( is_array( $field_group['hide_on_screen'] ) ) {
  801. $hide = array();
  802. foreach ( $field_group['hide_on_screen'] as $k ) {
  803. if ( isset( $elements[ $k ] ) ) {
  804. $id = $elements[ $k ];
  805. $hide[] = $id;
  806. $hide[] = '#screen-meta label[for=' . substr( $id, 1 ) . '-hide]';
  807. }
  808. }
  809. $style = implode( ', ', $hide ) . ' {display: none;}';
  810. }
  811. /**
  812. * Filters the generated CSS styles.
  813. *
  814. * @date 12/02/2014
  815. * @since 5.0.0
  816. *
  817. * @param string $style The CSS styles.
  818. * @param array $field_group The field group array.
  819. */
  820. return apply_filters( 'acf/get_field_group_style', $style, $field_group );
  821. }
  822. /**
  823. * acf_get_field_group_edit_link
  824. *
  825. * Checks if the current user can edit the field group and returns the edit url.
  826. *
  827. * @date 23/9/18
  828. * @since 5.7.7
  829. *
  830. * @param int $post_id The field group ID.
  831. * @return string
  832. */
  833. function acf_get_field_group_edit_link( $post_id ) {
  834. if ( $post_id && acf_current_user_can_admin() ) {
  835. return admin_url( 'post.php?post=' . $post_id . '&action=edit' );
  836. }
  837. return '';
  838. }
  839. /**
  840. * acf_prepare_field_group_for_export
  841. *
  842. * Returns a modified field group ready for export.
  843. *
  844. * @date 11/03/2014
  845. * @since 5.0.0
  846. *
  847. * @param array $field_group The field group array.
  848. * @return array
  849. */
  850. function acf_prepare_field_group_for_export( $field_group = array() ) {
  851. // Remove args.
  852. acf_extract_vars( $field_group, array( 'ID', 'local', '_valid' ) );
  853. // Prepare fields.
  854. $field_group['fields'] = acf_prepare_fields_for_export( $field_group['fields'] );
  855. /**
  856. * Filters the $field_group array before being returned to the export tool.
  857. *
  858. * @date 12/02/2014
  859. * @since 5.0.0
  860. *
  861. * @param array $field_group The $field group array.
  862. */
  863. return apply_filters( 'acf/prepare_field_group_for_export', $field_group );
  864. }
  865. /**
  866. * acf_prepare_field_group_for_import
  867. *
  868. * Prepares a field group for the import process.
  869. *
  870. * @date 21/11/19
  871. * @since 5.8.8
  872. *
  873. * @param array $field_group The field group array.
  874. * @return array
  875. */
  876. function acf_prepare_field_group_for_import( $field_group ) {
  877. // Update parent and menu_order properties for all fields.
  878. if ( $field_group['fields'] ) {
  879. foreach ( $field_group['fields'] as $i => &$field ) {
  880. $field['parent'] = $field_group['key'];
  881. $field['menu_order'] = $i;
  882. }
  883. }
  884. /**
  885. * Filters the $field_group array before being returned to the import tool.
  886. *
  887. * @date 21/11/19
  888. * @since 5.8.8
  889. *
  890. * @param array $field_group The field group array.
  891. */
  892. return apply_filters( 'acf/prepare_field_group_for_import', $field_group );
  893. }
  894. /**
  895. * acf_import_field_group
  896. *
  897. * Imports a field group into the databse.
  898. *
  899. * @date 11/03/2014
  900. * @since 5.0.0
  901. *
  902. * @param array $field_group The field group array.
  903. * @return array The new field group.
  904. */
  905. function acf_import_field_group( $field_group ) {
  906. // Disable filters to ensure data is not modified by local, clone, etc.
  907. $filters = acf_disable_filters();
  908. // Validate field group (ensures all settings exist).
  909. $field_group = acf_get_valid_field_group( $field_group );
  910. // Prepare group for import (modifies settings).
  911. $field_group = acf_prepare_field_group_for_import( $field_group );
  912. // Prepare fields for import (modifies settings).
  913. $fields = acf_prepare_fields_for_import( $field_group['fields'] );
  914. // Stores a map of field "key" => "ID".
  915. $ids = array();
  916. // If the field group has an ID, review and delete stale fields in the database.
  917. if ( $field_group['ID'] ) {
  918. // Load database fields.
  919. $db_fields = acf_prepare_fields_for_import( acf_get_fields( $field_group ) );
  920. // Generate map of "index" => "key" data.
  921. $keys = wp_list_pluck( $fields, 'key' );
  922. // Loop over db fields and delete those who don't exist in $new_fields.
  923. foreach ( $db_fields as $field ) {
  924. // Add field data to $ids map.
  925. $ids[ $field['key'] ] = $field['ID'];
  926. // Delete field if not in $keys.
  927. if ( ! in_array( $field['key'], $keys ) ) {
  928. acf_delete_field( $field['ID'] );
  929. }
  930. }
  931. }
  932. // When importing a new field group, insert a temporary post and set the field group's ID.
  933. // This allows fields to be updated before the field group (field group ID is needed for field parent setting).
  934. if ( ! $field_group['ID'] ) {
  935. $field_group['ID'] = wp_insert_post( array( 'post_title' => $field_group['key'] ) );
  936. }
  937. // Add field group data to $ids map.
  938. $ids[ $field_group['key'] ] = $field_group['ID'];
  939. // Loop over and add fields.
  940. if ( $fields ) {
  941. foreach ( $fields as $field ) {
  942. // Replace any "key" references with "ID".
  943. if ( isset( $ids[ $field['key'] ] ) ) {
  944. $field['ID'] = $ids[ $field['key'] ];
  945. }
  946. if ( isset( $ids[ $field['parent'] ] ) ) {
  947. $field['parent'] = $ids[ $field['parent'] ];
  948. }
  949. // Save field.
  950. $field = acf_update_field( $field );
  951. // Add field data to $ids map for children.
  952. $ids[ $field['key'] ] = $field['ID'];
  953. }
  954. }
  955. // Save field group.
  956. $field_group = acf_update_field_group( $field_group );
  957. // Enable filters again.
  958. acf_enable_filters( $filters );
  959. /**
  960. * Fires immediately after a field_group has been imported.
  961. *
  962. * @date 12/02/2014
  963. * @since 5.0.0
  964. *
  965. * @param array $field_group The field_group array.
  966. */
  967. do_action( 'acf/import_field_group', $field_group );
  968. // return new field group.
  969. return $field_group;
  970. }