Changeset 3346796
- Timestamp:
- 08/19/2025 06:56:30 AM (6 months ago)
- Location:
- emw-multiple-order-management/trunk
- Files:
-
- 10 edited
-
CHANGELOG.md (modified) (2 diffs)
-
assets/js/admin-settings.js (modified) (6 diffs)
-
emw-multiple-order-management.php (modified) (2 diffs)
-
includes/class-emw-mom-admin.php (modified) (14 diffs)
-
languages/emw-multiple-order-management.pot (modified) (1 diff)
-
readme.MD (modified) (3 diffs)
-
templates/criteria-settings.php (modified) (1 diff)
-
templates/notifications-settings.php (modified) (1 diff)
-
templates/pro-version-settings.php (modified) (1 diff)
-
templates/rest-api-settings.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
emw-multiple-order-management/trunk/CHANGELOG.md
r3344042 r3346796 3 3 All notable changes to this plugin will be documented in this file. 4 4 5 --- 6 7 ## [1.1.0] - 2025-08-19 8 9 ### Changed 10 - Improved the metadata structure used to store linked orders: 11 - Now, **all linked orders** (primary and secondary) consistently store a `multipleorders` meta entry. 12 - This structure includes: 13 - `is_primary` or `is_secondary` flag. 14 - Reference IDs for the linked orders (`primary_order_id` or `secondary_order_ids`). 15 - Updated the following methods to support full metadata persistence: 16 - `ajax_link_orders()` now updates meta for **all orders** in the group. 17 - `ajax_unlink_orders()` now properly removes metadata from all related orders. 18 - `ajax_get_linked_order_details()` now outputs accurate linked order data. 19 - Improved the admin **Linked Orders** meta box with a clearer UI and accurate link details. 20 - Refactored the plugin settings page (`render_settings_page()`): 21 - Now uses server-rendered tabs based on the `?tab=` URL parameter. 22 - Only the active tab’s template is loaded, improving performance and clarity. 23 - Removed dependency on frontend JavaScript for tab switching. 24 - Updated admin settings templates: 25 - Wrapped each tab’s content in individual PHP templates. 26 - Templates are now loaded conditionally based on the selected tab. 27 28 ### Deprecated 29 - Legacy partial `multipleorders` meta structure used prior to v1.0.1: 30 - Was only set for the primary order (or only for secondaries). 31 - **Fallback retained temporarily for backward compatibility.** 32 - ⚠️ **Deprecated:** This fallback will be removed in a future major release (e.g., `v2.0.0`). Please update any custom code depending on the old structure. 33 34 ### Fixed 35 - Fixed inconsistencies in how linked orders were displayed in the admin UI. 36 - Fixed issue where some secondary orders were not saving metadata correctly. 37 38 --- 39 5 40 ## [1.0.0] - 2025-08-13 41 6 42 ### Added 7 43 - Initial release of the Multiple Order Management plugin. … … 9 45 - Link grouped orders into primary/secondary relationships. 10 46 - Admin UI for managing grouped orders. 11 - Settings panel for order criteria, email templates, and API key. 12 - REST API to: 13 - Fetch all orders grouped by site: `/wp-json/emw-mom/v1/orders` 14 - Get multiple order group by order ID: `/wp-json/emw-mom/v1/multiple-order-group/{order_id}` 15 - Multisite support for fetching orders from all network sites. 16 - API authentication via API key (`X-EMW-MOM-API-Key`). 17 - Toggleable API documentation in plugin admin settings. 47 - Settings panel for: 48 - Order criteria. 49 - Email templates. 50 - Admin emails and CC. 51 - API key. 52 - REST API: 53 - Fetch grouped orders across the network: 54 `GET /wp-json/emw-mom/v1/orders` 55 - Get multiple order group by order ID: 56 `GET /wp-json/emw-mom/v1/multiple-order-group/{order_id}` 57 - Multisite support: Fetch orders across all network sites. 58 - API authentication via custom API key header (`X-EMW-MOM-API-Key`). 59 - Toggle REST API docs in plugin settings. 18 60 19 61 ### Fixed 20 - None — initial version.62 - None — initial stable release. 21 63 22 64 ### Security 23 - REST API secured via API key and settings toggle. 65 - REST API secured via API key and admin toggle. 66 67 --- -
emw-multiple-order-management/trunk/assets/js/admin-settings.js
r3344012 r3346796 16 16 $( document ).ready( 17 17 function () { 18 // Tab switching.19 $( '.nav-tab-wrapper a' ).on(20 'click',21 function ( e ) {22 e.preventDefault();23 var href = $( this ).attr( 'href' ).substring( 1 );24 var tabId = new URLSearchParams( href ).get( 'tab' );25 26 $( '.nav-tab-wrapper a' ).removeClass( 'nav-tab-active' );27 $( this ).addClass( 'nav-tab-active' );28 $( '.tab-content' ).hide();29 $( '#' + tabId ).show();30 }31 );32 33 // Show the first tab by default.34 $( '.nav-tab-wrapper a:first' ).trigger( 'click' );35 36 18 // Multi-select functionality. 37 19 $( document ).on( … … 46 28 47 29 if ( value ) { 48 var label = $this.find( 'option:selected' ).text();49 $selectedTags.append(50 '<span class="emw-mom-tag">' +51 label +52 '<span class="emw-mom-remove-tag" data-value="' + value + '">×</span>' +53 '</span>'54 );55 56 var currentValues = $multiSelect.val() || [];57 currentValues.push( value );58 $multiSelect.val( currentValues );59 $this.find( 'option[value="' + value + '"]' ).remove();60 $this.val( '' );30 var label = $this.find( 'option:selected' ).text(); 31 $selectedTags.append( 32 '<span class="emw-mom-tag">' + 33 label + 34 '<span class="emw-mom-remove-tag" data-value="' + value + '">×</span>' + 35 '</span>' 36 ); 37 38 var currentValues = $multiSelect.val() || []; 39 currentValues.push( value ); 40 $multiSelect.val( currentValues ); 41 $this.find( 'option[value="' + value + '"]' ).remove(); 42 $this.val( '' ); 61 43 } 62 44 } … … 109 91 debounce( 110 92 function ( e ) { 111 e.preventDefault(); 112 var groupId = $( this ).data( 'group-id' ); 113 var $popup = $( '#emw-mom-popup' ); 114 var $popupBody = $( '#emw-mom-popup-body' ); 115 116 $.ajax( 117 { 118 url: emw_mom_admin.ajax_url, 119 type: 'POST', 120 data: { 121 action: 'emw_mom_get_group_details', 122 nonce: emw_mom_admin.nonce_get_group_details, 123 group_id: groupId 124 }, 125 beforeSend: function () { 126 $( 'body' ).addClass( 'no-scroll' ); 127 }, 128 success: function ( response ) { 129 if ( response.success ) { 130 $popupBody.html( response.data.content ); 131 $popup.fadeIn(); 132 } else { 133 showError( response.data || 'Error loading group details.' ); 134 $( 'body' ).removeClass( 'no-scroll' ); 135 } 136 }, 137 error: function () { 138 showError( 'Failed to load group details.' ); 93 e.preventDefault(); 94 var groupId = $( this ).data( 'group-id' ); 95 var $popup = $( '#emw-mom-popup' ); 96 var $popupBody = $( '#emw-mom-popup-body' ); 97 98 $.ajax( 99 { 100 url: emw_mom_admin.ajax_url, 101 type: 'POST', 102 data: { 103 action: 'emw_mom_get_group_details', 104 nonce: emw_mom_admin.nonce_get_group_details, 105 group_id: groupId 106 }, 107 beforeSend: function () { 108 $( 'body' ).addClass( 'no-scroll' ); 109 }, 110 success: function ( response ) { 111 if ( response.success ) { 112 $popupBody.html( response.data.content ); 113 $popup.fadeIn(); 114 } else { 115 showError( response.data || 'Error loading group details.' ); 139 116 $( 'body' ).removeClass( 'no-scroll' ); 140 117 } 118 }, 119 error: function () { 120 showError( 'Failed to load group details.' ); 121 $( 'body' ).removeClass( 'no-scroll' ); 141 122 } 142 ); 123 } 124 ); 143 125 }, 144 126 300 … … 165 147 function ( e ) { 166 148 if ( $( e.target ).is( '#emw-mom-popup' ) ) { 167 var $popup = $( '#emw-mom-popup' );168 var $popupBody = $( '#emw-mom-popup-body' );169 $popup.fadeOut();170 $popupBody.empty();171 $( 'body' ).removeClass( 'no-scroll' );149 var $popup = $( '#emw-mom-popup' ); 150 var $popupBody = $( '#emw-mom-popup-body' ); 151 $popup.fadeOut(); 152 $popupBody.empty(); 153 $( 'body' ).removeClass( 'no-scroll' ); 172 154 } 173 155 } … … 180 162 debounce( 181 163 function ( e ) { 182 e.preventDefault();183 var $btn = $( this );184 var $form = $( '#emw-mom-link-orders-form' );185 var primaryOrder = $form.find( 'input[name="primary_order"]:checked' ).val();186 var secondaryOrders = [];187 188 $form.find( 'input[name="secondary_orders[]"]:checked' ).each(189 function () {190 secondaryOrders.push( $( this ).val() );191 }192 );164 e.preventDefault(); 165 var $btn = $( this ); 166 var $form = $( '#emw-mom-link-orders-form' ); 167 var primaryOrder = $form.find( 'input[name="primary_order"]:checked' ).val(); 168 var secondaryOrders = []; 169 170 $form.find( 'input[name="secondary_orders[]"]:checked' ).each( 171 function () { 172 secondaryOrders.push( $( this ).val() ); 173 } 174 ); 193 175 194 176 if ( ! primaryOrder ) { … … 202 184 } 203 185 204 var multipleOrderId = $btn.data( 'multiple-order-id' ); 205 206 $btn.prop( 'disabled', true ).text( 'Linking...' ); 207 208 $.ajax( 209 { 210 url: emw_mom_admin.ajax_url, 211 method: 'POST', 212 data: { 213 action: 'emw_mom_link_orders', 214 nonce: emw_mom_admin.nonce_link_orders, 215 primary_order_id: primaryOrder, 216 secondary_order_ids: secondaryOrders, 217 multiple_order_id: multipleOrderId, 218 }, 219 success: function ( response ) { 220 if ( response.success ) { 221 showNotice( 'Orders linked successfully.', 'success' ); 222 $( '#emw-mom-popup' ).fadeOut(); 223 $( '#emw-mom-popup-body' ).empty(); 224 $( 'body' ).removeClass( 'no-scroll' ); 225 } else { 226 showError( response.data || 'Error linking orders.' ); 227 } 228 }, 229 error: function () { 230 showError( 'AJAX request failed.' ); 231 }, 232 complete: function () { 233 $btn.prop( 'disabled', false ).text( 'Link Orders' ); 186 var multipleOrderId = $btn.data( 'multiple-order-id' ); 187 188 $btn.prop( 'disabled', true ).text( 'Linking...' ); 189 190 $.ajax( 191 { 192 url: emw_mom_admin.ajax_url, 193 method: 'POST', 194 data: { 195 action: 'emw_mom_link_orders', 196 nonce: emw_mom_admin.nonce_link_orders, 197 primary_order_id: primaryOrder, 198 secondary_order_ids: secondaryOrders, 199 multiple_order_id: multipleOrderId, 200 }, 201 success: function ( response ) { 202 if ( response.success ) { 203 showNotice( 'Orders linked successfully.', 'success' ); 204 $( '#emw-mom-popup' ).fadeOut(); 205 $( '#emw-mom-popup-body' ).empty(); 206 $( 'body' ).removeClass( 'no-scroll' ); 207 } else { 208 showError( response.data || 'Error linking orders.' ); 234 209 } 210 }, 211 error: function () { 212 showError( 'AJAX request failed.' ); 213 }, 214 complete: function () { 215 $btn.prop( 'disabled', false ).text( 'Link Orders' ); 235 216 } 236 ); 217 } 218 ); 237 219 }, 238 220 300 -
emw-multiple-order-management/trunk/emw-multiple-order-management.php
r3344042 r3346796 2 2 /** 3 3 * Plugin Name: Multiple Order Management For WooCommerce 4 * Plugin URI: https://wordpress.org/plugins/emw-multiple-order-management/ 4 5 * Description: A plugin to manage and link multiple WooCommerce orders based on custom criteria. 5 * Version: 1. 0.06 * Version: 1.1.0 6 7 * Author: Kiran M S 7 8 * Author URI: https://profiles.wordpress.org/kiranms1996/ … … 21 22 * Define plugin constants. 22 23 */ 23 define( 'EMW_MOM_VERSION', '1. 0.1' );24 define( 'EMW_MOM_VERSION', '1.1.0' ); 24 25 define( 'EMW_MOM_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 25 26 define( 'EMW_MOM_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); -
emw-multiple-order-management/trunk/includes/class-emw-mom-admin.php
r3344012 r3346796 165 165 public function render_settings_page() { 166 166 // Get settings data. 167 $wc_statuses = wc_get_order_statuses();168 $allowed_statuses = $this->settings->get_allowed_statuses();169 $email_subject = $this->settings->get_email_subject();170 $admin_email = $this->settings->get_admin_email();171 $cc_email = $this->settings->get_cc_email();172 $email_template = $this->settings->get_email_template();173 $criteria = $this->settings->get_criteria_settings();174 $rest_api_enabled = $this->settings->get_rest_api_enabled();175 $rest_api_key = $this->settings->get_rest_api_key();167 $wc_statuses = wc_get_order_statuses(); 168 $allowed_statuses = $this->settings->get_allowed_statuses(); 169 $email_subject = $this->settings->get_email_subject(); 170 $admin_email = $this->settings->get_admin_email(); 171 $cc_email = $this->settings->get_cc_email(); 172 $email_template = $this->settings->get_email_template(); 173 $criteria = $this->settings->get_criteria_settings(); 174 $rest_api_enabled = $this->settings->get_rest_api_enabled(); 175 $rest_api_key = $this->settings->get_rest_api_key(); 176 176 177 177 // Define tabs. 178 $tabs = array(178 $tabs = array( 179 179 'general' => esc_html__( 'General', 'emw-multiple-order-management' ), 180 180 'notifications' => esc_html__( 'Notifications', 'emw-multiple-order-management' ), … … 183 183 'pro-ver' => wp_kses_post( 'Pro Version <span class="dashicons dashicons-star-filled" style="color: #ffb900;vertical-align: middle;"></span>' ), 184 184 ); 185 185 186 $active_tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'general'; // phpcs:ignore WordPress.Security.NonceVerification 186 187 … … 188 189 <div class="wrap"> 189 190 <h1><?php esc_html_e( 'Order Management Settings', 'emw-multiple-order-management' ); ?></h1> 190 < h2class="nav-tab-wrapper">191 <nav class="nav-tab-wrapper"> 191 192 <?php foreach ( $tabs as $tab_id => $tab_name ) : ?> 192 193 <a href="?page=emw-mom-settings&tab=<?php echo esc_attr( $tab_id ); ?>" class="nav-tab <?php echo $active_tab === $tab_id ? 'nav-tab-active' : ''; ?>"> … … 194 195 </a> 195 196 <?php endforeach; ?> 196 </h2> 197 </nav> 198 197 199 <?php 198 require_once EMW_MOM_PLUGIN_DIR . 'templates/general-settings.php'; 199 require_once EMW_MOM_PLUGIN_DIR . 'templates/notifications-settings.php'; 200 require_once EMW_MOM_PLUGIN_DIR . 'templates/criteria-settings.php'; 201 require_once EMW_MOM_PLUGIN_DIR . 'templates/rest-api-settings.php'; 202 require_once EMW_MOM_PLUGIN_DIR . 'templates/pro-version-settings.php'; 200 switch ( $active_tab ) { 201 case 'notifications': 202 require_once EMW_MOM_PLUGIN_DIR . 'templates/notifications-settings.php'; 203 break; 204 205 case 'criteria': 206 require_once EMW_MOM_PLUGIN_DIR . 'templates/criteria-settings.php'; 207 break; 208 209 case 'rest-api': 210 require_once EMW_MOM_PLUGIN_DIR . 'templates/rest-api-settings.php'; 211 break; 212 213 case 'pro-ver': 214 require_once EMW_MOM_PLUGIN_DIR . 'templates/pro-version-settings.php'; 215 break; 216 217 case 'general': 218 default: 219 require_once EMW_MOM_PLUGIN_DIR . 'templates/general-settings.php'; 220 break; 221 } 203 222 ?> 204 223 </div> … … 247 266 /** 248 267 * AJAX handler for linking orders. 268 * 269 * Links primary and secondary orders together, updates post meta 270 * for all involved orders with complete linkage data. 249 271 */ 250 272 public function ajax_link_orders() { … … 264 286 } 265 287 288 // Collect all involved order IDs for shared linkage reference. 289 $all_linked_order_ids = array_merge( array( $primary_order_id ), $secondary_order_ids ); 290 291 // Update secondary orders. 266 292 foreach ( $secondary_order_ids as $secondary_order_id ) { 267 293 $secondary_order = wc_get_order( $secondary_order_id ); … … 274 300 'multipleorders', 275 301 array( 276 'is_secondary' => 'yes', 277 'primary_order_id' => $primary_order_id, 302 'is_secondary' => 'yes', 303 'primary_order_id' => $primary_order_id, 304 'linked_order_ids' => $all_linked_order_ids, 278 305 ) 279 306 ); 280 307 } 281 308 309 // Update primary order. 282 310 update_post_meta( 283 311 $primary_order_id, … … 286 314 'is_primary' => 'yes', 287 315 'secondary_order_ids' => $secondary_order_ids, 316 'linked_order_ids' => $all_linked_order_ids, 288 317 ) 289 318 ); 290 319 320 // Mark group as linked in custom DB table. 291 321 global $wpdb; 292 322 $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching … … 303 333 /** 304 334 * AJAX handler for unlinking orders. 335 * 336 * Removes the linkage metadata from all orders in a group, 337 * and marks the group as unlinked in the DB. 305 338 */ 306 339 public function ajax_unlink_orders() { … … 313 346 314 347 global $wpdb; 315 $group = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}emw_mom_order_groups WHERE id = %d", $group_id ), ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 348 349 // Fetch the order group. 350 $group = $wpdb->get_row( 351 $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}emw_mom_order_groups WHERE id = %d", $group_id ), // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 352 ARRAY_A 353 ); 354 316 355 if ( ! $group ) { 317 356 wp_send_json_error( esc_html__( 'Group not found.', 'emw-multiple-order-management' ) ); 318 357 } 319 358 320 $order_ids = explode( ',', $group['order_ids'] ); 359 // Explode and sanitize order IDs. 360 $order_ids = array_filter( array_map( 'intval', explode( ',', $group['order_ids'] ) ) ); 361 321 362 foreach ( $order_ids as $order_id ) { 322 delete_post_meta( $order_id, 'multipleorders' ); 323 } 324 363 $meta = get_post_meta( $order_id, 'multipleorders', true ); 364 365 // Ensure the meta is an array before proceeding. 366 if ( is_array( $meta ) ) { 367 // Remove only our known keys to avoid destroying unrelated data. 368 unset( 369 $meta['is_primary'], 370 $meta['is_secondary'], 371 $meta['primary_order_id'], 372 $meta['secondary_order_ids'], 373 $meta['linked_order_ids'] 374 ); 375 376 // If meta still has other keys, update it; otherwise delete it. 377 if ( ! empty( $meta ) ) { 378 update_post_meta( $order_id, 'multipleorders', $meta ); 379 } else { 380 delete_post_meta( $order_id, 'multipleorders' ); 381 } 382 } else { 383 // Meta is not structured as expected, remove it entirely. 384 delete_post_meta( $order_id, 'multipleorders' ); 385 } 386 } 387 388 // Mark group as unlinked. 325 389 $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 326 390 $wpdb->prefix . 'emw_mom_order_groups', … … 336 400 337 401 /** 338 * AJAX handler for getting linked order details. 402 * AJAX handler for retrieving linked order details. 403 * 404 * Responds to the request from the "View Linked Orders" button. 405 * Handles both legacy structure (`is_primary`, `is_secondary`, etc.) 406 * and new structure using `linked_order_ids` in all orders. 407 * 408 * @since 1.0.0 409 * @return void 339 410 */ 340 411 public function ajax_get_linked_order_details() { 341 412 check_ajax_referer( 'emw_mom_get_linked_order_details', 'nonce' ); 342 413 343 $order_id = isset( $_POST['order_id'] ) ? intval( $_POST['order_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification 414 // Get and validate order ID from POST data. 415 $order_id = isset( $_POST['order_id'] ) ? intval( $_POST['order_id'] ) : 0; 344 416 $order = wc_get_order( $order_id ); 417 345 418 if ( ! $order ) { 346 419 wp_die( esc_html__( 'Order not found.', 'emw-multiple-order-management' ) ); 347 420 } 348 421 422 // Fetch order meta for linked orders. 349 423 $meta = get_post_meta( $order_id, 'multipleorders', true ); 424 350 425 ob_start(); 426 427 // Handle missing or malformed meta data. 428 if ( ! is_array( $meta ) ) { 429 echo '<p>' . esc_html__( 'No linked order data found.', 'emw-multiple-order-management' ) . '</p>'; 430 wp_die( wp_kses_post( ob_get_clean() ) ); 431 } 432 433 // Extract values from meta. 434 $is_primary = isset( $meta['is_primary'] ) && 'yes' === $meta['is_primary']; 435 $is_secondary = isset( $meta['is_secondary'] ) && 'yes' === $meta['is_secondary']; 436 $linked_order_ids = isset( $meta['linked_order_ids'] ) && is_array( $meta['linked_order_ids'] ) ? $meta['linked_order_ids'] : array(); 437 351 438 ?> 352 <p> 353 <?php 354 if ( isset( $meta['is_primary'] ) && 'yes' === $meta['is_primary'] ) { 355 echo esc_html__( 'Primary Order', 'emw-multiple-order-management' ); 356 if ( ! empty( $meta['secondary_order_ids'] ) ) { 357 echo '<ul>'; 358 foreach ( $meta['secondary_order_ids'] as $secondary_id ) { 359 $secondary_order = wc_get_order( $secondary_id ); 360 if ( $secondary_order ) { 361 echo '<li><a href="' . esc_url( $secondary_order->get_edit_order_url() ) . '">#' . esc_html( $secondary_order->get_order_number() ) . '</a></li>'; 439 <div class="emw-mom-linked-order-details"> 440 <p> 441 <?php if ( $is_primary ) : ?> 442 <strong><?php esc_html_e( 'Primary Order', 'emw-multiple-order-management' ); ?></strong> 443 <?php elseif ( $is_secondary ) : ?> 444 <strong><?php esc_html_e( 'Secondary Order', 'emw-multiple-order-management' ); ?></strong> 445 <?php endif; ?> 446 </p> 447 448 <?php if ( ! empty( $linked_order_ids ) ) : ?> 449 <!-- New structure: Show all linked orders except current --> 450 <p><?php esc_html_e( 'Linked Orders:', 'emw-multiple-order-management' ); ?></p> 451 <ul> 452 <?php 453 foreach ( $linked_order_ids as $linked_id ) { 454 // Skip current order to avoid showing self in list. 455 if ( $linked_id == $order_id ) { 456 continue; 457 } 458 459 $linked_order = wc_get_order( $linked_id ); 460 if ( $linked_order ) { 461 printf( 462 '<li><a href="%1$s">#%2$s</a></li>', 463 esc_url( $linked_order->get_edit_order_url() ), 464 esc_html( $linked_order->get_order_number() ) 465 ); 362 466 } 363 467 } 364 echo '</ul>'; 365 } 366 } elseif ( isset( $meta['is_secondary'] ) && 'yes' === $meta['is_secondary'] ) { 367 $primary_order = wc_get_order( $meta['primary_order_id'] ); 368 if ( $primary_order ) { 369 printf( 370 esc_html__( 'Secondary Order, linked to Primary Order', 'emw-multiple-order-management' ) . ' #%s', 371 '<a href="' . esc_url( $primary_order->get_edit_order_url() ) . '">#' . esc_html( $primary_order->get_order_number() ) . '</a>' 372 ); 373 } 374 } 375 ?> 376 </p> 468 ?> 469 </ul> 470 471 <?php elseif ( $is_primary && ! empty( $meta['secondary_order_ids'] ) ) : ?> 472 <!-- Legacy structure: Show secondary orders under primary --> 473 <p><?php esc_html_e( 'Linked Secondary Orders:', 'emw-multiple-order-management' ); ?></p> 474 <ul> 475 <?php 476 foreach ( $meta['secondary_order_ids'] as $secondary_id ) { 477 $linked_order = wc_get_order( $secondary_id ); 478 if ( $linked_order ) { 479 printf( 480 '<li><a href="%1$s">#%2$s</a></li>', 481 esc_url( $linked_order->get_edit_order_url() ), 482 esc_html( $linked_order->get_order_number() ) 483 ); 484 } 485 } 486 ?> 487 </ul> 488 489 <?php elseif ( $is_secondary && ! empty( $meta['primary_order_id'] ) ) : ?> 490 <!-- Legacy structure: Show linked primary order for secondary --> 491 <p> 492 <?php 493 $primary_order = wc_get_order( $meta['primary_order_id'] ); 494 if ( $primary_order ) { 495 printf( 496 /* translators: %s: Link to primary order */ 497 esc_html__( 'Linked to Primary Order %s', 'emw-multiple-order-management' ), 498 '<a href="' . esc_url( $primary_order->get_edit_order_url() ) . '">#' . esc_html( $primary_order->get_order_number() ) . '</a>' 499 ); 500 } 501 ?> 502 </p> 503 504 <?php else : ?> 505 <!-- Fallback: No links found --> 506 <p><?php esc_html_e( 'No linked orders found.', 'emw-multiple-order-management' ); ?></p> 507 <?php endif; ?> 508 </div> 377 509 <?php 510 511 // Output final content and exit. 378 512 wp_die( wp_kses_post( ob_get_clean() ) ); 379 513 } … … 394 528 395 529 /** 396 * Render meta box content. 397 * 398 * @param WP_Post $post Post object. 530 * Renders the "Linked Orders" meta box on the order edit screen. 531 * 532 * This box shows whether the order is a primary or secondary in a group, 533 * and displays links to other related orders based on the metadata. 534 * 535 * Supports both: 536 * - New unified structure (`linked_order_ids`), 537 * - Legacy fallback structure (`is_primary`, `is_secondary`, `primary_order_id`, `secondary_order_ids`). 538 * 539 * @todo Remove legacy fallback support in a future version after migration. 540 * 541 * @param WP_Post $post The current order post object. 399 542 */ 400 543 public function render_order_meta_box( $post ) { 401 544 $order = wc_get_order( $post->ID ); 402 $meta = get_post_meta( $post->ID, 'multipleorders', true ); 403 if ( ! $meta ) { 545 546 // Fetch linked orders metadata. 547 $meta = get_post_meta( $post->ID, 'multipleorders', true ); 548 549 // If no metadata, there's nothing to display. 550 if ( ! $meta || ! is_array( $meta ) ) { 404 551 echo '<p>' . esc_html__( 'No linked orders.', 'emw-multiple-order-management' ) . '</p>'; 405 552 return; 406 553 } 554 555 // Extract meta values. 556 $is_primary = isset( $meta['is_primary'] ) && 'yes' === $meta['is_primary']; 557 $is_secondary = isset( $meta['is_secondary'] ) && 'yes' === $meta['is_secondary']; 558 $linked_order_ids = isset( $meta['linked_order_ids'] ) && is_array( $meta['linked_order_ids'] ) ? $meta['linked_order_ids'] : array(); 407 559 408 560 ?> … … 410 562 <p> 411 563 <?php 412 if ( isset( $meta['is_primary'] ) && 'yes' === $meta['is_primary'] ) { 564 // Display role badge. 565 if ( $is_primary ) { 413 566 echo '<span class="emw-mom-badge role-primary">' . esc_html__( 'Primary', 'emw-multiple-order-management' ) . '</span>'; 414 if ( ! empty( $meta['secondary_order_ids'] ) ) { 415 echo '<ul>'; 416 foreach ( $meta['secondary_order_ids'] as $secondary_id ) { 417 $secondary_order = wc_get_order( $secondary_id ); 418 if ( $secondary_order ) { 419 echo '<li><a href="' . esc_url( $secondary_order->get_edit_order_url() ) . '">#' . esc_html( $secondary_order->get_order_number() ) . '</a></li>'; 420 } 567 } elseif ( $is_secondary ) { 568 echo '<span class="emw-mom-badge role-secondary">' . esc_html__( 'Secondary', 'emw-multiple-order-management' ) . '</span>'; 569 } 570 ?> 571 572 <?php 573 // Display linked orders list using the new unified structure if available. 574 if ( ! empty( $linked_order_ids ) ) : 575 echo '<ul>'; 576 foreach ( $linked_order_ids as $linked_id ) { 577 // Skip self. 578 if ( $linked_id == $post->ID ) { 579 continue; 421 580 } 422 echo '</ul>'; 581 $linked_order = wc_get_order( $linked_id ); 582 if ( $linked_order ) { 583 printf( 584 '<li><a href="%1$s">#%2$s</a></li>', 585 esc_url( $linked_order->get_edit_order_url() ), 586 esc_html( $linked_order->get_order_number() ) 587 ); 588 } 423 589 } 424 } elseif ( isset( $meta['is_secondary'] ) && 'yes' === $meta['is_secondary'] ) { 590 echo '</ul>'; 591 592 /** 593 * LEGACY FALLBACK SUPPORT - to be removed in future versions. 594 * This block supports the old meta keys 'secondary_order_ids' and 'primary_order_id'. 595 */ 596 elseif ( $is_primary && ! empty( $meta['secondary_order_ids'] ) ) : 597 echo '<ul>'; 598 foreach ( $meta['secondary_order_ids'] as $secondary_id ) { 599 $secondary_order = wc_get_order( $secondary_id ); 600 if ( $secondary_order ) { 601 printf( 602 '<li><a href="%1$s">#%2$s</a></li>', 603 esc_url( $secondary_order->get_edit_order_url() ), 604 esc_html( $secondary_order->get_order_number() ) 605 ); 606 } 607 } 608 echo '</ul>'; 609 610 elseif ( $is_secondary && ! empty( $meta['primary_order_id'] ) ) : 425 611 $primary_order = wc_get_order( $meta['primary_order_id'] ); 426 612 if ( $primary_order ) { 427 echo '<span class="emw-mom-badge role-secondary">' . esc_html__( 'Secondary', 'emw-multiple-order-management' ) . '</span>';428 613 echo '<p>' . sprintf( 429 esc_html__( 'Linked to Primary Order ', 'emw-multiple-order-management' ) . ' %s',614 esc_html__( 'Linked to Primary Order %s', 'emw-multiple-order-management' ), 430 615 '<a href="' . esc_url( $primary_order->get_edit_order_url() ) . '">#' . esc_html( $primary_order->get_order_number() ) . '</a>' 431 616 ) . '</p>'; 432 617 } 433 }618 endif; 434 619 ?> 620 621 <!-- Button to open modal with full linked details --> 435 622 <button type="button" class="button view-linked-orders-btn" data-order-id="<?php echo esc_attr( $post->ID ); ?>"> 436 623 <?php esc_html_e( 'View Details', 'emw-multiple-order-management' ); ?> … … 438 625 </p> 439 626 </div> 627 628 <!-- Hidden modal for AJAX-loaded linked order content --> 440 629 <div id="emw-mom-linked-orders-modal" class="emw-mom-modal" style="display: none;"> 441 630 <div class="emw-mom-modal-content"> -
emw-multiple-order-management/trunk/languages/emw-multiple-order-management.pot
r3344012 r3346796 3 3 msgid "" 4 4 msgstr "" 5 "Project-Id-Version: EMW Multiple Order Management 1. 0.1\n"5 "Project-Id-Version: EMW Multiple Order Management 1.1.0\n" 6 6 "Report-Msgid-Bugs-To: https://example.com/support\n" 7 7 "POT-Creation-Date: 2025-07-03 16:14+0530\n" -
emw-multiple-order-management/trunk/readme.MD
r3344042 r3346796 4 4 Requires at least: 5.0 5 5 Tested up to: 6.8 6 Stable tag: 1. 0.06 Stable tag: 1.1.0 7 7 Requires PHP: 7.2 8 8 License: GPLv2 or later … … 48 48 - Multisite compatible – works across subsites. 49 49 50 51 50 == REST API == 52 51 This plugin exposes custom REST API endpoints for external access: … … 63 62 64 63 == Developer Notes == 65 You can extend the plugin using hooks 64 You can extend the plugin using the following hooks and filters: 65 - `emw_mom_order_group_created` 66 - `emw_mom_order_linked` 67 - `emw_mom_api_key_validated` 68 - ...and more. 66 69 67 70 == Changelog == 68 = 1.0.0 = 69 - Initial release of the Multiple Order Management plugin. 70 - Ability to group WooCommerce orders based on customizable criteria. 71 - Link grouped orders into primary/secondary relationships. 72 - Admin UI for managing grouped orders. 73 - Settings panel for order criteria, email templates, and API key. 74 - REST API to: 71 72 = 1.1.0 - 2025-08-18 = 73 * Changed: Unified `multipleorders` meta structure for all linked orders. 74 * Changed: Improved `ajax_link_orders` and `ajax_unlink_orders` functions to reflect accurate linked/unlinked state for each order. 75 * Changed: Updated `render_settings_page()` method to load settings tabs using PHP instead of JavaScript. 76 * Changed: Admin settings UI now loads only the active tab's content for better performance. 77 * Changed: Refactored tab template loading using a `switch` statement in `render_settings_page()`. 78 * Changed: Updated settings page navigation to use server-rendered tabs with persistent URLs. 79 * Changed: Improved Linked Orders meta box UI for clarity and usability. 80 * Deprecated: Legacy meta structure fallback for backward compatibility (to be removed in a future release). 81 * Fixed: Admin UI now displays correct linked order metadata across all views. 82 83 = 1.0.0 - 2025-08-13 = 84 * Initial release of the Multiple Order Management plugin. 85 * Ability to group WooCommerce orders based on customizable criteria. 86 * Link grouped orders into primary/secondary relationships. 87 * Admin UI for managing grouped orders. 88 * Settings panel for order criteria, email templates, and API key. 89 * REST API to: 75 90 - Fetch all orders grouped by site: `/wp-json/emw-mom/v1/orders` 76 91 - Get multiple order group by order ID: `/wp-json/emw-mom/v1/multiple-order-group/{order_id}` 77 -Multisite support for fetching orders from all network sites.78 -API authentication via API key (`X-EMW-MOM-API-Key`).79 -Toggleable API documentation in plugin admin settings.92 * Multisite support for fetching orders from all network sites. 93 * API authentication via API key (`X-EMW-MOM-API-Key`). 94 * Toggleable API documentation in plugin admin settings. -
emw-multiple-order-management/trunk/templates/criteria-settings.php
r3344012 r3346796 21 21 ?> 22 22 23 <div id="criteria" class="tab-content" style="display: none;">23 <div id="criteria" class="tab-content"> 24 24 <?php do_action( 'emw_mom_before_render_criteria_tab' ); ?> 25 25 <form method="post" action=""> -
emw-multiple-order-management/trunk/templates/notifications-settings.php
r3344012 r3346796 13 13 ?> 14 14 15 <div id="notifications" class="tab-content" style="display: none;">15 <div id="notifications" class="tab-content"> 16 16 <?php do_action( 'emw_mom_before_render_notifications_tab' ); ?> 17 17 <form method="post" action=""> -
emw-multiple-order-management/trunk/templates/pro-version-settings.php
r3344012 r3346796 11 11 ?> 12 12 13 <div id="pro-ver" class="tab-content" style="display: none;">13 <div id="pro-ver" class="tab-content"> 14 14 <div class="emw-mom-pro-notice"> 15 15 <h2><?php esc_html_e( 'Pro Features Coming Soon!', 'emw-multiple-order-management' ); ?></h2> -
emw-multiple-order-management/trunk/templates/rest-api-settings.php
r3344012 r3346796 13 13 ?> 14 14 15 <div id="rest-api" class="tab-content" style="display: none;">15 <div id="rest-api" class="tab-content"> 16 16 <form method="post" action=""> 17 17 <?php wp_nonce_field( 'emw_mom_save_settings', 'emw_mom_settings_nonce' ); ?>
Note: See TracChangeset
for help on using the changeset viewer.