├── index.php ├── admin ├── index.php ├── css │ ├── webfonts │ │ ├── fa-brands-400.eot │ │ ├── fa-brands-400.ttf │ │ ├── fa-solid-900.eot │ │ ├── fa-solid-900.ttf │ │ ├── fa-solid-900.woff │ │ ├── fa-brands-400.woff │ │ ├── fa-brands-400.woff2 │ │ ├── fa-regular-400.eot │ │ ├── fa-regular-400.ttf │ │ ├── fa-regular-400.woff │ │ ├── fa-solid-900.woff2 │ │ └── fa-regular-400.woff2 │ ├── ddwc-admin.min.css │ ├── fontawesome │ │ ├── regular.min.css │ │ ├── solid.min.css │ │ ├── brands.min.css │ │ ├── regular.css │ │ ├── solid.css │ │ ├── brands.css │ │ ├── svg-with-js.min.css │ │ └── svg-with-js.css │ └── ddwc-admin.css ├── partials │ └── ddwc-admin-display.php ├── js │ └── ddwc-admin.js ├── ddwc-woocommerce-account-tab.php ├── ddwc-woocommerce-orders.php ├── ddwc-metaboxes.php ├── ddwc-woocommerce-driver-ratings.php ├── ddwc-woocommerce-settings.php └── class-ddwc-admin.php ├── public ├── index.php ├── css │ ├── webfonts │ │ ├── fa-solid-900.eot │ │ ├── fa-solid-900.ttf │ │ ├── fa-brands-400.eot │ │ ├── fa-brands-400.ttf │ │ ├── fa-brands-400.woff │ │ ├── fa-regular-400.eot │ │ ├── fa-regular-400.ttf │ │ ├── fa-solid-900.woff │ │ ├── fa-solid-900.woff2 │ │ ├── fa-brands-400.woff2 │ │ ├── fa-regular-400.woff │ │ └── fa-regular-400.woff2 │ ├── fontawesome │ │ ├── regular.min.css │ │ ├── solid.min.css │ │ ├── brands.min.css │ │ ├── regular.css │ │ ├── brands.css │ │ ├── solid.css │ │ ├── svg-with-js.min.css │ │ └── svg-with-js.css │ ├── ddwc-public.min.css │ └── ddwc-public.css ├── partials │ └── ddwc-public-display.php ├── js │ ├── customer-signature-script.js │ ├── signature-pad.js │ └── ddwc-public.js ├── class-ddwc-public.php └── ddwc-customer-signature-script.php ├── includes ├── index.php ├── class-ddwc-deactivator.php ├── class-ddwc-activator.php ├── class-ddwc-i18n.php ├── class-ddwc-loader.php └── class-ddwc.php ├── assets ├── icon-128x128.jpg ├── screenshot-1.jpg ├── screenshot-2.jpg ├── screenshot-3.jpg ├── screenshot-4.jpg ├── screenshot-5.jpg ├── screenshot-6.jpg ├── screenshot-7.jpg └── banner-772x250.jpg ├── languages ├── delivery-drivers-for-woocommerce-ar_AR.mo ├── delivery-drivers-for-woocommerce-de_DE.mo ├── delivery-drivers-for-woocommerce-es_ES.mo ├── delivery-drivers-for-woocommerce-fr_FR.mo ├── delivery-drivers-for-woocommerce-hi_IN.mo ├── delivery-drivers-for-woocommerce-it_IT.mo ├── delivery-drivers-for-woocommerce.pot ├── delivery-drivers-for-woocommerce-hi_IN.po └── delivery-drivers-for-woocommerce-ar_AR.po ├── uninstall.php ├── README.md └── delivery-drivers-for-woocommerce.php /index.php: -------------------------------------------------------------------------------- 1 | 8 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 9 | * @link https://www.deviodigital.com 10 | */ 11 | 12 | // If uninstall not called from WordPress, then exit. 13 | if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) { 14 | wp_die(); 15 | } 16 | -------------------------------------------------------------------------------- /admin/partials/ddwc-admin-display.php: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /public/partials/ddwc-public-display.php: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /admin/css/ddwc-admin.min.css: -------------------------------------------------------------------------------- 1 | .forminp span.description{display:block}.ddwc-driver-picture{display:inline-block;margin-right:12px;position:relative;width:140px}.ddwc-remove-driver-picture{background:red;border:0;border-radius:50%;color:#fff;font-family:Helvetica,Arial,sans-serif;font-size:14px;font-weight:700;line-height:1px;padding:10px 6.61px;position:absolute;right:-5px;top:-5px;text-align:center}.ddwc-remove-driver-picture:hover{background:#df0000;color:#fff;cursor:pointer}.ddwc-driver-picture img{height:auto}.wp-core-ui select#ddwc_driver_transportation_type{width:22rem} -------------------------------------------------------------------------------- /admin/js/ddwc-admin.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function ($) { 2 | jQuery("select#ddwc_driver_id").change(function(e) { 3 | var itemid = $(this).attr("name"); 4 | var metakey = $(this).attr("id"); 5 | var metavalue = this.value; 6 | // Update driver ID metadata. 7 | $.post(WPaAjax.ajaxurl,{ 8 | action : "ddwc_delivery_driver_settings", 9 | item_id : itemid, 10 | metakey : metakey, 11 | metavalue : metavalue 12 | }); 13 | }); 14 | // Remove the link click wrapper on WooCommerce Edit Orders screen. 15 | $("td.delivery_driver.column-delivery_driver a").click(function(){ return false; }); 16 | }); 17 | -------------------------------------------------------------------------------- /admin/css/fontawesome/regular.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:"Font Awesome 5 Free";font-weight:400} -------------------------------------------------------------------------------- /public/css/fontawesome/regular.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:"Font Awesome 5 Free";font-weight:400} -------------------------------------------------------------------------------- /admin/css/fontawesome/solid.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */@font-face{font-family:'Font Awesome 5 Free',sans-serif;font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:'Font Awesome 5 Free',sans-serif;font-weight:900} -------------------------------------------------------------------------------- /public/css/fontawesome/solid.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */@font-face{font-family:'Font Awesome 5 Free',sans-serif;font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:'Font Awesome 5 Free',sans-serif;font-weight:900} -------------------------------------------------------------------------------- /admin/css/fontawesome/brands.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */@font-face{font-family:'Font Awesome 5 Brands',sans-serif;font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:'Font Awesome 5 Brands',sans-serif;font-weight:400} -------------------------------------------------------------------------------- /public/css/fontawesome/brands.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */@font-face{font-family:'Font Awesome 5 Brands',sans-serif;font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:'Font Awesome 5 Brands',sans-serif;font-weight:400} -------------------------------------------------------------------------------- /admin/css/fontawesome/regular.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Free'; 7 | font-style: normal; 8 | font-weight: 400; 9 | font-display: block; 10 | src: url("../webfonts/fa-regular-400.eot"); 11 | src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); 12 | } 13 | 14 | .far { 15 | font-family: 'Font Awesome 5 Free'; 16 | font-weight: 400; 17 | } 18 | -------------------------------------------------------------------------------- /public/css/fontawesome/regular.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Free'; 7 | font-style: normal; 8 | font-weight: 400; 9 | font-display: block; 10 | src: url("../webfonts/fa-regular-400.eot"); 11 | src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); 12 | } 13 | 14 | .far { 15 | font-family: 'Font Awesome 5 Free'; 16 | font-weight: 400; 17 | } 18 | -------------------------------------------------------------------------------- /admin/css/fontawesome/solid.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Free', sans-serif; 7 | font-style: normal; 8 | font-weight: 900; 9 | font-display: block; 10 | src: url("../webfonts/fa-solid-900.eot"); 11 | src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); 12 | } 13 | 14 | .fa, 15 | .fas { 16 | font-family: 'Font Awesome 5 Free', sans-serif; 17 | font-weight: 900; 18 | } 19 | -------------------------------------------------------------------------------- /admin/css/fontawesome/brands.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Brands', sans-serif; 7 | font-style: normal; 8 | font-weight: 400; 9 | font-display: block; 10 | src: url("../webfonts/fa-brands-400.eot"); 11 | src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); 12 | } 13 | 14 | .fab { 15 | font-family: 'Font Awesome 5 Brands', sans-serif; 16 | font-weight: 400; 17 | } 18 | -------------------------------------------------------------------------------- /public/css/fontawesome/brands.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Brands', sans-serif; 7 | font-style: normal; 8 | font-weight: 400; 9 | font-display: block; 10 | src: url("../webfonts/fa-brands-400.eot"); 11 | src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); 12 | } 13 | 14 | .fab { 15 | font-family: 'Font Awesome 5 Brands', sans-serif; 16 | font-weight: 400; 17 | } 18 | -------------------------------------------------------------------------------- /public/css/fontawesome/solid.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Free', sans-serif; 7 | font-style: normal; 8 | font-weight: 900; 9 | font-display: block; 10 | src: url("../webfonts/fa-solid-900.eot"); 11 | src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); 12 | } 13 | 14 | .fa, 15 | .fas { 16 | font-family: 'Font Awesome 5 Free', sans-serif; 17 | font-weight: 900; 18 | } 19 | -------------------------------------------------------------------------------- /admin/css/ddwc-admin.css: -------------------------------------------------------------------------------- 1 | /** 2 | * All of the CSS for your admin-specific functionality should be 3 | * included in this file. 4 | */ 5 | 6 | .forminp span.description { 7 | display: block; 8 | } 9 | 10 | .ddwc-driver-picture { 11 | display: inline-block; 12 | margin-right: 12px; 13 | position: relative; 14 | width: 140px; 15 | } 16 | 17 | .ddwc-remove-driver-picture { 18 | background: #f00; 19 | border: 0; 20 | border-radius: 50%; 21 | color: #fff; 22 | font-family: 'Helvetica', Arial, sans-serif; 23 | font-size: 14px; 24 | font-weight: 700; 25 | line-height: 1px; 26 | padding: 10px 6.61px; 27 | position: absolute; 28 | right: -5px; 29 | top: -5px; 30 | text-align: center; 31 | } 32 | 33 | .ddwc-remove-driver-picture:hover { 34 | background: #df0000; 35 | color: #fff; 36 | cursor: pointer; 37 | } 38 | 39 | .ddwc-driver-picture img { 40 | height: auto; 41 | } 42 | 43 | .wp-core-ui select#ddwc_driver_transportation_type { 44 | width: 22rem; 45 | } 46 | -------------------------------------------------------------------------------- /includes/class-ddwc-deactivator.php: -------------------------------------------------------------------------------- 1 | 9 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 10 | * @link https://www.deviodigital.com 11 | * @since 1.0.0 12 | */ 13 | 14 | /** 15 | * Fired during plugin deactivation. 16 | * 17 | * This class defines all code necessary to run during the plugin's deactivation. 18 | * 19 | * @package DDWC 20 | * @subpackage DDWC/includes 21 | * @author Devio Digital 22 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 23 | * @link https://www.deviodigital.com 24 | * @since 1.0.0 25 | */ 26 | class Delivery_Drivers_Deactivator { 27 | 28 | /** 29 | * Run on plugin deactivation 30 | * 31 | * @since 1.0.0 32 | * @return void 33 | */ 34 | public static function deactivate() { 35 | // Do something? 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /includes/class-ddwc-activator.php: -------------------------------------------------------------------------------- 1 | 9 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 10 | * @link https://www.deviodigital.com 11 | * @since 1.0.0 12 | */ 13 | 14 | /** 15 | * Fired during plugin activation. 16 | * 17 | * This class defines all code necessary to run during the plugin's activation. 18 | * 19 | * @package DDWC 20 | * @subpackage DDWC/includes 21 | * @author Devio Digital 22 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 23 | * @link https://www.deviodigital.com 24 | * @since 1.0.0 25 | */ 26 | class Delivery_Drivers_Activator { 27 | 28 | /** 29 | * Run on plugin activation 30 | * 31 | * @since 1.0.0 32 | * @return void 33 | */ 34 | public static function activate() { 35 | /** 36 | * Create Delivery Driver user role 37 | * 38 | * @since 1.0 39 | */ 40 | add_role( 'driver', __( 'Delivery Driver', 'delivery-drivers-for-woocommerce' ), array( 'read' => true, 'edit_posts' => false, 'delete_posts' => false ) ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /public/js/customer-signature-script.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function ($) { 2 | // Initialize SignaturePad. 3 | var canvas = document.getElementById('signature-canvas'); 4 | var signaturePad = new SignaturePad(canvas); 5 | 6 | // Clear Signature Button. 7 | $('#clear-signature').on('click', function (e) { 8 | e.preventDefault(); 9 | signaturePad.clear(); 10 | }); 11 | 12 | // Save Signature Data on Custom Button Click. 13 | $('#save-signature-button').on('click', function (e) { 14 | e.preventDefault(); 15 | var signatureData = signaturePad.toDataURL(); 16 | saveSignatureToOrder(signatureData); 17 | }); 18 | 19 | // Load Saved Signature on Order Details Page. 20 | if (script.order_id && $('#customer-signature').val()) { 21 | var savedSignature = $('#customer-signature').val(); 22 | signaturePad.fromDataURL(savedSignature); 23 | } 24 | }); 25 | 26 | // Function to Save Signature to Order. 27 | function saveSignatureToOrder(signatureData) { 28 | var orderId = script.order_id; 29 | var data = { 30 | action: 'save_customer_signature', 31 | order_id: orderId, 32 | customer_signature: signatureData, 33 | }; 34 | 35 | $.post(script.ajax_url, data, function (response) { 36 | console.log(response); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /includes/class-ddwc-i18n.php: -------------------------------------------------------------------------------- 1 | 12 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 13 | * @link https://www.deviodigital.com 14 | * @since 1.0.0 15 | */ 16 | 17 | /** 18 | * Define the internationalization functionality. 19 | * 20 | * Loads and defines the internationalization files for this plugin 21 | * so that it is ready for translation. 22 | * 23 | * @package DDWC 24 | * @subpackage DDWC/includes 25 | * @author Devio Digital 26 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 27 | * @link https://www.deviodigital.com 28 | * @since 1.0.0 29 | */ 30 | class Delivery_Drivers_i18n { 31 | 32 | /** 33 | * Load the plugin text domain for translation. 34 | * 35 | * @since 1.0.0 36 | * @return void 37 | */ 38 | public function load_plugin_textdomain() { 39 | 40 | load_plugin_textdomain( 41 | 'delivery-drivers-for-woocommerce', 42 | false, 43 | dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/' 44 | ); 45 | 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Delivery Drivers for WooCommerce](https://robertdevore.com/wp-content/uploads/2018/09/ddwc-logo.png) 2 | 3 | Brought to you by [Devio Digital](https://deviodigital.com) - [Release Notes](https://robertdevore.com/delivery-drivers-for-woocommerce/) - [Go Pro](https://deviodigital.com/product/delivery-drivers-for-woocommerce-pro/) 4 | 5 | ## Manage your mobile workforce 6 | 7 | Delivery Drivers for WooCommerce offers better driver management for all delivery services who use WooCommerce. 8 | 9 | Your business benefits from this plugin by giving your drivers the ability to easily connect with both the customer of the order and your dispatch center. 10 | 11 | Time saved is money earned. 12 | 13 | ### Get more done 14 | 15 | The Delivery Drivers for WooCommerce plugin helps your business by reducing paperwork, communications and other manual tasks that eat up your time. 16 | 17 | ### Manage your drivers 18 | 19 | This plugin gives you the ability to add new users with the designated `Driver` role to your WordPress site. 20 | 21 | Once the driver has been added to your userlist, you can edit orders and assign a specific driver to the order. 22 | 23 | ### Driver capabilites 24 | 25 | Give your drivers the ability to view their assigned orders, mark an order as `Out for Delivery` and then `Completed` after the order has been delivered. 26 | 27 | With these capabilities passed along to your drivers, you now have additional time free to manage other areas of your business. 28 | 29 | ## For any mobile workforce 30 | 31 | Below are a few examples of delivery services that can benefit from the **Delivery Drivers for WooCommerce** plugin. 32 | 33 | * Cannabis 34 | * Flowers 35 | * Health & Beauty 36 | * Mobile Massage 37 | * Alcohol Delivery 38 | * Restaurant 39 | * Grocery Stores 40 | * Healthcare 41 | * Cleaning 42 | * Laundry 43 | * Mechanics 44 | * ... and more! 45 | 46 | ## Pro Features 47 | 48 | [Delivery Drivers for WooCommerce Pro](https://deviodigital.com/product/delivery-drivers-for-woocommerce-pro/) includes the following additional features: 49 | 50 | * Auto-assign drivers when an order is submitted 51 | * Accept driver applications from the Driver Dashboard 52 | * Integration with [Twilio](https://www.twilio.com) for SMS messages 53 | * Email/SMS driver when they've been assigned a new order 54 | * Email/SMS customer when the driver marks an order as "Out for Delivery" 55 | * Email/SMS administrator when the driver marks an order as "Completed" 56 | 57 | ## Changelog 58 | 59 | View [CHANGELOG.md](https://github.com/robertdevore/delivery-drivers-for-woocommerce/blob/master/CHANGELOG.md) -------------------------------------------------------------------------------- /admin/ddwc-woocommerce-account-tab.php: -------------------------------------------------------------------------------- 1 | 9 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 10 | * @link https://www.deviodigital.com 11 | * @since 1.0.0 12 | */ 13 | 14 | /** 15 | * Register new endpoint to use inside My Account page. 16 | * 17 | * @see https://developer.wordpress.org/reference/functions/add_rewrite_endpoint/ 18 | * @return void 19 | */ 20 | function ddwc_endpoints() { 21 | add_rewrite_endpoint( 'driver-dashboard', EP_ROOT | EP_PAGES ); 22 | } 23 | add_action( 'init', 'ddwc_endpoints' ); 24 | 25 | /** 26 | * Add new query var. 27 | * 28 | * @param array $vars 29 | * 30 | * @since 1.2 31 | * @return array 32 | */ 33 | add_filter( 'woocommerce_get_query_vars', function ( $vars ) { 34 | foreach ( ['driver-dashboard'] as $e ) { 35 | $vars[$e] = $e; 36 | } 37 | return $vars; 38 | } ); 39 | 40 | /** 41 | * Flush rewrite rules. 42 | * 43 | * @return void 44 | */ 45 | function ddwc_flush_rewrite_rules() { 46 | add_rewrite_endpoint( 'driver-dashboard', EP_ROOT | EP_PAGES ); 47 | flush_rewrite_rules(); 48 | } 49 | register_activation_hook( __FILE__, 'ddwc_flush_rewrite_rules' ); 50 | 51 | /** 52 | * Insert the new endpoint into the My Account menu. 53 | * 54 | * @param array $items 55 | * 56 | * @return array 57 | */ 58 | function ddwc_my_account_menu_items( $items ) { 59 | // Get customer-logout menu item. 60 | $logout = $items['customer-logout']; 61 | // Remove the customer-logout menu item. 62 | unset( $items['customer-logout'] ); 63 | // Set user roles. 64 | $roles = array( 'administrator', 'driver' ); 65 | // Check user role. 66 | if ( ddwc_check_user_roles( apply_filters( 'ddwc_my_account_check_user_role_array', $roles ) ) ) { 67 | // Insert the driver-dashboard endpoint. 68 | $items['driver-dashboard'] = apply_filters( 'ddwc_my_account_menu_item_driver_dashboard', esc_attr__( 'Driver Dashboard', 'delivery-drivers-for-woocommerce' ) ); 69 | } 70 | // Insert back the customer-logout item. 71 | $items['customer-logout'] = $logout; 72 | 73 | return $items; 74 | } 75 | add_filter( 'woocommerce_account_menu_items', 'ddwc_my_account_menu_items' ); 76 | 77 | /** 78 | * Endpoint HTML content. 79 | * 80 | * @return string 81 | */ 82 | function ddwc_endpoint_content() { 83 | echo do_shortcode( '[ddwc_dashboard]' ); 84 | } 85 | add_action( 'woocommerce_account_driver-dashboard_endpoint', 'ddwc_endpoint_content', 99, 1 ); 86 | 87 | /** 88 | * Change endpoint title. 89 | * 90 | * @param string $title 91 | * 92 | * @return string 93 | */ 94 | function ddwc_endpoint_title( $title ) { 95 | // Change title on driver dashboard page. 96 | if ( is_wc_endpoint_url( 'driver-dashboard' ) && in_the_loop() ) { 97 | $title = apply_filters( 'ddwc_my_account_endpoint_title_driver_dashboard', esc_attr__( 'Driver Dashboard', 'ddwc-pro' ) ); 98 | } 99 | return $title; 100 | } 101 | add_filter( 'the_title', 'ddwc_endpoint_title', 10, 1 ); 102 | -------------------------------------------------------------------------------- /admin/ddwc-woocommerce-orders.php: -------------------------------------------------------------------------------- 1 | 9 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 10 | * @link https://www.deviodigital.com 11 | * @since 1.0.0 12 | */ 13 | 14 | /** 15 | * Registering Returned post status 16 | * 17 | * @since 2.5 18 | * @return void 19 | */ 20 | function ddwc_register_order_returned_order_status() { 21 | register_post_status( 'wc-order-returned', array( 22 | 'label' => esc_attr__( 'Order Returned', 'delivery-drivers-for-woocommerce' ), 23 | 'public' => true, 24 | 'show_in_admin_status_list' => true, 25 | 'show_in_admin_all_list' => true, 26 | 'exclude_from_search' => false, 27 | 'label_count' => _n_noop( 'Returned (%s)', 'Returned (%s)' ) 28 | ) ); 29 | } 30 | add_action( 'init', 'ddwc_register_order_returned_order_status' ); 31 | 32 | /** 33 | * Registering Out for Delivery post status 34 | * 35 | * @since 1.0 36 | * @return void 37 | */ 38 | function ddwc_register_out_for_delivery_order_status() { 39 | register_post_status( 'wc-out-for-delivery', array( 40 | 'label' => esc_attr__( 'Out for Delivery', 'delivery-drivers-for-woocommerce' ), 41 | 'public' => true, 42 | 'show_in_admin_status_list' => true, 43 | 'show_in_admin_all_list' => true, 44 | 'exclude_from_search' => false, 45 | 'label_count' => _n_noop( 'Out for Delivery (%s)', 'Out for Delivery (%s)' ) 46 | ) ); 47 | } 48 | add_action( 'init', 'ddwc_register_out_for_delivery_order_status' ); 49 | 50 | /** 51 | * Registering Driver Assigned post status 52 | * 53 | * @since 1.0 54 | * @return void 55 | */ 56 | function ddwc_register_driver_assigned_order_status() { 57 | register_post_status( 'wc-driver-assigned', array( 58 | 'label' => esc_attr__( 'Driver Assigned', 'delivery-drivers-for-woocommerce' ), 59 | 'public' => true, 60 | 'show_in_admin_status_list' => true, 61 | 'show_in_admin_all_list' => true, 62 | 'exclude_from_search' => false, 63 | 'label_count' => _n_noop( 'Driver Assigned (%s)', 'Driver Assigned (%s)' ) 64 | ) ); 65 | } 66 | add_action( 'init', 'ddwc_register_driver_assigned_order_status' ); 67 | 68 | /** 69 | * Add Custom Statuses to the order status list. 70 | * 71 | * @param array $order_statuses 72 | * 73 | * @since 1.0 74 | * @return array 75 | */ 76 | function ddwc_add_custom_order_statuses( $order_statuses ) { 77 | // Create new status array. 78 | $new_order_statuses = array(); 79 | // Loop though statuses. 80 | foreach ( $order_statuses as $key => $status ) { 81 | // Add status to our new statuses. 82 | $new_order_statuses[ $key ] = $status; 83 | // Add our custom statuses. 84 | if ( 'wc-processing' === $key ) { 85 | $new_order_statuses['wc-driver-assigned'] = esc_attr__( 'Driver Assigned', 'delivery-drivers-for-woocommerce' ); 86 | $new_order_statuses['wc-out-for-delivery'] = esc_attr__( 'Out for Delivery', 'delivery-drivers-for-woocommerce' ); 87 | $new_order_statuses['wc-order-returned'] = esc_attr__( 'Order Returned', 'delivery-drivers-for-woocommerce' ); 88 | } 89 | } 90 | 91 | return $new_order_statuses; 92 | } 93 | add_filter( 'wc_order_statuses', 'ddwc_add_custom_order_statuses' ); 94 | -------------------------------------------------------------------------------- /public/class-ddwc-public.php: -------------------------------------------------------------------------------- 1 | 8 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 9 | * @link https://www.deviodigital.com 10 | * @since 1.0.0 11 | */ 12 | 13 | /** 14 | * The public-facing functionality of the plugin. 15 | * 16 | * Defines the plugin name, version, and two examples hooks for how to 17 | * enqueue the public-facing stylesheet and JavaScript. 18 | * 19 | * @package DDWC 20 | * @subpackage DDWC/public 21 | * @author Devio Digital 22 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 23 | * @link https://www.deviodigital.com 24 | * @since 1.0.0 25 | */ 26 | class Delivery_Drivers_Public { 27 | 28 | /** 29 | * The ID of this plugin. 30 | * 31 | * @since 1.0.0 32 | * @access private 33 | * @var string $_plugin_name The ID of this plugin. 34 | */ 35 | private $_plugin_name; 36 | 37 | /** 38 | * The version of this plugin. 39 | * 40 | * @since 1.0.0 41 | * @access private 42 | * @var string $_version The current version of this plugin. 43 | */ 44 | private $_version; 45 | 46 | /** 47 | * Initialize the class and set its properties. 48 | * 49 | * @param string $_plugin_name The name of the plugin. 50 | * @param string $_version The version of this plugin. 51 | * 52 | * @since 1.0.0 53 | * @return void 54 | */ 55 | public function __construct( $_plugin_name, $_version ) { 56 | 57 | $this->plugin_name = $_plugin_name; 58 | $this->version = $_version; 59 | 60 | } 61 | 62 | /** 63 | * Register the stylesheets for the public-facing side of the site. 64 | * 65 | * @since 1.0.0 66 | * @return void 67 | */ 68 | public function enqueue_styles() { 69 | // Stylesheet. 70 | wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/ddwc-public.min.css', array(), $this->version, 'all' ); 71 | wp_enqueue_style( $this->plugin_name . '-fontawesome', plugin_dir_url( __FILE__ ) . 'css/fontawesome/all.min.css', array(), $this->version, 'all' ); 72 | } 73 | 74 | /** 75 | * Register the JavaScript for the public-facing side of the site. 76 | * 77 | * @since 1.0.0 78 | * @return void 79 | */ 80 | public function enqueue_scripts() { 81 | // Only load scripts on customer order pages. 82 | if ( is_wc_endpoint_url( 'view-order' ) ) { 83 | wp_enqueue_script( $this->plugin_name . '-star-rating', 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js', array( 'jquery' ), $this->version, false ); 84 | wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/ddwc-public.js', array( 'jquery' ), $this->version, false ); 85 | } elseif ( is_wc_endpoint_url( 'driver-dashboard' ) ) { 86 | wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/ddwc-public.js', array( 'jquery' ), $this->version, false ); 87 | } 88 | // Localize the ddwc-public.js file. 89 | wp_localize_script( $this->plugin_name, 'WPaAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) ); 90 | 91 | if ( is_wc_endpoint_url( 'view-order' ) ) { 92 | 93 | $order_id = absint( get_query_var( 'view-order' ) ); 94 | 95 | // Enqueue SignaturePad library. 96 | wp_enqueue_script( 'signature-pad', plugin_dir_url( __FILE__ ) . 'js/signature-pad.js', array( 'jquery' ), $this->version, true ); 97 | 98 | // Enqueue custom script for signature functionality. 99 | wp_enqueue_script( 'customer-signature-script', plugin_dir_url( __FILE__ ) . '/js/customer-signature-script.js', array( 'jquery', 'signature-pad' ), $this->version, true ); 100 | 101 | // Localize script with order ID for custom script. 102 | wp_localize_script( 'customer-signature-script', 'script', array( 'order_id' => $order_id, 'ajax_url' => admin_url( 'admin-ajax.php' ) ) ); 103 | } 104 | } 105 | 106 | } 107 | 108 | /** 109 | * Driver availability option on Driver Dashboard 110 | * 111 | * @since 2.3 112 | * @return string 113 | */ 114 | function ddwc_driver_dashboard_driver_availability() { 115 | // Checked. 116 | $checked = ''; 117 | // Driver availability. 118 | if ( 'on' === get_user_meta( get_current_user_id(), 'ddwc_driver_availability', true ) ) { 119 | $checked = 'checked'; 120 | } 121 | 122 | echo '
123 |

' . esc_attr__( 'Accepting deliveries', 'delivery-drivers-for-woocommerce' ) . '

124 | 128 |
'; 129 | } 130 | add_action( 'ddwc_driver_dashboard_top', 'ddwc_driver_dashboard_driver_availability' ); 131 | -------------------------------------------------------------------------------- /delivery-drivers-for-woocommerce.php: -------------------------------------------------------------------------------- 1 | 8 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 9 | * @link https://www.deviodigital.com 10 | * 11 | * @wordpress-plugin 12 | * Plugin Name: Delivery Drivers for WooCommerce 13 | * Plugin URI: https://www.deviodigital.com 14 | * Description: Streamline your mobile workforce & increase your bottom line 15 | * Version: 3.6.1 16 | * Author: Devio Digital 17 | * Author URI: https://www.deviodigital.com 18 | * License: GPL-2.0+ 19 | * License URI: http://www.gnu.org/licenses/gpl-2.0.txt 20 | * Text Domain: delivery-drivers-for-woocommerce 21 | * Domain Path: /languages 22 | * WC requires at least: 3.5.0 23 | * WC tested up to: 8.5.1 24 | */ 25 | 26 | // If this file is called directly, abort. 27 | if ( ! defined( 'WPINC' ) ) { 28 | die; 29 | } 30 | 31 | /** 32 | * Current plugin version. 33 | */ 34 | define( 'DDWC_VERSION', '3.6.1' ); 35 | 36 | /** 37 | * The code that runs during plugin activation. 38 | * This action is documented in includes/class-ddwc-activator.php 39 | * 40 | * @return void 41 | */ 42 | function activate_ddwc() { 43 | require_once plugin_dir_path( __FILE__ ) . 'includes/class-ddwc-activator.php'; 44 | Delivery_Drivers_Activator::activate(); 45 | } 46 | 47 | /** 48 | * The code that runs during plugin deactivation. 49 | * This action is documented in includes/class-ddwc-deactivator.php 50 | * 51 | * @return void 52 | */ 53 | function deactivate_ddwc() { 54 | require_once plugin_dir_path( __FILE__ ) . 'includes/class-ddwc-deactivator.php'; 55 | Delivery_Drivers_Deactivator::deactivate(); 56 | } 57 | 58 | register_activation_hook( __FILE__, 'activate_ddwc' ); 59 | register_deactivation_hook( __FILE__, 'deactivate_ddwc' ); 60 | 61 | /** 62 | * The core plugin class that is used to define internationalization, 63 | * admin-specific hooks, and public-facing site hooks. 64 | */ 65 | require plugin_dir_path( __FILE__ ) . 'includes/class-ddwc.php'; 66 | 67 | /** 68 | * Begins execution of the plugin. 69 | * 70 | * Since everything within the plugin is registered via hooks, 71 | * then kicking off the plugin from this point in the file does 72 | * not affect the page life cycle. 73 | * 74 | * @since 1.0.0 75 | * @return void 76 | */ 77 | function run_ddwc() { 78 | 79 | $plugin = new DDWC(); 80 | $plugin->run(); 81 | 82 | } 83 | run_ddwc(); 84 | 85 | // Create variable for settings link filter. 86 | $plugin_name = plugin_basename( __FILE__ ); 87 | 88 | /** 89 | * Add settings link on plugin page 90 | * 91 | * @param array $links an array of links related to the plugin. 92 | * 93 | * @since 1.0.3 94 | * @return array updatead array of links related to the plugin. 95 | */ 96 | function ddwc_settings_link( $links ) { 97 | // Pro link. 98 | $pro_link = '' . esc_attr__( 'Go Pro', 'delivery-drivers-for-woocommerce' ) . ''; 99 | // Settings link. 100 | $settings_link = '' . esc_html__( 'Settings', 'delivery-drivers-for-woocommerce' ) . ''; 101 | 102 | array_unshift( $links, $settings_link ); 103 | if ( ! function_exists( 'ddwc_pro_all_settings' ) ) { 104 | array_unshift( $links, $pro_link ); 105 | } 106 | return $links; 107 | } 108 | add_filter( "plugin_action_links_$plugin_name", 'ddwc_settings_link' ); 109 | 110 | /** 111 | * Check DDWC Pro version number. 112 | * 113 | * If the DDWC Pro version number is less than what's defined below, there will 114 | * be a notice added to the admin screen letting the user know there's a new 115 | * version of the DDWC Pro plugin available. 116 | * 117 | * @since 2.9 118 | * @return void 119 | */ 120 | function ddwc_check_pro_version() { 121 | // Only run if DDWC Pro is active. 122 | if ( function_exists( 'ddwc_pro_all_settings' ) ) { 123 | // Check if DDWC Pro version is defined. 124 | if ( ! defined( 'DDWC_PRO_VERSION' ) ) { 125 | define( 'DDWC_PRO_VERSION', 0 ); // default to zero. 126 | } 127 | // Set pro version number. 128 | $pro_version = DDWC_PRO_VERSION; 129 | if ( '0' == $pro_version || $pro_version < '2.3.1' ) { 130 | add_action( 'admin_notices', 'ddwc_update_ddwc_pro_notice' ); 131 | } 132 | } 133 | } 134 | add_action( 'admin_init', 'ddwc_check_pro_version' ); 135 | 136 | /** 137 | * Error notice - Runs if DDWC Pro is out of date. 138 | * 139 | * @see ddwc_check_pro_version() 140 | * @since 2.9 141 | * @return string 142 | */ 143 | function ddwc_update_ddwc_pro_notice() { 144 | $ddwc_orders = '' . esc_html__( 'Orders', 'delivery-drivers-for-woocommerce' ) . ''; 145 | $error = sprintf( __( 'There is a new version of DDWC Pro available. Download your copy from the %1$s page on Devio Digital.', 'delivery-drivers-for-woocommerce' ), $ddwc_orders ); 146 | echo '

' . $error . '

'; 147 | } 148 | -------------------------------------------------------------------------------- /admin/ddwc-metaboxes.php: -------------------------------------------------------------------------------- 1 | 9 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 10 | * @link https://www.deviodigital.com 11 | * @since 1.0.0 12 | */ 13 | 14 | /** 15 | * Order Details metabox 16 | * 17 | * Adds the order details metabox. 18 | * 19 | * @since 1.0 20 | * @return void 21 | */ 22 | function ddwc_metaboxes() { 23 | add_meta_box( 24 | 'ddwc_metaboxes', 25 | esc_attr__( 'Delivery Driver', 'delivery-drivers-for-woocommerce' ), 26 | 'ddwc_build', 27 | 'shop_order', 28 | 'side', 29 | 'default' 30 | ); 31 | } 32 | add_action( 'add_meta_boxes', 'ddwc_metaboxes' ); 33 | 34 | /** 35 | * Building the metabox 36 | * 37 | * @return string 38 | */ 39 | function ddwc_build() { 40 | global $post; 41 | 42 | // Noncename needed to verify where the data originated. 43 | echo ''; 45 | 46 | // Get the driver data if its already been entered. 47 | $ddwc_driver_id = get_post_meta( $post->ID, 'ddwc_driver_id', true ); 48 | 49 | // Echo Delivery Driver Metabox Input Field. 50 | echo '
'; 51 | wp_dropdown_users( array( 52 | 'show_option_none' => '--', 53 | 'role' => 'driver', 54 | 'name' => 'ddwc_driver_id', 55 | 'id' => 'ddwc_driver_id', 56 | 'selected' => $ddwc_driver_id, 57 | 'class' => 'widefat', 58 | 'show' => 'display_name' 59 | ) ); 60 | echo '
'; 61 | 62 | // Get driver rating. 63 | $ddwc_driver_rating = get_post_meta( $post->ID, 'ddwc_delivery_rating', true ); 64 | // Get driver phone number. 65 | $ddwc_driver_number = get_user_meta( $ddwc_driver_id, 'billing_phone', true ); 66 | echo '

'; 67 | // Display driver button. 68 | if ( ! empty( $ddwc_driver_number ) && '-1' != $ddwc_driver_id ) { 69 | echo '' . esc_attr__( 'Call Driver', 'delivery-drivers-for-woocommerce' ) . ' '; 70 | } 71 | echo '' . esc_attr__( 'View Profile', 'delivery-drivers-for-woocommerce' ) . ''; 72 | echo '

'; 73 | // Display driver rating. 74 | if ( ! empty( $ddwc_driver_rating ) ) { 75 | // Star icon. 76 | $star = ''; 77 | // Delivery rating. 78 | echo '

' . esc_attr__( 'Customer rating', 'delivery-drivers-for-woocommerce' ) . ': ' . str_repeat( $star, $ddwc_driver_rating ) . '

'; 79 | } 80 | } 81 | 82 | /** 83 | * Save the Metabox Data 84 | * 85 | * @param int $post_id 86 | * 87 | * @return void 88 | */ 89 | function ddwc_driver_save_order_details( $post_id ) { 90 | // Verify nonce. 91 | if ( ! isset( $_POST['ddwc_meta_noncename'] ) || ! wp_verify_nonce( $_POST['ddwc_meta_noncename'], plugin_basename( __FILE__ ) ) ) { 92 | return; 93 | } 94 | 95 | // Check if user has permission to edit post. 96 | if ( ! current_user_can( 'edit_post', $post_id ) ) { 97 | return; 98 | } 99 | 100 | // Get driver ID. 101 | $ddwc_driver_id = isset( $_POST['ddwc_driver_id'] ) ? $_POST['ddwc_driver_id'] : ''; 102 | 103 | // Get the current driver ID. 104 | $current_driver_id = get_post_meta( $post_id, 'ddwc_driver_id', true ); 105 | 106 | // Save driver ID. 107 | if ( -1 != $ddwc_driver_id ) { 108 | update_post_meta( $post_id, 'ddwc_driver_id', $ddwc_driver_id ); 109 | 110 | // Get the driver name. 111 | $driver_name = ''; 112 | if ( ! empty( $ddwc_driver_id ) && '-1' != $ddwc_driver_id ) { 113 | $driver_name = get_the_author_meta( 'display_name', $ddwc_driver_id ); 114 | } 115 | 116 | // If the driver data is different than the current driver, add a note to the order. 117 | if ( $ddwc_driver_id != $current_driver_id ) { 118 | $note = sprintf( esc_html__( 'Delivery driver changed to %s', 'delivery-drivers-for-woocommerce' ), $driver_name ); 119 | $order = wc_get_order( $post_id ); 120 | $order->add_order_note( $note ); 121 | 122 | // If the driver ID goes from none to any driver, update order status to processing. 123 | if ( empty( $current_driver_id ) && ! empty( $ddwc_driver_id ) ) { 124 | $order->update_status( 'driver-assigned' ); 125 | } 126 | } 127 | } elseif ( -1 == $ddwc_driver_id ) { 128 | // Only run if current driver ID isn't empty. 129 | if ( '' != $current_driver_id ) { 130 | // Delete driver ID and add note that driver was removed. 131 | delete_post_meta( $post_id, 'ddwc_driver_id' ); 132 | // Create the order note. 133 | $note = esc_html__( 'Delivery driver removed', 'delivery-drivers-for-woocommerce' ); 134 | $order = wc_get_order( $post_id ); 135 | // Add the order note. 136 | $order->add_order_note( $note ); 137 | // Update the order status. 138 | $order->update_status( 'processing' ); 139 | } 140 | } 141 | } 142 | add_action( 'save_post', 'ddwc_driver_save_order_details', 10, 1 ); 143 | -------------------------------------------------------------------------------- /public/ddwc-customer-signature-script.php: -------------------------------------------------------------------------------- 1 | 9 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 10 | * @link https://www.deviodigital.com 11 | * @since 3.6.0 12 | */ 13 | 14 | // If this file is called directly, abort. 15 | if ( ! defined( 'WPINC' ) ) { 16 | wp_die(); 17 | } 18 | 19 | /** 20 | * Add Signature Box to Order Page 21 | * 22 | * @since 3.6.0 23 | * @return void 24 | */ 25 | function add_signature_box_to_order_page( $order ) { 26 | // Get order data. 27 | $order_data = $order->get_data(); 28 | // Get the current order. 29 | $order_status = $order_data['status']; 30 | // Check if the order status is "out-for-delivery" or "completed". 31 | if ( $order && in_array( $order_status, apply_filters( 'ddwc_customer_signature_box_order_status', array( 'out-for-delivery', 'completed' ) ) ) ) { 32 | $signature = get_post_meta( $order->get_id(), 'customer_signature', true ); 33 | if ( ! $signature ) { 34 | echo '
35 |

' . apply_filters( 'ddwc_customer_signature_box_title', __( 'Signature box', 'delivery-drivers-for-woocommerce' ) ) . '

36 |

' . apply_filters( 'ddwc_customer_signature_box_description', __( 'Please sign below to acknowledge you received the order via delivery', 'delivery-drivers-for-woocommerce' ) ) . ':

37 |
38 | 39 | 40 | 41 |
'; 42 | } 43 | } 44 | } 45 | add_action( 'woocommerce_order_details_after_order_table', 'add_signature_box_to_order_page' ); 46 | 47 | /** 48 | * Display Signature on Order Admin Page 49 | * 50 | * @param object $order - 51 | * 52 | * @since 3.6.0 53 | * @return void 54 | */ 55 | function display_customer_signature_on_admin_page( $order ) { 56 | $signature = get_post_meta( $order->get_id(), 'customer_signature', true ); 57 | echo '

' . __( 'Customer Signature', 'delivery-drivers-for-woocommerce' ) . ':

'; 58 | ddwc_display_customer_signature_image( $order->get_id() ); 59 | } 60 | add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_customer_signature_on_admin_page' ); 61 | 62 | /** 63 | * Save Signature Field on Order 64 | * 65 | * @since 3.6.0 66 | * @return void 67 | */ 68 | function ddwc_ajax_save_customer_signature() { 69 | if ( isset( $_POST['action'] ) && $_POST['action'] === 'save_customer_signature' ) { 70 | $order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0; 71 | $signature = isset( $_POST['customer_signature'] ) ? sanitize_text_field( $_POST['customer_signature'] ) : ''; 72 | 73 | if ( $order_id && $signature ) { 74 | // Convert base64-encoded signature to image and save as attachment 75 | $attachment_id = ddwc_save_signature_image( $order_id, $signature ); 76 | 77 | // Save the signature field value. 78 | update_post_meta( $order_id, 'customer_signature', $attachment_id ); 79 | 80 | // Update order status to completed. 81 | $order = wc_get_order( $order_id ); 82 | if ( $order ) { 83 | $order->update_status( 'completed', 'Order marked as completed.', true ); 84 | } 85 | 86 | echo 'Signature saved successfully.'; 87 | } else { 88 | echo 'Error: Invalid order ID or signature data.'; 89 | } 90 | 91 | exit(); 92 | } 93 | } 94 | add_action( 'wp_ajax_save_customer_signature', 'ddwc_ajax_save_customer_signature' ); 95 | 96 | /** 97 | * Save signature image 98 | * 99 | * @since 3.6.0 100 | * @return void 101 | */ 102 | function ddwc_save_signature_image( $order_id, $signature ) { 103 | $upload_dir = wp_upload_dir(); 104 | 105 | // Create a unique filename for the signature image 106 | $filename = 'signature_' . $order_id . '_' . md5( $signature ) . '.png'; 107 | $upload_path = $upload_dir['path'] . '/' . $filename; 108 | 109 | // Decode the base64-encoded signature and save as an image file 110 | $image_data = base64_decode( str_replace( 'data:image/png;base64,', '', $signature ) ); 111 | file_put_contents( $upload_path, $image_data ); 112 | 113 | // Prepare attachment data 114 | $attachment = array( 115 | 'guid' => $upload_dir['url'] . '/' . $filename, 116 | 'post_mime_type' => 'image/png', 117 | 'post_title' => $filename, 118 | 'post_content' => '', 119 | 'post_status' => 'inherit', 120 | ); 121 | 122 | // Insert the attachment into the media library 123 | $attachment_id = wp_insert_attachment( $attachment, $upload_path, $order_id ); 124 | 125 | // Generate metadata for the attachment and update the database record 126 | $attachment_data = wp_generate_attachment_metadata( $attachment_id, $upload_path ); 127 | wp_update_attachment_metadata( $attachment_id, $attachment_data ); 128 | 129 | return $attachment_id; 130 | } 131 | -------------------------------------------------------------------------------- /admin/css/fontawesome/svg-with-js.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;-webkit-box-sizing:border-box;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom right;transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom left;transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top left;transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:solid .08em #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{-webkit-transform:scale(1,-1);transform:scale(1,-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1,-1);transform:scale(-1,-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2.5em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1.25em}.svg-inline--fa.fa-stack-2x{height:2em;width:2.5em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.svg-inline--fa .fa-primary{fill:var(--fa-primary-color,currentColor);opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa .fa-secondary{fill:var(--fa-secondary-color,currentColor);opacity:.4;opacity:var(--fa-secondary-opacity,.4)}.svg-inline--fa.fa-swap-opacity .fa-primary{opacity:.4;opacity:var(--fa-secondary-opacity,.4)}.svg-inline--fa.fa-swap-opacity .fa-secondary{opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa mask .fa-primary,.svg-inline--fa mask .fa-secondary{fill:#000}.fad.fa-inverse{color:#fff} -------------------------------------------------------------------------------- /includes/class-ddwc-loader.php: -------------------------------------------------------------------------------- 1 | 9 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 10 | * @link https://www.deviodigital.com 11 | * @since 1.0.0 12 | */ 13 | 14 | /** 15 | * Register all actions and filters for the plugin. 16 | * 17 | * Maintain a list of all hooks that are registered throughout 18 | * the plugin, and register them with the WordPress API. Call the 19 | * run function to execute the list of actions and filters. 20 | * 21 | * @package DDWC 22 | * @subpackage DDWC/includes 23 | * @author Devio Digital 24 | * @license GPL-2.0+ http://www.gnu.org/licenses/gpl-2.0.txt 25 | * @link https://www.deviodigital.com 26 | * @since 1.0.0 27 | */ 28 | class Delivery_Drivers_Loader { 29 | 30 | /** 31 | * The array of actions registered with WordPress. 32 | * 33 | * @since 1.0.0 34 | * @access protected 35 | * @var array $actions The actions registered with WordPress to fire when the plugin loads. 36 | */ 37 | protected $actions; 38 | 39 | /** 40 | * The array of filters registered with WordPress. 41 | * 42 | * @since 1.0.0 43 | * @access protected 44 | * @var array $filters The filters registered with WordPress to fire when the plugin loads. 45 | */ 46 | protected $filters; 47 | 48 | /** 49 | * Initialize the collections used to maintain the actions and filters. 50 | * 51 | * @since 1.0.0 52 | */ 53 | public function __construct() { 54 | 55 | $this->actions = array(); 56 | $this->filters = array(); 57 | 58 | } 59 | 60 | /** 61 | * Add a new action to the collection to be registered with WordPress. 62 | * 63 | * @param string $hook The name of the WordPress action that is being registered. 64 | * @param object $component A reference to the instance of the object on which the action is defined. 65 | * @param string $callback The name of the function definition on the $component. 66 | * @param int $priority Optional. The priority at which the function should be fired. Default is 10. 67 | * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1. 68 | * 69 | * @since 1.0.0 70 | * @return void 71 | */ 72 | public function add_action( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) { 73 | $this->actions = $this->add( $this->actions, $hook, $component, $callback, $priority, $accepted_args ); 74 | } 75 | 76 | /** 77 | * Add a new filter to the collection to be registered with WordPress. 78 | * 79 | * @param string $hook The name of the WordPress action that is being registered. 80 | * @param object $component A reference to the instance of the object on which the action is defined. 81 | * @param string $callback The name of the function definition on the $component. 82 | * @param int $priority Optional. The priority at which the function should be fired. Default is 10. 83 | * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1. 84 | * 85 | * @since 1.0.0 86 | * @return void 87 | */ 88 | public function add_filter( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) { 89 | $this->filters = $this->add( $this->filters, $hook, $component, $callback, $priority, $accepted_args ); 90 | } 91 | 92 | /** 93 | * A utility function that is used to register the actions and hooks into a single 94 | * collection. 95 | * 96 | * @param array $hooks The collection of hooks that is being registered (that is, actions or filters). 97 | * @param string $hook The name of the WordPress filter that is being registered. 98 | * @param object $component A reference to the instance of the object on which the filter is defined. 99 | * @param string $callback The name of the function definition on the $component. 100 | * @param int $priority The priority at which the function should be fired. 101 | * @param int $accepted_args The number of arguments that should be passed to the $callback. 102 | * 103 | * @access private 104 | * @since 1.0.0 105 | * @return array The collection of actions and filters registered with WordPress. 106 | */ 107 | private function add( $hooks, $hook, $component, $callback, $priority, $accepted_args ) { 108 | 109 | $hooks[] = array( 110 | 'hook' => $hook, 111 | 'component' => $component, 112 | 'callback' => $callback, 113 | 'priority' => $priority, 114 | 'accepted_args' => $accepted_args 115 | ); 116 | 117 | return $hooks; 118 | } 119 | 120 | /** 121 | * Register the filters and actions with WordPress. 122 | * 123 | * @since 1.0.0 124 | * @return void 125 | */ 126 | public function run() { 127 | 128 | foreach ( $this->filters as $hook ) { 129 | add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] ); 130 | } 131 | 132 | foreach ( $this->actions as $hook ) { 133 | add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] ); 134 | } 135 | 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /public/css/fontawesome/svg-with-js.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;-webkit-box-sizing:border-box;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom right;transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom left;transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top left;transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:solid .08em #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{-webkit-transform:scale(1,-1);transform:scale(1,-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1,-1);transform:scale(-1,-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2.5em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1.25em}.svg-inline--fa.fa-stack-2x{height:2em;width:2.5em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.svg-inline--fa .fa-primary{fill:var(--fa-primary-color,currentColor);opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa .fa-secondary{fill:var(--fa-secondary-color,currentColor);opacity:.4;opacity:var(--fa-secondary-opacity,.4)}.svg-inline--fa.fa-swap-opacity .fa-primary{opacity:.4;opacity:var(--fa-secondary-opacity,.4)}.svg-inline--fa.fa-swap-opacity .fa-secondary{opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa mask .fa-primary,.svg-inline--fa mask .fa-secondary{fill:#000}.fad.fa-inverse{color:#fff} -------------------------------------------------------------------------------- /public/js/signature-pad.js: -------------------------------------------------------------------------------- 1 | !function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.SignaturePad=b()}):"object"==typeof exports?module.exports=b():a.SignaturePad=b()}(this,function(){/*! 2 | * Signature Pad v1.5.3 | https://github.com/szimek/signature_pad 3 | * (c) 2016 Szymon Nowak | Released under the MIT license 4 | */ 5 | var a=function(a){"use strict";var b=function(a,b){var c=this,d=b||{};this.velocityFilterWeight=d.velocityFilterWeight||.7,this.minWidth=d.minWidth||.5,this.maxWidth=d.maxWidth||2.5,this.dotSize=d.dotSize||function(){return(this.minWidth+this.maxWidth)/2},this.penColor=d.penColor||"black",this.backgroundColor=d.backgroundColor||"rgba(0,0,0,0)",this.onEnd=d.onEnd,this.onBegin=d.onBegin,this._canvas=a,this._ctx=a.getContext("2d"),this.clear(),this._handleMouseDown=function(a){1===a.which&&(c._mouseButtonDown=!0,c._strokeBegin(a))},this._handleMouseMove=function(a){c._mouseButtonDown&&c._strokeUpdate(a)},this._handleMouseUp=function(a){1===a.which&&c._mouseButtonDown&&(c._mouseButtonDown=!1,c._strokeEnd(a))},this._handleTouchStart=function(a){if(1==a.targetTouches.length){var b=a.changedTouches[0];c._strokeBegin(b)}},this._handleTouchMove=function(a){a.preventDefault();var b=a.targetTouches[0];c._strokeUpdate(b)},this._handleTouchEnd=function(a){var b=a.target===c._canvas;b&&(a.preventDefault(),c._strokeEnd(a))},this._handleMouseEvents(),this._handleTouchEvents()};b.prototype.clear=function(){var a=this._ctx,b=this._canvas;a.fillStyle=this.backgroundColor,a.clearRect(0,0,b.width,b.height),a.fillRect(0,0,b.width,b.height),this._reset()},b.prototype.toDataURL=function(){var a=this._canvas;return a.toDataURL.apply(a,arguments)},b.prototype.fromDataURL=function(a){var b=this,c=new Image,d=window.devicePixelRatio||1,e=this._canvas.width/d,f=this._canvas.height/d;this._reset(),c.src=a,c.onload=function(){b._ctx.drawImage(c,0,0,e,f)},this._isEmpty=!1},b.prototype._strokeUpdate=function(a){var b=this._createPoint(a);this._addPoint(b)},b.prototype._strokeBegin=function(a){this._reset(),this._strokeUpdate(a),"function"==typeof this.onBegin&&this.onBegin(a)},b.prototype._strokeDraw=function(a){var b=this._ctx,c="function"==typeof this.dotSize?this.dotSize():this.dotSize;b.beginPath(),this._drawPoint(a.x,a.y,c),b.closePath(),b.fill()},b.prototype._strokeEnd=function(a){var b=this.points.length>2,c=this.points[0];!b&&c&&this._strokeDraw(c),"function"==typeof this.onEnd&&this.onEnd(a)},b.prototype._handleMouseEvents=function(){this._mouseButtonDown=!1,this._canvas.addEventListener("mousedown",this._handleMouseDown),this._canvas.addEventListener("mousemove",this._handleMouseMove),a.addEventListener("mouseup",this._handleMouseUp)},b.prototype._handleTouchEvents=function(){this._canvas.style.msTouchAction="none",this._canvas.style.touchAction="none",this._canvas.addEventListener("touchstart",this._handleTouchStart),this._canvas.addEventListener("touchmove",this._handleTouchMove),this._canvas.addEventListener("touchend",this._handleTouchEnd)},b.prototype.on=function(){this._handleMouseEvents(),this._handleTouchEvents()},b.prototype.off=function(){this._canvas.removeEventListener("mousedown",this._handleMouseDown),this._canvas.removeEventListener("mousemove",this._handleMouseMove),a.removeEventListener("mouseup",this._handleMouseUp),this._canvas.removeEventListener("touchstart",this._handleTouchStart),this._canvas.removeEventListener("touchmove",this._handleTouchMove),this._canvas.removeEventListener("touchend",this._handleTouchEnd)},b.prototype.isEmpty=function(){return this._isEmpty},b.prototype._reset=function(){this.points=[],this._lastVelocity=0,this._lastWidth=(this.minWidth+this.maxWidth)/2,this._isEmpty=!0,this._ctx.fillStyle=this.penColor},b.prototype._createPoint=function(a){var b=this._canvas.getBoundingClientRect();return new c(a.clientX-b.left,a.clientY-b.top)},b.prototype._addPoint=function(a){var b,c,e,f,g=this.points;g.push(a),g.length>2&&(3===g.length&&g.unshift(g[0]),f=this._calculateCurveControlPoints(g[0],g[1],g[2]),b=f.c2,f=this._calculateCurveControlPoints(g[1],g[2],g[3]),c=f.c1,e=new d(g[1],b,c,g[2]),this._addCurve(e),g.shift())},b.prototype._calculateCurveControlPoints=function(a,b,d){var e=a.x-b.x,f=a.y-b.y,g=b.x-d.x,h=b.y-d.y,i={x:(a.x+b.x)/2,y:(a.y+b.y)/2},j={x:(b.x+d.x)/2,y:(b.y+d.y)/2},k=Math.sqrt(e*e+f*f),l=Math.sqrt(g*g+h*h),m=i.x-j.x,n=i.y-j.y,o=l/(k+l),p={x:j.x+m*o,y:j.y+n*o},q=b.x-p.x,r=b.y-p.y;return{c1:new c(i.x+q,i.y+r),c2:new c(j.x+q,j.y+r)}},b.prototype._addCurve=function(a){var b,c,d=a.startPoint,e=a.endPoint;b=e.velocityFrom(d),b=this.velocityFilterWeight*b+(1-this.velocityFilterWeight)*this._lastVelocity,c=this._strokeWidth(b),this._drawCurve(a,this._lastWidth,c),this._lastVelocity=b,this._lastWidth=c},b.prototype._drawPoint=function(a,b,c){var d=this._ctx;d.moveTo(a,b),d.arc(a,b,c,0,2*Math.PI,!1),this._isEmpty=!1},b.prototype._drawCurve=function(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o=this._ctx,p=c-b;for(d=Math.floor(a.length()),o.beginPath(),f=0;d>f;f++)g=f/d,h=g*g,i=h*g,j=1-g,k=j*j,l=k*j,m=l*a.startPoint.x,m+=3*k*g*a.control1.x,m+=3*j*h*a.control2.x,m+=i*a.endPoint.x,n=l*a.startPoint.y,n+=3*k*g*a.control1.y,n+=3*j*h*a.control2.y,n+=i*a.endPoint.y,e=b+i*p,this._drawPoint(m,n,e);o.closePath(),o.fill()},b.prototype._strokeWidth=function(a){return Math.max(this.maxWidth/(a+1),this.minWidth)};var c=function(a,b,c){this.x=a,this.y=b,this.time=c||(new Date).getTime()};c.prototype.velocityFrom=function(a){return this.time!==a.time?this.distanceTo(a)/(this.time-a.time):1},c.prototype.distanceTo=function(a){return Math.sqrt(Math.pow(this.x-a.x,2)+Math.pow(this.y-a.y,2))};var d=function(a,b,c,d){this.startPoint=a,this.control1=b,this.control2=c,this.endPoint=d};return d.prototype.length=function(){var a,b,c,d,e,f,g,h,i=10,j=0;for(a=0;i>=a;a++)b=a/i,c=this._point(b,this.startPoint.x,this.control1.x,this.control2.x,this.endPoint.x),d=this._point(b,this.startPoint.y,this.control1.y,this.control2.y,this.endPoint.y),a>0&&(g=c-e,h=d-f,j+=Math.sqrt(g*g+h*h)),e=c,f=d;return j},d.prototype._point=function(a,b,c,d,e){return b*(1-a)*(1-a)*(1-a)+3*c*(1-a)*(1-a)*a+3*d*(1-a)*a*a+e*a*a*a},b}(document);return a}); -------------------------------------------------------------------------------- /public/css/ddwc-public.min.css: -------------------------------------------------------------------------------- 1 | table.ddwc-dashboard{border:1px solid #ddd;width:100%}table.ddwc-dashboard.order-details{margin-bottom:24px}table.ddwc-dashboard thead{background:#f1f1f1;font-weight:700}table.ddwc-dashboard td{padding:10px}table.ddwc-dashboard .delivery-rating{color:#edb867}table.ddwc-dashboard tr{border-bottom:1px solid #f1f1f1}table.ddwc-dashboard tr:last-child{border-bottom:0}table.ddwc-dashboard tr.delivery-charge,table.ddwc-dashboard tr.order-total{background:#f1f1f1}.ddwc-dashboard{font-size:14px}h3.ddwc{margin-top:0;margin-bottom:24px;position:relative}h3.ddwc span{background:0 0;border-radius:3px;border:1px solid #454545;color:#454545;display:inline-block;font-size:16px;margin-left:10px;margin-top:0;padding:6px 12px;position:absolute;top:0;text-transform:uppercase}h3.ddwc span.completed{border-color:#76bd1d;color:#76bd1d;position:relative;display:inline-block}h3.ddwc span.out-for-delivery{color:#56a8c7;border-color:#56a8c7}h3.ddwc span.cancelled,h3.ddwc span.failed,h3.ddwc span.refunded{color:#c94c42;border-color:#c94c42}p.ddwc-map-api-error-msg{background:#c94c42;color:#fff;font-size:14px;padding:10px}p.ddwc-map-api-error-msg a,p.ddwc-map-api-error-msg a:visited{color:#fff;text-decoration:underline}p.ddwc-map-api-error-msg a:hover{color:#fff;text-decoration:none}a.button.ddwc-button{background:#222;padding:.75em 2em;border-radius:3px;color:#fff;font-weight:600}a.button.ddwc-button:active,a.button.ddwc-button:focus,a.button.ddwc-button:hover{background:#767676;color:#fff;border:0;box-shadow:none}.ddwc-display-options{font-size:14px;float:left;line-height:1;margin-bottom:12px;padding:5px;width:100%}.ddwc-driver-picture{position:relative;width:140px;display:inline-block;margin-right:12px}button.remove-ddwc-driver-picture{background:red;border:0;color:#fff;border-radius:50%;font-family:Helvetica,Arial,sans-serif;font-size:14px;font-weight:700;line-height:1px;padding:10px 6.61px;position:absolute;top:-5px;right:-5px;text-align:center}button.remove-ddwc-driver-picture:hover{background:#df0000;color:#fff}div.ddwc-driver-details{position:relative;float:left;width:100%;display:flex;justify-content:space-between;flex-wrap:wrap}.ddwc-driver-details-img{flex-basis:140px}.ddwc-driver-details-text{flex:1;padding-left:24px;position:relative}.ddwc-driver-details h2{flex-basis:100%}.ddwc-driver-details img,.ddwc-driver-picture img{float:left;height:auto;margin:0 12px 24px 0!important;width:140px}.ddwc-driver-details h4,.ddwc-driver-details p{margin-bottom:12px!important}.ddwc-driver-details-text h4,.entry-content .ddwc-driver-details-text h4{margin-top:0}.woocommerce-order-details :last-child,table.ddwc-driver-details{margin-bottom:12px!important}table.ddwc-driver-details{margin-top:12px}table.ddwc-driver-details tr td{padding:10px}.br-theme-fontawesome-stars .br-widget{height:28px;white-space:nowrap}.br-theme-fontawesome-stars .br-widget a{font:normal normal normal 20px/1 'Font Awesome 5 Free';text-rendering:auto;-webkit-font-smoothing:antialiased;text-decoration:none;margin-right:2px}.br-theme-fontawesome-stars .br-widget a::after{content:'\f005';color:#d2d2d2}.br-theme-fontawesome-stars .br-widget a.br-active::after{color:#edb867}.br-theme-fontawesome-stars .br-widget a.br-selected::after{color:#edb867}.br-theme-fontawesome-stars .br-widget .br-current-rating{display:none}.br-theme-fontawesome-stars .br-readonly a{cursor:default}@media print{.br-theme-fontawesome-stars .br-widget a::after{content:'\f006';color:#000}.br-theme-fontawesome-stars .br-widget a.br-active::after,.br-theme-fontawesome-stars .br-widget a.br-selected::after{content:'\f005';color:#000}}span.rating-tooltip{visibility:hidden;opacity:0;transition:visibility 0s,opacity .5s linear;padding:6px 0;font-size:13px;color:#000;position:absolute;left:auto;bottom:0}span.rating-tooltip.rated{visibility:visible;opacity:1}input.ddwc-ofdmsg{margin-bottom:12px;min-width:260px}.ddwc-orders form input[type=submit].ddwc-change-status{padding:.75em 1em}.ddwc-orders form input[type=submit].ddwc-change-status.order-returned{margin-right:12px}.ddwc-pro-sms-updates h3{font-size:24px;margin-bottom:12px}.ddwc-availability{background:#eee;border:1px solid #ddd;padding:5px;margin-bottom:24px}@media screen and (max-width:767px){.ddwc-availability{margin-top:24px}}.ddwc-availability h4,.entry-content .ddwc-availability h4{font-size:20px;display:inline-block;line-height:34px;margin:0 0 0 5px}.ddwc-availability label.switch{float:right;margin-top:2px}.ddwc-availability .switch{position:relative;display:inline-block;width:60px;height:30px}.ddwc-availability .switch input{opacity:0;width:0;height:0}.ddwc-availability .switch .slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;-webkit-transition:.4s;transition:.4s}.ddwc-availability .switch .slider::before{position:absolute;content:"";height:22px;width:22px;left:4px;bottom:4px;background-color:#fff;-webkit-transition:.4s;transition:.4s}.ddwc-availability input:checked+.slider{background-color:#76bd1d}.ddwc-availability input:focus+.slider{box-shadow:0 0 1px #76bd1d}.ddwc-availability input:checked+.slider::before{-webkit-transform:translateX(28px);-ms-transform:translateX(28px);transform:translateX(28px)}.ddwc-availability .switch .slider.round{border-radius:22px}.ddwc-availability .switch .slider.round::before{border-radius:50%}table.ddwc-dashboard.delivery-drivers span.driver-status.unavailable{color:rgba(0,0,0,.5)}table.ddwc-dashboard.delivery-drivers span.driver-status.available{color:#76bd1d;font-weight:700}table.ddwc-dashboard.delivery-drivers a.button.ddwc-button{background:#222;display:inline-block;min-height:36px;padding:.75em}table.ddwc-dashboard.delivery-drivers a.button.ddwc-button:hover{background:#767676}table.ddwc-dashboard.delivery-drivers a.button.ddwc-button svg{fill:#fff}table.ddwc-dashboard.delivery-drivers a.button.ddwc-button:last-child:not(:first-child){margin-left:6px}table.ddwc-dashboard.delivery-drivers td:first-child img{max-width:24px;margin-right:6px;float:left}table.ddwc-dashboard.delivery-drivers td:first-child span.driver-name{float:left;margin-right:6px}table.ddwc-dashboard.admin-orders{margin-bottom:24px}form.ddwc-order-filters{display:flex;justify-content:space-between;margin-bottom:0}form.ddwc-order-filters .form-group{display:flex;flex-direction:column;margin-bottom:24px}form.ddwc-order-filters .form-group:last-child{align-self:flex-end}form.ddwc-order-filters .form-group input[type=date],form.ddwc-order-filters .form-group select{padding:.75em;border:1px solid #ddd;border-radius:0;box-shadow:none;height:48px}form.ddwc-order-filters input[type=submit]{padding:16px 24px}@media screen and (max-width:1080px){form.ddwc-order-filters{flex-direction:column}}#signature-box{position:relative;float:left;width:100%}#signature-canvas{border:1px solid #000}.woocommerce-order-details p.order-again{position:relative;float:left;width:100%} -------------------------------------------------------------------------------- /public/js/ddwc-public.js: -------------------------------------------------------------------------------- 1 | (function( $ ) { 2 | "use strict"; 3 | 4 | document.addEventListener("DOMContentLoaded", function() { 5 | // Get the "Save Signature" button element. 6 | var saveSignatureButton = document.getElementById("save-signature-button"); 7 | 8 | // Get the signature box element. 9 | var signatureBox = document.getElementById("signature-box"); 10 | 11 | // Get the message element. 12 | var messageElement = document.createElement("div"); 13 | messageElement.innerText = "Thank you. Your signature has been saved."; 14 | messageElement.style.color = "green"; 15 | 16 | // Add a click event listener to the "Save Signature" button. 17 | saveSignatureButton.addEventListener("click", function() { 18 | // Set the content of the signature box to an empty string. 19 | signatureBox.innerHTML = ""; 20 | 21 | // Append the message element to the signature box. 22 | signatureBox.appendChild(messageElement); 23 | 24 | // Remove the message after a certain duration. 25 | setTimeout(function() { 26 | signatureBox.removeChild(messageElement); 27 | }, 5000); 28 | }); 29 | }); 30 | 31 | })( jQuery ); 32 | 33 | /** 34 | * jQuery Star Rating 35 | * 36 | * source: https://github.com/antennaio/jquery-bar-rating/ 37 | */ 38 | !function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(jQuery)}(function(t){var e=function(){function e(){var e=this,n=function(){var n=["br-wrapper"];""!==e.options.theme&&n.push("br-theme-"+e.options.theme),e.$elem.wrap(t("
",{"class":n.join(" ")}))},i=function(){e.$elem.unwrap()},a=function(n){return t.isNumeric(n)&&(n=Math.floor(n)),t('option[value="'+n+'"]',e.$elem)},r=function(){var n=e.options.initialRating;return n?a(n):t("option:selected",e.$elem)},o=function(){var n=e.$elem.find('option[value="'+e.options.emptyValue+'"]');return!n.length&&e.options.allowEmpty?(n=t("