Created
May 7, 2013 19:17
-
-
Save beingtree/5535333 to your computer and use it in GitHub Desktop.
Use Custom Content Type Manager (CCTM http://wordpress.org/extend/plugins/custom-content-type-manager/) to manage product variation custom fields in a WordPress site using WooCommerce (v 1.6.6 http://downloads.wordpress.org/plugin/woocommerce.1.6.6.zip)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* ... */ | |
/* add the below to your functions.php | |
the th_ prefix is just to avoid naming collisions | |
basically copied most of this from the cctm and woocommerce code and modified as needed | |
*/ | |
if ( is_admin() ) { | |
require_once (ABSPATH . '/wp-content/plugins/custom-content-type-manager/includes/CCTM.php'); | |
// only do any of this if the CCTM class is loaded | |
if ( class_exists('CCTM') ) { | |
// get the field from CCTM | |
function th_get_custom_fields($post_type) { | |
if (isset(CCTM::$data['post_type_defs'][$post_type]['custom_fields'])) { | |
return CCTM::$data['post_type_defs'][$post_type]['custom_fields']; | |
} | |
else { | |
return array(); | |
} | |
} | |
// print out the fields in the variation box | |
function th_print_custom_fields($loop, $post) | |
{ | |
if(!$loop) | |
$loop = 0; | |
$post_type = 'product_variation'; // the 7th arg from add_meta_box() | |
$custom_fields = th_get_custom_fields($post_type); | |
$output = ''; | |
// If no custom content fields are defined, or if this is a built-in post type that hasn't been activated... | |
if ( empty($custom_fields) ) { | |
return; | |
} | |
foreach ( $custom_fields as $cf ) { | |
if (!isset(CCTM::$data['custom_field_defs'][$cf])) { | |
// throw error!! | |
continue; | |
} | |
$def = CCTM::$data['custom_field_defs'][$cf]; | |
if (isset($def['required']) && $def['required'] == 1) { | |
$def['label'] = $def['label'] . '*'; // Add asterisk | |
} | |
$output_this_field = ''; | |
if (!$FieldObj = CCTM::load_object($def['type'],'fields')) { | |
continue; | |
} | |
if ( substr($_SERVER['SCRIPT_NAME'],strrpos($_SERVER['SCRIPT_NAME'],'/')+1) == 'post-new.php' || !$post ) { | |
$def['name'] = 'variable_'.$def['name']."[$loop]"; | |
$FieldObj->set_props($def); | |
$output_this_field = $FieldObj->get_create_field_instance(); | |
} | |
else { | |
$current_value = get_post_meta( $post->ID, $def['name'], true ); | |
// Check for validation errors. | |
if (isset(CCTM::$post_validation_errors[ $def['name'] ])) { | |
$def['error_msg'] = sprintf('<span class="cctm_validation_error">%s</span>', CCTM::$post_validation_errors[ $def['name'] ]); | |
if (isset($def['class'])) { | |
$def['class'] .= 'cctm_validation_error'; | |
} | |
else { | |
$def['class'] = 'cctm_validation_error'; | |
} | |
} | |
$def['name'] = 'variable_'.$def['name']."[$loop]"; | |
$FieldObj->set_props($def); | |
$output_this_field = $FieldObj->get_edit_field_instance($current_value); | |
} | |
$output .= $output_this_field; | |
} | |
// Print the nonce: this offers security and it will help us know when we | |
// should do custom saving logic in the save_custom_fields function | |
$output .= '<input type="hidden" name="_cctm_nonce" value="'.wp_create_nonce('cctm_create_update_post').'" />'; | |
// Print the form | |
print '<div class="form-wrap">'.$output.'</div>'; | |
} | |
// show custom fields for variations in admin write panel | |
function th_product_variable_custom_fields($loop, $variation_data) { | |
th_print_custom_fields( $loop, get_post($variation_data['variation_post_id']) ); | |
} | |
/* | |
// working on this... getting Uncaught SyntaxError: Unexpected reserved word | |
// has something to do with the way the field is being output | |
// removing $FieldObj->get_create_field_instance(); gets rid of error | |
// but then of course there's no field printed... | |
// see note after end of function | |
function th_print_custom_fields_js() | |
{ | |
$post_type = 'product_variation'; // the 7th arg from add_meta_box() | |
$custom_fields = th_get_custom_fields($post_type); | |
$output = ''; | |
// If no custom content fields are defined, or if this is a built-in post type that hasn't been activated... | |
if ( empty($custom_fields) ) { | |
return; | |
} | |
foreach ( $custom_fields as $cf ) { | |
if (!isset(CCTM::$data['custom_field_defs'][$cf])) { | |
// throw error!! | |
continue; | |
} | |
$def = CCTM::$data['custom_field_defs'][$cf]; | |
if (isset($def['required']) && $def['required'] == 1) { | |
$def['label'] = $def['label'] . '*'; // Add asterisk | |
} | |
$output_this_field = ''; | |
if (!$FieldObj = CCTM::load_object($def['type'],'fields')) { | |
continue; | |
} | |
$def['name'] = 'variable_'.$def['name']."["+loop+"]"; | |
$FieldObj->set_props($def); | |
$output_this_field = $FieldObj->get_create_field_instance(); | |
$output .= $output_this_field; | |
} | |
// Print the nonce: this offers security and it will help us know when we | |
// should do custom saving logic in the save_custom_fields function | |
$output .= '<input type="hidden" name="_cctm_nonce" value="'.wp_create_nonce('cctm_create_update_post').'" />'; | |
// Print the form | |
print '<div class="form-wrap">'.$output.'</div>'; | |
} | |
*/ | |
/* | |
OK. this is ruby/rails, but may be used as a guide to get where we want to be here.... | |
i think we need to do something similar to the rails escape_javascript function | |
run that on $output | |
JS_ESCAPE_MAP = { | |
'\\' => '\\\\', | |
'</' => '<\/', | |
"\r\n" => '\n', | |
"\n" => '\n', | |
"\r" => '\n', | |
'"' => '\\"', | |
"'" => "\\'" | |
} | |
if "ruby".encoding_aware? | |
JS_ESCAPE_MAP["\342\200\250".force_encoding('UTF-8').encode!] = '
' | |
else | |
JS_ESCAPE_MAP["\342\200\250"] = '
' | |
end | |
# Escapes carriage returns and single and double quotes for JavaScript segments. | |
# | |
# Also available through the alias j(). This is particularly helpful in JavaScript responses, like: | |
# | |
# $('some_element').replaceWith('<%=j render 'some/element_template' %>'); | |
def escape_javascript(javascript) | |
if javascript | |
result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] } | |
javascript.html_safe? ? result.html_safe : result | |
else | |
'' | |
end | |
end | |
*/ | |
// show custom fields for variations in admin write panel (via js) [not using yet, bc i can't get it to work] | |
function th_product_variable_custom_fields_js() { | |
th_print_custom_fields_js(); | |
} | |
if( function_exists('th_print_custom_fields') ) { | |
add_action('woocommerce_product_after_variable_attributes', 'th_product_variable_custom_fields',10, 2); | |
} | |
if( function_exists('th_print_custom_fields_js') ) { | |
add_action('woocommerce_product_after_variable_attributes_js', 'th_product_variable_custom_fields_js',10); | |
} | |
} else { | |
trigger_error("Unable to load class: CCTM", E_USER_WARNING); | |
} | |
/** | |
* Save the variable product options andcustom fields. | |
* THIS OVERRIDES THE WOO FUNCTION FOUND IN plugins/woocommerce/admin/writepanels/writepanel-product-type-variable.php | |
* The override adds the functionality for looping through and adding any CCTM custom fields for the variation | |
* | |
* @access public | |
* @param mixed $post_id | |
* @return void | |
*/ | |
function th_process_product_meta_variable( $post_id ) { | |
global $woocommerce, $wpdb; | |
if (isset($_POST['variable_sku'])) { | |
// get and set up CCTM custom fields for processing [this is part of the override] | |
$custom_field_prefix = 'cctm_variable_'; | |
$custom_fields = array(); | |
foreach($_POST as $k=>$v) { | |
if(strpos($k,$custom_field_prefix) === 0) { | |
$cfname = str_replace($custom_field_prefix,"", $k); | |
if( !array_key_exists($k, $custom_fields) ) { | |
$custom_fields[$k] = $cfname; | |
} | |
} | |
} | |
// these are woo's built-in fields | |
$variable_post_id = $_POST['variable_post_id']; | |
$variable_sku = $_POST['variable_sku']; | |
$variable_weight = $_POST['variable_weight']; | |
$variable_length = $_POST['variable_length']; | |
$variable_width = $_POST['variable_width']; | |
$variable_height = $_POST['variable_height']; | |
$variable_stock = $_POST['variable_stock']; | |
$variable_price = $_POST['variable_price']; | |
$variable_sale_price = $_POST['variable_sale_price']; | |
$upload_image_id = $_POST['upload_image_id']; | |
$variable_file_path = $_POST['variable_file_path']; | |
$variable_download_limit = $_POST['variable_download_limit']; | |
$variable_shipping_class = $_POST['variable_shipping_class']; | |
$variable_tax_class = $_POST['variable_tax_class']; | |
$variable_menu_order = $_POST['variation_menu_order']; | |
if (isset($_POST['variable_enabled'])) | |
$variable_enabled = $_POST['variable_enabled']; | |
if (isset($_POST['variable_is_virtual'])) | |
$variable_is_virtual = $_POST['variable_is_virtual']; | |
if (isset($_POST['variable_is_downloadable'])) | |
$variable_is_downloadable = $_POST['variable_is_downloadable']; | |
$attributes = (array) maybe_unserialize( get_post_meta($post_id, '_product_attributes', true) ); | |
$max_loop = max( array_keys( $_POST['variable_post_id'] ) ); | |
for ( $i=0; $i <= $max_loop; $i++ ) { | |
if ( ! isset( $variable_post_id[$i] ) ) continue; | |
$variation_id = (int) $variable_post_id[$i]; | |
// Virtal/Downloadable | |
if (isset($variable_is_virtual[$i])) $is_virtual = 'yes'; else $is_virtual = 'no'; | |
if (isset($variable_is_downloadable[$i])) $is_downloadable = 'yes'; else $is_downloadable = 'no'; | |
// Enabled or disabled | |
if (isset($variable_enabled[$i])) $post_status = 'publish'; else $post_status = 'private'; | |
// Generate a useful post title | |
$variation_post_title = sprintf(__('Variation #%s of %s', 'woocommerce'), $variation_id, get_the_title($post_id)); | |
// Update or Add post | |
if (!$variation_id) : | |
$variation = array( | |
'post_title' => $variation_post_title, | |
'post_content' => '', | |
'post_status' => $post_status, | |
'post_author' => get_current_user_id(), | |
'post_parent' => $post_id, | |
'post_type' => 'product_variation', | |
'menu_order' => $variable_menu_order[$i] | |
); | |
$variation_id = wp_insert_post( $variation ); | |
else : | |
$wpdb->update( $wpdb->posts, array( 'post_status' => $post_status, 'post_title' => $variation_post_title, 'menu_order' => $variable_menu_order[$i] ), array( 'ID' => $variation_id ) ); | |
endif; | |
// Update post meta | |
update_post_meta( $variation_id, '_sku', esc_html( $variable_sku[$i] ) ); | |
update_post_meta( $variation_id, '_price', $variable_price[$i] ); | |
update_post_meta( $variation_id, '_sale_price', $variable_sale_price[$i] ); | |
update_post_meta( $variation_id, '_weight', $variable_weight[$i] ); | |
update_post_meta( $variation_id, '_length', $variable_length[$i] ); | |
update_post_meta( $variation_id, '_width', $variable_width[$i] ); | |
update_post_meta( $variation_id, '_height', $variable_height[$i] ); | |
update_post_meta( $variation_id, '_stock', $variable_stock[$i] ); | |
update_post_meta( $variation_id, '_thumbnail_id', $upload_image_id[$i] ); | |
update_post_meta( $variation_id, '_virtual', $is_virtual ); | |
update_post_meta( $variation_id, '_downloadable', $is_downloadable ); | |
if ( $variable_tax_class[$i] !== 'parent' ) | |
update_post_meta( $variation_id, '_tax_class', $variable_tax_class[$i] ); | |
else | |
delete_post_meta( $variation_id, '_tax_class' ); | |
if ($is_downloadable=='yes') : | |
update_post_meta( $variation_id, '_download_limit', $variable_download_limit[$i] ); | |
update_post_meta( $variation_id, '_file_path', $variable_file_path[$i] ); | |
else : | |
update_post_meta( $variation_id, '_download_limit', '' ); | |
update_post_meta( $variation_id, '_file_path', '' ); | |
endif; | |
// Update custom fields [this is part of the override] | |
foreach($custom_fields as $post_variable_name=>$cctm_name) { | |
error_log("updating custom field for $variation_id: $cctm_name will be set to ".$_POST[$post_variable_name][$i]); | |
update_post_meta( $variation_id, $cctm_name, $_POST[$post_variable_name][$i] ); | |
} | |
// Save shipping class | |
$variable_shipping_class[$i] = $variable_shipping_class[$i] > 0 ? (int) $variable_shipping_class[$i] : ''; | |
wp_set_object_terms( $variation_id, $variable_shipping_class[$i], 'product_shipping_class'); | |
// Remove old taxonomies attributes so data is kept up to date | |
if ( $variation_id ) { | |
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE 'attribute_%%' AND post_id = %d;", $variation_id ) ); | |
wp_cache_delete( $variation_id, 'post_meta'); | |
} | |
// Update taxonomies | |
foreach ($attributes as $attribute) : | |
if ( $attribute['is_variation'] ) : | |
$value = esc_attr(trim($_POST[ 'attribute_' . sanitize_title($attribute['name']) ][$i])); | |
update_post_meta( $variation_id, 'attribute_' . sanitize_title($attribute['name']), $value ); | |
endif; | |
endforeach; | |
} | |
} | |
// Update parent if variable so price sorting works and stays in sync with the cheapest child | |
$post_parent = $post_id; | |
$children = get_posts( array( | |
'post_parent' => $post_parent, | |
'posts_per_page'=> -1, | |
'post_type' => 'product_variation', | |
'fields' => 'ids', | |
'post_status' => 'publish' | |
)); | |
$lowest_price = $lowest_regular_price = $lowest_sale_price = $highest_price = $highest_regular_price = $highest_sale_price = ''; | |
if ($children) { | |
foreach ($children as $child) { | |
$child_price = get_post_meta($child, '_price', true); | |
$child_sale_price = get_post_meta($child, '_sale_price', true); | |
// Low price | |
if (!is_numeric($lowest_regular_price) || $child_price < $lowest_regular_price) $lowest_regular_price = $child_price; | |
if ($child_sale_price!=='' && (!is_numeric($lowest_sale_price) || $child_sale_price < $lowest_sale_price)) $lowest_sale_price = $child_sale_price; | |
// High price | |
if (!is_numeric($highest_regular_price) || $child_price > $highest_regular_price) $highest_regular_price = $child_price; | |
if ($child_sale_price!=='' && (!is_numeric($highest_sale_price) || $child_sale_price > $highest_sale_price)) $highest_sale_price = $child_sale_price; | |
} | |
$lowest_price = ($lowest_sale_price==='' || $lowest_regular_price < $lowest_sale_price) ? $lowest_regular_price : $lowest_sale_price; | |
$highest_price = ($highest_sale_price==='' || $highest_regular_price > $highest_sale_price) ? $highest_regular_price : $highest_sale_price; | |
} | |
update_post_meta( $post_parent, '_price', $lowest_price ); | |
update_post_meta( $post_parent, '_min_variation_price', $lowest_price ); | |
update_post_meta( $post_parent, '_max_variation_price', $highest_price ); | |
update_post_meta( $post_parent, '_min_variation_regular_price', $lowest_regular_price ); | |
update_post_meta( $post_parent, '_max_variation_regular_price', $highest_regular_price ); | |
update_post_meta( $post_parent, '_min_variation_sale_price', $lowest_sale_price ); | |
update_post_meta( $post_parent, '_max_variation_sale_price', $highest_sale_price ); | |
// Update default attribute options setting | |
$default_attributes = array(); | |
foreach ($attributes as $attribute) : | |
if ( $attribute['is_variation'] ) : | |
$value = esc_attr(trim($_POST[ 'default_attribute_' . sanitize_title($attribute['name']) ])); | |
if ($value) : | |
$default_attributes[sanitize_title($attribute['name'])] = $value; | |
endif; | |
endif; | |
endforeach; | |
update_post_meta( $post_parent, '_default_attributes', $default_attributes ); | |
} | |
remove_action( 'woocommerce_process_product_meta_variable', 'process_product_meta_variable'); | |
add_action('woocommerce_process_product_meta_variable', 'th_process_product_meta_variable'); | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment