Changeset 3382611
- Timestamp:
- 10/22/2025 12:53:29 PM (5 months ago)
- Location:
- storeman
- Files:
-
- 2 added
- 12 edited
- 1 copied
-
tags/2.2.8 (copied) (copied from storeman/trunk)
-
tags/2.2.8/README.txt (modified) (3 diffs)
-
tags/2.2.8/admin/class-storeman-admin.php (modified) (9 diffs)
-
tags/2.2.8/admin/class-webhook-storeman-action-new.php (added)
-
tags/2.2.8/admin/class-webhook-storeman-action.php (modified) (3 diffs)
-
tags/2.2.8/includes/class-storeman.php (modified) (1 diff)
-
tags/2.2.8/public/js/storeman-public.js (modified) (2 diffs)
-
tags/2.2.8/storeman.php (modified) (2 diffs)
-
trunk/README.txt (modified) (3 diffs)
-
trunk/admin/class-storeman-admin.php (modified) (9 diffs)
-
trunk/admin/class-webhook-storeman-action-new.php (added)
-
trunk/admin/class-webhook-storeman-action.php (modified) (3 diffs)
-
trunk/includes/class-storeman.php (modified) (1 diff)
-
trunk/public/js/storeman-public.js (modified) (2 diffs)
-
trunk/storeman.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
storeman/tags/2.2.8/README.txt
r2912185 r3382611 3 3 Tags: storeman , woocommerce , stock manager , export product , import product , stock, orders, bulk edit products 4 4 Requires at lest: 3.0.1 5 Tested up to: 6. 06 Stable tag: 2.2. 75 Tested up to: 6.8 6 Stable tag: 2.2.8 7 7 License: GPLv2 or later 8 8 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 28 28 no. this plugin is just plug&play. 29 29 30 = Use upsert and stock endpoints? = 31 32 stock body: 33 { 34 "fromFile":false, 35 "url":null, // if from file 36 "mode":"set", // enums: add / set. def: set 37 "data":[{"sku":"EG","quantity":1}] 38 } 39 upsert body: 40 { 41 "create_if_missing": true, // def: true 42 "products":[{"sku":"test","name":"test name"},{"sku":"test variation","name":"test variation name","parent_sku":"test"}] 43 } 44 30 45 == Screenshots == 31 46 … … 33 48 34 49 == Changelog == 50 = 2.2.8 = 51 add elementor pro new action storeman, add woocommerce end point stock and upsert 35 52 = 2.2.7 = 36 53 add elementor pro form toDo field and storeman_webhook_response action on get response. and also storeman_webhooks_fields and storeman_webhooks_print_response filters -
storeman/tags/2.2.8/admin/class-storeman-admin.php
r2912177 r3382611 23 23 class Storeman_Admin 24 24 { 25 26 25 /** 27 26 * The ID of this plugin. … … 166 165 return $c; 167 166 } 168 public function register_action( $form_actions_registrar ) { 167 public function register_action($form_actions_registrar) 168 { 169 169 170 170 171 171 try { 172 require_once plugin_dir_path( dirname( __FILE__ )) . 'admin/class-webhook-storeman-action.php';173 $form_actions_registrar->register( new \StoremanElementorAction());172 require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-webhook-storeman-action.php'; 173 $form_actions_registrar->register(new \StoremanElementorAction()); 174 174 } catch (\Exception $th) { 175 // cant add action to elementor pro form 176 } 177 178 } 175 // cant add action to elementor pro form 176 } 177 try { 178 require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-webhook-storeman-action-new.php'; 179 $form_actions_registrar->register(new \StoremanElementorActionNew()); 180 } catch (\Exception $th) { 181 // cant add action to elementor pro form 182 } 183 184 } 179 185 public function set_get_item_schema($c) 180 186 { … … 301 307 $attributes = array(); 302 308 $parent = wc_get_product($variation->get_parent_id()); 303 309 304 310 if (! $parent) { 305 311 return new WP_Error( … … 310 316 ); 311 317 } 312 318 313 319 $parent_attributes = $parent->get_attributes(); 314 320 315 321 foreach ($request['attributes'] as $attribute) { 316 322 $attribute_id = 0; 317 323 $attribute_name = ''; 318 324 319 325 // Check ID for global attributes or name for product attributes. 320 326 if (! empty($attribute['id'])) { … … 324 330 $attribute_name = sanitize_title($attribute['name']); 325 331 } 326 332 327 333 if (! $attribute_id && ! $attribute_name) { 328 334 continue; 329 335 } 330 336 331 337 if (! isset($parent_attributes[ $attribute_name ]) || ! $parent_attributes[ $attribute_name ]->get_variation()) { 332 338 $attribute_name = strtolower($attribute_name); 333 if (! isset($parent_attributes[ $attribute_name ]) || ! $parent_attributes[ $attribute_name ]->get_variation()) {339 if (! isset($parent_attributes[ $attribute_name ]) || ! $parent_attributes[ $attribute_name ]->get_variation()) { 334 340 continue; 335 341 } 336 342 } 337 343 338 344 $attribute_key = sanitize_title($parent_attributes[ $attribute_name ]->get_name()); 339 345 $attribute_value = isset($attribute['option']) ? wc_clean(stripslashes($attribute['option'])) : ''; 340 346 341 347 if ($parent_attributes[ $attribute_name ]->is_taxonomy()) { 342 348 // If dealing with a taxonomy, we need to get the slug from the name posted to the API. 343 349 $term = get_term_by('name', $attribute_value, $attribute_name); 344 350 345 351 if ($term && ! is_wp_error($term)) { 346 352 $attribute_value = $term->slug; 347 // $attribute_value = sanitize_title($attribute_value);353 // $attribute_value = sanitize_title($attribute_value); 348 354 } else { 349 355 $attribute_value = sanitize_title($attribute_value); 350 356 } 351 357 } 352 358 353 359 $attributes[ $attribute_key ] = $attribute_value; 354 360 } 355 361 356 362 $variation->set_attributes($attributes); 357 363 } 358 364 359 365 360 366 return $variation; 361 367 } … … 366 372 } 367 373 $languages = pll_the_languages(array( 'raw' => 1 )); 368 369 374 375 370 376 371 377 $product = wc_get_product($parent_post_id); … … 408 414 ), 409 415 ); 410 416 411 417 return array_merge($topic_hooks, $new_hooks); 412 418 } … … 419 425 'update_variation', 420 426 ); 421 427 422 428 return array_merge($topic_events, $new_events); 423 429 } … … 429 435 'product.update_variation' => __('Product Variation Updated', 'woocommerce'), 430 436 ); 437 438 return array_merge($topics, $new_topics); 439 } 440 public function storeman_update_stock_permission(\WP_REST_Request $request) 441 { 442 // אם WooCommerce לא פעיל – אין מה להמשיך 443 if (!class_exists('WooCommerce')) { 444 return false; 445 } 446 447 list($ck, $cs) = $this->storeman_wc_get_basic_auth_pair($request); 448 449 // אם סופקו מפתחות – נוודא שהם קיימים ובעלי write 450 if ($ck !== '' && $cs !== '') { 451 $row = $this->storeman_wc_find_api_key_row_by_consumer_key($ck); 452 if (!$row) { 453 return false; 454 } 455 456 // בדיקת התאמת secret 457 if (!hash_equals((string)$row['consumer_secret'], (string)$cs)) { 458 return false; 459 } 460 461 // הרשאות צריכות להכיל write 462 $perm = isset($row['permissions']) ? strtolower((string)$row['permissions']) : ''; 463 if (!in_array($perm, ['write','read_write'], true)) { 464 return false; 465 } 466 467 // נחשב שהבקשה אושרה – ה-user_id של המפתח יקבע ע"י מנגנון auth של WC (אם פועל), 468 // אך מבחינתנו מספיק שהמפתח תקף ובעל write. 469 return true; 470 } 471 472 // ללא CK/CS – נאפשר למשתמשים שיש להם יכולות מתאימות במערכת (לדוגמה חיבור קיים) 473 if (current_user_can('edit_products') || current_user_can('manage_woocommerce')) { 474 return true; 475 } 476 477 return false; 478 } 479 public function register_custom_routes() 480 { 481 register_rest_route('wc/v3', '/stock', [ 482 'methods' => 'POST', 483 'callback' => [$this,'storeman_update_stock_handler'], 484 'permission_callback' => [$this, 'storeman_update_stock_permission'], 485 'args' => [ 486 'fromFile' => [ 487 'description' => 'if true - send a url to load the json from file', 488 'type' => 'boolean', 489 'required' => false, 490 491 ], 492 'url' => [ 493 'description' => 'the url to load the json from if fromFile is true', 494 'type' => 'string', 495 'required' => false, 496 497 ], 498 'mode' => [ 499 'description' => 'set או add. ברירת מחדל set', 500 'type' => 'string', 501 'required' => false, 502 'enum' => ['set','add'], 503 ], 504 ], 505 ]); 506 register_rest_route('wc/v3', '/upsert', [ 507 'methods' => 'POST', 508 'callback' => [$this,'wc_upsert_by_sku_via_core'], 509 'permission_callback' => [$this, 'storeman_update_stock_permission'], 510 'args' => [ 511 'create_if_missing' => [ 512 'description' => 'אם המוצר/וריאציה לא קיימים, האם ליצור אותם אוטומטית', 513 'type' => 'boolean', 514 'required' => false, 515 516 ], 517 'products' => [ 518 'required' => true, 519 'type' => 'array', 520 'items' => [ 521 'type' => 'object', 522 'properties' => [ 523 'sku' => [ 'required' => true, 'type' => 'string' ], 524 'type' => [ 'required' => false, 'type' => 'string', 'enum' => ['simple','variable','external','grouped','variation'] ], 525 'create_if_missing' => [ 'required' => false, 'type' => 'boolean' ], 526 'parent_sku' => [ 'required' => false, 'type' => 'string' ], 527 ], 528 ], 529 ], 530 ], 531 ]); 532 } 533 public function storeman_update_stock_handler(\WP_REST_Request $request) 534 { 535 if (!class_exists('WooCommerce')) { 536 return new \WP_REST_Response(['success' => false,'message' => 'WooCommerce not active'], 400); 537 } 538 539 $mode = $request->get_param('mode') ?: 'set'; 540 $fromFile = $request->get_param('fromFile') ?: false; 541 if ($fromFile) { 542 $url = $request->get_param('url') ?: ''; 543 if ($url === '') { 544 return new \WP_REST_Response(['success' => false,'message' => 'Missing url parameter'], 400); 545 } 546 // schedule a single WP event to load/process the file in background 547 $url = esc_url_raw($url); 548 $args = array( 549 'url' => $url, 550 'mode' => $mode, 551 ); 552 553 // avoid double-scheduling the exact same job 554 if (! wp_next_scheduled('load_stock_from_file', $args)) { 555 wp_schedule_single_event(time() + 5, 'load_stock_from_file', $args); 556 $return = [ 557 'status' => true, 558 'message' => 'File scheduled for background processing', 559 'scheduled' => true, 560 'url' => $url, 561 ]; 562 } else { 563 $return = [ 564 'status' => false, 565 'message' => 'A job for this file is already scheduled', 566 'scheduled' => false, 567 'url' => $url, 568 ]; 569 } 570 571 } 572 else 573 { 574 $raw = $request->get_param('data'); 575 if(is_string($raw)){ 576 $data = json_decode($raw, true); 431 577 432 return array_merge($topics, $new_topics); 433 } 578 // תמיכה במבנה "אובייקטים מופרדים בפסיקים" שנשלחו בלי סוגריים 579 if (!is_array($data)) { 580 $try = json_decode('['.$raw.']', true); 581 if (is_array($try)) { 582 $data = $try; 583 } 584 } 585 if (!is_array($data)) { 586 return new \WP_REST_Response(['success' => false,'message' => 'Invalid JSON array'], 400); 587 } 588 } 589 else{ 590 $data = $raw; 591 } 592 593 $results = []; 594 $updated = 0; 595 $return = $this->update_batch_stock($data, $mode); 596 597 } 598 return new \WP_REST_Response($return, 200); 599 } 600 public function do_event_load_file_and_update_stock($url, $mode) 601 { 602 if (!class_exists('WooCommerce')) { 603 // log error 604 return; 605 } 606 607 // wp_single_event('storeman_log_event', 'info', 'Fetching stock update file from URL: '.$url); 608 $response = wp_remote_get($url); 609 if (is_wp_error($response)) { 610 // wp_single_event('storeman_log_event', 'error', 'Error fetching stock update file from URL: '.$url.' Error: '.$response->get_error_message()); 611 return; 612 } 613 $raw = wp_remote_retrieve_body($response); 614 $data = json_decode($raw, true); 615 616 if (!is_array($data)) { 617 // wp_single_event('storeman_log_event', 'error', 'Invalid JSON array in stock update file from URL: '.$url); 618 return; 619 } 620 621 $result = $this->update_batch_stock($data, $mode); 622 // wp_single_event('storeman_log_event', 'info', 'Stock update from file completed. Updated items: '.$result['updated'].' Total items processed: '.count($data)); 623 } 624 private function update_batch_stock(array $data, $mode) 625 { 626 $results = []; 627 $updated = 0; 628 629 foreach ($data as $idx => $item) { 630 $sku = isset($item['sku']) ? trim((string)$item['sku']) : ''; 631 $qty = isset($item['quantity']) ? $item['quantity'] : null; 632 633 // פר-פריט: האם לא לגעת ב-manage_stock אם הוא כבוי? 634 // ברירת מחדל: false (כלומר כן להדליק ניהול מלאי אם כבוי) 635 $dont_toggle_manage = !empty($item['dont_toggle_manage_stock']); 636 637 if ($sku === '' || !is_numeric($qty)) { 638 $results[] = [ 639 'index' => $idx, 640 'sku' => $sku, 641 'status' => 'error', 642 'error' => 'Missing sku or invalid quantity' 643 ]; 644 continue; 645 } 646 647 // איתור מוצר/וריאציה לפי SKU 648 $product_id = wc_get_product_id_by_sku($sku); 649 if (!$product_id) { 650 $results[] = [ 651 'index' => $idx, 652 'sku' => $sku, 653 'status' => 'not_found' 654 ]; 655 continue; 656 } 657 658 $product = wc_get_product($product_id); 659 if (!$product) { 660 $results[] = [ 661 'index' => $idx, 662 'sku' => $sku, 663 'status' => 'error', 664 'error' => 'Product load failed' 665 ]; 666 continue; 667 } 668 669 $was_managing = $product->managing_stock(); 670 671 // אם ניהול מלאי כבוי: 672 // - אם dont_toggle_manage_stock=true => לא משנים מצב ולא מעדכנים כמות (שזו המשמעות המתבקשת), 673 // ונחזיר status שמסביר את הדילוג. 674 // - אחרת נדליק ניהול מלאי. 675 if (!$was_managing) { 676 if ($dont_toggle_manage) { 677 $results[] = [ 678 'index' => $idx, 679 'sku' => $sku, 680 'status' => 'skipped_manage_stock_off', 681 'reason' => 'Product is not set to manage stock and dont_toggle_manage_stock=true', 682 'product_id' => $product->get_id(), 683 'type' => $product->get_type(), 684 ]; 685 continue; 686 } else { 687 $product->set_manage_stock(true); 688 } 689 } 690 691 try { 692 $delta = (float)$qty; 693 if ($mode === 'set') { 694 wc_update_product_stock($product, $delta, 'set'); 695 } else { 696 if ($delta > 0) { 697 wc_update_product_stock($product, $delta, 'increase'); 698 } elseif ($delta < 0) { 699 wc_update_product_stock($product, abs($delta), 'decrease'); 700 } // 0 => אין שינוי 701 } 702 703 $product->save(); 704 705 $results[] = [ 706 'index' => $idx, 707 'sku' => $sku, 708 'status' => 'updated', 709 'stock_quantity' => (float) $product->get_stock_quantity(), 710 'product_id' => $product->get_id(), 711 'type' => $product->get_type(), 712 'manage_stock' => $product->managing_stock(), 713 ]; 714 $updated++; 715 } catch (\Throwable $e) { 716 $results[] = [ 717 'index' => $idx, 718 'sku' => $sku, 719 'status' => 'error', 720 'error' => $e->getMessage() 721 ]; 722 } 723 } 724 return [ 725 'success' => true, 726 'mode' => $mode, 727 'updated' => $updated, 728 'results' => $results 729 ]; 730 } 731 public function wc_upsert_by_sku_via_core(WP_REST_Request $request) 732 { 733 if (! class_exists('WooCommerce')) { 734 return new WP_REST_Response(['error' => 'WooCommerce not active'], 400); 735 } 736 737 // ודא שהבקרים טעונים 738 if (! class_exists('WC_REST_Products_Controller') || ! class_exists('WC_REST_Product_Variations_Controller')) { 739 return new WP_REST_Response(['error' => 'WooCommerce REST controllers unavailable'], 500); 740 } 741 742 $data = $request->get_json_params() ?: []; 743 $products = isset($data['products']) && is_array($data['products']) ? $data['products'] : []; 744 $create_if_missing = isset($data['create_if_missing']) ? (bool)$data['create_if_missing'] : true; 745 $results = []; 746 foreach ($products as $k => $data) { 747 $result = ['index' => $k]; 748 $sku = trim((string)($data['sku'] ?? '')); 749 if (!$sku) { 750 $result['status'] = false; 751 $result['error'] = 'Missing sku'; 752 $results[] = $result; 753 continue; 754 } 755 756 $type = $data['type'] ?? 'simple'; 757 $create_if_missing = array_key_exists('create_if_missing', $data) ? (bool)$data['create_if_missing'] : $create_if_missing; 758 759 try { 760 if ($type === 'variation') { 761 // ----- וריאציה: צריך parent_sku, ונתמקד בבקר הוריאציות של ווקומרס ----- 762 $parent_sku = trim((string)($data['parent_sku'] ?? '')); 763 if (!$parent_sku) { 764 765 $result['status'] = false; 766 $result['error'] = 'Variation requires parent_sku'; 767 $results[] = $result; 768 continue; 769 770 } 771 772 // מצא/צור הורה לפי SKU (באמצעות בקר המוצרים) 773 $parent_id = wc_get_product_id_by_sku($parent_sku); 774 $products_controller = new WC_REST_Products_Controller(); 775 776 if (!$parent_id) { 777 if (!$create_if_missing) { 778 $result['status'] = false; 779 $result['error'] = 'Parent not found by parent_sku and create_if_missing=false'; 780 $results[] = $result; 781 continue; 782 } 783 // צור הורה מסוג variable (באמצעות create_item הרשמי) 784 $parent_create_req = new WP_REST_Request('POST', '/wc/v3/products'); 785 $parent_payload = $data; 786 $parent_payload['sku'] = $parent_sku; 787 $parent_payload['type'] = 'variable'; 788 $parent_create_req->set_body_params($parent_payload); 789 $parent_resp = $products_controller->create_item($parent_create_req); 790 if ($parent_resp instanceof WP_Error) { 791 792 $result['status'] = false; 793 $result['error'] = $parent_resp->get_error_message(); 794 $results[] = $result; 795 continue; 796 } 797 $parent_arr = $parent_resp->get_data(); 798 $parent_id = (int)($parent_arr['id'] ?? 0); 799 if (!$parent_id) { 800 $result['status'] = false; 801 $result['error'] = 'Failed to create parent'; 802 $results[] = $result; 803 continue; 804 } 805 } else { 806 // אם ההורה קיים אך אינו variable – עדכן דרך הבקר הרשמי 807 $parent = wc_get_product($parent_id); 808 if ($parent && $parent->get_type() !== 'variable') { 809 $parent_update_req = new WP_REST_Request('PUT', '/wc/v3/products/'.$parent_id); 810 $parent_update_req->set_url_params(['id' => $parent_id]); 811 $parent_update_req->set_body_params(['type' => 'variable']); 812 $u = $products_controller->update_item($parent_update_req); 813 if ($u instanceof WP_Error) { 814 $result['status'] = false; 815 $result['error'] = $u->get_error_message(); 816 $results[] = $result; 817 continue; 818 } 819 } 820 } 821 822 // כעת – וריאציה לפי SKU 823 $variation_id = wc_get_product_id_by_sku($sku); 824 $variations_controller = new WC_REST_Product_Variations_Controller(); 825 826 if ($variation_id) { 827 // UPDATE ע"י הבקר הרשמי: /products/{product_id}/variations/{id} 828 $upd_req = new WP_REST_Request('PUT', '/wc/v3/products/'.$parent_id.'/variations/'.$variation_id); 829 $upd_req->set_url_params(['product_id' => $parent_id, 'id' => $variation_id]); 830 $upd_req->set_body_params($data); 831 $resp = $variations_controller->update_item($upd_req); 832 if ($resp instanceof WP_Error) { 833 $result['status'] = false; 834 $result['error'] = $resp->get_error_message(); 835 $results[] = $result; 836 continue; 837 } 838 return $resp; // מחזיר את המערך התקני של WooCommerce 839 } else { 840 if (!$create_if_missing) { 841 return new WP_REST_Response(['error' => 'Variation not found by sku and create_if_missing=false'], 404); 842 } 843 // CREATE ע"י הבקר הרשמי 844 $crt_req = new WP_REST_Request('POST', '/wc/v3/products/'.$parent_id.'/variations'); 845 $crt_req->set_url_params(['product_id' => $parent_id]); 846 $crt_req->set_body_params($data); 847 $resp = $variations_controller->create_item($crt_req); 848 if ($resp instanceof WP_Error) { 849 return new WP_REST_Response(['error' => $resp->get_error_message()], 400); 850 } 851 $result['status'] = true; 852 $result['data'] = $resp->get_data(); 853 $results[] = $result; 854 continue; 855 // return $resp; 856 } 857 858 } else { 859 // ----- מוצר (לא וריאציה): נשען על WC_REST_Products_Controller ----- 860 $product_id = wc_get_product_id_by_sku($sku); 861 $products_controller = new WC_REST_Products_Controller(); 862 863 if ($product_id) { 864 // UPDATE ע"י הבקר הרשמי: /products/{id} 865 $upd_req = new WP_REST_Request('PUT', '/wc/v3/products/'.$product_id); 866 $upd_req->set_url_params(['id' => $product_id]); 867 $upd_req->set_body_params($data); 868 $resp = $products_controller->update_item($upd_req); 869 if ($resp instanceof WP_Error) { 870 871 $result['status'] = false; 872 $result['error'] = $resp->get_error_message(); 873 $results[] = $result; 874 continue; 875 } 876 $result['status'] = true; 877 $result['data'] = $resp->get_data(); 878 $results[] = $result; 879 continue; 880 } else { 881 if (!$create_if_missing) { 882 $result['status'] = false; 883 $result['error'] = 'Product not found by sku and create_if_missing=false'; 884 $results[] = $result; 885 continue; 886 } 887 // CREATE ע"י הבקר הרשמי 888 // ודא type אם לא נשלח 889 if (empty($data['type'])) { 890 $data['type'] = 'simple'; 891 } 892 $crt_req = new WP_REST_Request('POST', '/wc/v3/products'); 893 $crt_req->set_body_params($data); 894 $resp = $products_controller->create_item($crt_req); 895 if ($resp instanceof WP_Error) { 896 $result['status'] = false; 897 $result['error'] = $resp->get_error_message(); 898 $results[] = $result; 899 continue; 900 } 901 $result['status'] = true; 902 $result['data'] = $resp->get_data(); 903 $results[] = $result; 904 continue; 905 } 906 } 907 908 } catch (Throwable $e) { 909 $result['status'] = false; 910 $result['error'] = $e->getMessage(); 911 $results[] = $result; 912 continue; 913 // return new WP_REST_Response(['error' => $e->getMessage()], 500); 914 } 915 // $result['status'] = true; 916 // $results[] = $result; 917 } 918 return new WP_REST_Response(['results' => $results], 200); 919 } 920 public function storeman_wc_get_basic_auth_pair(\WP_REST_Request $request): array 921 { 922 // 1) Authorization: Basic ... 923 $auth = isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] : (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) ? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] : ''); 924 if (!$auth && function_exists('apache_request_headers')) { 925 $headers = apache_request_headers(); 926 if (!empty($headers['Authorization'])) { 927 $auth = $headers['Authorization']; 928 } 929 } 930 if ($auth && stripos($auth, 'Basic ') === 0) { 931 $decoded = base64_decode(substr($auth, 6)); 932 if ($decoded !== false && strpos($decoded, ':') !== false) { 933 list($user, $pass) = explode(':', $decoded, 2); 934 return [trim($user), trim($pass)]; 935 } 936 } 937 938 // 2) Query / Body params (WooCommerce REST API תומך גם בזה) 939 $ck = $request->get_param('consumer_key') ?: ''; 940 $cs = $request->get_param('consumer_secret') ?: ''; 941 if ($ck !== '' && $cs !== '') { 942 return [$ck, $cs]; 943 } 944 945 return ['', '']; 946 } 947 948 public function storeman_wc_find_api_key_row_by_consumer_key($consumer_key) 949 { 950 global $wpdb; 951 952 if ($consumer_key === '') { 953 return null; 954 } 955 956 // WooCommerce שומר consumer_key בהאש SHA256 (לרוב דרך wc_api_hash אם קיים) 957 if (function_exists('wc_api_hash')) { 958 $hash = wc_api_hash($consumer_key); 959 } else { 960 $hash = hash('sha256', $consumer_key); 961 } 962 963 $table = $wpdb->prefix . 'woocommerce_api_keys'; 964 // expected columns: key_id, user_id, permissions, consumer_key (hashed), consumer_secret, truncated_key, last_access, nonces, etc. 965 $row = $wpdb->get_row( 966 $wpdb->prepare("SELECT * FROM {$table} WHERE consumer_key = %s LIMIT 1", $hash), 967 ARRAY_A 968 ); 969 970 return $row ?: null; 971 } 972 973 974 975 434 976 } 435 // add_filter('storeman_stock_quantity_doubleval' , function($type){436 // return true;437 // }); -
storeman/tags/2.2.8/admin/class-webhook-storeman-action.php
r2912185 r3382611 9 9 public function get_label() 10 10 { 11 return 'Storeman ';11 return 'Storeman (Legacy)'; 12 12 } 13 13 // namespace Elementor\Core\Base; … … 30 30 'storeman_domain', 31 31 [ 32 'label' => esc_html__('Domain ', 'elementor'),32 'label' => esc_html__('Domain (without / at the end)', 'elementor'), 33 33 'type' => 'text', 34 'default' => get_site_url().".storeman.co.il",34 'default' => "", 35 35 36 36 … … 60 60 'storeman_action', 61 61 [ 62 'label' => esc_html__(' ToDo', 'elementor'),62 'label' => esc_html__('toDo', 'elementor'), 63 63 'type' => 'text', 64 64 'default' => '', -
storeman/tags/2.2.8/includes/class-storeman.php
r2912177 r3382611 199 199 $this->loader->add_action("woocommerce_rest_pre_insert_product_variation_object", $plugin_admin, 'remove_product_variation_webhook_action',1,3); 200 200 $this->loader->add_action("woocommerce_rest_insert_product_variation_object", $plugin_admin, 'remove_product_variation_webhook_action',999,3); 201 202 201 202 $this->loader->add_action('rest_api_init', $plugin_admin, 'register_custom_routes' ); 203 $this->loader->add_action('load_stock_from_file', $plugin_admin, 'do_event_load_file_and_update_stock',999,2); 203 204 } 204 205 -
storeman/tags/2.2.8/public/js/storeman-public.js
r2912177 r3382611 3 3 $(document).on('submit_success', function (e, form) { 4 4 5 6 if (form.data.storeman_webhook_response && form.data.storeman_webhook_response.redirect) { 7 window.location.href = form.data.storeman_webhook_response.redirect; 8 return false; 9 } 5 10 if (form.data.storeman_webhook_response) { 6 11 $("#storeman_webhook_response").remove(); … … 9 14 10 15 } 16 // if (form.data.storeman_webhook_redirect) { 17 18 // $("#storeman_webhook_response").remove(); 19 // var div = $("<div id='storeman_webhook_response'>"+form.data.storeman_webhook_response+"</div>"); 20 // $(e.target).append(div); 21 22 // } 11 23 12 24 -
storeman/tags/2.2.8/storeman.php
r2912185 r3382611 17 17 * Plugin URI: https://storeman.co.il 18 18 * Description: add storeman to your WordPress site. 19 * Version: 2.2. 719 * Version: 2.2.8 20 20 * Author: avitrop 21 21 * Author URI: https://profiles.wordpress.org/avitrop/ … … 36 36 * Rename this for your plugin and update it as you release new versions. 37 37 */ 38 define( 'STOREMAN_VERSION', '2.2. 7' );38 define( 'STOREMAN_VERSION', '2.2.8' ); 39 39 40 40 /** -
storeman/trunk/README.txt
r2912185 r3382611 3 3 Tags: storeman , woocommerce , stock manager , export product , import product , stock, orders, bulk edit products 4 4 Requires at lest: 3.0.1 5 Tested up to: 6. 06 Stable tag: 2.2. 75 Tested up to: 6.8 6 Stable tag: 2.2.8 7 7 License: GPLv2 or later 8 8 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 28 28 no. this plugin is just plug&play. 29 29 30 = Use upsert and stock endpoints? = 31 32 stock body: 33 { 34 "fromFile":false, 35 "url":null, // if from file 36 "mode":"set", // enums: add / set. def: set 37 "data":[{"sku":"EG","quantity":1}] 38 } 39 upsert body: 40 { 41 "create_if_missing": true, // def: true 42 "products":[{"sku":"test","name":"test name"},{"sku":"test variation","name":"test variation name","parent_sku":"test"}] 43 } 44 30 45 == Screenshots == 31 46 … … 33 48 34 49 == Changelog == 50 = 2.2.8 = 51 add elementor pro new action storeman, add woocommerce end point stock and upsert 35 52 = 2.2.7 = 36 53 add elementor pro form toDo field and storeman_webhook_response action on get response. and also storeman_webhooks_fields and storeman_webhooks_print_response filters -
storeman/trunk/admin/class-storeman-admin.php
r2912177 r3382611 23 23 class Storeman_Admin 24 24 { 25 26 25 /** 27 26 * The ID of this plugin. … … 166 165 return $c; 167 166 } 168 public function register_action( $form_actions_registrar ) { 167 public function register_action($form_actions_registrar) 168 { 169 169 170 170 171 171 try { 172 require_once plugin_dir_path( dirname( __FILE__ )) . 'admin/class-webhook-storeman-action.php';173 $form_actions_registrar->register( new \StoremanElementorAction());172 require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-webhook-storeman-action.php'; 173 $form_actions_registrar->register(new \StoremanElementorAction()); 174 174 } catch (\Exception $th) { 175 // cant add action to elementor pro form 176 } 177 178 } 175 // cant add action to elementor pro form 176 } 177 try { 178 require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-webhook-storeman-action-new.php'; 179 $form_actions_registrar->register(new \StoremanElementorActionNew()); 180 } catch (\Exception $th) { 181 // cant add action to elementor pro form 182 } 183 184 } 179 185 public function set_get_item_schema($c) 180 186 { … … 301 307 $attributes = array(); 302 308 $parent = wc_get_product($variation->get_parent_id()); 303 309 304 310 if (! $parent) { 305 311 return new WP_Error( … … 310 316 ); 311 317 } 312 318 313 319 $parent_attributes = $parent->get_attributes(); 314 320 315 321 foreach ($request['attributes'] as $attribute) { 316 322 $attribute_id = 0; 317 323 $attribute_name = ''; 318 324 319 325 // Check ID for global attributes or name for product attributes. 320 326 if (! empty($attribute['id'])) { … … 324 330 $attribute_name = sanitize_title($attribute['name']); 325 331 } 326 332 327 333 if (! $attribute_id && ! $attribute_name) { 328 334 continue; 329 335 } 330 336 331 337 if (! isset($parent_attributes[ $attribute_name ]) || ! $parent_attributes[ $attribute_name ]->get_variation()) { 332 338 $attribute_name = strtolower($attribute_name); 333 if (! isset($parent_attributes[ $attribute_name ]) || ! $parent_attributes[ $attribute_name ]->get_variation()) {339 if (! isset($parent_attributes[ $attribute_name ]) || ! $parent_attributes[ $attribute_name ]->get_variation()) { 334 340 continue; 335 341 } 336 342 } 337 343 338 344 $attribute_key = sanitize_title($parent_attributes[ $attribute_name ]->get_name()); 339 345 $attribute_value = isset($attribute['option']) ? wc_clean(stripslashes($attribute['option'])) : ''; 340 346 341 347 if ($parent_attributes[ $attribute_name ]->is_taxonomy()) { 342 348 // If dealing with a taxonomy, we need to get the slug from the name posted to the API. 343 349 $term = get_term_by('name', $attribute_value, $attribute_name); 344 350 345 351 if ($term && ! is_wp_error($term)) { 346 352 $attribute_value = $term->slug; 347 // $attribute_value = sanitize_title($attribute_value);353 // $attribute_value = sanitize_title($attribute_value); 348 354 } else { 349 355 $attribute_value = sanitize_title($attribute_value); 350 356 } 351 357 } 352 358 353 359 $attributes[ $attribute_key ] = $attribute_value; 354 360 } 355 361 356 362 $variation->set_attributes($attributes); 357 363 } 358 364 359 365 360 366 return $variation; 361 367 } … … 366 372 } 367 373 $languages = pll_the_languages(array( 'raw' => 1 )); 368 369 374 375 370 376 371 377 $product = wc_get_product($parent_post_id); … … 408 414 ), 409 415 ); 410 416 411 417 return array_merge($topic_hooks, $new_hooks); 412 418 } … … 419 425 'update_variation', 420 426 ); 421 427 422 428 return array_merge($topic_events, $new_events); 423 429 } … … 429 435 'product.update_variation' => __('Product Variation Updated', 'woocommerce'), 430 436 ); 437 438 return array_merge($topics, $new_topics); 439 } 440 public function storeman_update_stock_permission(\WP_REST_Request $request) 441 { 442 // אם WooCommerce לא פעיל – אין מה להמשיך 443 if (!class_exists('WooCommerce')) { 444 return false; 445 } 446 447 list($ck, $cs) = $this->storeman_wc_get_basic_auth_pair($request); 448 449 // אם סופקו מפתחות – נוודא שהם קיימים ובעלי write 450 if ($ck !== '' && $cs !== '') { 451 $row = $this->storeman_wc_find_api_key_row_by_consumer_key($ck); 452 if (!$row) { 453 return false; 454 } 455 456 // בדיקת התאמת secret 457 if (!hash_equals((string)$row['consumer_secret'], (string)$cs)) { 458 return false; 459 } 460 461 // הרשאות צריכות להכיל write 462 $perm = isset($row['permissions']) ? strtolower((string)$row['permissions']) : ''; 463 if (!in_array($perm, ['write','read_write'], true)) { 464 return false; 465 } 466 467 // נחשב שהבקשה אושרה – ה-user_id של המפתח יקבע ע"י מנגנון auth של WC (אם פועל), 468 // אך מבחינתנו מספיק שהמפתח תקף ובעל write. 469 return true; 470 } 471 472 // ללא CK/CS – נאפשר למשתמשים שיש להם יכולות מתאימות במערכת (לדוגמה חיבור קיים) 473 if (current_user_can('edit_products') || current_user_can('manage_woocommerce')) { 474 return true; 475 } 476 477 return false; 478 } 479 public function register_custom_routes() 480 { 481 register_rest_route('wc/v3', '/stock', [ 482 'methods' => 'POST', 483 'callback' => [$this,'storeman_update_stock_handler'], 484 'permission_callback' => [$this, 'storeman_update_stock_permission'], 485 'args' => [ 486 'fromFile' => [ 487 'description' => 'if true - send a url to load the json from file', 488 'type' => 'boolean', 489 'required' => false, 490 491 ], 492 'url' => [ 493 'description' => 'the url to load the json from if fromFile is true', 494 'type' => 'string', 495 'required' => false, 496 497 ], 498 'mode' => [ 499 'description' => 'set או add. ברירת מחדל set', 500 'type' => 'string', 501 'required' => false, 502 'enum' => ['set','add'], 503 ], 504 ], 505 ]); 506 register_rest_route('wc/v3', '/upsert', [ 507 'methods' => 'POST', 508 'callback' => [$this,'wc_upsert_by_sku_via_core'], 509 'permission_callback' => [$this, 'storeman_update_stock_permission'], 510 'args' => [ 511 'create_if_missing' => [ 512 'description' => 'אם המוצר/וריאציה לא קיימים, האם ליצור אותם אוטומטית', 513 'type' => 'boolean', 514 'required' => false, 515 516 ], 517 'products' => [ 518 'required' => true, 519 'type' => 'array', 520 'items' => [ 521 'type' => 'object', 522 'properties' => [ 523 'sku' => [ 'required' => true, 'type' => 'string' ], 524 'type' => [ 'required' => false, 'type' => 'string', 'enum' => ['simple','variable','external','grouped','variation'] ], 525 'create_if_missing' => [ 'required' => false, 'type' => 'boolean' ], 526 'parent_sku' => [ 'required' => false, 'type' => 'string' ], 527 ], 528 ], 529 ], 530 ], 531 ]); 532 } 533 public function storeman_update_stock_handler(\WP_REST_Request $request) 534 { 535 if (!class_exists('WooCommerce')) { 536 return new \WP_REST_Response(['success' => false,'message' => 'WooCommerce not active'], 400); 537 } 538 539 $mode = $request->get_param('mode') ?: 'set'; 540 $fromFile = $request->get_param('fromFile') ?: false; 541 if ($fromFile) { 542 $url = $request->get_param('url') ?: ''; 543 if ($url === '') { 544 return new \WP_REST_Response(['success' => false,'message' => 'Missing url parameter'], 400); 545 } 546 // schedule a single WP event to load/process the file in background 547 $url = esc_url_raw($url); 548 $args = array( 549 'url' => $url, 550 'mode' => $mode, 551 ); 552 553 // avoid double-scheduling the exact same job 554 if (! wp_next_scheduled('load_stock_from_file', $args)) { 555 wp_schedule_single_event(time() + 5, 'load_stock_from_file', $args); 556 $return = [ 557 'status' => true, 558 'message' => 'File scheduled for background processing', 559 'scheduled' => true, 560 'url' => $url, 561 ]; 562 } else { 563 $return = [ 564 'status' => false, 565 'message' => 'A job for this file is already scheduled', 566 'scheduled' => false, 567 'url' => $url, 568 ]; 569 } 570 571 } 572 else 573 { 574 $raw = $request->get_param('data'); 575 if(is_string($raw)){ 576 $data = json_decode($raw, true); 431 577 432 return array_merge($topics, $new_topics); 433 } 578 // תמיכה במבנה "אובייקטים מופרדים בפסיקים" שנשלחו בלי סוגריים 579 if (!is_array($data)) { 580 $try = json_decode('['.$raw.']', true); 581 if (is_array($try)) { 582 $data = $try; 583 } 584 } 585 if (!is_array($data)) { 586 return new \WP_REST_Response(['success' => false,'message' => 'Invalid JSON array'], 400); 587 } 588 } 589 else{ 590 $data = $raw; 591 } 592 593 $results = []; 594 $updated = 0; 595 $return = $this->update_batch_stock($data, $mode); 596 597 } 598 return new \WP_REST_Response($return, 200); 599 } 600 public function do_event_load_file_and_update_stock($url, $mode) 601 { 602 if (!class_exists('WooCommerce')) { 603 // log error 604 return; 605 } 606 607 // wp_single_event('storeman_log_event', 'info', 'Fetching stock update file from URL: '.$url); 608 $response = wp_remote_get($url); 609 if (is_wp_error($response)) { 610 // wp_single_event('storeman_log_event', 'error', 'Error fetching stock update file from URL: '.$url.' Error: '.$response->get_error_message()); 611 return; 612 } 613 $raw = wp_remote_retrieve_body($response); 614 $data = json_decode($raw, true); 615 616 if (!is_array($data)) { 617 // wp_single_event('storeman_log_event', 'error', 'Invalid JSON array in stock update file from URL: '.$url); 618 return; 619 } 620 621 $result = $this->update_batch_stock($data, $mode); 622 // wp_single_event('storeman_log_event', 'info', 'Stock update from file completed. Updated items: '.$result['updated'].' Total items processed: '.count($data)); 623 } 624 private function update_batch_stock(array $data, $mode) 625 { 626 $results = []; 627 $updated = 0; 628 629 foreach ($data as $idx => $item) { 630 $sku = isset($item['sku']) ? trim((string)$item['sku']) : ''; 631 $qty = isset($item['quantity']) ? $item['quantity'] : null; 632 633 // פר-פריט: האם לא לגעת ב-manage_stock אם הוא כבוי? 634 // ברירת מחדל: false (כלומר כן להדליק ניהול מלאי אם כבוי) 635 $dont_toggle_manage = !empty($item['dont_toggle_manage_stock']); 636 637 if ($sku === '' || !is_numeric($qty)) { 638 $results[] = [ 639 'index' => $idx, 640 'sku' => $sku, 641 'status' => 'error', 642 'error' => 'Missing sku or invalid quantity' 643 ]; 644 continue; 645 } 646 647 // איתור מוצר/וריאציה לפי SKU 648 $product_id = wc_get_product_id_by_sku($sku); 649 if (!$product_id) { 650 $results[] = [ 651 'index' => $idx, 652 'sku' => $sku, 653 'status' => 'not_found' 654 ]; 655 continue; 656 } 657 658 $product = wc_get_product($product_id); 659 if (!$product) { 660 $results[] = [ 661 'index' => $idx, 662 'sku' => $sku, 663 'status' => 'error', 664 'error' => 'Product load failed' 665 ]; 666 continue; 667 } 668 669 $was_managing = $product->managing_stock(); 670 671 // אם ניהול מלאי כבוי: 672 // - אם dont_toggle_manage_stock=true => לא משנים מצב ולא מעדכנים כמות (שזו המשמעות המתבקשת), 673 // ונחזיר status שמסביר את הדילוג. 674 // - אחרת נדליק ניהול מלאי. 675 if (!$was_managing) { 676 if ($dont_toggle_manage) { 677 $results[] = [ 678 'index' => $idx, 679 'sku' => $sku, 680 'status' => 'skipped_manage_stock_off', 681 'reason' => 'Product is not set to manage stock and dont_toggle_manage_stock=true', 682 'product_id' => $product->get_id(), 683 'type' => $product->get_type(), 684 ]; 685 continue; 686 } else { 687 $product->set_manage_stock(true); 688 } 689 } 690 691 try { 692 $delta = (float)$qty; 693 if ($mode === 'set') { 694 wc_update_product_stock($product, $delta, 'set'); 695 } else { 696 if ($delta > 0) { 697 wc_update_product_stock($product, $delta, 'increase'); 698 } elseif ($delta < 0) { 699 wc_update_product_stock($product, abs($delta), 'decrease'); 700 } // 0 => אין שינוי 701 } 702 703 $product->save(); 704 705 $results[] = [ 706 'index' => $idx, 707 'sku' => $sku, 708 'status' => 'updated', 709 'stock_quantity' => (float) $product->get_stock_quantity(), 710 'product_id' => $product->get_id(), 711 'type' => $product->get_type(), 712 'manage_stock' => $product->managing_stock(), 713 ]; 714 $updated++; 715 } catch (\Throwable $e) { 716 $results[] = [ 717 'index' => $idx, 718 'sku' => $sku, 719 'status' => 'error', 720 'error' => $e->getMessage() 721 ]; 722 } 723 } 724 return [ 725 'success' => true, 726 'mode' => $mode, 727 'updated' => $updated, 728 'results' => $results 729 ]; 730 } 731 public function wc_upsert_by_sku_via_core(WP_REST_Request $request) 732 { 733 if (! class_exists('WooCommerce')) { 734 return new WP_REST_Response(['error' => 'WooCommerce not active'], 400); 735 } 736 737 // ודא שהבקרים טעונים 738 if (! class_exists('WC_REST_Products_Controller') || ! class_exists('WC_REST_Product_Variations_Controller')) { 739 return new WP_REST_Response(['error' => 'WooCommerce REST controllers unavailable'], 500); 740 } 741 742 $data = $request->get_json_params() ?: []; 743 $products = isset($data['products']) && is_array($data['products']) ? $data['products'] : []; 744 $create_if_missing = isset($data['create_if_missing']) ? (bool)$data['create_if_missing'] : true; 745 $results = []; 746 foreach ($products as $k => $data) { 747 $result = ['index' => $k]; 748 $sku = trim((string)($data['sku'] ?? '')); 749 if (!$sku) { 750 $result['status'] = false; 751 $result['error'] = 'Missing sku'; 752 $results[] = $result; 753 continue; 754 } 755 756 $type = $data['type'] ?? 'simple'; 757 $create_if_missing = array_key_exists('create_if_missing', $data) ? (bool)$data['create_if_missing'] : $create_if_missing; 758 759 try { 760 if ($type === 'variation') { 761 // ----- וריאציה: צריך parent_sku, ונתמקד בבקר הוריאציות של ווקומרס ----- 762 $parent_sku = trim((string)($data['parent_sku'] ?? '')); 763 if (!$parent_sku) { 764 765 $result['status'] = false; 766 $result['error'] = 'Variation requires parent_sku'; 767 $results[] = $result; 768 continue; 769 770 } 771 772 // מצא/צור הורה לפי SKU (באמצעות בקר המוצרים) 773 $parent_id = wc_get_product_id_by_sku($parent_sku); 774 $products_controller = new WC_REST_Products_Controller(); 775 776 if (!$parent_id) { 777 if (!$create_if_missing) { 778 $result['status'] = false; 779 $result['error'] = 'Parent not found by parent_sku and create_if_missing=false'; 780 $results[] = $result; 781 continue; 782 } 783 // צור הורה מסוג variable (באמצעות create_item הרשמי) 784 $parent_create_req = new WP_REST_Request('POST', '/wc/v3/products'); 785 $parent_payload = $data; 786 $parent_payload['sku'] = $parent_sku; 787 $parent_payload['type'] = 'variable'; 788 $parent_create_req->set_body_params($parent_payload); 789 $parent_resp = $products_controller->create_item($parent_create_req); 790 if ($parent_resp instanceof WP_Error) { 791 792 $result['status'] = false; 793 $result['error'] = $parent_resp->get_error_message(); 794 $results[] = $result; 795 continue; 796 } 797 $parent_arr = $parent_resp->get_data(); 798 $parent_id = (int)($parent_arr['id'] ?? 0); 799 if (!$parent_id) { 800 $result['status'] = false; 801 $result['error'] = 'Failed to create parent'; 802 $results[] = $result; 803 continue; 804 } 805 } else { 806 // אם ההורה קיים אך אינו variable – עדכן דרך הבקר הרשמי 807 $parent = wc_get_product($parent_id); 808 if ($parent && $parent->get_type() !== 'variable') { 809 $parent_update_req = new WP_REST_Request('PUT', '/wc/v3/products/'.$parent_id); 810 $parent_update_req->set_url_params(['id' => $parent_id]); 811 $parent_update_req->set_body_params(['type' => 'variable']); 812 $u = $products_controller->update_item($parent_update_req); 813 if ($u instanceof WP_Error) { 814 $result['status'] = false; 815 $result['error'] = $u->get_error_message(); 816 $results[] = $result; 817 continue; 818 } 819 } 820 } 821 822 // כעת – וריאציה לפי SKU 823 $variation_id = wc_get_product_id_by_sku($sku); 824 $variations_controller = new WC_REST_Product_Variations_Controller(); 825 826 if ($variation_id) { 827 // UPDATE ע"י הבקר הרשמי: /products/{product_id}/variations/{id} 828 $upd_req = new WP_REST_Request('PUT', '/wc/v3/products/'.$parent_id.'/variations/'.$variation_id); 829 $upd_req->set_url_params(['product_id' => $parent_id, 'id' => $variation_id]); 830 $upd_req->set_body_params($data); 831 $resp = $variations_controller->update_item($upd_req); 832 if ($resp instanceof WP_Error) { 833 $result['status'] = false; 834 $result['error'] = $resp->get_error_message(); 835 $results[] = $result; 836 continue; 837 } 838 return $resp; // מחזיר את המערך התקני של WooCommerce 839 } else { 840 if (!$create_if_missing) { 841 return new WP_REST_Response(['error' => 'Variation not found by sku and create_if_missing=false'], 404); 842 } 843 // CREATE ע"י הבקר הרשמי 844 $crt_req = new WP_REST_Request('POST', '/wc/v3/products/'.$parent_id.'/variations'); 845 $crt_req->set_url_params(['product_id' => $parent_id]); 846 $crt_req->set_body_params($data); 847 $resp = $variations_controller->create_item($crt_req); 848 if ($resp instanceof WP_Error) { 849 return new WP_REST_Response(['error' => $resp->get_error_message()], 400); 850 } 851 $result['status'] = true; 852 $result['data'] = $resp->get_data(); 853 $results[] = $result; 854 continue; 855 // return $resp; 856 } 857 858 } else { 859 // ----- מוצר (לא וריאציה): נשען על WC_REST_Products_Controller ----- 860 $product_id = wc_get_product_id_by_sku($sku); 861 $products_controller = new WC_REST_Products_Controller(); 862 863 if ($product_id) { 864 // UPDATE ע"י הבקר הרשמי: /products/{id} 865 $upd_req = new WP_REST_Request('PUT', '/wc/v3/products/'.$product_id); 866 $upd_req->set_url_params(['id' => $product_id]); 867 $upd_req->set_body_params($data); 868 $resp = $products_controller->update_item($upd_req); 869 if ($resp instanceof WP_Error) { 870 871 $result['status'] = false; 872 $result['error'] = $resp->get_error_message(); 873 $results[] = $result; 874 continue; 875 } 876 $result['status'] = true; 877 $result['data'] = $resp->get_data(); 878 $results[] = $result; 879 continue; 880 } else { 881 if (!$create_if_missing) { 882 $result['status'] = false; 883 $result['error'] = 'Product not found by sku and create_if_missing=false'; 884 $results[] = $result; 885 continue; 886 } 887 // CREATE ע"י הבקר הרשמי 888 // ודא type אם לא נשלח 889 if (empty($data['type'])) { 890 $data['type'] = 'simple'; 891 } 892 $crt_req = new WP_REST_Request('POST', '/wc/v3/products'); 893 $crt_req->set_body_params($data); 894 $resp = $products_controller->create_item($crt_req); 895 if ($resp instanceof WP_Error) { 896 $result['status'] = false; 897 $result['error'] = $resp->get_error_message(); 898 $results[] = $result; 899 continue; 900 } 901 $result['status'] = true; 902 $result['data'] = $resp->get_data(); 903 $results[] = $result; 904 continue; 905 } 906 } 907 908 } catch (Throwable $e) { 909 $result['status'] = false; 910 $result['error'] = $e->getMessage(); 911 $results[] = $result; 912 continue; 913 // return new WP_REST_Response(['error' => $e->getMessage()], 500); 914 } 915 // $result['status'] = true; 916 // $results[] = $result; 917 } 918 return new WP_REST_Response(['results' => $results], 200); 919 } 920 public function storeman_wc_get_basic_auth_pair(\WP_REST_Request $request): array 921 { 922 // 1) Authorization: Basic ... 923 $auth = isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] : (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) ? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] : ''); 924 if (!$auth && function_exists('apache_request_headers')) { 925 $headers = apache_request_headers(); 926 if (!empty($headers['Authorization'])) { 927 $auth = $headers['Authorization']; 928 } 929 } 930 if ($auth && stripos($auth, 'Basic ') === 0) { 931 $decoded = base64_decode(substr($auth, 6)); 932 if ($decoded !== false && strpos($decoded, ':') !== false) { 933 list($user, $pass) = explode(':', $decoded, 2); 934 return [trim($user), trim($pass)]; 935 } 936 } 937 938 // 2) Query / Body params (WooCommerce REST API תומך גם בזה) 939 $ck = $request->get_param('consumer_key') ?: ''; 940 $cs = $request->get_param('consumer_secret') ?: ''; 941 if ($ck !== '' && $cs !== '') { 942 return [$ck, $cs]; 943 } 944 945 return ['', '']; 946 } 947 948 public function storeman_wc_find_api_key_row_by_consumer_key($consumer_key) 949 { 950 global $wpdb; 951 952 if ($consumer_key === '') { 953 return null; 954 } 955 956 // WooCommerce שומר consumer_key בהאש SHA256 (לרוב דרך wc_api_hash אם קיים) 957 if (function_exists('wc_api_hash')) { 958 $hash = wc_api_hash($consumer_key); 959 } else { 960 $hash = hash('sha256', $consumer_key); 961 } 962 963 $table = $wpdb->prefix . 'woocommerce_api_keys'; 964 // expected columns: key_id, user_id, permissions, consumer_key (hashed), consumer_secret, truncated_key, last_access, nonces, etc. 965 $row = $wpdb->get_row( 966 $wpdb->prepare("SELECT * FROM {$table} WHERE consumer_key = %s LIMIT 1", $hash), 967 ARRAY_A 968 ); 969 970 return $row ?: null; 971 } 972 973 974 975 434 976 } 435 // add_filter('storeman_stock_quantity_doubleval' , function($type){436 // return true;437 // }); -
storeman/trunk/admin/class-webhook-storeman-action.php
r2912185 r3382611 9 9 public function get_label() 10 10 { 11 return 'Storeman ';11 return 'Storeman (Legacy)'; 12 12 } 13 13 // namespace Elementor\Core\Base; … … 30 30 'storeman_domain', 31 31 [ 32 'label' => esc_html__('Domain ', 'elementor'),32 'label' => esc_html__('Domain (without / at the end)', 'elementor'), 33 33 'type' => 'text', 34 'default' => get_site_url().".storeman.co.il",34 'default' => "", 35 35 36 36 … … 60 60 'storeman_action', 61 61 [ 62 'label' => esc_html__(' ToDo', 'elementor'),62 'label' => esc_html__('toDo', 'elementor'), 63 63 'type' => 'text', 64 64 'default' => '', -
storeman/trunk/includes/class-storeman.php
r2912177 r3382611 199 199 $this->loader->add_action("woocommerce_rest_pre_insert_product_variation_object", $plugin_admin, 'remove_product_variation_webhook_action',1,3); 200 200 $this->loader->add_action("woocommerce_rest_insert_product_variation_object", $plugin_admin, 'remove_product_variation_webhook_action',999,3); 201 202 201 202 $this->loader->add_action('rest_api_init', $plugin_admin, 'register_custom_routes' ); 203 $this->loader->add_action('load_stock_from_file', $plugin_admin, 'do_event_load_file_and_update_stock',999,2); 203 204 } 204 205 -
storeman/trunk/public/js/storeman-public.js
r2912177 r3382611 3 3 $(document).on('submit_success', function (e, form) { 4 4 5 6 if (form.data.storeman_webhook_response && form.data.storeman_webhook_response.redirect) { 7 window.location.href = form.data.storeman_webhook_response.redirect; 8 return false; 9 } 5 10 if (form.data.storeman_webhook_response) { 6 11 $("#storeman_webhook_response").remove(); … … 9 14 10 15 } 16 // if (form.data.storeman_webhook_redirect) { 17 18 // $("#storeman_webhook_response").remove(); 19 // var div = $("<div id='storeman_webhook_response'>"+form.data.storeman_webhook_response+"</div>"); 20 // $(e.target).append(div); 21 22 // } 11 23 12 24 -
storeman/trunk/storeman.php
r2912185 r3382611 17 17 * Plugin URI: https://storeman.co.il 18 18 * Description: add storeman to your WordPress site. 19 * Version: 2.2. 719 * Version: 2.2.8 20 20 * Author: avitrop 21 21 * Author URI: https://profiles.wordpress.org/avitrop/ … … 36 36 * Rename this for your plugin and update it as you release new versions. 37 37 */ 38 define( 'STOREMAN_VERSION', '2.2. 7' );38 define( 'STOREMAN_VERSION', '2.2.8' ); 39 39 40 40 /**
Note: See TracChangeset
for help on using the changeset viewer.