Advertisement
Guest User

Taxonomy fields and terms relations database update

a guest
Feb 20th, 2019
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 9.76 KB | None | 0 0
  1. <?php
  2.  
  3. ini_set('memory_limit','128M');
  4. ini_set('max_execution_time', 0);
  5. set_time_limit(0);
  6.  
  7.  
  8. /**
  9.  * Taken from Wordpress Search and Replace DB tool
  10.  *
  11.  * Search through the file name passed for a set of defines used to set up
  12.  * WordPress db access.
  13.  *
  14.  * @param string $filename The file name we need to scan for the defines.
  15.  *
  16.  * @return array    List of db connection details.
  17.  */
  18. function define_find( $filename = 'wp-config.php' ) {
  19.  
  20.     if ( $filename == 'wp-config.php' ) {
  21.         $filename = dirname( __FILE__ ) . '/' . basename( $filename );
  22.  
  23.         // look up one directory if config file doesn't exist in current directory
  24.         if ( ! file_exists( $filename ) )
  25.             $filename = dirname( __FILE__ ) . '/../' . basename( $filename );
  26.     }
  27.  
  28.     if ( file_exists( $filename ) && is_file( $filename ) && is_readable( $filename ) ) {
  29.         $file = @fopen( $filename, 'r' );
  30.         $file_content = fread( $file, filesize( $filename ) );
  31.         @fclose( $file );
  32.     }
  33.  
  34.     preg_match_all( '/define\s*?\(\s*?([\'"])(DB_NAME|DB_USER|DB_PASSWORD|DB_HOST|DB_CHARSET|DB_COLLATE)\1\s*?,\s*?([\'"])([^\3]*?)\3\s*?\)\s*?;/si', $file_content, $defines );
  35.  
  36.     if ( ( isset( $defines[ 2 ] ) && ! empty( $defines[ 2 ] ) ) && ( isset( $defines[ 4 ] ) && ! empty( $defines[ 4 ] ) ) ) {
  37.         foreach( $defines[ 2 ] as $key => $define ) {
  38.  
  39.             switch( $define ) {
  40.                 case 'DB_NAME':
  41.                     $name = $defines[ 4 ][ $key ];
  42.                     break;
  43.                 case 'DB_USER':
  44.                     $user = $defines[ 4 ][ $key ];
  45.                     break;
  46.                 case 'DB_PASSWORD':
  47.                     $pass = $defines[ 4 ][ $key ];
  48.                     break;
  49.                 case 'DB_HOST':
  50.                     $host = $defines[ 4 ][ $key ];
  51.                     break;
  52.                 case 'DB_CHARSET':
  53.                     $char = $defines[ 4 ][ $key ];
  54.                     break;
  55.                 case 'DB_COLLATE':
  56.                     $coll = $defines[ 4 ][ $key ];
  57.                     break;
  58.             }
  59.         }
  60.     }
  61.  
  62.     return array(
  63.         'host' => $host,
  64.         'name' => $name,
  65.         'user' => $user,
  66.         'pass' => $pass,
  67.         'char' => $char,
  68.         'coll' => $coll
  69.     );
  70. }
  71.  
  72. // Connecting to the database. Mysqli is used by WP, so it should work for everyone.
  73.  
  74. $db_details = define_find(dirname( __FILE__ ) . '/wp-config.php' );
  75.  
  76. if ( $db_details ) {
  77.  
  78.     define('DB_NAME', $db_details['name']);
  79.     define('DB_USER', $db_details['user']);
  80.     define('DB_PASSWORD', $db_details['pass']);
  81.     define('DB_HOST', $db_details['host']);
  82.     define('DB_CHARSET', $db_details['char']);
  83.     define('DB_COLLATE', $db_details['coll']);
  84. } else {
  85.     die('Something is wrong with your wp-config.php, cannot connect to the database.');
  86. }
  87.  
  88. $mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
  89.  
  90.  
  91.  
  92. // Beginning of the script itself
  93.  
  94. /**
  95.  * STEP 1 - Script for copying all ACF TAXONOMY fields from wp_postmeta table into the wp_term_relationships
  96.  * where links between taxonomies and posts belong by default.
  97.  */
  98.  
  99.  
  100. /**
  101.  * Following SQL selects IDs of all "acf-field-group" post types which contains at least one "acf-field" of TAXONOMY type
  102.  * including the REPEATER type consisting of taxonomy fields. Those IDs will further be reused in another query.
  103.  * Moreover we store repeaters fields post_name attribute, which we will need later.
  104.  *
  105.  * Note: You will not find any 'acf-field-group' nor 'repeater' string in the query, it is based on a knowledge
  106.  * how ACF plugin stores its data into the database.
  107.  *
  108.  **/
  109.  
  110. $sql = "SELECT DISTINCT IF(post_type = 'acf-field' AND post_parent > 0, post_parent, ID) AS id, post_type, post_name
  111.         FROM wp_posts
  112.         WHERE ID IN (
  113.             SELECT DISTINCT post_parent
  114.             FROM wp_posts
  115.             WHERE post_type = 'acf-field' AND post_content LIKE '%\"type\";s:8:\"taxonomy\"%'
  116.             )
  117.         ";
  118.  
  119. $res = $mysqli->query($sql);
  120.  
  121. $taxonomy_fields_ids = [];
  122. $taxonomy_repeaters = [];
  123.  
  124. while ($field_group_data = $res->fetch_assoc()) {
  125.     $taxonomy_fields_ids[] = $field_group_data['id'];
  126.     // this condition passes for repeater fields of taxonomy fields only. We need to store their post_name attributes
  127.     // for the later usage
  128.     if ($field_group_data['post_type'] == 'acf-field') {
  129.         $taxonomy_repeaters[] = $field_group_data['post_name'];
  130.     }
  131. }
  132.  
  133. /**
  134.  * Now we can select all "acf-field-group" type pots using taxonomy fields or repeaters of taxonomy fields.
  135.  * We need them to make the main query faster by finding out (and specifying in the main query) POST TYPES
  136.  * which uses TAXONOMY fields.
  137.  */
  138.  
  139. $sql = "SELECT ID, post_content, post_type
  140.     FROM wp_posts
  141.     WHERE ID IN ('" . join("','", $taxonomy_fields_ids) . "')";
  142.  
  143.  
  144. $res = $mysqli->query($sql);
  145.  
  146. $post_types = [];
  147. $unexpected = [];
  148.  
  149. // Storing taxonomy-ACF-fields-relevant post types. $unexpected array should remain empty after the following loop.
  150. // If it is not, something went wrong.
  151.  
  152. while ($field_group = $res->fetch_assoc()) {
  153.     $field_group_data = unserialize($field_group['post_content']);
  154.     foreach ($field_group_data['location'] as $conditions) {
  155.         foreach ($conditions as $condition) {
  156.             if ($condition['param'] == 'post_type' && $condition['operator'] == '==') {
  157.                 $post_types[] = $condition['value'];
  158.             } else {
  159.                 $field_group->post_content = $field_group_data;
  160.                 $unexpected[] = $field_group;
  161.             }
  162.         }
  163.     }
  164. }
  165.  
  166. if (count($unexpected) > 0) {
  167.     echo 'Error while handling following posts: ' . json_encode($unexpected) . '<br><br>';
  168. }
  169.  
  170.  
  171. $post_types = array_values(array_unique($post_types));
  172.  
  173. if (count($post_types)) {
  174.  
  175.     // Fetch POST_NAME attributes of all TAXONOMY acf-fields. This will be important for building of the main query
  176.     // to make it faster
  177.     $res = $mysqli->query("SELECT * FROM `wp_posts` WHERE `post_type` LIKE 'acf-field' AND post_content LIKE '%;s:8:\"taxonomy\"%'");
  178.     $taxonomy_fields = [];
  179.  
  180.     while ($field = $res->fetch_assoc()) {
  181.         $taxonomy_fields[] = $field['post_name'];
  182.     }
  183.  
  184.     // Adding post_names of the repeater fields selected above into the array of taxonomy fields' post names
  185.     $taxonomy_fields = array_merge($taxonomy_fields, $taxonomy_repeaters);
  186.  
  187.     /**
  188.      * Finally building the main query.
  189.      * This selects all ACF's assignments of taxonomies to posts.
  190.      * Based on this data we can then make inserts into wp_term_relationships table and make ACF-generated links
  191.      * between posts and taxonomies "Wordpress-correct".
  192.      */
  193.     $sql = "SELECT DISTINCT pm.meta_id, pm.post_id, pm.meta_key, pm.meta_value, p.post_type
  194.         FROM wp_postmeta pm
  195.         JOIN wp_postmeta pm2 ON pm2.meta_key = CONCAT('_', pm.meta_key)
  196.         JOIN wp_posts p ON p.ID = pm.post_id
  197.         WHERE p.post_type IN ('" . join("','", $post_types) . "')
  198.         AND pm2.meta_value IN ('" . join("','", $taxonomy_fields) . "')";
  199.  
  200.     $result = $mysqli->query($sql);
  201.  
  202.     while ($row = $result->fetch_assoc()) {
  203.  
  204.         // META_VALUE column can be empty, numeric or array. Let's decide what to do with it based on that.
  205.         if ($row['meta_value']) {
  206.             if (!is_numeric($row['meta_value'])) {
  207.                 $data = unserialize($row['meta_value']);
  208.                 if (is_array($data)) {
  209.                     $row['meta_value'] = $data;
  210.                 } else {
  211.                     continue;
  212.                 }
  213.             }
  214.         } else {
  215.             continue;
  216.         }
  217.  
  218.         /**
  219.          * Building the inserts
  220.          */
  221.         if (is_array($row['meta_value'])) {
  222.             if (count($row['meta_value']) == 1) {
  223.                 $sql = sprintf("INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('%u','%u')", $row['post_id'], $row['meta_value'][0]);
  224.             } else {
  225.                 $sql = "INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ";
  226.                 foreach ($row['meta_value'] as $terms_id) {
  227.                     $sql .= sprintf("('%u','%u'), ", $row['post_id'], $terms_id);
  228.                 }
  229.                 $sql = substr($sql, 0, -2);
  230.             }
  231.         } else {
  232.             // For numeric meta_value field
  233.             $sql = sprintf("INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('%u','%u')", $row['post_id'], $row['meta_value']);
  234.         }
  235.  
  236.         //echo $sql . '<br>';
  237.  
  238.         $mysqli->query($sql);
  239.  
  240.     }
  241.  
  242.     echo "WP_TERM_RELATIONSHIPS table has been updated. <br>";
  243.  
  244. }
  245.  
  246. /**
  247.  * STEP 2 - Make all TAXONOMY ACF fields updating the terms in wp_term_relationships table on their save
  248.  */
  249.  
  250. $sql = "UPDATE wp_posts
  251. SET field = REPLACE(post_content, '\"save_terms\";i:0;', '\"save_terms\";i:1;')
  252. WHERE post_type = 'acf-field' AND post_content LIKE '%\"type\";s:8:\"taxonomy\"%' ;";
  253.  
  254. $mysqli->query($sql);
  255.  
  256. echo "All taxonomy ACF fields has been updated to SAVE their changes into wp_term_relationships table. <br>";
  257.  
  258. /**
  259.  * STEP 3 - Make all TAXONOMY ACF fields EXCLUDING THOSE FROM REPEATERS (keeping on mind an ACF issue reported here
  260.  * https://support.advancedcustomfields.com/forums/topic/taxonomy-inside-repeater-field/
  261.  * ) LOADING terms from wp_term_relationships table rather than from posts metadata into the admin area fields.
  262.  **/
  263.  
  264. $sql = "UPDATE wp_posts p1
  265. JOIN wp_posts p2 ON p2.ID = p1.post_parent
  266. SET p1.field = REPLACE(p1.post_content, '\"load_terms\";i:0;', '\"load_terms\";i:1;')
  267. WHERE p1.post_type = 'acf-field'
  268. AND p2.post_type = 'acf-field-group';
  269. AND p1.post_content LIKE '%\"type\";s:8:\"taxonomy\"%'";
  270.  
  271. $mysqli->query($sql);
  272.  
  273. echo "All taxonomy ACF fields except of those from repeaters has been updated to LOAD their initial values from wp_term_relationships table. <br>";
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement