settings = array(
array(
'name' => self::__( 'Advanced Order Numbers'),
'desc' => self::__( 'Configure the format and the counters of the order numbers in WooCommerce.'),
'type' => 'title',
'id' => 'ordernumber_options'
),
array(
'name' => self::__( 'Customize Order Numbers'),
'desc' => self::__( 'Check to use custom order numbers rather than the default wordpress post ID.'),
'id' => 'customize_ordernumber',
'type' => 'checkbox',
'default' => 'no'
),
array(
'title' => self::__( 'Order number format'),
'desc' => self::__( 'The format for the order numbers (variables can be entered as [...], the counter is indicated by the #). To use a different counter name than displayed, put the custom counter name after a |, e.g. "[year]-[month]/#|[year]" to use the month in the order number, but reset the counter only yearly. Advanced settings for the counter can be added as [#####:start/step], e.g. [#:100] to start new counters at 100, or [#/5] to increment the counter by 5. The number of # in the format determine how many digits are shown at least, e.g. [########] will always show at least 8 digits for the counter, e.g. 00000014.'),
'desc_tip' => true,
'id' => 'ordernumber_format',
'default' => '#',
'type' => 'text',
'css' => 'width: 100%',
),
array(
'title' => self::__( 'Use global counter'),
'desc' => self::__( 'A global counter is independent of the number format and will never reset. A non-global counter runs within the number format and will start from the inital value whenever any of the variables used in the format changes (to be precise: a new counter will be used, so it is possible to have multiple counters running in parallel).'),
'desc_tip' => true,
'id' => 'ordernumber_global',
'type' => 'checkbox',
'default' => 'no',
),
// array(
// 'title' => self::__( 'Counter Digits'),
// 'desc' => self::__( 'Minimum number of digits for the number'),
// 'desc_tip' => true,
// 'id' => 'ordernumber_padding',
// 'type' => 'number',
// 'default' => '0'
// ),
// array(
// 'title' => self::__( 'Counter Start'),
// 'desc' => self::__( 'Start value for each new counter'),
// 'desc_tip' => true,
// 'id' => 'ordernumber_start',
// 'type' => 'number',
// 'default' => '1'
// ),
// array(
// 'title' => self::__( 'Counter step'),
// 'desc' => self::__( 'By how much the counter will be increased after each order. Typically 1.'),
// 'desc_tip' => true,
// 'id' => 'ordernumber_step',
// 'type' => 'number',
// 'default' => '1'
// ),
array( 'type' => 'sectionend', 'id' => 'ordernumber_options' ),
// TODO: customize order password, and other numbers!
array(
'name' => self::__( 'Custom Variables'),
'desc' => self::__( 'Define your own (conditional) variables for use in the number formats'),
'type' => 'title',
'id' => 'ordernumber_variables'
),
array(
'id' => 'ordernumber_variables',
'type' => 'ordernumber_variables',
),
array( 'type' => 'sectionend', 'id' => 'ordernumber_variables' ),
array(
'name' => self::__( 'Current Counters'),
'type' => 'title',
'id' => 'ordernumber_counters'
),
array(
'name' => self::__( 'All Ordernumber Counters'),
'desc' => self::__( 'View and modify the current counter values. The counter value is the value used for the previous number. All changes are immediately applied!'),
'desc_tip' => true,
'id' => 'ordernumber_counters',
'type' => 'ordernumber_counters',
),
array( 'type' => 'sectionend', 'id' => 'ordernumber_counters' ),
);
// Default options
add_option ('customize_ordernumber', '0');
add_option ('ordernumber_format', "#");
add_option ('ordernumber_global', 'no');
// add_option ('ordernumber_padding', '1');
// add_option ('ordernumber_start', '1');
// add_option ('ordernumber_step', '1');
add_option ('ordernumber_variables', array());
// register filters and actions
// CONFIGURATION SCREENS
add_filter( 'woocommerce_get_sections_checkout', array($this, 'add_admin_section'));
// The checkout settings page assumes all subpages are payment gateways, so we have to override this and manually pass our settings:
add_action( 'woocommerce_settings_checkout', array( $this, 'settings_output' ) );
add_action( 'woocommerce_settings_save_checkout', array( $this, 'settings_save' ) );
add_action( 'woocommerce_admin_field_ordernumber_counters', array( $this, 'admin_field_counters' ) );
add_action( 'woocommerce_admin_field_ordernumber_variables', array( $this, 'admin_field_variables' ) );
add_action( 'pre_update_option_ordernumber_variables', array( $this, 'update_option_variables'));
add_action( 'admin_print_styles-woocommerce_page_wc-settings', array($this, 'print_admin_styles'));
add_action( 'admin_print_scripts-woocommerce_page_wc-settings', array($this, 'print_admin_scripts'));
// AJAX counter modifications
add_action( 'wp_ajax_set_counter', array($this, 'counter_set_callback') );
add_action( 'wp_ajax_add_counter', array($this, 'counter_add_callback') );
add_action( 'wp_ajax_delete_counter', array($this, 'counter_delete_callback') );
// Add the ordernumber post meta to the search in the backend
add_filter( 'woocommerce_shop_order_search_fields', array($this, 'order_search_fields'));
// Sort the order list in the backend by order number rather than ID, make sure this is called LAST so we modify the defaults passed as arguments
add_filter( 'manage_edit-shop_order_sortable_columns', array( $this, 'modify_order_column_sortkey' ), 9999 );
// When a new order is created, we immediately assign the order number:
add_action( 'wp_insert_post', array(&$this, 'check_create_ordernumber'), 10, 3);
// add_action( 'save_post', array(&$this, 'check_create_ordernumber'), 10, 3);
// The filter to actually return the order number for the given order
add_filter ('woocommerce_order_number', array(&$this, 'get_ordernumber'), 10, 2/*<= Also get the order object! */);
}
// Activate the plugin
public static function activate() {}
// Deactivate the plugin
public static function deactivate() {}
/**
* Insert our own section in the checkout setting page. Rearrange the sections array to make sure our settings
* come second place, directly after the default page with the '' key and before all the payment gateways
*/
function add_admin_section($sections) {
$newsections = array();
foreach ($sections as $sec => $name ) {
$newsections[$sec] = $name;
if ($sec == '') {
$newsections['ordernumber'] = self::__('Order Numbers');
}
}
return $newsections;
}
public function settings_output() {
global $current_section;
if ($current_section == 'ordernumber') {
$settings = $this->settings;
WC_Admin_Settings::output_fields( $settings );
}
}
public function settings_save() {
global $current_section;
if ($current_section == 'ordernumber') {
$settings = $this->settings;
WC_Admin_Settings::save_fields( $settings );
}
}
/**
* Print the CSS for the counter values and counter variables tables to the page header in the WC backend admin setting page
*/
public function print_admin_styles () {
wp_register_style ( 'ordernumber-counter-style', self::css_url('ordernumber-counter.css') );
wp_enqueue_style('ordernumber-counter-style');
wp_register_style ( 'ordernumber-variables-style', self::css_url('ordernumber-variables.css') );
wp_enqueue_style('ordernumber-variables-style');
}
/**
* Print the JS for the counter values and counter variables tables to the page header in the WC backend admin setting page
*/
public function print_admin_scripts() {
wp_register_script( 'ordernumber-counter-script', self::js_url( 'ordernumber-counter.js', __FILE__), array('jquery') );
wp_enqueue_script( 'ordernumber-counter-script');
// Handle the translations:
$localizations = array( 'ajax_url' => admin_url( 'admin-ajax.php' ) );
$localizations['ORDERNUMBER_JS_JSONERROR'] = self::__("Error reading response from server:");
$localizations['ORDERNUMBER_JS_NOT_AUTHORIZED'] = self::__("You are not authorized to modify order number counters.");
$localizations['ORDERNUMBER_JS_NEWCOUNTER'] = self::__("Please enter the format/name of the new counter:");
$localizations['ORDERNUMBER_JS_ADD_FAILED'] = self::__("Failed adding counter {0}");
$localizations['ORDERNUMBER_JS_INVALID_COUNTERVALUE'] = self::__("You entered an invalid value for the counter.\n\n");
$localizations['ORDERNUMBER_JS_EDITCOUNTER'] = self::__("{0}Please enter the new value for the counter '{1}' (current value: {2}):");
$localizations['ORDERNUMBER_JS_MODIFY_FAILED'] = self::__("Failed modifying counter {0}");
$localizations['ORDERNUMBER_JS_DELETECOUNTER'] = self::__("Really delete counter '{0}' with value '{1}'?");
$localizations['ORDERNUMBER_JS_DELETE_FAILED'] = self::__("Failed deleting counter {0}");
// in JavaScript, object properties are accessed as ajax_object.ajax_url, ajax_object.we_value
wp_localize_script( 'ordernumber-counter-script', 'ajax_ordernumber', $localizations );
wp_register_script( 'ordernumber-variables-script', self::js_url( 'ordernumber-variables.js'), array('jquery') );
wp_enqueue_script( 'ordernumber-variables-script');
}
/**
* Render the Custom Variables configuration table
*/
public function admin_field_variables($settings) {
$variables = get_option( $settings['id'], array() );
if (!is_array($variables)) {
$variables = array();
} ?>
';
return $html;
}
/**
* Store the variable replacements array into the options. Need to transpose the array before we can store it into the options...
* This filter is called directly before the option is saved.
*/
public function update_option_variables ($value) {
if (!is_array($value))
return array();
$keys = array_keys($value);
$vallist = array();
foreach (array_keys($value[$keys[0]]) as $i) {
$entry = array();
foreach ($keys as $k) {
$entry[$k] = $value[$k][$i];
}
$vallist[] = $entry;
}
return $vallist;
}
/**
* Render the Counter Values modification table
*/
public function admin_field_counters ($settings) {
// Description handling
$field_description = WC_Admin_Settings::get_field_description( $settings );
extract( $field_description );
// First, get all counter names:
$counters = array();
$pfxlen = strlen($this->ordernumber_counter_prefix );
foreach (wp_load_alloptions() as $name => $value) {
if (substr($name, 0, $pfxlen) == $this->ordernumber_counter_prefix) {
$parts = explode('-', substr($name, $pfxlen), 2);
if (sizeof($parts)==1) {
array_unshift($parts, 'ordernumber');
}
$counters[] = array(
'type' => $parts[0],
'name' => $parts[1],
'value' => $value,
);
}
}
?>
No counters match the regexp '$regexp' in the format '$fmt'
");
}
// Replace all extended counter definitions by a single #
// Split at a | to get the number format and a possibly different counter increment format
// If a separate counter format is given after the |, use it, otherwise reuse the number format itself as counter format
$parts = explode ("|", $fmt);
$ctrsettings["${type}_format"] = $parts[0];
$ctrsettings["${type}_counter"] = ($ctrsettings["${type}_global"]=='yes')?"":$parts[(count($parts)>1)?1:0];
// print("
Counter settings are: ".print_r($ctrsettings,1)."
");
return $ctrsettings;
}
/* replace the variables in the given format. $type indicates the type of number, currently only 'ordernumber', because WooCommerce does not support invoices or customer numbers. We might allow the shop owner to customize the order password, though. */
function createNumber ($fmt, $type, $order, $customvars, $ctrsettings) {
$reps = $this->setupReplacements ($type, $order);
$reps = $this->setupCustomVariables ($type, $order, $reps, $customvars);
$format = $this->setupNumberFormatString($fmt, $type, $order, $reps);
$format = $this->doReplacements($format, $reps);
$ctrsettings = $this->extractCounterSettings ($format, $type, $ctrsettings);
$countername = $ctrsettings["${type}_counter"];
// Look up the current counter
$count = $this->_getCounter($type, $countername, $ctrsettings["${type}_start"] - $ctrsettings["${type}_step"]) + $ctrsettings["${type}_step"];
$this->_setCounter($type, $countername, $count);
// return the format with the counter inserted
$number = str_replace ("#", sprintf('%0' . $ctrsettings["${type}_padding"] . 's', $count), $ctrsettings["${type}_format"]);
return $number;
}
function create_ordernumber($orderid, $order, $type='ordernumber') {
if (get_option('customize_'.$type, 'false')) {
$fmt = get_option ($type.'_format', "#");
$ctrsettings = array(
"${type}_format" => '',
"${type}_counter" => '',
"${type}_global" => get_option ($type.'_global', 'no'),
"${type}_padding" => 1,
"${type}_step" => 1,
"${type}_start" => 1,
// "${type}_padding" => get_option ($type.'_padding', 1),
// "${type}_step" => get_option ($type.'_step', 1),
// "${type}_start" => get_option ($type.'_start', 1),
);
$customvars = get_option ('ordernumber_variables', array());
$number = $this->createNumber ($fmt, $type, $order, $customvars, $ctrsettings);
update_post_meta( $orderid, $this->ordernumber_meta, $number );
return $number;
} else {
return $orderid;
}
}
/**
* The hook to assign a customized order number (unless the order already has one assigned)
*/
function assign_new_ordernumber($orderid, $order, $update=true) {
if ((!$update) /*&& ($order->post_status == 'auto-draft')*/) {
// New order => assign placeholder, which will later be overwritten the real order number
update_post_meta( $orderid, $this->ordernumber_meta, $this->ordernumber_new_placeholder );
}
// If we do not have an order (yet), we cannot proceed. But we probably have created the
// ordernumber placeholder for that post, so this function has done its job and we can return
if (!$order instanceof WC_Order) {
return;
}
$number = get_post_meta( $orderid, $this->ordernumber_meta, 'true');
if ($number == $this->ordernumber_new_placeholder && $order->post_status != 'auto-draft') {
$number = $this->create_ordernumber($orderid, $order, 'ordernumber');
// Assign a new number
}
return $number;
}
/**
* The hook to customize order numbers (requests the order number from the database; creates a new ordernumber if no entry exists in the database)
*/
function get_ordernumber($orderid, $order) {
$stored_number = get_post_meta( $orderid, $this->ordernumber_meta, 'true');
if ($stored_number == $this->ordernumber_new_placeholder) {
// Check whether the order was now really created => create order number now
return $this->assign_new_ordernumber($orderid, $order);
} elseif (!empty($stored_number)) {
// Order number already exists => simply return it
return $stored_number;
} else {
// No order number was created for this order, so simply use the orderid as default.
return $orderid;
}
}
}
}
if (class_exists("OpenToolsOrdernumbers")) {
// Installation and uninstallation hooks
register_activation_hook(__FILE__, array('OpenToolsOrdernumbers', 'activate'));
register_deactivation_hook(__FILE__, array('OpenToolsOrdernumbers', 'deactivate'));
// instantiate the plugin class
$ordernumber_plugin = new OpenToolsOrdernumbers();
}
}