Bez popisu

upgrades.php 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. <?php
  2. /**
  3. * acf_has_upgrade
  4. *
  5. * Returns true if this site has an upgrade avaialble.
  6. *
  7. * @date 24/8/18
  8. * @since 5.7.4
  9. *
  10. * @param void
  11. * @return bool
  12. */
  13. function acf_has_upgrade() {
  14. // vars
  15. $db_version = acf_get_db_version();
  16. // return true if DB version is < latest upgrade version
  17. if ( $db_version && acf_version_compare( $db_version, '<', '5.5.0' ) ) {
  18. return true;
  19. }
  20. // update DB version if needed
  21. if ( $db_version !== ACF_VERSION ) {
  22. acf_update_db_version( ACF_VERSION );
  23. }
  24. // return
  25. return false;
  26. }
  27. /**
  28. * acf_upgrade_all
  29. *
  30. * Returns true if this site has an upgrade avaialble.
  31. *
  32. * @date 24/8/18
  33. * @since 5.7.4
  34. *
  35. * @param void
  36. * @return bool
  37. */
  38. function acf_upgrade_all() {
  39. // increase time limit
  40. @set_time_limit( 600 );
  41. // start timer
  42. timer_start();
  43. // log
  44. acf_dev_log( 'ACF Upgrade Begin.' );
  45. // vars
  46. $db_version = acf_get_db_version();
  47. // 5.0.0
  48. if ( acf_version_compare( $db_version, '<', '5.0.0' ) ) {
  49. acf_upgrade_500();
  50. }
  51. // 5.5.0
  52. if ( acf_version_compare( $db_version, '<', '5.5.0' ) ) {
  53. acf_upgrade_550();
  54. }
  55. // upgrade DB version once all updates are complete
  56. acf_update_db_version( ACF_VERSION );
  57. // log
  58. global $wpdb;
  59. acf_dev_log( 'ACF Upgrade Complete.', $wpdb->num_queries, timer_stop( 0 ) );
  60. }
  61. /**
  62. * acf_get_db_version
  63. *
  64. * Returns the ACF DB version.
  65. *
  66. * @date 10/09/2016
  67. * @since 5.4.0
  68. *
  69. * @param void
  70. * @return string
  71. */
  72. function acf_get_db_version() {
  73. return get_option( 'acf_version' );
  74. }
  75. /*
  76. * acf_update_db_version
  77. *
  78. * Updates the ACF DB version.
  79. *
  80. * @date 10/09/2016
  81. * @since 5.4.0
  82. *
  83. * @param string $version The new version.
  84. * @return void
  85. */
  86. function acf_update_db_version( $version = '' ) {
  87. update_option( 'acf_version', $version );
  88. }
  89. /**
  90. * acf_upgrade_500
  91. *
  92. * Version 5 introduces new post types for field groups and fields.
  93. *
  94. * @date 23/8/18
  95. * @since 5.7.4
  96. *
  97. * @param void
  98. * @return void
  99. */
  100. function acf_upgrade_500() {
  101. // log
  102. acf_dev_log( 'ACF Upgrade 5.0.0.' );
  103. // action
  104. do_action( 'acf/upgrade_500' );
  105. // do tasks
  106. acf_upgrade_500_field_groups();
  107. // update version
  108. acf_update_db_version( '5.0.0' );
  109. }
  110. /**
  111. * acf_upgrade_500_field_groups
  112. *
  113. * Upgrades all ACF4 field groups to ACF5
  114. *
  115. * @date 23/8/18
  116. * @since 5.7.4
  117. *
  118. * @param void
  119. * @return void
  120. */
  121. function acf_upgrade_500_field_groups() {
  122. // log
  123. acf_dev_log( 'ACF Upgrade 5.0.0 Field Groups.' );
  124. // get old field groups
  125. $ofgs = get_posts(
  126. array(
  127. 'numberposts' => -1,
  128. 'post_type' => 'acf',
  129. 'orderby' => 'menu_order title',
  130. 'order' => 'asc',
  131. 'suppress_filters' => true,
  132. )
  133. );
  134. // loop
  135. if ( $ofgs ) {
  136. foreach ( $ofgs as $ofg ) {
  137. acf_upgrade_500_field_group( $ofg );
  138. }
  139. }
  140. }
  141. /**
  142. * acf_upgrade_500_field_group
  143. *
  144. * Upgrades a ACF4 field group to ACF5
  145. *
  146. * @date 23/8/18
  147. * @since 5.7.4
  148. *
  149. * @param object $ofg The old field group post object.
  150. * @return array $nfg The new field group array.
  151. */
  152. function acf_upgrade_500_field_group( $ofg ) {
  153. // log
  154. acf_dev_log( 'ACF Upgrade 5.0.0 Field Group.', $ofg );
  155. // vars
  156. $nfg = array(
  157. 'ID' => 0,
  158. 'title' => $ofg->post_title,
  159. 'menu_order' => $ofg->menu_order,
  160. );
  161. // construct the location rules
  162. $rules = get_post_meta( $ofg->ID, 'rule', false );
  163. $anyorall = get_post_meta( $ofg->ID, 'allorany', true );
  164. if ( is_array( $rules ) ) {
  165. // if field group was duplicated, rules may be a serialized string!
  166. $rules = array_map( 'maybe_unserialize', $rules );
  167. // convert rules to groups
  168. $nfg['location'] = acf_convert_rules_to_groups( $rules, $anyorall );
  169. }
  170. // settings
  171. if ( $position = get_post_meta( $ofg->ID, 'position', true ) ) {
  172. $nfg['position'] = $position;
  173. }
  174. if ( $layout = get_post_meta( $ofg->ID, 'layout', true ) ) {
  175. $nfg['layout'] = $layout;
  176. }
  177. if ( $hide_on_screen = get_post_meta( $ofg->ID, 'hide_on_screen', true ) ) {
  178. $nfg['hide_on_screen'] = maybe_unserialize( $hide_on_screen );
  179. }
  180. // save field group
  181. // acf_upgrade_field_group will call the acf_get_valid_field_group function and apply 'compatibility' changes
  182. $nfg = acf_update_field_group( $nfg );
  183. // log
  184. acf_dev_log( '> Complete.', $nfg );
  185. // action for 3rd party
  186. do_action( 'acf/upgrade_500_field_group', $nfg, $ofg );
  187. // upgrade fields
  188. acf_upgrade_500_fields( $ofg, $nfg );
  189. // trash?
  190. if ( $ofg->post_status == 'trash' ) {
  191. acf_trash_field_group( $nfg['ID'] );
  192. }
  193. // return
  194. return $nfg;
  195. }
  196. /**
  197. * acf_upgrade_500_fields
  198. *
  199. * Upgrades all ACF4 fields to ACF5 from a specific field group
  200. *
  201. * @date 23/8/18
  202. * @since 5.7.4
  203. *
  204. * @param object $ofg The old field group post object.
  205. * @param array $nfg The new field group array.
  206. * @return void
  207. */
  208. function acf_upgrade_500_fields( $ofg, $nfg ) {
  209. // log
  210. acf_dev_log( 'ACF Upgrade 5.0.0 Fields.' );
  211. // global
  212. global $wpdb;
  213. // get field from postmeta
  214. $rows = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d AND meta_key LIKE %s", $ofg->ID, 'field_%' ), ARRAY_A );
  215. // check
  216. if ( $rows ) {
  217. // vars
  218. $checked = array();
  219. // loop
  220. foreach ( $rows as $row ) {
  221. // vars
  222. $field = $row['meta_value'];
  223. $field = maybe_unserialize( $field );
  224. $field = maybe_unserialize( $field ); // run again for WPML
  225. // bail early if key already migrated (potential duplicates in DB)
  226. if ( isset( $checked[ $field['key'] ] ) ) {
  227. continue;
  228. }
  229. $checked[ $field['key'] ] = 1;
  230. // add parent
  231. $field['parent'] = $nfg['ID'];
  232. // migrate field
  233. $field = acf_upgrade_500_field( $field );
  234. }
  235. }
  236. }
  237. /**
  238. * acf_upgrade_500_field
  239. *
  240. * Upgrades a ACF4 field to ACF5
  241. *
  242. * @date 23/8/18
  243. * @since 5.7.4
  244. *
  245. * @param array $field The old field.
  246. * @return array $field The new field.
  247. */
  248. function acf_upgrade_500_field( $field ) {
  249. // log
  250. acf_dev_log( 'ACF Upgrade 5.0.0 Field.', $field );
  251. // order_no is now menu_order
  252. $field['menu_order'] = acf_extract_var( $field, 'order_no', 0 );
  253. // correct very old field keys (field2 => field_2)
  254. if ( substr( $field['key'], 0, 6 ) !== 'field_' ) {
  255. $field['key'] = 'field_' . str_replace( 'field', '', $field['key'] );
  256. }
  257. // extract sub fields
  258. $sub_fields = array();
  259. if ( $field['type'] == 'repeater' ) {
  260. // loop over sub fields
  261. if ( ! empty( $field['sub_fields'] ) ) {
  262. foreach ( $field['sub_fields'] as $sub_field ) {
  263. $sub_fields[] = $sub_field;
  264. }
  265. }
  266. // remove sub fields from field
  267. unset( $field['sub_fields'] );
  268. } elseif ( $field['type'] == 'flexible_content' ) {
  269. // loop over layouts
  270. if ( is_array( $field['layouts'] ) ) {
  271. foreach ( $field['layouts'] as $i => $layout ) {
  272. // generate key
  273. $layout['key'] = uniqid( 'layout_' );
  274. // loop over sub fields
  275. if ( ! empty( $layout['sub_fields'] ) ) {
  276. foreach ( $layout['sub_fields'] as $sub_field ) {
  277. $sub_field['parent_layout'] = $layout['key'];
  278. $sub_fields[] = $sub_field;
  279. }
  280. }
  281. // remove sub fields from layout
  282. unset( $layout['sub_fields'] );
  283. // update
  284. $field['layouts'][ $i ] = $layout;
  285. }
  286. }
  287. }
  288. // save field
  289. $field = acf_update_field( $field );
  290. // log
  291. acf_dev_log( '> Complete.', $field );
  292. // sub fields
  293. if ( $sub_fields ) {
  294. foreach ( $sub_fields as $sub_field ) {
  295. $sub_field['parent'] = $field['ID'];
  296. acf_upgrade_500_field( $sub_field );
  297. }
  298. }
  299. // action for 3rd party
  300. do_action( 'acf/update_500_field', $field );
  301. // return
  302. return $field;
  303. }
  304. /**
  305. * acf_upgrade_550
  306. *
  307. * Version 5.5 adds support for the wp_termmeta table added in WP 4.4.
  308. *
  309. * @date 23/8/18
  310. * @since 5.7.4
  311. *
  312. * @param void
  313. * @return void
  314. */
  315. function acf_upgrade_550() {
  316. // log
  317. acf_dev_log( 'ACF Upgrade 5.5.0.' );
  318. // action
  319. do_action( 'acf/upgrade_550' );
  320. // do tasks
  321. acf_upgrade_550_termmeta();
  322. // update version
  323. acf_update_db_version( '5.5.0' );
  324. }
  325. /**
  326. * acf_upgrade_550_termmeta
  327. *
  328. * Upgrades all ACF4 termmeta saved in wp_options to the wp_termmeta table.
  329. *
  330. * @date 23/8/18
  331. * @since 5.7.4
  332. *
  333. * @param void
  334. * @return void
  335. */
  336. function acf_upgrade_550_termmeta() {
  337. // log
  338. acf_dev_log( 'ACF Upgrade 5.5.0 Termmeta.' );
  339. // bail early if no wp_termmeta table
  340. if ( get_option( 'db_version' ) < 34370 ) {
  341. return;
  342. }
  343. // get all taxonomies
  344. $taxonomies = get_taxonomies( false, 'objects' );
  345. // loop
  346. if ( $taxonomies ) {
  347. foreach ( $taxonomies as $taxonomy ) {
  348. acf_upgrade_550_taxonomy( $taxonomy->name );
  349. }
  350. }
  351. // action for 3rd party
  352. do_action( 'acf/upgrade_550_termmeta' );
  353. }
  354. /*
  355. * acf_wp_upgrade_550_termmeta
  356. *
  357. * When the database is updated to support term meta, migrate ACF term meta data across.
  358. *
  359. * @date 23/8/18
  360. * @since 5.7.4
  361. *
  362. * @param string $wp_db_version The new $wp_db_version.
  363. * @param string $wp_current_db_version The old (current) $wp_db_version.
  364. * @return void
  365. */
  366. function acf_wp_upgrade_550_termmeta( $wp_db_version, $wp_current_db_version ) {
  367. if ( $wp_db_version >= 34370 && $wp_current_db_version < 34370 ) {
  368. if ( acf_version_compare( acf_get_db_version(), '>', '5.5.0' ) ) {
  369. acf_upgrade_550_termmeta();
  370. }
  371. }
  372. }
  373. add_action( 'wp_upgrade', 'acf_wp_upgrade_550_termmeta', 10, 2 );
  374. /**
  375. * acf_upgrade_550_taxonomy
  376. *
  377. * Upgrades all ACF4 termmeta for a specific taxonomy.
  378. *
  379. * @date 24/8/18
  380. * @since 5.7.4
  381. *
  382. * @param string $taxonomy The taxonomy name.
  383. * @return void
  384. */
  385. function acf_upgrade_550_taxonomy( $taxonomy ) {
  386. // log
  387. acf_dev_log( 'ACF Upgrade 5.5.0 Taxonomy.', $taxonomy );
  388. // global
  389. global $wpdb;
  390. // vars
  391. $search = $taxonomy . '_%';
  392. $_search = '_' . $search;
  393. // escape '_'
  394. // http://stackoverflow.com/questions/2300285/how-do-i-escape-in-sql-server
  395. $search = str_replace( '_', '\_', $search );
  396. $_search = str_replace( '_', '\_', $_search );
  397. // search
  398. // results show faster query times using 2 LIKE vs 2 wildcards
  399. $rows = $wpdb->get_results(
  400. $wpdb->prepare(
  401. "SELECT *
  402. FROM $wpdb->options
  403. WHERE option_name LIKE %s
  404. OR option_name LIKE %s",
  405. $search,
  406. $_search
  407. ),
  408. ARRAY_A
  409. );
  410. // loop
  411. if ( $rows ) {
  412. foreach ( $rows as $row ) {
  413. /*
  414. Use regex to find "(_)taxonomy_(term_id)_(field_name)" and populate $matches:
  415. Array
  416. (
  417. [0] => _category_3_color
  418. [1] => _
  419. [2] => 3
  420. [3] => color
  421. )
  422. */
  423. if ( ! preg_match( "/^(_?){$taxonomy}_(\d+)_(.+)/", $row['option_name'], $matches ) ) {
  424. continue;
  425. }
  426. // vars
  427. $term_id = $matches[2];
  428. $meta_key = $matches[1] . $matches[3];
  429. $meta_value = $row['option_value'];
  430. // update
  431. // memory usage reduced by 50% by using a manual insert vs update_metadata() function.
  432. // update_metadata( 'term', $term_id, $meta_name, $meta_value );
  433. $wpdb->insert(
  434. $wpdb->termmeta,
  435. array(
  436. 'term_id' => $term_id,
  437. 'meta_key' => $meta_key,
  438. 'meta_value' => $meta_value,
  439. )
  440. );
  441. // log
  442. acf_dev_log( 'ACF Upgrade 5.5.0 Term.', $term_id, $meta_key );
  443. // action
  444. do_action( 'acf/upgrade_550_taxonomy_term', $term_id );
  445. }
  446. }
  447. // action for 3rd party
  448. do_action( 'acf/upgrade_550_taxonomy', $taxonomy );
  449. }