Changeset 3173906
- Timestamp:
- 10/22/2024 08:31:40 PM (17 months ago)
- Location:
- bd-courier-order-ratio-checker/trunk
- Files:
-
- 2 edited
-
bd-courier-order-ratio-checker.php (modified) (2 diffs)
-
readme.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
bd-courier-order-ratio-checker/trunk/bd-courier-order-ratio-checker.php
r3163388 r3173906 4 4 * Plugin URI: https://rasedulhaque.com/bd-courier-order-ratio-checker 5 5 * Description: A plugin to show customer order ratio from BD Courier with settings and search functionality. 6 * Version: 1. 86 * Version: 1.9 7 7 * Author: Rasedul Haque 8 * Author URI: https://ras hedulhaque.com8 * Author URI: https://rasedulhaque.com 9 9 * Text Domain: bd-courier-order-ratio-checker 10 10 * License: GPLv2 or later … … 16 16 } 17 17 18 class Order_Ratio_Checker { 19 20 /** 21 * Constructor to initialize hooks and actions. 22 */ 23 public function __construct() { 24 // Hook for loading frontend-side scripts (for search form) 25 add_action('wp_enqueue_scripts', [$this, 'enqueue_search_script']); 26 add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts']); 27 28 // Add menu for search page in WordPress Admin 29 add_action('admin_menu', [$this, 'add_bd_courier_menu']); 30 31 // Hook for settings page and submenu 32 add_action('admin_menu', [$this, 'add_bd_courier_settings_page']); 33 add_action('admin_init', [$this, 'register_bd_courier_settings']); 34 35 // Shortcode for search form 36 add_shortcode('bdcourier_search', [$this, 'display_search_form']); 37 38 // Ajax action for search form (both for logged-in and guest users) 39 add_action('wp_ajax_search_courier_data', [$this, 'search_courier_data']); 40 add_action('wp_ajax_nopriv_search_courier_data', [$this, 'search_courier_data']); 41 42 // Hook to display data on WooCommerce admin order edit page 43 add_action('woocommerce_admin_order_data_after_order_details', [$this, 'display_order_ratio_in_admin']); 44 45 // Hook for the AJAX request (for logged-in users) 46 add_action('wp_ajax_refresh_courier_data', [$this, 'refresh_courier_data']); 47 } 48 49 /** 50 * Enqueue admin-side scripts for handling order details page Ajax requests. 51 */ 52 public function enqueue_admin_scripts( $hook_suffix ) { 53 // For the BD Courier search page 54 if ( 'toplevel_page_bd-courier-search' === $hook_suffix ) { 55 wp_enqueue_script( 'jquery' ); 56 wp_enqueue_script( 57 'bdcourier-search-ajax', 58 plugin_dir_url( __FILE__ ) . 'bdcourier-search-ajax.js', 59 [ 'jquery' ], 60 null, 61 true 62 ); 63 wp_localize_script( 64 'bdcourier-search-ajax', 65 'bdcourierSearchAjax', 66 [ 67 'ajaxurl' => admin_url( 'admin-ajax.php' ), 68 'nonce' => wp_create_nonce( 'bdcourier_search_nonce' ), // Nonce creation 69 ] 70 ); 71 } 72 73 74 wp_enqueue_script( 'jquery' ); 75 wp_enqueue_script( 76 'order-ratio-ajax', 77 plugin_dir_url( __FILE__ ) . 'order-ratio-ajax.js', 78 [ 'jquery' ], 79 null, 80 true 81 ); 82 wp_localize_script( 83 'order-ratio-ajax', 84 'orderRatioAjax', 85 [ 86 'ajaxurl' => admin_url( 'admin-ajax.php' ), 87 'nonce' => wp_create_nonce( 'refresh_order_ratio_nonce' ), // Nonce creation 88 ] 89 ); 90 91 } 92 93 /** 94 * Add BD Courier menu in WordPress Admin. 95 */ 96 public function add_bd_courier_menu() { 97 add_menu_page( 98 'Courier Search', // Page title 99 'Courier Search', // Menu title 100 'manage_options', // Capability 101 'bd-courier-search', // Menu slug 102 [$this, 'render_search_page'], // Callback function 103 'dashicons-search', // Icon 104 25 // Position 105 ); 106 } 107 108 /** 109 * Render the courier search page in the admin area. 110 */ 111 public function render_search_page() { 112 ?> 113 <div id="courier-search-container" style="max-width: 600px; margin: 20px auto; padding: 20px; background-color: white; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"> 114 <form id="bdcourier-search-form" method="post" style="margin-bottom: 20px; text-align: center; margin-top: 20px;"> 115 <?php wp_nonce_field( 'bdcourier_search_nonce_action', 'bdcourier_search_nonce_field' ); ?> 116 <input type="text" id="phone" name="phone" placeholder="Enter Phone Number" required style="padding: 10px; width: 70%; border: 1px solid #ddd; border-radius: 5px; display: inline-block; margin-right: 10px;"> 117 <button type="submit" style="padding: 10px 20px; background-color: #28a745; color: white; border: none; border-radius: 5px; cursor: pointer; display: inline-block;">Search</button> 118 </form> 119 <div id="courier-search-result" style="max-width: 100%; margin-top: 20px;"></div> 120 </div> 121 <?php 122 } 123 124 /** 125 * Add BD Courier settings page under WooCommerce. 126 */ 127 public function add_bd_courier_settings_page() { 128 add_menu_page( 129 'BD Courier Settings', // Page title 130 'BD Courier Settings', // Menu title 131 'manage_options', // Capability 132 'bd-courier-settings', // Menu slug 133 [$this, 'render_settings_page'], // Callback function 134 'dashicons-admin-generic', // Icon 135 56 // Position 136 ); 137 } 138 139 /** 140 * Render the settings page. 141 */ 142 public function render_settings_page() { 143 ?> 144 <div class="wrap"> 145 <h1>BD Courier Settings</h1> 146 <form method="post" action="options.php"> 147 <?php 148 settings_fields('bd_courier_settings_group'); 149 do_settings_sections('bd-courier-settings'); 150 submit_button(); 151 ?> 152 </form> 153 </div> 154 <?php 155 } 156 157 /** 158 * Register the BD Courier settings. 159 */ 160 public function register_bd_courier_settings() { 161 register_setting('bd_courier_settings_group', 'bd_courier_api_token'); 162 163 add_settings_section( 164 'bd_courier_settings_section', 165 'API Settings', 166 null, 167 'bd-courier-settings' 168 ); 169 170 add_settings_field( 171 'bd_courier_api_token', 172 'API Token', 173 [$this, 'render_api_token_field'], 174 'bd-courier-settings', 175 'bd_courier_settings_section' 176 ); 177 } 178 179 /** 180 * Render the API token input field. 181 */ 182 public function render_api_token_field() { 183 $api_token = get_option('bd_courier_api_token'); 184 echo '<input type="text" name="bd_courier_api_token" value="' . esc_attr($api_token) . '" class="regular-text" />'; 185 } 186 187 /** 188 * Display the search form via shortcode. 189 */ 190 public function display_search_form() { 191 ob_start(); 192 ?> 193 <form id="bdcourier-search-form" method="post" style="margin-bottom: 20px;"> 194 <?php wp_nonce_field( 'bdcourier_search_nonce_action', 'bdcourier_search_nonce_field' ); ?> 195 <input type="text" id="phone" name="phone" placeholder="Enter Phone Number" required style="padding: 10px; width: 300px; border: 1px solid #ddd;"> 196 <button type="submit" style="padding: 10px 20px; background-color: #28a745; color: white; border: none; cursor: pointer;">Search</button> 197 </form> 198 <div id="courier-search-result"></div> 199 <?php 200 return ob_get_clean(); 201 } 202 203 /** 204 * Enqueue frontend-side scripts for handling search form Ajax requests. 205 */ 206 public function enqueue_search_script() { 207 wp_enqueue_script('jquery'); 208 wp_enqueue_script( 209 'bdcourier-search-ajax', 210 plugin_dir_url(__FILE__) . 'bdcourier-search-ajax.js', 211 ['jquery'], 212 null, 213 true 214 ); 215 wp_localize_script( 216 'bdcourier-search-ajax', 217 'bdcourierSearchAjax', 218 [ 219 'ajaxurl' => admin_url('admin-ajax.php'), 220 'nonce' => wp_create_nonce('bdcourier_search_nonce'), // Security nonce 221 ] 222 ); 223 } 224 225 /** 226 * Handle the Ajax request and verify nonce. 227 */ 228 public function search_courier_data() { 229 // Verify the nonce 230 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'bdcourier_search_nonce' ) ) { 231 wp_send_json_error( esc_html__( 'Invalid nonce.', 'bd-courier-order-ratio-checker' ) ); 232 return; 233 } 234 235 // Process the request if nonce is valid 236 if ( isset( $_POST['phone'] ) && ! empty( $_POST['phone'] ) ) { 237 $phone = sanitize_text_field( wp_unslash( $_POST['phone'] ) ); 238 } else { 239 wp_send_json_error( esc_html__( 'Phone number is required.', 'bd-courier-order-ratio-checker' ) ); 240 } 241 242 $courier_data = $this->fetch_order_ratio_from_api( $phone ); 243 244 if ( $courier_data ) { 245 ob_start(); 246 $this->display_courier_data( $courier_data ); 247 $table_html = ob_get_clean(); 248 wp_send_json_success( [ 'table' => $table_html ] ); 249 } else { 250 wp_send_json_error( esc_html__( 'Failed to fetch data from API.', 'bd-courier-order-ratio-checker' ) ); 251 } 252 } 253 254 255 /** 256 * Display courier data in table format with a summary row and progress bar. 257 */ 258 private function display_courier_data($courier_data) { 259 if (!$courier_data || !is_array($courier_data)) { 260 return; 261 } 262 263 // Start table HTML 264 echo '<div style="margin-top:20px;">'; 265 echo '<table style="width:100%; border-collapse: collapse; margin-bottom: 20px;">'; 266 echo '<thead>'; 267 echo '<tr style="background-color:#f2f2f2;">'; 268 echo '<th style="padding:10px; text-align:left;">Courier</th>'; 269 echo '<th style="padding:10px; text-align:left;">Total</th>'; 270 echo '<th style="padding:10px; text-align:left;">Success</th>'; 271 echo '<th style="padding:10px; text-align:left;">Cancel</th>'; 272 echo '</tr>'; 273 echo '</thead>'; 274 echo '<tbody>'; 275 276 foreach ($courier_data as $courier => $data) { 277 if ($courier !== 'summary' && is_array($data)) { 278 $total_parcel = isset($data['total_parcel']) ? $data['total_parcel'] : 'N/A'; 279 $success_parcel = isset($data['success_parcel']) ? $data['success_parcel'] : 'N/A'; 280 $cancel_parcel = isset($data['total_parcel']) && isset($data['success_parcel']) ? $total_parcel - $success_parcel : 'N/A'; 281 282 echo '<tr>'; 283 echo '<td style="padding:10px; border: 1px solid #ddd;">' . esc_html( ucfirst($courier) ) . '</td>'; 284 echo '<td style="padding:10px; border: 1px solid #ddd;">' . esc_html( $total_parcel ) . '</td>'; 285 echo '<td style="padding:10px; border: 1px solid #ddd;">' . esc_html( $success_parcel ) . '</td>'; 286 echo '<td style="padding:10px; border: 1px solid #ddd;">' . esc_html( $cancel_parcel ) . '</td>'; 287 echo '</tr>'; 288 } 289 } 290 291 echo '</tbody>'; 292 echo '</table>'; 293 294 // Summary row 295 if (isset($courier_data['summary']) && is_array($courier_data['summary'])) { 296 $total_parcel = isset($courier_data['summary']['total_parcel']) ? $courier_data['summary']['total_parcel'] : 'N/A'; 297 $success_parcel = isset($courier_data['summary']['success_parcel']) ? $courier_data['summary']['success_parcel'] : 'N/A'; 298 $success_ratio = isset($courier_data['summary']['success_ratio']) ? $courier_data['summary']['success_ratio'] : 0; 299 $cancel_ratio = $total_parcel > 0 ? 100 - $success_ratio : 0; 300 301 // Styling for pills 302 $pill_style = 'display: inline-block; padding: 10px 20px; border-radius: 50px; color: white; font-weight: bold; margin-right: 10px;'; 303 304 // Summary pills display 305 echo '<div style="margin-top: 20px;">'; 306 307 // Total Parcels Pill (neutral color) 308 echo '<span style="' . esc_attr( $pill_style ) . ' background-color: #6c757d;">Total : ' . esc_html( $total_parcel ) . '</span>'; 309 310 // Success Parcels Pill (green) 311 echo '<span style="' . esc_attr( $pill_style ) . ' background-color: #28a745;">Success : ' . esc_html( $success_parcel ) . '</span>'; 312 313 // Cancel Parcels Pill (red) 314 echo '<span style="' . esc_attr( $pill_style ) . ' background-color: #dc3545;">Cancel : ' . esc_html( $total_parcel - $success_parcel ) . '</span>'; 315 316 // Progress bar for Success/Cancel ratio 317 echo '<div style="background-color:#f3f3f3; border-radius: 5px; width: 100%; height: 20px; margin-top: 20px; position: relative;">'; 318 319 // Only show the success bar if the success ratio is greater than zero 320 if ($success_ratio > 0) { 321 echo '<div style="width:' . esc_attr( $success_ratio ) . '%; background-color:#28a745; height: 100%; position: absolute; left: 0;"></div>'; 322 } 323 324 // Only show the cancel bar if the cancel ratio is greater than zero 325 if ($cancel_ratio > 0) { 326 echo '<div style="width:' . esc_attr( $cancel_ratio ) . '%; background-color:#dc3545; height: 100%; position: absolute; right: 0;"></div>'; 327 } 328 329 // Only show the text if both success and cancel ratios are greater than zero 330 if ($success_ratio > 0 || $cancel_ratio > 0) { 331 echo '<span style="position: absolute; width: 100%; text-align: center; line-height: 20px; color: #fff; font-weight: bold;">' . esc_html( $success_ratio ) . '% Success / ' . esc_html( $cancel_ratio ) . '% Cancel</span>'; 332 } 333 334 echo '</div>'; // End of the progress bar div 335 echo '</div>'; 336 } 337 338 echo '</div>'; 339 } 340 341 /** 342 * Fetch courier data from the remote API. 343 */ 344 private function fetch_order_ratio_from_api($phone) { 345 // Get the API token from settings 346 $api_token = get_option('bd_courier_api_token'); 347 348 // URL for the API 349 $url = 'https://bdcourier.com/api/courier-check?phone=' . urlencode($phone); 350 351 // Set headers for the API request 352 $headers = [ 353 'Authorization' => 'Bearer ' . esc_attr($api_token), 354 'Content-Type' => 'application/json', 355 ]; 356 357 // Make the POST request using wp_remote_post with timeout and error handling 358 $response = wp_remote_post($url, [ 359 'headers' => $headers, 360 'timeout' => 100, 361 ]); 362 363 // Handle any WP errors during the API call 364 if (is_wp_error($response)) { 365 $error_message = $response->get_error_message(); 366 error_log("API request failed: $error_message"); 367 return null; 368 } 369 370 // Retrieve and decode the body of the response 371 $body = wp_remote_retrieve_body($response); 372 $data = json_decode($body, true); 373 374 // Check if the response body is empty or invalid JSON 375 if (empty($body) || is_null($data)) { 376 error_log("Invalid API response: " . $body); 377 return null; 378 } 379 380 // Return the courier data if it exists, otherwise return null 381 return isset($data['courierData']) ? $data['courierData'] : null; 382 } 383 384 // Refresh courier data with nonce verification 385 public function refresh_courier_data() { 386 // Verify nonce 387 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'refresh_order_ratio_nonce' ) ) { 388 wp_send_json_error( esc_html__( 'Invalid nonce.', 'bd-courier-order-ratio-checker' ) ); 389 return; 390 } 391 392 if ( isset( $_POST['order_id'] ) && ! empty( $_POST['order_id'] ) ) { 393 $order_id = intval( wp_unslash( $_POST['order_id'] ) ); 394 } else { 395 wp_send_json_error( esc_html__( 'Invalid order ID.', 'bd-courier-order-ratio-checker' ) ); 396 } 397 398 $order = wc_get_order( $order_id ); 399 if ( ! $order ) { 400 wp_send_json_error( esc_html__( 'Order not found.', 'bd-courier-order-ratio-checker' ) ); 401 } 402 403 $phone = $order->get_billing_phone(); 404 if ( ! $phone ) { 405 wp_send_json_error( esc_html__( 'No phone number found.', 'bd-courier-order-ratio-checker' ) ); 406 } 407 408 $courier_data = $this->fetch_order_ratio_from_api( $phone ); 409 if ( $courier_data ) { 410 update_post_meta( $order_id, '_courier_data', $courier_data ); 411 412 ob_start(); 413 $this->display_courier_data( $courier_data ); 414 $table_html = ob_get_clean(); 415 416 wp_send_json_success( [ 'table' => $table_html ] ); 417 } else { 418 wp_send_json_error( esc_html__( 'Failed to fetch courier data.', 'bd-courier-order-ratio-checker' ) ); 419 } 420 } 421 422 public function display_order_ratio_in_admin($order) { 423 // Get the customer phone number from the billing data 424 $customer_phone = $order->get_billing_phone(); 425 426 if (!$customer_phone) { 427 echo '<p style="color: red;">No phone number found for this order.</p>'; 428 return; 429 } 430 431 // Check if courier data already exists in the order meta 432 $courier_data = get_post_meta($order->get_id(), '_courier_data', true); 433 434 if (!$courier_data) { 435 // Fetch courier data from API if not already stored 436 $courier_data = $this->fetch_order_ratio_from_api($customer_phone); 437 if ($courier_data) { 438 update_post_meta($order->get_id(), '_courier_data', $courier_data); 439 } 440 } 441 442 if ($courier_data) { 443 // Display the courier data if it exists 444 echo '<div id="courier-data-table">'; 445 $this->display_courier_data($courier_data); 446 echo '</div>'; 447 echo '<button id="refresh-courier-data" data-order-id="' . esc_attr($order->get_id()) . '" class="button" style="margin-top: 10px; background-color: #28a745; color: white; border: none; padding: 10px; cursor: pointer;">Refresh Courier Data</button>'; 448 } else { 449 echo '<p style="color: red;">Failed to fetch courier data.</p>'; 450 } 451 } 452 } 18 include 'lib/class.OrderRatioChecker.php'; 453 19 454 20 // Initialize the plugin 455 new Order _Ratio_Checker();21 new OrderRatioChecker(); -
bd-courier-order-ratio-checker/trunk/readme.txt
r3163421 r3173906 5 5 Requires at least: 6.0 6 6 Tested up to: 6.6.2 7 Stable tag: 1. 87 Stable tag: 1.9 8 8 Requires PHP: 7.4 9 9 License: GPLv2 or later
Note: See TracChangeset
for help on using the changeset viewer.