%s', admin_url( 'tools.php?page=' . self::SLUG_PREFIX . 'tools' ), 'Tools' );
array_unshift( $links, $tools_link );
}
return $links;
}
/**
* Render (echo) the "WooCommerce Fixit" submenu in the Tools section
*
* @since 1.00
*
* @return void Echoes HTML markup for the submenu page
*/
public static function render_tools_page() {
//error_log( 'Woo_Fixit::render_tools_page() $_REQUEST = ' . var_export( $_REQUEST, true ), 0 );
if ( !current_user_can( 'manage_options' ) ) {
echo "WooCommerce Fixit - Error\n";
wp_die( 'You do not have permission to manage plugin settings.' );
}
$setting_actions = array(
'help' => array( 'handler' => '', 'comment' => 'Enter first/last Product ID values above to restrict tool application range. You can find ID values by hovering over the "Name" column in the WooCommerce/Products submenu table.' ),
'warning' => array( 'handler' => '', 'comment' => 'These tools make permanent updates to your database. Make a backup before you use the tools so you can restore your old values if you don’t like the results.' ),
'c0' => array( 'handler' => '', 'comment' => '
Operations on ALL Media Library Images
' ),
'Clear Title' => array( 'handler' => '_clear_title',
'comment' => 'Delete ALL item Title fields.' ),
'c1' => array( 'handler' => '', 'comment' => '
' ),
'Fill Title' => array( 'handler' => '_fill_title',
'comment' => 'Fill empty item Title field with re-formatted file name.' ),
'Replace Title' => array( 'handler' => '_replace_title',
'comment' => 'Replace ALL item Title fields with re-formatted file name.' ),
'c2' => array( 'handler' => '', 'comment' => 'Operations on Product Image/Product Gallery Images
' ),
'Clear ALT Text' => array( 'handler' => '_clear_alt_text',
'comment' => 'Delete ALL ALT Text fields for Product Image/Product Gallery items.' ),
'c3' => array( 'handler' => '', 'comment' => '
' ),
'Fill ALT Text' => array( 'handler' => '_fill_alt_text',
'comment' => 'Fill empty ALT Text field with first top-level Product Category.' ),
'Replace ALT Text' => array( 'handler' => '_replace_alt_text',
'comment' => 'Replace ALL ALT Text field with first top-level Product Category.' ),
'c4' => array( 'handler' => '', 'comment' => 'Operations on the Featured Image and Product Gallery
' ),
'Remove Feature' => array( 'handler' => '_remove_feature',
'comment' => 'Remove Product/Featured Image from the Product Gallery.' ),
'Restore Feature' => array( 'handler' => '_restore_feature',
'comment' => 'Restore Product/Featured Image to the Product Gallery.' ),
'Reverse Gallery' => array( 'handler' => '_reverse_gallery',
'comment' => 'Reverse the image order in the Product Gallery.' ),
'c5' => array( 'handler' => '', 'comment' => 'Operations on the Product Image and Product Tags Taxonomy
' ),
'Clear Product Tags' => array( 'handler' => '_clear_product_tags',
'comment' => 'Delete ALL Product Tags assignments where a Product Image exists.' ),
'Fill Product Tags' => array( 'handler' => '_fill_product_tags',
'comment' => 'Fill empty Product Tags assignments from Product Image Att. Tags where a Product Image exists.' ),
'Add Product Tags' => array( 'handler' => '_fill_product_tags',
'comment' => 'Append Product Tags assignments to ALL Products from Product Image Att. Tags where a Product Image exists.' ),
'Replace Product Tags' => array( 'handler' => '_replace_product_tags',
'comment' => 'Replace ALL Product Tags assignments from Product Image Att. Tags where a Product Image exists.' ),
'c6' => array( 'handler' => '', 'comment' => 'Operations on Products, using the Product Image, Product Categories and Att. Tags
' ),
'Clear Product Cats' => array( 'handler' => '_clear_product_categories',
'comment' => 'Delete ALL Products’ Product Categories assignments where a Product Image exists.' ),
'Fill Product Cats' => array( 'handler' => '_fill_product_categories',
'comment' => 'Fill empty Product Categories assignments from Product Image Att. Tags,
where the Product Image Att. Tag matches an existing Product Category.' ),
'Add Product Cats' => array( 'handler' => '_append_product_categories',
'comment' => 'Append Product Categories assignments to ALL Products from Product Image Att. Tags,
where the Product Image Att. Tag matches an existing Product Category.' ),
'Replace Product Cats' => array( 'handler' => '_replace_product_categories',
'comment' => 'Replace ALL Product Categories assignments from Product Image Att. Tags,
where the Product Image Att. Tag matches an existing Product Category.' ),
'c7' => array( 'handler' => '', 'comment' => 'Operations on the Att. Categories Taxonomy
' ),
'Clear Att. Cats' => array( 'handler' => '_clear_attachment_categories',
'comment' => 'Delete ALL Att. Categories assignments.' ),
'Fill Att. Cats' => array( 'handler' => '_fill_attachment_categories',
'comment' => 'Fill empty Att. Categories assignments from Att. Tags, where the Att. Tag matches an existing Att. Category.' ),
'Add Att. Cats' => array( 'handler' => '_append_attachment_categories',
'comment' => 'Append Att. Categories assignments to ALL items from Att. Tags,
where the Att. Tag matches an existing Att. Category.' ),
'Replace Att. Cats' => array( 'handler' => '_replace_attachment_categories',
'comment' => 'Replace ALL Att. Categories assignments from Att. Tags, where the Att. Tag matches an existing Att. Category.' ),
);
echo '' . "\n";
echo "\t\t" . '
' . "\n";
echo "\t\t" . '
WooCommerce Fixit Tools v' . self::CURRENT_VERSION . '
' . "\n";
if ( isset( $_REQUEST[ self::SLUG_PREFIX . 'action' ] ) ) {
$label = $_REQUEST[ self::SLUG_PREFIX . 'action' ];
if( isset( $setting_actions[ $label ] ) ) {
$action = $setting_actions[ $label ]['handler'];
if ( ! empty( $action ) ) {
echo self::$action();
} else {
echo "\t\t
ERROR: no handler for action: \"{$label}\"\n";
}
} else {
echo "\t\t
ERROR: unknown action: \"{$label}\"\n";
}
}
echo "\t\t" . '
' . "\n";
echo "\t\t" . '
' . "\n";
echo "\t\t" . '
' . "\n";
echo "\t\t" . '
' . "\n";
}
/**
* Array of Products giving Product Image and Product Gallery attachments:
* product_id => array( '_thumbnail_id' => image_id, '_product_image_gallery' => gallery_ids (comma-delimited string)
*
* @since 1.00
*
* @var array
*/
private static $product_attachments = array();
/**
* Array of Attachments giving Product assignments:
* attachment_id => array( '_thumbnail_id' => array( thumbnail_ids ), '_product_image_gallery' => array( gallery_ids )
*
* @since 1.00
*
* @var array
*/
private static $attachment_products = array();
/**
* Compile array of Product Image and Product Gallery attachments
*
* @since 1.00
*
* @return void
*/
private static function _build_product_attachments() {
global $wpdb;
$query = sprintf( 'SELECT m.* FROM %1$s as m INNER JOIN %2$s as p ON m.post_id = p.ID WHERE ( p.post_type = \'product\' ) AND ( m.meta_key IN ( \'_product_image_gallery\', \'_thumbnail_id\' ) ) GROUP BY m.post_id, m.meta_id ORDER BY m.post_id', $wpdb->postmeta, $wpdb->posts );
$results = $wpdb->get_results( $query );
//error_log( 'Woo_Fixit::_build_product_attachments() $results = ' . var_export( $results, true ), 0 );
if ( ! empty( $_REQUEST[ self::SLUG_PREFIX . 'lower' ] ) ) {
$lower_bound = (integer) $_REQUEST[ self::SLUG_PREFIX . 'lower' ];
} else {
$lower_bound = 0;
}
if ( ! empty( $_REQUEST[ self::SLUG_PREFIX . 'upper' ] ) ) {
$upper_bound = (integer) $_REQUEST[ self::SLUG_PREFIX . 'upper' ];
} elseif ( $lower_bound ) {
$upper_bound = $lower_bound;
} else {
$upper_bound = 0x7FFFFFFF;
}
self::$product_attachments = array();
self::$attachment_products = array();
foreach ( $results as $result ) {
if ( ( $lower_bound > $result->post_id ) || ( $upper_bound < $result->post_id ) ) {
continue;
}
self::$product_attachments[ $result->post_id ][ $result->meta_key ] = trim( $result->meta_value );
if ( '_thumbnail_id' == $result->meta_key ) {
$key = (integer) $result->meta_value;
if ( isset( self::$attachment_products[ $key ] ) ) {
self::$attachment_products[ $key ]['_thumbnail_id'][] = (integer) $result->post_id;
} else {
self::$attachment_products[ $key ]['_thumbnail_id'] = array( (integer) $result->post_id );
}
} else {
foreach( explode( ',', $result->meta_value ) as $key ) {
$key = (integer) trim( $key);
if ( isset( self::$attachment_products[ $key ] ) ) {
self::$attachment_products[ $key ]['_product_image_gallery'][] = (integer) $result->post_id;
} else {
self::$attachment_products[ $key ]['_product_image_gallery'] = array( (integer) $result->post_id );
}
}
}
}
//error_log( 'Woo_Fixit::_build_product_attachments() self::$product_attachments = ' . var_export( self::$product_attachments, true ), 0 );
//error_log( 'Woo_Fixit::_build_product_attachments() self::$attachment_products = ' . var_export( self::$attachment_products, true ), 0 );
} // _build_product_attachments
/**
* Replace ALL item Title fields with empty value
*
* @since 1.00
*
* @return string HTML markup for results/messages
*/
private static function _clear_title() {
global $wpdb;
$results = $wpdb->query( "UPDATE {$wpdb->posts} SET post_title = '' WHERE post_type = 'attachment'" );
return "
_clear_title() performed {$results} update(s).\n";
} // _clear_title
/**
* Fill empty item Title field with re-formatted file name
*
* @since 1.00
*
* @return string HTML markup for results/messages
*/
private static function _fill_title() {
global $wpdb;
$query = sprintf( 'SELECT m.post_id, m.meta_value FROM %1$s as m INNER JOIN %2$s as p ON m.post_id = p.ID WHERE ( p.post_title = \'\' ) AND ( p.post_type = \'attachment\' ) AND ( m.meta_key IN ( \'_wp_attached_file\' ) )', $wpdb->postmeta, $wpdb->posts );
$results = $wpdb->get_results( $query );
$update_count = 0;
$select_bits = '';
$where_bits = array();
$chunk_count = 0;
foreach( $results as $result ) {
$path_info = pathinfo( $result->meta_value );
$new_title = str_replace( array( '-', '_', '.' ), ' ', $path_info['filename'] );
$select_bits .= " WHEN ID = {$result->post_id} THEN '{$new_title}'";
$where_bits[] = $result->post_id;
/*
* Run an update when the chunk is full
*/
if ( 25 <= ++$chunk_count ) {
$where_bits = implode( ',', $where_bits );
$update_query = "UPDATE {$wpdb->posts} SET post_title = CASE{$select_bits} ELSE post_title END WHERE ID IN ( {$where_bits} )";
$query_result = $wpdb->query( $update_query );
$update_count += $chunk_count;
$select_bits = '';
$where_bits = array();
$chunk_count = 0;
}
}
/*
* Run a final update if the chunk is partially filled
*/
if ( $chunk_count ) {
$where_bits = implode( ',', $where_bits );
$update_query = "UPDATE {$wpdb->posts} SET post_title = CASE{$select_bits} ELSE post_title END WHERE ID IN ( {$where_bits} )";
$query_result = $wpdb->query( $update_query );
$update_count += $chunk_count;
}
return "
_fill_title() performed {$update_count} update(s).\n";
} // _fill_title
/**
* Replace ALL item Title fields with re-formatted file name
*
* @since 1.00
*
* @return string HTML markup for results/messages
*/
private static function _replace_title() {
global $wpdb;
$query = sprintf( 'SELECT m.post_id, m.meta_value FROM %1$s as m INNER JOIN %2$s as p ON m.post_id = p.ID WHERE ( p.post_mime_type LIKE \'%3$s\' ) AND ( p.post_type = \'attachment\' ) AND ( m.meta_key IN ( \'_wp_attached_file\' ) )', $wpdb->postmeta, $wpdb->posts, 'image/%' );
$results = $wpdb->get_results( $query );
$update_count = 0;
$select_bits = '';
$where_bits = array();
$chunk_count = 0;
foreach( $results as $result ) {
$path_info = pathinfo( $result->meta_value );
$new_title = str_replace( array( '-', '_', '.' ), ' ', $path_info['filename'] );
$select_bits .= " WHEN ID = {$result->post_id} THEN '{$new_title}'";
$where_bits[] = $result->post_id;
/*
* Run an update when the chunk is full
*/
if ( 25 <= ++$chunk_count ) {
$where_bits = implode( ',', $where_bits );
$update_query = "UPDATE {$wpdb->posts} SET post_title = CASE{$select_bits} ELSE post_title END WHERE ID IN ( {$where_bits} )";
$query_result = $wpdb->query( $update_query );
$update_count += $chunk_count;
$select_bits = '';
$where_bits = array();
$chunk_count = 0;
}
}
/*
* Run a final update if the chunk is partially filled
*/
if ( $chunk_count ) {
$where_bits = implode( ',', $where_bits );
$update_query = "UPDATE {$wpdb->posts} SET post_title = CASE{$select_bits} ELSE post_title END WHERE ID IN ( {$where_bits} )";
$query_result = $wpdb->query( $update_query );
$update_count += $chunk_count;
}
return "
_replace_title() performed {$update_count} update(s).\n";
} // _replace_title
/**
* Empty ALT Text field in all Product Image/Product Gallery items
*
* @since 1.00
*
* @return string HTML markup for results/messages
*/
private static function _clear_alt_text() {
global $wpdb;
self::_build_product_attachments();
ksort( self::$attachment_products );
$update_count = 0;
foreach ( array_chunk( self::$attachment_products, 25, true ) as $chunk ) {
$keys = implode( ',', array_keys( $chunk ) );
$delete_query = "DELETE FROM {$wpdb->postmeta} WHERE ( post_id IN ( {$keys} ) ) AND ( meta_key = '_wp_attachment_image_alt' )";
$query_result = $wpdb->query( $delete_query );
$update_count += $query_result;
}
return "
_clear_alt_text() performed {$update_count} delete(s).\n";
} // _clear_alt_text
/**
* Fill empty ALT Text field with first top-level Product Category
*
* @since 1.00
*
* @return string HTML markup for results/messages
*/
private static function _fill_alt_text() {
global $wpdb;
self::_build_product_attachments();
$delete_count = 0;
$insert_count = 0;
foreach ( array_chunk( self::$product_attachments, 25, true ) as $chunk ) {
$terms = wp_get_object_terms( array_keys( $chunk ), 'product_cat', array( 'orderby' => 'name', 'fields' => 'all_with_object_id' ) );
/*
* Build an array of "first product category" names
*/
$product_terms = array();
foreach ( $terms as $term ) {
if ( isset( $product_terms[ $term->object_id ] ) ) {
/*
* The first top-level term wins
*/
if ( 0 == $product_terms[ $term->object_id ]['parent'] ) {
continue;
} elseif ( ( (integer) $term->parent ) < $product_terms[ $term->object_id ]['parent'] ) {
$product_terms[ $term->object_id ] = array( 'name' => $term->name, 'parent' => (integer) $term->parent );
}
} else {
$product_terms[ $term->object_id ] = array( 'name' => $term->name, 'parent' => (integer) $term->parent );
}
}
/*
* Assign the names to each attachment
*/
$attachment_values = array();
foreach ( $chunk as $key => $value ) {
if ( empty( $product_terms[ $key ] ) ) {
continue;
}
if ( ! empty( $value['_thumbnail_id'] ) ) {
$attachment_values[ $value['_thumbnail_id'] ] = $product_terms[ $key ]['name'];
}
if ( ! empty( $value['_product_image_gallery'] ) ) {
$ids = explode( ',', $value['_product_image_gallery'] );
foreach( $ids as $id ) {
$attachment_values[ $id ] = $product_terms[ $key ]['name'];
}
}
}
/*
* Find the existing ALT Text values and remove them from the update
*/
$keys = implode( ',', array_keys( $attachment_values ) );
$select_query = "SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE ( post_id IN ( {$keys} ) ) AND ( meta_key = '_wp_attachment_image_alt' )";
$empty_values = array();
foreach( $wpdb->get_results( $select_query ) as $existing_value ) {
$trim = trim( $existing_value->meta_value );
if ( empty( $trim ) ) {
$empty_values[] = $existing_value->post_id;
continue;
}
unset( $attachment_values[ (integer) $existing_value->post_id ] );
}
/*
* Delete empty ALT Text values
*/
if ( ! empty( $empty_values ) ) {
$keys = implode( ',', $empty_values );
$delete_query = "DELETE FROM {$wpdb->postmeta} WHERE ( post_id IN ( {$keys} ) ) AND ( meta_key = '_wp_attachment_image_alt' )";
$query_result = $wpdb->query( $delete_query );
$delete_count += $query_result;
}
/*
* Insert the new values
*/
foreach ( $attachment_values as $attachment => $text ) {
$insert_query = "INSERT INTO {$wpdb->postmeta} ( `post_id`,`meta_key`,`meta_value` )
VALUES ( {$attachment},'_wp_attachment_image_alt','{$text}' )";
$query_result = $wpdb->query( $insert_query );
$insert_count += $query_result;
}
}
return "
_fill_alt_text() performed {$delete_count} delete(s), {$insert_count} inserts(s).\n";
} // _fill_alt_text
/**
* Replace ALL ALT Text field with first top-level Product Category
*
* @since 1.00
*
* @return string HTML markup for results/messages
*/
private static function _replace_alt_text() {
global $wpdb;
self::_build_product_attachments();
$delete_count = 0;
$insert_count = 0;
foreach ( array_chunk( self::$product_attachments, 25, true ) as $chunk ) {
$terms = wp_get_object_terms( array_keys( $chunk ), 'product_cat', array( 'orderby' => 'name', 'fields' => 'all_with_object_id' ) );
/*
* Build an array of "first product category" names
*/
$product_terms = array();
foreach ( $terms as $term ) {
if ( isset( $product_terms[ $term->object_id ] ) ) {
/*
* The first top-level term wins
*/
if ( 0 == $product_terms[ $term->object_id ]['parent'] ) {
continue;
} elseif ( ( (integer) $term->parent ) < $product_terms[ $term->object_id ]['parent'] ) {
$product_terms[ $term->object_id ] = array( 'name' => $term->name, 'parent' => (integer) $term->parent );
}
} else {
$product_terms[ $term->object_id ] = array( 'name' => $term->name, 'parent' => (integer) $term->parent );
}
}
/*
* Assign the names to each attachment
*/
$attachment_values = array();
foreach ( $chunk as $key => $value ) {
if ( isset( $value['_thumbnail_id'] ) ) {
$attachment_values[ $value['_thumbnail_id'] ] = $product_terms[ $key ]['name'];
}
if ( ! empty( $value['_product_image_gallery'] ) ) {
$ids = explode( ',', $value['_product_image_gallery'] );
foreach( $ids as $id ) {
$attachment_values[ $id ] = $product_terms[ $key ]['name'];
}
}
}
/*
* Remove the old ALT Text values
*/
$keys = implode( ',', array_keys( $attachment_values ) );
$delete_query = "DELETE FROM {$wpdb->postmeta} WHERE ( post_id IN ( {$keys} ) ) AND ( meta_key = '_wp_attachment_image_alt' )";
$query_result = $wpdb->query( $delete_query );
$delete_count += $query_result;
/*
* Insert the new values
*/
foreach ( $attachment_values as $attachment => $text ) {
$insert_query = "INSERT INTO {$wpdb->postmeta} ( `post_id`,`meta_key`,`meta_value` )
VALUES ( {$attachment},'_wp_attachment_image_alt','{$text}' )";
$query_result = $wpdb->query( $insert_query );
$insert_count += $query_result;
}
}
return "
_replace_alt_text() performed {$delete_count} delete(s), {$insert_count} inserts(s).\n";
} // _replace_alt_text
/**
* Remove Product/Featured Image from the Product Gallery
*
* @since 1.10
*
* @return string HTML markup for results/messages
*/
private static function _remove_feature() {
global $wpdb;
self::_build_product_attachments();
$update_count = 0;
$select_bits = '';
$where_bits = array();
$chunk_count = 0;
foreach( self::$product_attachments as $post_id => $result ) {
if ( empty( $result['_thumbnail_id'] ) ) {
continue;
}
$feature = (integer) $result['_thumbnail_id'];
$gallery = array();
$feature_found = false;
if ( ! empty( $result['_product_image_gallery'] ) ) {
foreach ( explode( ',', $result['_product_image_gallery'] ) as $item ) {
if ( $feature == (integer) $item ) {
$feature_found = true;
} else {
$gallery[] = $item;
}
} // foreach gallery item
}
if ( $feature_found ) {
$new_gallery = implode( ',', $gallery );
$select_bits .= " WHEN post_id = {$post_id} THEN '{$new_gallery}'";
$where_bits[] = $post_id;
/*
* Run an update when the chunk is full
*/
if ( 25 <= ++$chunk_count ) {
$where_bits = implode( ',', $where_bits );
$update_query = "UPDATE {$wpdb->postmeta} SET meta_value = CASE{$select_bits} ELSE meta_value END WHERE post_id IN ( {$where_bits} ) AND meta_key = '_product_image_gallery'";
$query_result = $wpdb->query( $update_query );
$update_count += $chunk_count;
$select_bits = '';
$where_bits = array();
$chunk_count = 0;
}
} // feature removed
} // foreach product
/*
* Run a final update if the chunk is partially filled
*/
if ( $chunk_count ) {
$where_bits = implode( ',', $where_bits );
$update_query = "UPDATE {$wpdb->postmeta} SET meta_value = CASE{$select_bits} ELSE meta_value END WHERE post_id IN ( {$where_bits} ) AND meta_key = '_product_image_gallery'";
$query_result = $wpdb->query( $update_query );
$update_count += $chunk_count;
}
return "
_remove_feature() performed {$update_count} update(s).\n";
} // _remove_feature
/**
* Restore Product/Featured Image to the Product Gallery
*
* @since 1.10
*
* @return string HTML markup for results/messages
*/
private static function _restore_feature() {
global $wpdb;
self::_build_product_attachments();
$update_count = 0;
$select_bits = '';
$where_bits = array();
$chunk_count = 0;
foreach( self::$product_attachments as $post_id => $result ) {
if ( empty( $result['_thumbnail_id'] ) ) {
continue;
}
$feature = (integer) $result['_thumbnail_id'];
$gallery = array();
$feature_found = false;
if ( ! empty( $result['_product_image_gallery'] ) ) {
foreach ( explode( ',', $result['_product_image_gallery'] ) as $item ) {
if ( $feature == (integer) $item ) {
$feature_found = true;
} else {
$gallery[] = $item;
}
} // foreach gallery item
}
if ( ! $feature_found ) {
if ( count( $gallery ) ) {
$new_gallery = implode( ',', $gallery ) . ',' . $feature;
} else {
$new_gallery = (string) $feature;
}
$select_bits .= " WHEN post_id = {$post_id} THEN '{$new_gallery}'";
$where_bits[] = $post_id;
/*
* Run an update when the chunk is full
*/
if ( 25 <= ++$chunk_count ) {
$where_bits = implode( ',', $where_bits );
$update_query = "UPDATE {$wpdb->postmeta} SET meta_value = CASE{$select_bits} ELSE meta_value END WHERE post_id IN ( {$where_bits} ) AND meta_key = '_product_image_gallery'";
$query_result = $wpdb->query( $update_query );
$update_count += $chunk_count;
$select_bits = '';
$where_bits = array();
$chunk_count = 0;
}
} // feature restored
} // foreach product
/*
* Run a final update if the chunk is partially filled
*/
if ( $chunk_count ) {
$where_bits = implode( ',', $where_bits );
$update_query = "UPDATE {$wpdb->postmeta} SET meta_value = CASE{$select_bits} ELSE meta_value END WHERE post_id IN ( {$where_bits} ) AND meta_key = '_product_image_gallery'";
$query_result = $wpdb->query( $update_query );
$update_count += $chunk_count;
}
return "
_restore_feature() performed {$update_count} update(s).\n";
} // _restore_feature
/**
* Reverse the image order in the Product Gallery
*
* @since 1.10
*
* @return string HTML markup for results/messages
*/
private static function _reverse_gallery() {
global $wpdb;
self::_build_product_attachments();
$update_count = 0;
$select_bits = '';
$where_bits = array();
$chunk_count = 0;
foreach( self::$product_attachments as $post_id => $result ) {
if ( empty( $result['_product_image_gallery'] ) ) {
$gallery = array();
} else {
$gallery = explode( ',', $result['_product_image_gallery'] );
}
if ( 1 < count( $gallery ) ) {
$new_gallery = implode( ',', array_reverse( $gallery ) );
$select_bits .= " WHEN post_id = {$post_id} THEN '{$new_gallery}'";
$where_bits[] = $post_id;
/*
* Run an update when the chunk is full
*/
if ( 25 <= ++$chunk_count ) {
$where_bits = implode( ',', $where_bits );
$update_query = "UPDATE {$wpdb->postmeta} SET meta_value = CASE{$select_bits} ELSE meta_value END WHERE post_id IN ( {$where_bits} ) AND meta_key = '_product_image_gallery'";
$query_result = $wpdb->query( $update_query );
$update_count += $chunk_count;
$select_bits = '';
$where_bits = array();
$chunk_count = 0;
}
} // gallery reversed
} // foreach product
/*
* Run a final update if the chunk is partially filled
*/
if ( $chunk_count ) {
$where_bits = implode( ',', $where_bits );
$update_query = "UPDATE {$wpdb->postmeta} SET meta_value = CASE{$select_bits} ELSE meta_value END WHERE post_id IN ( {$where_bits} ) AND meta_key = '_product_image_gallery'";
$query_result = $wpdb->query( $update_query );
$update_count += $chunk_count;
}
return "
_reverse_gallery() performed {$update_count} update(s).\n";
} // _reverse_gallery
/**
* Delete ALL Products' Product Tags assignments where a Product Image exists
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _clear_product_tags() {
return self::_update_product_tags( 'clear' );
} // _clear_product_tags
/**
* Fill empty Product Tags assignments from Product Image Att. Tags,
* where the Product Image exists
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _fill_product_tags() {
return self::_update_product_tags( 'fill' );
} // _fill_product_tags
/**
* Append Product Tags assignments to ALL Products from Product Image Att. Tags,
* where the Product Image exists
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _append_product_tags() {
return self::_update_product_tags( 'append' );
} // _append_product_tags
/**
* Replace ALL Product Tags assignments from Product Image Att. Tags,
* where the Product Image exists
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _replace_product_tags() {
return self::_update_product_tags( 'replace' );
} // _replace_product_tags
/**
* Common code for the Product Category operations
*
* @since 1.11
*
* @param string Action to be taken - clear, fill, append, replace
*
* @return string HTML markup for results/messages
*/
private static function _update_product_tags( $action ) {
global $wpdb;
self::_build_product_attachments();
$update_count = 0;
$delete_count = 0;
$terms_added = 0;
$terms_removed = 0;
foreach ( array_chunk( self::$product_attachments, 25, true ) as $chunk ) {
// Find the Products that have Product Images
$products = array();
foreach ( $chunk as $product_id => $attachments ) {
if ( ! empty( $attachments['_thumbnail_id'] ) ) {
$id = absint( $attachments['_thumbnail_id'] );
$products[ $product_id ] = $id;
}
}
if ( count( $products ) == 0 ) {
continue;
}
switch ( $action ) {
case 'clear':
case 'fill':
// Select the attachments that have product_tag term assignments
$ids = implode( ',', array_keys( $products ) );
$query = sprintf( 'SELECT DISTINCT tr.object_id FROM %1$s as tr INNER JOIN %2$s as tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE ( tr.object_id IN ( %3$s ) AND tt.taxonomy = \'product_tag\' ) ', $wpdb->term_relationships, $wpdb->term_taxonomy, $ids );
$assignments = $wpdb->get_col( $query );
if ( 'clear' == $action ) {
foreach ( $assignments as $assignment ) {
wp_delete_object_term_relationships( $assignment, 'product_tag' );
$update_count++;
} // each assignment
} else {
// Find the products that have no assignments
$assignments = array_diff_key( $products, array_flip( $assignments ) );
foreach ( $assignments as $product_id => $assignment ) {
$attachment_tags = wp_get_object_terms( $assignment, 'attachment_tag', array( 'orderby' => 'none', 'fields' => 'names' ) );
if ( ! empty( $attachment_tags ) ) {
$term_taxonomy_ids = wp_set_object_terms( $product_id, $attachment_tags, 'product_tag' );
$terms_added += count( $term_taxonomy_ids );
$update_count++;
}
} // each assignment
}
break;
case 'append':
case 'replace':
foreach ( $products as $product_id => $assignment ) {
$attachment_tags = wp_get_object_terms( $assignment, 'attachment_tag', array( 'orderby' => 'none', 'fields' => 'names' ) );
if ( 'append' == $action ) {
if ( ! empty( $attachment_tags ) ) {
$old_term_taxonomy_ids = wp_get_object_terms( $product_id, 'product_tag', array( 'orderby' => 'none', 'fields' => 'tt_ids' ) );
$term_taxonomy_ids = wp_set_object_terms( $product_id, $attachment_tags, 'product_tag', true );
$new_terms = count( array_diff( $term_taxonomy_ids, $old_term_taxonomy_ids ) );
if ( 0 < $new_terms ) {
$terms_added += $new_terms;
$update_count++;
}
} // common terms
} else {
if ( ! empty( $attachment_tags ) ) {
$term_taxonomy_ids = wp_set_object_terms( $product_id, $attachment_tags, 'product_tag', false );
$new_terms = count( $term_taxonomy_ids );
if ( 0 < $new_terms ) {
$terms_added += $new_terms;
$update_count++;
}
} else {
$term_taxonomy_ids = wp_get_object_terms( $product_id, 'product_tag', array( 'orderby' => 'none', 'fields' => 'tt_ids' ) );
$old_terms = count( $term_taxonomy_ids );
if ( 0 < $old_terms ) {
$terms_removed += $old_terms;
$delete_count++;
$term_taxonomy_ids = wp_set_object_terms( $product_id, NULL, 'product_tag', false );
}
} // no common terms
}
} // each assignment
} // action
} // each chunk
switch ( $action ) {
case 'clear':
return "
_clear_product_categories() cleared {$update_count} Product(s).\n";
break;
case 'fill':
return "
_fill_product_categories() added {$terms_added} term(s) to {$update_count} Product(s).\n";
break;
case 'append':
return "
_append_product_categories() added {$terms_added} term(s) to {$update_count} Product(s).\n";
break;
case 'replace':
return "
_replace_product_categories() replaced {$terms_added} term(s) in {$update_count} Product(s), and deleted {$terms_removed} term(s) from {$delete_count} Product(s).\n";
}
return "
Unknown _update_product_categories action: {$action}";
} // _update_product_categories
/**
* Delete ALL Products' Product Categories assignments where a Product Image exists
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _clear_product_categories() {
return self::_update_product_categories( 'clear' );
} // _clear_product_categories
/**
* Fill empty Product Categories assignments from Product Image Att. Tags,
* where the Product Image Att. Tag matches an existing Product Category
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _fill_product_categories() {
return self::_update_product_categories( 'fill' );
} // _fill_product_categories
/**
* Append Product Categories assignments to ALL Products from Product Image Att. Tags,
* where the Product Image Att. Tag matches an existing Product Category
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _append_product_categories() {
return self::_update_product_categories( 'append' );
} // _append_product_categories
/**
* Replace ALL Product Categories assignments from Product Image Att. Tags,
* where the Product Image Att. Tag matches an existing Product Category
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _replace_product_categories() {
return self::_update_product_categories( 'replace' );
} // _replace_product_categories
/**
* Common code for the Product Category operations
*
* @since 1.11
*
* @param string Action to be taken - clear, fill, append, replace
*
* @return string HTML markup for results/messages
*/
private static function _update_product_categories( $action ) {
global $wpdb;
self::_build_product_attachments();
if ( 'clear' != $action ) {
// Get the array of the Product Category term objects for comparison
$product_categories = get_terms( 'product_cat', array( 'orderby' => 'none', 'hide_empty' => 0, 'fields' => 'id=>name' ) );
} else {
$product_categories = array();
}
$update_count = 0;
$delete_count = 0;
$terms_added = 0;
$terms_removed = 0;
foreach ( array_chunk( self::$product_attachments, 25, true ) as $chunk ) {
// Find the Products that have Product Images
$products = array();
foreach ( $chunk as $product_id => $attachments ) {
if ( ! empty( $attachments['_thumbnail_id'] ) ) {
$id = absint( $attachments['_thumbnail_id'] );
$products[ $product_id ] = $id;
}
}
if ( count( $products ) == 0 ) {
continue;
}
switch ( $action ) {
case 'clear':
case 'fill':
// Select the attachments that have product_cat term assignments
$ids = implode( ',', array_keys( $products ) );
$query = sprintf( 'SELECT DISTINCT tr.object_id FROM %1$s as tr INNER JOIN %2$s as tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE ( tr.object_id IN ( %3$s ) AND tt.taxonomy = \'product_cat\' ) ', $wpdb->term_relationships, $wpdb->term_taxonomy, $ids );
$assignments = $wpdb->get_col( $query );
if ( 'clear' == $action ) {
foreach ( $assignments as $assignment ) {
wp_delete_object_term_relationships( $assignment, 'product_cat' );
$update_count++;
} // each assignment
} else {
// Find the products that have no assignments
$assignments = array_diff_key( $products, array_flip( $assignments ) );
foreach ( $assignments as $product_id => $assignment ) {
$attachment_tags = wp_get_object_terms( $assignment, 'attachment_tag', array( 'orderby' => 'none', 'fields' => 'names' ) );
$common_terms = array_keys( array_intersect( $product_categories, $attachment_tags ) );
if ( ! empty( $common_terms ) ) {
$term_taxonomy_ids = wp_set_object_terms( $product_id, $common_terms, 'product_cat' );
$terms_added += count( $term_taxonomy_ids );
$update_count++;
} // common terms
} // each assignment
}
break;
case 'append':
case 'replace':
foreach ( $products as $product_id => $assignment ) {
$attachment_tags = wp_get_object_terms( $assignment, 'attachment_tag', array( 'orderby' => 'none', 'fields' => 'names' ) );
$common_terms = array_keys( array_intersect( $product_categories, $attachment_tags ) );
if ( 'append' == $action ) {
if ( ! empty( $common_terms ) ) {
$old_term_taxonomy_ids = wp_get_object_terms( $product_id, 'product_cat', array( 'orderby' => 'none', 'fields' => 'tt_ids' ) );
$term_taxonomy_ids = wp_set_object_terms( $product_id, $common_terms, 'product_cat', true );
$new_terms = count( array_diff( $term_taxonomy_ids, $old_term_taxonomy_ids ) );
if ( 0 < $new_terms ) {
$terms_added += $new_terms;
$update_count++;
}
} // common terms
} else {
if ( ! empty( $common_terms ) ) {
$term_taxonomy_ids = wp_set_object_terms( $product_id, $common_terms, 'product_cat', false );
$new_terms = count( $term_taxonomy_ids );
if ( 0 < $new_terms ) {
$terms_added += $new_terms;
$update_count++;
}
} else {
$term_taxonomy_ids = wp_get_object_terms( $product_id, 'product_cat', array( 'orderby' => 'none', 'fields' => 'tt_ids' ) );
$old_terms = count( $term_taxonomy_ids );
if ( 0 < $old_terms ) {
$terms_removed += $old_terms;
$delete_count++;
$term_taxonomy_ids = wp_set_object_terms( $product_id, NULL, 'product_cat', false );
}
} // no common terms
}
} // each assignment
} // action
} // each chunk
switch ( $action ) {
case 'clear':
return "
_clear_product_categories() cleared {$update_count} Product(s).\n";
break;
case 'fill':
return "
_fill_product_categories() added {$terms_added} term(s) to {$update_count} Product(s).\n";
break;
case 'append':
return "
_append_product_categories() added {$terms_added} term(s) to {$update_count} Product(s).\n";
break;
case 'replace':
return "
_replace_product_categories() replaced {$terms_added} term(s) in {$update_count} Product(s), and deleted {$terms_removed} term(s) from {$delete_count} Product(s).\n";
}
return "
Unknown _update_product_categories action: {$action}";
} // _update_product_categories
/**
* Delete ALL Att. Categories assignments
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _clear_attachment_categories() {
global $wpdb;
$update_count = 0;
$offset = 0;
$limit = 25;
do {
// Select a chunk of attachment IDs
$query = sprintf( 'SELECT p.ID FROM %1$s as p WHERE ( p.post_type = \'attachment\' ) ORDER BY p.ID LIMIT %2$d, %3$d', $wpdb->posts, $offset, $limit );
$results = $wpdb->get_col( $query );
if ( is_array( $results ) && count( $results ) > 0 ) {
// Select the attachments that have attachment_category term assignments
$ids = implode( ',', $results );
$query = sprintf( 'SELECT DISTINCT tr.object_id FROM %1$s as tr INNER JOIN %2$s as tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE ( tr.object_id IN ( %3$s ) AND tt.taxonomy = \'attachment_category\' ) ', $wpdb->term_relationships, $wpdb->term_taxonomy, $ids );
$assignments = $wpdb->get_col( $query );
foreach ( $assignments as $assignment ) {
wp_delete_object_term_relationships( $assignment, 'attachment_category' );
$update_count++;
}
} else {
$results = array();
}
$offset += $limit;
} while ( count( $results ) == $limit );
return "
_clear_attachment_categories() cleared {$update_count} items(s).\n";
} // _clear_attachment_categories
/**
* Fill empty Att. Categories assignments from Att. Tags,
* where the Att. Tag matches an existing Att. Category
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _fill_attachment_categories() {
global $wpdb;
// Get the array of the Att. Category term objects for comparison
$attachment_categories = get_terms( 'attachment_category', array( 'orderby' => 'none', 'hide_empty' => 0, 'fields' => 'id=>name' ) );
$update_count = 0;
$terms_added = 0;
$offset = 0;
$limit = 25;
do {
// Select a chunk of attachment IDs
$query = sprintf( 'SELECT p.ID FROM %1$s as p WHERE ( p.post_type = \'attachment\' ) ORDER BY p.ID LIMIT %2$d, %3$d', $wpdb->posts, $offset, $limit );
$results = $wpdb->get_col( $query );
if ( is_array( $results ) && count( $results ) > 0 ) {
// Select the attachments that have attachment_category term assignments
$ids = implode( ',', $results );
$query = sprintf( 'SELECT DISTINCT tr.object_id FROM %1$s as tr INNER JOIN %2$s as tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE ( tr.object_id IN ( %3$s ) AND tt.taxonomy = \'attachment_category\' ) ', $wpdb->term_relationships, $wpdb->term_taxonomy, $ids );
$assignments = $wpdb->get_col( $query );
// find the attachments that have no assignments
$assignments = array_diff( $results, $assignments );
foreach ( $assignments as $assignment ) {
$attachment_tags = wp_get_object_terms( $assignment, 'attachment_tag', array( 'orderby' => 'none', 'fields' => 'names' ) );
$common_terms = array_keys( array_intersect( $attachment_categories, $attachment_tags ) );
if ( ! empty( $common_terms ) ) {
$term_taxonomy_ids = wp_set_object_terms( $assignment, $common_terms, 'attachment_category' );
$terms_added += count( $term_taxonomy_ids );
$update_count++;
}
}
} else {
$results = array();
}
$offset += $limit;
} while ( count( $results ) == $limit );
return "
_fill_attachment_categories() added {$terms_added} term(s) to {$update_count} item(s).\n";
} // _fill_attachment_categories
/**
* Append Att. Categories assignments to ALL items from Att. Tags,
* where the Att. Tag matches an existing Att. Category
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _append_attachment_categories() {
global $wpdb;
// Get the array of the Att. Category term objects for comparison
$attachment_categories = get_terms( 'attachment_category', array( 'orderby' => 'none', 'hide_empty' => 0, 'fields' => 'id=>name' ) );
$update_count = 0;
$terms_added = 0;
$offset = 0;
$limit = 25;
do {
// Select a chunk of attachment IDs
$query = sprintf( 'SELECT p.ID FROM %1$s as p WHERE ( p.post_type = \'attachment\' ) ORDER BY p.ID LIMIT %2$d, %3$d', $wpdb->posts, $offset, $limit );
$results = $wpdb->get_col( $query );
if ( is_array( $results ) && count( $results ) > 0 ) {
// Select the attachments that have attachment_tag term assignments
$ids = implode( ',', $results );
$query = sprintf( 'SELECT DISTINCT tr.object_id FROM %1$s as tr INNER JOIN %2$s as tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE ( tr.object_id IN ( %3$s ) AND tt.taxonomy = \'attachment_tag\' ) ', $wpdb->term_relationships, $wpdb->term_taxonomy, $ids );
$assignments = $wpdb->get_col( $query );
foreach ( $assignments as $assignment ) {
$attachment_tags = wp_get_object_terms( $assignment, 'attachment_tag', array( 'orderby' => 'none', 'fields' => 'names' ) );
$common_terms = array_keys( array_intersect( $attachment_categories, $attachment_tags ) );
if ( ! empty( $common_terms ) ) {
$old_term_taxonomy_ids = wp_get_object_terms( $assignment, 'attachment_category', array( 'orderby' => 'none', 'fields' => 'tt_ids' ) );
$term_taxonomy_ids = wp_set_object_terms( $assignment, $common_terms, 'attachment_category', true );
$new_terms = count( array_diff( $term_taxonomy_ids, $old_term_taxonomy_ids ) );
if ( 0 < $new_terms ) {
$terms_added += $new_terms;
$update_count++;
}
}
}
} else {
$results = array();
}
$offset += $limit;
} while ( count( $results ) == $limit );
return "
_append_attachment_categories() added {$terms_added} term(s) to {$update_count} item(s).\n";
} // _append_attachment_categories
/**
* Replace ALL Att. Categories assignments from Att. Tags,
* where the Att. Tag matches an existing Att. Category
*
* @since 1.11
*
* @return string HTML markup for results/messages
*/
private static function _replace_attachment_categories() {
global $wpdb;
// Get the array of the Att. Category term objects for comparison
$attachment_categories = get_terms( 'attachment_category', array( 'orderby' => 'none', 'hide_empty' => 0, 'fields' => 'id=>name' ) );
$update_count = 0;
$delete_count = 0;
$terms_added = 0;
$terms_removed = 0;
$offset = 0;
$limit = 25;
do {
// Select a chunk of attachment IDs
$query = sprintf( 'SELECT p.ID FROM %1$s as p WHERE ( p.post_type = \'attachment\' ) ORDER BY p.ID LIMIT %2$d, %3$d', $wpdb->posts, $offset, $limit );
$results = $wpdb->get_col( $query );
if ( is_array( $results ) && count( $results ) > 0 ) {
foreach ( $results as $assignment ) {
$attachment_tags = wp_get_object_terms( $assignment, 'attachment_tag', array( 'orderby' => 'none', 'fields' => 'names' ) );
$common_terms = array_keys( array_intersect( $attachment_categories, $attachment_tags ) );
if ( ! empty( $common_terms ) ) {
$term_taxonomy_ids = wp_set_object_terms( $assignment, $common_terms, 'attachment_category' );
$new_terms = count( $term_taxonomy_ids );
if ( 0 < $new_terms ) {
$terms_added += $new_terms;
$update_count++;
}
} else {
$term_taxonomy_ids = wp_get_object_terms( $assignment, 'attachment_category', array( 'orderby' => 'none', 'fields' => 'tt_ids' ) );
$old_terms = count( $term_taxonomy_ids );
if ( 0 < $old_terms ) {
$terms_removed += $old_terms;
$delete_count++;
$term_taxonomy_ids = wp_set_object_terms( $assignment, NULL, 'attachment_category' );
}
} // no common terms
}
} else {
$results = array();
}
$offset += $limit;
} while ( count( $results ) == $limit );
return "
_replace_attachment_categories() replaced {$terms_added} term(s) in {$update_count} item(s), and deleted {$terms_removed} term(s) from {$delete_count} item(s).\n";
} // _replace_attachment_categories
} //Woo_Fixit
/*
* Install the submenu at an early opportunity
*/
add_action('init', 'Woo_Fixit::initialize');
?>