Skip to content

Instantly share code, notes, and snippets.

@beingtree
Created May 7, 2013 19:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save beingtree/5535333 to your computer and use it in GitHub Desktop.
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)
<?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!] = '&#x2028;'
else
JS_ESCAPE_MAP["\342\200\250"] = '&#x2028;'
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