Hướng dẫn chuyển thuộc tính tuỳ chỉnh của sản phẩm sang thuộc tính taxonomy

<?php
/**
 * Plugin Name:   WooPAM: Woo Product Attributes Modifier
 * Description:   Bulk update 'custom meta product attributes' to 'taxonomy product attributes' in WooCommerce. Supports the GET variables, like: woopam_mode=run&woopam_from_attribute_meta=colour&woopam_to_attribute_tax=pa_colour&woopam_keep_attribute_meta&woopam_posts_per_page=10&woopam_paged=0&woopam_post_type=product&woopam_post_status=any. WARNING: Backup DB first!!!
 * Plugin Author: birgire
 * Author URI:    https://github.com/birgire
 * Plugin URI:	  https://gist.github.com/birgire/0ed300ae4436fcaf508c
 * Version:       1.0.0
 * License:       GPL2+
 * Text Domain:   woopam
 * Requires PHP:  5.4
 */
 
 /*
  *---------
  * Support:
  *---------
  * If this helped your project and saved you some time, you can support the developement here:
  *
  * https://www.buymeacoffee.com/birgire
  *
  * Thanks.
  *
  *---------------
  * Usage Example: 
  *---------------
  *
  *     To change all custom product meta attributes "color" to "pa_color" products taxonomy (where pa_ is a WooCommerce auto-added prefix),  we can run:
  * 
  *         https://example.com/?woopam_mode=run&woopam_from_attribute_meta=color&woopam_to_attribute_tax=pa_color&woopam_keep_attribute_meta=1&woopam_posts_per_page=100&woopam_paged=0&woopam_post_type=product&woopam_post_status=any
  *
  *     REMEMBER: Create the product taxonomy beforehand here (without pa_ prefixing it yourself):
  *
  *        https://example.com/wp-admin/edit.php?post_type=product&page=product_attributes
  *
  *     WARNING: Remember to backup your database first!!!
  * 
  *-----------
  * CHANGELOG:
  *-----------
  *
  * 2021-12-13 v1.0.0 Overhaul (Work: 5 hours)
  * 
  *------
  * TODO:
  *------
  *
  * - Split into more smaller functions.
  * - Add tests.
  * - Add more documentation.
  * - Look into UI.
  */
  
