Commit e383885c authored by Reinhold Kainhofer's avatar Reinhold Kainhofer

Add readme.txt, fix issues with both versions installed, make it ready for the first release

parent 071d35c6
Material
sync.sh
.build
This diff is collapsed.
BASE=ordernumbers
PLATTFORM=woocommerce
VENDOR=opentools
VERSION=1.0
DIR = $(shell pwd)
BUILDDIR=.build/
BASICBUILDDIR=$(VENDOR)-$(PLATTFORM)-$(BASE)-basic
ADVBUILDDIR=$(VENDOR)-$(PLATTFORM)-$(BASE)-advanced
PLUGINFILES=library/ assets/ ordernumber_helper_woocommerce.php ordernumbers_woocommerce_basic.php readme.txt LICENSE.txt
BASICPLUGINFILES=woocommerce-custom-ordernumbers.php
ADVPLUGINFILES=woocommerce-advanced-ordernumbers.php ordernumbers_woocommerce.php
TRANSLATIONS=
ZIPFILE=$(VENDOR)-$(PLATTFORM)-$(BASE)-basic_v$(VERSION).zip
ADVZIPFILE=$(VENDOR)-$(PLATTFORM)-$(BASE)-advanced_v$(VERSION).zip
all: zip
zip: $(PLUGINFILES) $(ADVPLUGINFILES) $(BASICPLUGINFILES) $(TRANSLATIONS)
echo $(DIR)
@echo "Packing basic plugin version into distribution file $(ZIPFILE):"
mkdir -p $(BUILDDIR)/$(BASICBUILDDIR)
cp --parents -r $(PLUGINFILES) $(BASICPLUGINFILES) $(TRANSLATIONS) $(BUILDDIR)/$(BASICBUILDDIR)
cd $(BUILDDIR) && zip -r $(DIR)/$(ZIPFILE) $(BASICBUILDDIR)
# @zip -r
mkdir -p $(BUILDDIR)/$(ADVBUILDDIR)
echo `pwd`mak
cp --parents -r $(PLUGINFILES) $(ADVPLUGINFILES) $(TRANSLATIONS) $(BUILDDIR)/$(ADVBUILDDIR)
cp readme-adv.txt $(BUILDDIR)/$(ADVBUILDDIR)/readme.txt
cd $(BUILDDIR) && zip -r $(DIR)/$(ADVZIPFILE) $(ADVBUILDDIR)
cd $(DIR)
clean:
rm -f $(ZIPFILE) $(ADVZIPFILE) $(BUILDDIR) $(ADVBUILDDIR)
=== Advanced Ordernumbers ===
Contributors: opetools
Tags: WooCommerce, Order numbers, orders
Requires at least: 4.0
Tested up to: 4.1.1
Stable tag: trunk
License: GPLv2
Freely customize order numbers in WooCommerce. Lots of variables and counter settings can be used in the order number format.
== Description ==
Freely customize order numbers in WooCommerce. Lots of variables and counter settings can be used in the order number format.
\ No newline at end of file
div#opentools-ordernumber-upgrade {
/* margin-top: 1em; */
/* padding-left: 15px; */
/* border-radius: 5px; */
/* border: 1px solid red; */
/* background: #ff8080; */
padding: 5px 10px;
}
div#opentools-ordernumber-upgrade.postbox {
display: inline-block;
}
div#opentools-ordernumber-upgrade h3 {
margin-top: 5px;
margin-bottom: 5px;
padding: 0px 10px 5px 10px;
border-bottom: 1px solid #e0e0e0;
}
div#opentools-ordernumber-upgrade ul {
list-style: disc;
/* list-style-position: inside; */
margin-left: 5px;
padding-left: 5px;
}
div#opentools-ordernumber-upgrade li {
margin-left: 2em;
}
div#opentools-ordernumber-upgrade .column1, div#opentools-ordernumber-upgrade .column2 {
float: left;
}
div#opentools-ordernumber-upgrade .logoleft {
float: left;
padding-right: 10px;
position: absolute;
left: 15px;
}
div#opentools-ordernumber-upgrade .contents {
padding-left: 120px;
}
\ No newline at end of file
......@@ -9,6 +9,10 @@
if ( !defined( 'ABSPATH' ) && !defined('_JEXEC') ) {
die( 'Direct Access to ' . basename( __FILE__ ) . ' is not allowed.' );
}
// NULL function to indicate translatable strings without actually doing any translation
function trl($string) {
return $string;
}
class OrdernumberHelper {
static $_version = "0.1";
......@@ -19,6 +23,9 @@ class OrdernumberHelper {
'variable-table-class' => "",
'variable-table-style' => "",
);
protected $flags = array(
'extract-counter-settings' => 1,
);
/**
* An array containing all language keys for the translations used in the JavaScript code.
* Make sure to set those in the ajax_ordernumber JavaScript array!
......@@ -46,6 +53,20 @@ class OrdernumberHelper {
}
return $helper;
}
public function setFlag($flag, $value) {
$this->flags[$flag] = $value;
}
public function getFlag($flag, $default) {
if (isset($this->flags[$flag])) {
return $this->flags[$flag];
} else {
return $default;
}
}
public function unsetFlat($flag) {
unset($this->flags[$flag]);
}
function getStyle($key) {
if (isset($this->_styles[$key])) {
......@@ -206,7 +227,7 @@ class OrdernumberHelper {
return self::randomString ($alphabet, $len);
}
protected function setupDateTimeReplacements (&$reps, $details, $nrtype) {
public function setupDateTimeReplacements (&$reps, $details, $nrtype) {
$utime = microtime(true);
$reps["[year]"] = date ("Y", $utime);
$reps["[year2]"] = date ("y", $utime);
......@@ -314,41 +335,44 @@ class OrdernumberHelper {
}
protected function extractCounterSettings ($fmt, $type, $ctrsettings) {
// First, extract all counter settings, i.e. all strings of the form [#####:startval/increment] or [####/increment:startval]
$regexp = '%\[(#+)(/([0-9]+))?(:([0-9]+))?(/([0-9]+))?\]%';
$parts=array($fmt);
if ($this->getFlag('extract-counter-settings', true)) {
// First, extract all counter settings, i.e. all strings of the form [#####:startval/increment] or [####/increment:startval]
$regexp = '%\[(#+)(/([0-9]+))?(:([0-9]+))?(/([0-9]+))?\]%';
if (preg_match($regexp, $fmt, $counters)) {
// $counters is an array of the form:
// Array (
// [0] => [#####:100/3]
// [1] => #####
// [2] =>
// [3] =>
// [4] => :100
// [5] => 100
// [6] => /3
// [7] => 3
// )
$ctrsettings["${type}_padding"] = strlen($counters[1]);
if (!empty($counters[2])) {
// $counters[2] contains the whole "/n" part, while $counters[3] contains just the step itself
$ctrsettings["${type}_step"] = $counters[3];
}
if (!empty($counters[4])) {
// $counters[4] contains the whole ":n" part, while $counters[5] contains just the start value itself
$ctrsettings["${type}_start"] = $counters[5];
}
if (preg_match($regexp, $fmt, $counters)) {
// $counters is an array of the form:
// Array (
// [0] => [#####:100/3]
// [1] => #####
// [2] =>
// [3] =>
// [4] => :100
// [5] => 100
// [6] => /3
// [7] => 3
// )
$ctrsettings["${type}_padding"] = strlen($counters[1]);
if (!empty($counters[2])) {
// $counters[2] contains the whole "/n" part, while $counters[3] contains just the step itself
$ctrsettings["${type}_step"] = $counters[3];
}
if (!empty($counters[4])) {
// $counters[4] contains the whole ":n" part, while $counters[5] contains just the start value itself
$ctrsettings["${type}_start"] = $counters[5];
}
if (!empty($counters[6])) {
// $counters[6] contains the whole ":n" part, while $counters[7] contains just the start value itself
$ctrsettings["${type}_step"] = $counters[7];
}
if (!empty($counters[6])) {
// $counters[6] contains the whole ":n" part, while $counters[7] contains just the start value itself
$ctrsettings["${type}_step"] = $counters[7];
}
$fmt = preg_replace($regexp, "#", $fmt);
$fmt = preg_replace($regexp, "#", $fmt);
}
// 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);
}
// 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];
......@@ -469,7 +493,7 @@ class OrdernumberHelper {
'variables_ifvar' => $this->__('PLG_ORDERNUMBER_REPL_IFVAR'),
'variables_ifop' => '',
'variables_ifval' => $this->__('PLG_ORDERNUMBER_REPL_IFVAL'),
'variables_then' => $this->__(''),
'variables_then' => '',
'variables_thenvar' => $this->__('PLG_ORDERNUMBER_REPL_SETVAR'),
'variables_thenval' => $this->__('PLG_ORDERNUMBER_REPL_TOVAL'),
'sort' => '',
......
......@@ -82,7 +82,6 @@ class OrdernumberHelperWooCommerce extends OrdernumberHelper {
if (sizeof($parts)==1) {
array_unshift($parts, 'ordernumber');
}
// print("<h1>$type Counter: $name with value $value encountered, prefix=".self::$ordernumber_counter_prefix.", parts=".print_r($parts,1)."</h1>");
if ($parts[0]==$type) {
$counters[] = array(
'type' => $parts[0],
......
......@@ -9,116 +9,61 @@
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class OpenToolsOrdernumbers {
public $ordernumber_meta = "_oton_number_";
public $ordernumber_new_placeholder = "[New Order]";
protected $helper = null;
protected $settings = array();
if (!class_exists( 'OpenToolsOrdernumbersBasic' ))
require_once (dirname(__FILE__) . '/ordernumbers_woocommerce_basic.php');
class OpenToolsOrdernumbers extends OpenToolsOrdernumbersBasic {
/**
* Construct the plugin object
*/
public function __construct()
{
$this->helper = OrdernumberHelperWooCommerce::getHelper();
$this->initializeSettings();
$this->initializeHooks();
public function __construct($basename) {
parent::__construct($basename);
$this->is_advanced = true;
$this->helper->registerCallback('setupStoreReplacements', array($this, 'setupStoreReplacements'));
$this->helper->registerCallback('setupOrderReplacements', array($this, 'setupOrderReplacements'));
$this->helper->registerCallback('setupUserReplacements', array($this, 'setupUserReplacements'));
$this->helper->registerCallback('setupShippingReplacements', array($this, 'setupShippingReplacements'));
$this->helper->registerCallback('setupThirdPartyReplacements', array($this, 'setupThirdPartyReplacements'));
}
/**
* Override the initializeBasicSettings method, which restricts some functionality in the basic plugin.
*/
protected function initializeBasicSettings() {}
/**
* Install all neccessary filters and actions for this plugin
*/
protected function initializeHooks() {
$helper = OrdernumberHelperWooCommerce::getHelper();
// 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' ) );
parent::initializeHooks();
// Custom table widget for custom variable definitions: Hooks for creating and storing values
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( 'woocommerce_order_actions', array( $this, 'add_order_action_new_number' ) );
add_action( 'woocommerce_order_action_assign_new_ordernumber', array( $this, 'order_action_assign_new_ordernumber' ) );
add_action( 'admin_print_styles-woocommerce_page_wc-settings', array($helper, 'print_admin_styles'));
add_action( 'admin_print_scripts-woocommerce_page_wc-settings', array($this, 'print_admin_scripts'));
// AJAX counter modifications
add_action( 'wp_ajax_setCounter', array($this, 'counter_set_callback') );
add_action( 'wp_ajax_addCounter', array($this, 'counter_add_callback') );
add_action( 'wp_ajax_deleteCounter', 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_assignNumber'), 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! */);
// Install hooks for third-party plugin support:
$this->thirdparty_wpo_wcpdf_init();
}
protected function initializeSettingsGeneral() {
// Remove the NAG screen of the basic version
return array();
}
/**
* Setup all options and the corresponding settings UI to configure this plugin, using the WP settings API
* Return the tooltip for the number format settings textinput (the two plugin versions have different features!)
*/
protected function initializeSettings() {
// Init settings
$this->settings = array(
array(
'name' => $this->helper->__( 'Advanced Order Numbers'),
'desc' => $this->helper->__( 'Configure the format and the counters of the order numbers in WooCommerce.'),
'type' => 'title',
'id' => 'ordernumber_options'
),
array(
'name' => $this->helper->__( 'Customize Order Numbers'),
'desc' => $this->helper->__( 'Check to use custom order numbers rather than the default wordpress post ID.'),
'id' => 'customize_ordernumber',
'type' => 'checkbox',
'default' => 'no'
),
array(
'title' => $this->helper->__( 'Order number format'),
'desc' => $this->helper->__( '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' => $this->helper->__( 'Use global counter'),
'desc' => $this->helper->__( 'A global counter never resets. Non-global counters run within each number format and reset whenever any variable changes.'),
'id' => 'ordernumber_global',
'type' => 'checkbox',
'default' => 'no',
),
array(
'name' => $this->helper->__( 'All order number counters'),
'desc' => $this->helper->__( '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',
'nrtype' => 'ordernumber',
),
array( 'type' => 'sectionend', 'id' => 'ordernumber_options' ),
protected function getNumberFormatSettingsLabel() {
return $this->helper->__( '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.');
}
protected function initializeSettingsOther() {
return array_merge(
$this->initializeSettingsInvoiceNumbers(),
$this->initializeSettingsReplacements()
);
}
protected function initializeSettingsInvoiceNumbers() {
$settings = array(
/**
* Invoice number settings
*/
......@@ -161,10 +106,17 @@ class OpenToolsOrdernumbers {
'type' => 'ordernumber_counters',
'nrtype' => 'invoice',
),
array( 'type' => 'sectionend', 'id' => 'invoice_options' ),
// TODO: customize order password, and other numbers!
array( 'type' => 'sectionend', 'id' => 'invoice_options' )
);
add_option ('customize_invoice', 'no');
add_option ('invoice_format', "#");
add_option ('invoice_global', 'no');
return $settings;
}
protected function initializeSettingsReplacements() {
$settings = array(
array(
'name' => $this->helper->__( 'Custom Variables'),
'desc' => $this->helper->__( 'Define your own (conditional) variables for use in the number formats'),
......@@ -175,62 +127,13 @@ class OpenToolsOrdernumbers {
'id' => 'ordernumber_variables',
'type' => 'ordernumber_variables',
),
array( 'type' => 'sectionend', 'id' => 'ordernumber_variables' ),
array( 'type' => 'sectionend', 'id' => 'ordernumber_variables' )
);
// Default options
add_option ('customize_ordernumber', 'no');
add_option ('ordernumber_format', "#");
add_option ('ordernumber_global', 'no');
add_option ('customize_invoice', 'no');
add_option ('invoice_format', "#");
add_option ('invoice_global', 'no');
add_option ('ordernumber_variables', array());
return $settings;
}
/**
* 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'] = $this->helper->__('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 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() {
$this->helper->print_admin_scripts();
wp_register_script( 'ordernumber-admin', plugins_url('assets/js/ordernumber-config.js', __FILE__), array('jquery'));
wp_enqueue_script( 'ordernumber-admin');
}
/**
* Render the Custom Variables configuration table
*/
......@@ -257,102 +160,7 @@ class OpenToolsOrdernumbers {
return OrdernumberHelper::transposeCustomVariables($value);
}
/**
* 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 );
?>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="<?php echo esc_attr( $settings['id'] ); ?>"><?php echo esc_html( $settings['title'] ); ?></label>
<?php echo $tooltip_html; ?>
</th>
<td class="forminp forminp-<?php echo sanitize_title( $settings['nrtype'] ) ?>">
<?php
$counters = $this->helper->getAllCounters($settings['nrtype']);
echo $this->helper->counter_modification_create_table($settings['nrtype'], $counters);
?>
</td>
</tr>
<?php
}
/**
* Hook to add the order numer post meta field to the searchable field
* (so the admin can search for the order number in the backend)
*/
public function order_search_fields($fields) {
$fields[] = $this->ordernumber_meta;
return $fields;
}
/**
* Sort the order list's "Order" column by our post meta rather than by ID
*/
public function modify_order_column_sortkey($columns) {
$columns['order_title'] = $this->ordernumber_meta;
return $columns;
}
/**
* Add the "create new order number" action to the edit order page in the Backend
*/
public function add_order_action_new_number($actions) {
$actions['assign_new_ordernumber'] = $this->helper->__('Assign a new order number');
return $actions;
}
/**
* Handle the "Assign a new order number" action from the edit order page in the backend
*/
public function order_action_assign_new_ordernumber( $order ) {
$number = $this->generateNumber($order->id, $order, 'ordernumber');
}
/**
* Handle new posts created in the frontend. This action will be called for all posts,
* not only for orders, so we need to check explicitly. Also, this function will be called
* for order updates, so we need to check the update argument, too.
*/
public function check_assignNumber($post_id, $post, $update) {
// Is the post really an order?
// Order numbers are only assigned to orders on creation, not when updating!
if ($post->post_type != 'shop_order') {
return;
} else {
// Handle new admin-created orders, where the address is entered later on!
// Assign an order number:
$number = $this->assign_new_ordernumber($post_id, $post, $update);
}
}
/**
* AJAX Counter handling (simple loading/storing counters), storing them as options
*/
public function counter_delete_callback() {
$json = $this->helper->ajax_counter_delete($_POST['nrtype'], $_POST['counter']);
wp_send_json($json);
}
public function counter_add_callback () {
$json = $this->helper->ajax_counter_add($_POST['nrtype'], $_POST['counter'], isset($_POST['value'])?$_POST['value']:"0");
wp_send_json($json);
}
public function counter_set_callback () {
$json = $this->helper->ajax_counter_set($_POST['nrtype'], $_POST['counter'], $_POST['value']);
wp_send_json($json);
}
/** ***********************************************************
*
* REPLACEMENT FUNCTIONS
......@@ -447,84 +255,6 @@ class OpenToolsOrdernumbers {
$reps = apply_filters( 'opentools_ordernumber_replacements', $reps, $details, $nrtype);
}
function generateNumber($orderid, $order, $type='ordernumber') {
if (get_option('customize_'.$type, 'no')!='no') {
$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,
);
$customvars = get_option ('ordernumber_variables', array());
$number = $this->helper->createNumber ($fmt, $type, $order, $customvars, $ctrsettings);
update_post_meta( $orderid, $this->ordernumber_meta.$type, $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.'ordernumber', $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.'ordernumber', 'true');
if ($number == $this->ordernumber_new_placeholder && $order->post_status != 'auto-draft') {
$number = $this->generateNumber($orderid, $order, 'ordernumber');
// Assign a new number
}
return $number;
}
function get_or_create_number($orderid, $order, $type = 'ordernumber') {
$stored_number = get_post_meta( $orderid, $this->ordernumber_meta.$type, true);
if (!empty($stored_number)) {
return $stored_number;
} else {
return $this->generateNumber($orderid, $order, $type);
}