add_action( 'template_redirect', function() {

	// Activate product attribute modification (only available for admins).
	if ( ! current_user_can( 'manage_options' ) || 'run' !== filter_input( INPUT_GET, 'woopam_mode' ) ) {
		return;
	}

	// User input.
	$keep_attribute_meta = filter_input( INPUT_GET, 'woopam_keep_attribute_meta', FILTER_VALIDATE_BOOLEAN );
	$from_attribute_meta = filter_input( INPUT_GET, 'woopam_from_attribute_meta', FILTER_SANITIZE_STRING );
	$to_attribute_tax    = filter_input( INPUT_GET, 'woopam_to_attribute_tax', FILTER_SANITIZE_STRING );
	$post_type           = filter_input( INPUT_GET, 'woopam_post_type', FILTER_SANITIZE_STRING );
	$post_status         = filter_input( INPUT_GET, 'woopam_post_status', FILTER_SANITIZE_STRING );
	$posts_per_page      = filter_input( INPUT_GET, 'woopam_posts_per_page', FILTER_SANITIZE_NUMBER_INT );
	$paged 	             = filter_input( INPUT_GET, 'woopam_paged', FILTER_SANITIZE_NUMBER_INT );

	// Default values.
	if ( empty( $posts_per_page ) ) {
		$posts_per_page = 10;
	}

	if ( empty( $paged ) ) {
		$paged = 1;
	}

	if ( empty( $post_type ) ) {
		$post_type = 'product';
	}

	if ( empty( $keep_attribute_meta ) ) {
		$keep_attribute_meta = false;
	}

	if ( empty( $post_status ) ) {
		$post_status = 'any';
	}
	
	if ( empty( $from_attribute_meta ) || empty( $to_attribute_tax ) ) {
		wp_die( esc_html__( 'Oh, rembember that the "from_attribute_meta" and "to_attribute_tax" variable must be set!', 'woopam' ) );
	}
	
	$meta_key = '_product_attributes';

	// Fetch products with product attributes:
	$args = array(
		'post_type'      => sanitize_key( $post_type ), 
		'fields'         => 'ids', 
		'posts_per_page' => (int) $posts_per_page,
		'paged'		 => absint ( $paged ),
		'meta_key'       => $meta_key,
		'post_status'    => sanitize_key( $post_status ),
	);
	$post_ids = get_posts( $args );
	
	$total = 0;
	$total_modified = 0;

	$msg = esc_html__( "Bulk update 'custom meta product attributes' to 'taxonomy product attributes'", 'woopam' );

	printf( 
		'<h1>%s</h1>%s<ul>',
		$msg,
		esc_html__( 'START', 'woopam' )
	);

	foreach ( (array) $post_ids as $post_id ) {		

		$total++;

		$meta                 = get_post_meta( $post_id, $meta_key, true );
		$product_needs_update = false;

		foreach ( (array) $meta as $key => $terms ) {

			// Locate our meta attribute.
			if ( $from_attribute_meta === $terms['name'] ) {
				$product_needs_update = true;
				$tmp                  = explode( '|', $terms['value'] );			
				$product_terms        = array();
				
				foreach ( (array) $tmp as $term ) {
					$product_terms[] = $term;
				}

				// Remove the product meta attribute:
				if ( ! $keep_attribute_meta ) {
					unset( $meta[$key] );		
				}
				
				// Add it again as product taxonomy attribute:
				$meta["{$to_attribute_tax}"] = array( 
					'name'         => "{$to_attribute_tax}",
					'value' 	   => '',
					'position'     => $terms['position'], 
					'is_visible'   => $terms['is_visible'], 
					'is_variation' => $terms['is_variation'], 
					'is_taxonomy'  => 1, 
				);	
				
			} // end if
		} // end foreach

		echo '<li>';

		if ( $product_needs_update ) {
		
			// Assign terms to the post (create them if they don't exists).
			$term_taxonomy_ids = wp_set_object_terms( $post_id, $product_terms, $to_attribute_tax, false );
			if ( is_wp_error( $term_taxonomy_ids ) ) {
				$msg = sprintf( 
					esc_html__( 'Error! Terms couldn\'t be set for product id: %d and WP error description: "%s" and product taxonomy slug: "%s"', 'woopam' ),
					(int) $post_id,
					esc_html( $term_taxonomy_ids->get_error_code() ), 
					esc_html( $to_attribute_tax )
				);
				printf( '<strong>%s</strong><br/>', $msg );

			} else {
				update_post_meta( $post_id, $meta_key, $meta );
				$total_modified++;
				$msg = sprintf(
					esc_html__( 'Success! The taxonomy post attributes were set for product id: %d', 'woopam' ),
					(int) $post_id
				);
				printf( '<strong>%s</strong><br/>', $msg );
			}
		} else {
			$msg = sprintf(
				esc_html__( 'Nothing to do here! No product attributes were set for product id: %d', 'woopam' ),
				$post_id
			);
			printf( '%s<br/>', $msg );
		}
		echo '</li>';
		
	} // end foreach post.
	echo '</ul><br/>';

	printf( 
		esc_html__( 'Total products checked: %d', 'woopam' ),
		(int) $total
	);
	
	echo '<br/>';
	
	printf(
		esc_html__( 'Total modified products: %d', 'woopam' ),
		(int) $total_modified
	);
	
	echo '<br/>';
	echo '<br/>';
	
	die( esc_html__( 'END', 'woopam' ) );
} );

Nguồn: WordPress: WooCommerce Product Attributes - Bulk Modifier ( from custom meta attributes to taxonomy attributes) · GitHub