Changeset 3765411
- Timestamp:
- 10/26/2026 01:31:50 AM (67 minutes ago)
- Location:
- ods-ournest-dropship
- Files:
-
- 4 added
- 6 edited
- 23 copied
-
tags/1.3.0 (copied) (copied from ods-ournest-dropship/trunk )
-
tags/1.3.0/assets/js/admin-common.js (copied) (copied from ods-ournest-dropship/trunk/assets/js/admin-common.js )
-
tags/1.3.0/assets/js/mapping-drawer.js (copied) (copied from ods-ournest-dropship/trunk/assets/js/mapping-drawer.js )
-
tags/1.3.0/assets/js/orders.js (copied) (copied from ods-ournest-dropship/trunk/assets/js/orders.js )
-
tags/1.3.0/assets/js/product.js (copied) (copied from ods-ournest-dropship/trunk/assets/js/product.js )
-
tags/1.3.0/assets/js/settings.js (copied) (copied from ods-ournest-dropship/trunk/assets/js/settings.js )
-
tags/1.3.0/assets/js/support-assistant.js (added)
-
tags/1.3.0/assets/style.css (copied) (copied from ods-ournest-dropship/trunk/assets/style.css ) (1 diff)
-
tags/1.3.0/includes/admin/page-orders.php (copied) (copied from ods-ournest-dropship/trunk/includes/admin/page-orders.php )
-
tags/1.3.0/includes/admin/page-settings.php (copied) (copied from ods-ournest-dropship/trunk/includes/admin/page-settings.php )
-
tags/1.3.0/includes/ajax/ajax-import.php (copied) (copied from ods-ournest-dropship/trunk/includes/ajax/ajax-import.php )
-
tags/1.3.0/includes/ajax/ajax-mapping.php (copied) (copied from ods-ournest-dropship/trunk/includes/ajax/ajax-mapping.php ) (1 diff)
-
tags/1.3.0/includes/ajax/ajax-orders.php (copied) (copied from ods-ournest-dropship/trunk/includes/ajax/ajax-orders.php )
-
tags/1.3.0/includes/ajax/ajax-support.php (added)
-
tags/1.3.0/includes/class-i18n.php (copied) (copied from ods-ournest-dropship/trunk/includes/class-i18n.php ) (1 diff)
-
tags/1.3.0/includes/class-onboarding.php (copied) (copied from ods-ournest-dropship/trunk/includes/class-onboarding.php )
-
tags/1.3.0/includes/class-order-handler.php (copied) (copied from ods-ournest-dropship/trunk/includes/class-order-handler.php ) (1 diff)
-
tags/1.3.0/includes/class-order-sync.php (copied) (copied from ods-ournest-dropship/trunk/includes/class-order-sync.php )
-
tags/1.3.0/includes/class-privacy.php (copied) (copied from ods-ournest-dropship/trunk/includes/class-privacy.php )
-
tags/1.3.0/includes/class-product-importer.php (copied) (copied from ods-ournest-dropship/trunk/includes/class-product-importer.php )
-
tags/1.3.0/includes/class-product-mapper.php (copied) (copied from ods-ournest-dropship/trunk/includes/class-product-mapper.php )
-
tags/1.3.0/includes/class-settings.php (copied) (copied from ods-ournest-dropship/trunk/includes/class-settings.php )
-
tags/1.3.0/includes/class-stock-sync.php (copied) (copied from ods-ournest-dropship/trunk/includes/class-stock-sync.php )
-
tags/1.3.0/ournest-dropship.php (copied) (copied from ods-ournest-dropship/trunk/ournest-dropship.php ) (5 diffs)
-
tags/1.3.0/readme.txt (copied) (copied from ods-ournest-dropship/trunk/readme.txt ) (4 diffs)
-
trunk/assets/js/support-assistant.js (added)
-
trunk/assets/style.css (modified) (1 diff)
-
trunk/includes/ajax/ajax-mapping.php (modified) (1 diff)
-
trunk/includes/ajax/ajax-support.php (added)
-
trunk/includes/class-i18n.php (modified) (1 diff)
-
trunk/includes/class-order-handler.php (modified) (1 diff)
-
trunk/ournest-dropship.php (modified) (5 diffs)
-
trunk/readme.txt (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
ods-ournest-dropship/tags/1.3.0/assets/style.css
r3760832 r3765411 3546 3546 color: #6b7280; 3547 3547 } 3548 3549 /* ────────────────────────────────────────── 3550 Support assistant (floating help) 3551 ────────────────────────────────────────── */ 3552 .ods-support-assistant { 3553 position: fixed; 3554 right: 24px; 3555 bottom: 24px; 3556 z-index: 100000; 3557 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; 3558 } 3559 3560 .ods-support-fab { 3561 width: 52px; 3562 height: 52px; 3563 border-radius: 999px; 3564 border: none; 3565 background: var(--ali-primary, #2563eb); 3566 color: #fff; 3567 box-shadow: var(--ali-shadow-lg); 3568 cursor: pointer; 3569 display: flex; 3570 align-items: center; 3571 justify-content: center; 3572 transition: transform 0.15s ease, background 0.15s ease; 3573 } 3574 3575 .ods-support-fab:hover { 3576 background: var(--ali-primary-dark, #1d4ed8); 3577 transform: translateY(-1px); 3578 } 3579 3580 .ods-support-fab-icon { 3581 font-size: 22px; 3582 font-weight: 700; 3583 line-height: 1; 3584 } 3585 3586 .ods-support-panel { 3587 display: none; 3588 position: absolute; 3589 right: 0; 3590 bottom: 64px; 3591 width: min(380px, calc(100vw - 32px)); 3592 max-height: min(560px, calc(100vh - 120px)); 3593 background: #fff; 3594 border: 1px solid var(--ali-border, #e2e8f0); 3595 border-radius: 12px; 3596 box-shadow: var(--ali-shadow-lg); 3597 flex-direction: column; 3598 overflow: hidden; 3599 } 3600 3601 .ods-support-assistant.is-open .ods-support-panel { 3602 display: flex; 3603 } 3604 3605 .ods-support-assistant.is-open .ods-support-fab { 3606 display: none; 3607 } 3608 3609 .ods-support-body { 3610 position: relative; 3611 flex: 1 1 auto; 3612 min-height: 220px; 3613 display: flex; 3614 flex-direction: column; 3615 overflow: hidden; 3616 } 3617 3618 .ods-support-header { 3619 display: flex; 3620 align-items: flex-start; 3621 gap: 8px; 3622 padding: 14px 14px 10px; 3623 border-bottom: 1px solid var(--ali-border, #e2e8f0); 3624 background: #f8fafc; 3625 } 3626 3627 .ods-support-header-text { 3628 flex: 1; 3629 min-width: 0; 3630 display: flex; 3631 flex-direction: column; 3632 gap: 2px; 3633 } 3634 3635 .ods-support-header-text strong { 3636 font-size: 14px; 3637 color: #0f172a; 3638 } 3639 3640 .ods-support-header-text span { 3641 font-size: 12px; 3642 color: var(--ali-text-muted, #64748b); 3643 } 3644 3645 .ods-support-close { 3646 border: none; 3647 background: transparent; 3648 color: #64748b; 3649 font-size: 22px; 3650 line-height: 1; 3651 cursor: pointer; 3652 padding: 0 4px; 3653 } 3654 3655 .ods-support-messages { 3656 flex: 1 1 auto; 3657 overflow-y: auto; 3658 padding: 12px 14px; 3659 display: flex; 3660 flex-direction: column; 3661 gap: 10px; 3662 background: #fff; 3663 } 3664 3665 .ods-support-msg { 3666 display: flex; 3667 flex-direction: column; 3668 gap: 4px; 3669 max-width: 95%; 3670 } 3671 3672 .ods-support-msg--user { 3673 align-self: flex-end; 3674 } 3675 3676 .ods-support-msg--assistant { 3677 align-self: flex-start; 3678 } 3679 3680 .ods-support-bubble { 3681 padding: 10px 12px; 3682 border-radius: 10px; 3683 font-size: 13px; 3684 line-height: 1.45; 3685 color: #1e293b; 3686 background: #f1f5f9; 3687 white-space: normal; 3688 word-break: break-word; 3689 } 3690 3691 .ods-support-msg--user .ods-support-bubble { 3692 background: #2563eb; 3693 color: #fff; 3694 } 3695 3696 .ods-support-bubble--thinking { 3697 color: #64748b; 3698 font-style: italic; 3699 } 3700 3701 .ods-support-meta { 3702 font-size: 11px; 3703 color: #64748b; 3704 padding: 0 2px; 3705 } 3706 3707 .ods-support-cites { 3708 margin-top: 2px; 3709 } 3710 3711 .ods-support-cite { 3712 display: inline-block; 3713 background: #eff6ff; 3714 color: #1d4ed8; 3715 border-radius: 4px; 3716 padding: 1px 6px; 3717 margin: 2px 2px 0 0; 3718 } 3719 3720 .ods-support-fallback a, 3721 .ods-support-footer a, 3722 .ods-support-docs-link { 3723 color: #2563eb; 3724 } 3725 3726 .ods-support-docs-link { 3727 text-decoration: underline; 3728 font-weight: 600; 3729 } 3730 3731 .ods-support-error { 3732 color: #b91c1c; 3733 } 3734 3735 /* Quick prompts: float above messages inside the panel; stagger in/out from the left. */ 3736 .ods-support-quick { 3737 position: absolute; 3738 left: 10px; 3739 right: 10px; 3740 bottom: 10px; 3741 z-index: 2; 3742 display: flex; 3743 flex-direction: column; 3744 align-items: flex-start; 3745 gap: 8px; 3746 pointer-events: none; 3747 } 3748 3749 .ods-support-chip { 3750 border: 1px solid #cbd5e1; 3751 background: rgba(255, 255, 255, 0.96); 3752 color: #334155; 3753 border-radius: 999px; 3754 padding: 7px 12px; 3755 font-size: 11px; 3756 cursor: pointer; 3757 line-height: 1.35; 3758 text-align: left; 3759 box-shadow: var(--ali-shadow); 3760 max-width: 92%; 3761 white-space: normal; 3762 opacity: 0; 3763 transform: translateX(-120%); 3764 pointer-events: none; 3765 transition: 3766 transform 0.32s cubic-bezier(0.22, 1, 0.36, 1), 3767 opacity 0.28s ease; 3768 transition-delay: 0ms; 3769 } 3770 3771 .ods-support-quick.is-visible .ods-support-chip { 3772 opacity: 1; 3773 transform: translateX(0); 3774 pointer-events: auto; 3775 transition-delay: calc(var(--ods-quick-i, 0) * 70ms); 3776 } 3777 3778 .ods-support-quick.is-hiding .ods-support-chip { 3779 opacity: 0; 3780 transform: translateX(-120%); 3781 pointer-events: none; 3782 transition-delay: calc((2 - var(--ods-quick-i, 0)) * 70ms); 3783 } 3784 3785 .ods-support-chip:hover { 3786 border-color: #2563eb; 3787 color: #1d4ed8; 3788 } 3789 3790 .ods-support-form { 3791 display: flex; 3792 gap: 8px; 3793 padding: 0 14px 10px; 3794 align-items: flex-end; 3795 } 3796 3797 .ods-support-input { 3798 flex: 1; 3799 min-height: 44px; 3800 max-height: 96px; 3801 resize: vertical; 3802 border: 1px solid #cbd5e1; 3803 border-radius: 8px; 3804 padding: 8px 10px; 3805 font-size: 13px; 3806 line-height: 1.4; 3807 } 3808 3809 .ods-support-input:focus { 3810 outline: none; 3811 border-color: #2563eb; 3812 box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.15); 3813 } 3814 3815 .ods-support-send { 3816 border: none; 3817 background: #2563eb; 3818 color: #fff; 3819 border-radius: 8px; 3820 padding: 10px 14px; 3821 font-size: 13px; 3822 font-weight: 600; 3823 cursor: pointer; 3824 white-space: nowrap; 3825 } 3826 3827 .ods-support-send:disabled { 3828 opacity: 0.55; 3829 cursor: not-allowed; 3830 } 3831 3832 .ods-support-footer { 3833 padding: 8px 14px 12px; 3834 border-top: 1px solid var(--ali-border, #e2e8f0); 3835 font-size: 11px; 3836 color: #64748b; 3837 background: #f8fafc; 3838 } 3839 3840 @media (max-width: 782px) { 3841 .ods-support-assistant { 3842 right: 16px; 3843 bottom: 16px; 3844 } 3845 } -
ods-ournest-dropship/tags/1.3.0/includes/ajax/ajax-mapping.php
r3757662 r3765411 827 827 828 828 // ────────────────────────────────────────── 829 // Save default logistics for a mapped variation830 // ──────────────────────────────────────────831 add_action(832 'wp_ajax_ournest_dropship_save_mapping_logistics',833 function (): void {834 Settings::verify_request();835 836 $product_id = ournest_dropship_post_int( 'product_id', 0 );837 $variation_id = ournest_dropship_post_int( 'variation_id', 0 );838 $service = ournest_dropship_post_text( 'logistics_service', '' );839 $company = ournest_dropship_post_text( 'logistics_company', '' );840 $ae_product_id = ournest_dropship_post_text( 'ae_product_id', '' );841 $ae_sku_id = ournest_dropship_post_text( 'ae_sku_id', '' );842 $ae_sku_title = ournest_dropship_post_text( 'ae_sku_title', '' );843 $ae_sku_img = esc_url_raw( ournest_dropship_post_unslash_string( 'ae_sku_img' ) );844 $ae_sku_path = ournest_dropship_post_text( 'ae_sku_path', '' );845 846 if ( ! $variation_id ) {847 wp_send_json_error( array( 'message' => __( 'Variation ID is required.', 'ods-ournest-dropship' ) ) );848 }849 if ( ! $product_id ) {850 wp_send_json_error( array( 'message' => __( 'Product ID is required.', 'ods-ournest-dropship' ) ) );851 }852 853 $product = wc_get_product( $product_id );854 if ( ! $product ) {855 wp_send_json_error( array( 'message' => __( 'Product not found.', 'ods-ournest-dropship' ) ) );856 }857 if ( $product->is_type( 'variable' ) ) {858 $children = array_map( 'intval', $product->get_children() );859 if ( ! in_array( $variation_id, $children, true ) ) {860 wp_send_json_error( array( 'message' => __( 'Variation does not belong to this product.', 'ods-ournest-dropship' ) ) );861 }862 } elseif ( $variation_id !== $product_id ) {863 wp_send_json_error( array( 'message' => __( 'Variation does not belong to this product.', 'ods-ournest-dropship' ) ) );864 }865 866 $existing = Product_Mapper::get_variation_mapping( $variation_id );867 if ( ! $existing ) {868 if ( $ae_product_id === '' || $ae_sku_id === '' ) {869 wp_send_json_error( array( 'message' => __( 'Map an AliExpress SKU before saving logistics.', 'ods-ournest-dropship' ) ) );870 }871 Product_Mapper::map_variation(872 $product_id,873 $variation_id,874 $ae_product_id,875 $ae_sku_id,876 $ae_sku_title,877 $ae_sku_img,878 $ae_sku_path879 );880 Product_Mapper::auto_maintain_suppliers( $product_id );881 } elseif ( $ae_sku_id !== '' && (string) ( $existing['ae_sku_id'] ?? '' ) !== $ae_sku_id ) {882 // Draft SKU changed before Save Mapping — sync then clear stale logistics via map.883 Product_Mapper::map_variation(884 $product_id,885 $variation_id,886 $ae_product_id !== '' ? $ae_product_id : (string) ( $existing['ae_product_id'] ?? '' ),887 $ae_sku_id,888 $ae_sku_title !== '' ? $ae_sku_title : (string) ( $existing['ae_sku_title'] ?? '' ),889 $ae_sku_img !== '' ? $ae_sku_img : (string) ( $existing['ae_sku_img'] ?? '' ),890 $ae_sku_path !== '' ? $ae_sku_path : (string) ( $existing['ae_sku_path'] ?? '' )891 );892 }893 894 $result = Product_Mapper::save_mapping_logistics( $variation_id, $service, $company );895 if ( is_wp_error( $result ) ) {896 wp_send_json_error( array( 'message' => $result->get_error_message() ) );897 }898 899 wp_send_json_success(900 array(901 'message' => __( 'Logistics saved.', 'ods-ournest-dropship' ),902 'logistics_service' => $service,903 'logistics_company' => $company,904 )905 );906 }907 );908 909 // ──────────────────────────────────────────910 829 // Add supplier to a WC product 911 830 // ────────────────────────────────────────── -
ods-ournest-dropship/tags/1.3.0/includes/class-i18n.php
r3757662 r3765411 352 352 'completedProgress' => __( '%1$d / %2$d completed', 'ods-ournest-dropship' ), 353 353 'dismissFailed' => __( 'Failed to dismiss', 'ods-ournest-dropship' ), 354 355 // Support assistant 356 'supportOpen' => __( 'Help', 'ods-ournest-dropship' ), 357 'supportClose' => __( 'Close', 'ods-ournest-dropship' ), 358 'supportTitle' => __( 'ODS Assistant', 'ods-ournest-dropship' ), 359 'supportSubtitle' => __( 'Operator help from the ODS manual', 'ods-ournest-dropship' ), 360 'supportPlaceholder' => __( 'Ask how to connect, map, or place orders…', 'ods-ournest-dropship' ), 361 'supportSend' => __( 'Send', 'ods-ournest-dropship' ), 362 'supportHuman' => __( 'Need a human?', 'ods-ournest-dropship' ), 363 'supportThinking' => __( 'Looking up the manual…', 'ods-ournest-dropship' ), 364 'supportEmptyAnswer' => __( 'No answer returned.', 'ods-ournest-dropship' ), 365 'supportError' => __( 'Something went wrong. Please try again.', 'ods-ournest-dropship' ), 366 'supportCitations' => __( 'From the manual:', 'ods-ournest-dropship' ), 367 'supportFallbackHint' => __( 'If this does not help, email', 'ods-ournest-dropship' ), 368 /* translators: %s: HTML link labeled "operator manual". */ 369 'supportWelcome' => __( 'Ask an ODS how-to question. Answers follow the %s.', 'ods-ournest-dropship' ), 370 'supportManualLink' => __( 'operator manual', 'ods-ournest-dropship' ), 371 'supportWelcomeDisconnected' => __( 'You can ask how to connect AliExpress even before authorization. Connect for fulfillment details.', 'ods-ournest-dropship' ), 372 'supportQuickConnect' => __( 'How do I connect AliExpress?', 'ods-ournest-dropship' ), 373 'supportQuickMapping' => __( 'How do I map product SKUs?', 'ods-ournest-dropship' ), 374 'supportQuickPlace' => __( 'Place order failed — what should I check?', 'ods-ournest-dropship' ), 354 375 ); 355 376 } -
ods-ournest-dropship/tags/1.3.0/includes/class-order-handler.php
r3760832 r3765411 49 49 $list['counts'] = self::compute_tab_counts( $search_ids, $buckets ); 50 50 return $list; 51 }52 53 /**54 * @return array{orders: array, total: int, pages: int}55 */56 public static function get_wc_orders( string $tab = 'paid', string $keyword = '', int $page = 1, int $per_page = 20 ): array {57 $page = max( 1, $page );58 $per_page = max( 1, min( 100, $per_page ) );59 60 $search_ids = null;61 if ( $keyword !== '' ) {62 $search_ids = array_map( 'absint', wc_order_search( $keyword ) );63 if ( empty( $search_ids ) ) {64 return array(65 'orders' => array(),66 'total' => 0,67 'pages' => 0,68 );69 }70 }71 72 return self::query_orders_for_tab( $tab, $search_ids, $page, $per_page, self::place_order_display_buckets() );73 }74 75 /**76 * Order counts per display-status tab (same filter rules as get_wc_orders).77 *78 * @return array<string,int>79 */80 public static function get_tab_counts( string $keyword = '' ): array {81 $search_ids = null;82 if ( $keyword !== '' ) {83 $search_ids = array_map( 'absint', wc_order_search( $keyword ) );84 if ( empty( $search_ids ) ) {85 return array_fill_keys(86 array( 'pending', 'paid', 'processing', 'shipping', 'fulfilled', 'cancelled', 'failed' ),87 088 );89 }90 }91 92 return self::compute_tab_counts( $search_ids, self::place_order_display_buckets() );93 51 } 94 52 -
ods-ournest-dropship/tags/1.3.0/ournest-dropship.php
r3760832 r3765411 11 11 * Plugin URI: https://anest.top/ods/ 12 12 * Description: AliExpress dropshipping for WooCommerce by OurNest (ODS). Browse, import, map SKUs, and fulfill orders from your WordPress store. 13 * Version: 1. 2.013 * Version: 1.3.0 14 14 * Requires at least: 6.0 15 15 * Requires PHP: 8.0 … … 30 30 // Constants 31 31 // ────────────────────────────────────────────── 32 define( 'OURNEST_DROPSHIP_VERSION', '1. 2.0' );32 define( 'OURNEST_DROPSHIP_VERSION', '1.3.0' ); 33 33 define( 'OURNEST_DROPSHIP_PATH', plugin_dir_path( __FILE__ ) ); 34 34 define( 'OURNEST_DROPSHIP_URL', plugin_dir_url( __FILE__ ) ); … … 47 47 if ( ! defined( 'OURNEST_DROPSHIP_SERVER_URL' ) ) { 48 48 define( 'OURNEST_DROPSHIP_SERVER_URL', 'https://api.anest.top' ); 49 } 50 // Shared with ae-server [support].service_key — PHP only, never localize to JS. 51 if ( ! defined( 'OURNEST_DROPSHIP_SUPPORT_KEY' ) ) { 52 define( 'OURNEST_DROPSHIP_SUPPORT_KEY', 'd7c8cc25fc2d63f637a9371cf2c247fbd363795912cb7c50cb427f097608e798' ); 49 53 } 50 54 … … 375 379 ? \Ournest\Dropship\Settings::is_api_key_valid() 376 380 : false, 377 'countries' => $needs_countries && function_exists( 'ournest_dropship_countries' ) 381 'current_page' => $page, 382 'support_email' => 'support@anest.top', 383 'docs_url' => 'https://anest.top/ods/help', 384 'countries' => $needs_countries && function_exists( 'ournest_dropship_countries' ) 378 385 ? ournest_dropship_countries() 379 386 : array(), 380 387 'i18n' => class_exists( '\\Ournest\Dropship\\I18n' ) ? \Ournest\Dropship\I18n::js_strings() : array(), 381 388 ) 389 ); 390 wp_enqueue_script( 391 'ournest-dropship-support-assistant', 392 OURNEST_DROPSHIP_URL . 'assets/js/support-assistant.js', 393 array( $common_handle ), 394 ournest_dropship_asset_ver( 'assets/js/support-assistant.js' ), 395 true 382 396 ); 383 397 … … 490 504 require_once $ournest_dropship_onboarding_ajax; 491 505 } 506 507 $ournest_dropship_support_ajax = OURNEST_DROPSHIP_PATH . 'includes/ajax/ajax-support.php'; 508 if ( file_exists( $ournest_dropship_support_ajax ) ) { 509 require_once $ournest_dropship_support_ajax; 510 } -
ods-ournest-dropship/tags/1.3.0/readme.txt
r3760832 r3765411 9 9 WC requires at least: 8.0 10 10 WC tested up to: 9.8 11 Stable tag: 1. 2.011 Stable tag: 1.3.0 12 12 License: GPLv2 or later 13 13 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 38 38 * Apply optional USD exchange rates in pricing rules 39 39 * Optional daily AliExpress stock sync with per-product exclusion 40 * Floating smart assistant for operator how-to questions (manual-based) 40 41 41 42 = How It Works = … … 140 141 141 142 == Changelog == 143 144 = 1.3.0 = 145 146 * Smart assistant: floating help on all ODS admin pages for operator how-to questions. 147 * Smart assistant: quick prompts with staggered show/hide; answers cite the operator manual. 148 * Smart assistant: “operator manual” links to https://anest.top/ods/help . 149 * Smart assistant: works before AliExpress is connected (how-to connect still available). 150 * Removed unused order-list helpers and an unused mapping-logistics AJAX endpoint. 142 151 143 152 = 1.2.0 = … … 246 255 == Upgrade Notice == 247 256 257 = 1.3.0 = 258 Adds a floating smart assistant for ODS operator how-to questions, with manual citations and docs link. Recommended update for all stores. 259 248 260 = 1.2.0 = 249 261 Improves My Orders compatibility with WooCommerce 11, links Order # to Woo edit, and shows AE SKU image/title in place-order and AE drawers. Recommended update for all stores. -
ods-ournest-dropship/trunk/assets/style.css
r3760832 r3765411 3546 3546 color: #6b7280; 3547 3547 } 3548 3549 /* ────────────────────────────────────────── 3550 Support assistant (floating help) 3551 ────────────────────────────────────────── */ 3552 .ods-support-assistant { 3553 position: fixed; 3554 right: 24px; 3555 bottom: 24px; 3556 z-index: 100000; 3557 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; 3558 } 3559 3560 .ods-support-fab { 3561 width: 52px; 3562 height: 52px; 3563 border-radius: 999px; 3564 border: none; 3565 background: var(--ali-primary, #2563eb); 3566 color: #fff; 3567 box-shadow: var(--ali-shadow-lg); 3568 cursor: pointer; 3569 display: flex; 3570 align-items: center; 3571 justify-content: center; 3572 transition: transform 0.15s ease, background 0.15s ease; 3573 } 3574 3575 .ods-support-fab:hover { 3576 background: var(--ali-primary-dark, #1d4ed8); 3577 transform: translateY(-1px); 3578 } 3579 3580 .ods-support-fab-icon { 3581 font-size: 22px; 3582 font-weight: 700; 3583 line-height: 1; 3584 } 3585 3586 .ods-support-panel { 3587 display: none; 3588 position: absolute; 3589 right: 0; 3590 bottom: 64px; 3591 width: min(380px, calc(100vw - 32px)); 3592 max-height: min(560px, calc(100vh - 120px)); 3593 background: #fff; 3594 border: 1px solid var(--ali-border, #e2e8f0); 3595 border-radius: 12px; 3596 box-shadow: var(--ali-shadow-lg); 3597 flex-direction: column; 3598 overflow: hidden; 3599 } 3600 3601 .ods-support-assistant.is-open .ods-support-panel { 3602 display: flex; 3603 } 3604 3605 .ods-support-assistant.is-open .ods-support-fab { 3606 display: none; 3607 } 3608 3609 .ods-support-body { 3610 position: relative; 3611 flex: 1 1 auto; 3612 min-height: 220px; 3613 display: flex; 3614 flex-direction: column; 3615 overflow: hidden; 3616 } 3617 3618 .ods-support-header { 3619 display: flex; 3620 align-items: flex-start; 3621 gap: 8px; 3622 padding: 14px 14px 10px; 3623 border-bottom: 1px solid var(--ali-border, #e2e8f0); 3624 background: #f8fafc; 3625 } 3626 3627 .ods-support-header-text { 3628 flex: 1; 3629 min-width: 0; 3630 display: flex; 3631 flex-direction: column; 3632 gap: 2px; 3633 } 3634 3635 .ods-support-header-text strong { 3636 font-size: 14px; 3637 color: #0f172a; 3638 } 3639 3640 .ods-support-header-text span { 3641 font-size: 12px; 3642 color: var(--ali-text-muted, #64748b); 3643 } 3644 3645 .ods-support-close { 3646 border: none; 3647 background: transparent; 3648 color: #64748b; 3649 font-size: 22px; 3650 line-height: 1; 3651 cursor: pointer; 3652 padding: 0 4px; 3653 } 3654 3655 .ods-support-messages { 3656 flex: 1 1 auto; 3657 overflow-y: auto; 3658 padding: 12px 14px; 3659 display: flex; 3660 flex-direction: column; 3661 gap: 10px; 3662 background: #fff; 3663 } 3664 3665 .ods-support-msg { 3666 display: flex; 3667 flex-direction: column; 3668 gap: 4px; 3669 max-width: 95%; 3670 } 3671 3672 .ods-support-msg--user { 3673 align-self: flex-end; 3674 } 3675 3676 .ods-support-msg--assistant { 3677 align-self: flex-start; 3678 } 3679 3680 .ods-support-bubble { 3681 padding: 10px 12px; 3682 border-radius: 10px; 3683 font-size: 13px; 3684 line-height: 1.45; 3685 color: #1e293b; 3686 background: #f1f5f9; 3687 white-space: normal; 3688 word-break: break-word; 3689 } 3690 3691 .ods-support-msg--user .ods-support-bubble { 3692 background: #2563eb; 3693 color: #fff; 3694 } 3695 3696 .ods-support-bubble--thinking { 3697 color: #64748b; 3698 font-style: italic; 3699 } 3700 3701 .ods-support-meta { 3702 font-size: 11px; 3703 color: #64748b; 3704 padding: 0 2px; 3705 } 3706 3707 .ods-support-cites { 3708 margin-top: 2px; 3709 } 3710 3711 .ods-support-cite { 3712 display: inline-block; 3713 background: #eff6ff; 3714 color: #1d4ed8; 3715 border-radius: 4px; 3716 padding: 1px 6px; 3717 margin: 2px 2px 0 0; 3718 } 3719 3720 .ods-support-fallback a, 3721 .ods-support-footer a, 3722 .ods-support-docs-link { 3723 color: #2563eb; 3724 } 3725 3726 .ods-support-docs-link { 3727 text-decoration: underline; 3728 font-weight: 600; 3729 } 3730 3731 .ods-support-error { 3732 color: #b91c1c; 3733 } 3734 3735 /* Quick prompts: float above messages inside the panel; stagger in/out from the left. */ 3736 .ods-support-quick { 3737 position: absolute; 3738 left: 10px; 3739 right: 10px; 3740 bottom: 10px; 3741 z-index: 2; 3742 display: flex; 3743 flex-direction: column; 3744 align-items: flex-start; 3745 gap: 8px; 3746 pointer-events: none; 3747 } 3748 3749 .ods-support-chip { 3750 border: 1px solid #cbd5e1; 3751 background: rgba(255, 255, 255, 0.96); 3752 color: #334155; 3753 border-radius: 999px; 3754 padding: 7px 12px; 3755 font-size: 11px; 3756 cursor: pointer; 3757 line-height: 1.35; 3758 text-align: left; 3759 box-shadow: var(--ali-shadow); 3760 max-width: 92%; 3761 white-space: normal; 3762 opacity: 0; 3763 transform: translateX(-120%); 3764 pointer-events: none; 3765 transition: 3766 transform 0.32s cubic-bezier(0.22, 1, 0.36, 1), 3767 opacity 0.28s ease; 3768 transition-delay: 0ms; 3769 } 3770 3771 .ods-support-quick.is-visible .ods-support-chip { 3772 opacity: 1; 3773 transform: translateX(0); 3774 pointer-events: auto; 3775 transition-delay: calc(var(--ods-quick-i, 0) * 70ms); 3776 } 3777 3778 .ods-support-quick.is-hiding .ods-support-chip { 3779 opacity: 0; 3780 transform: translateX(-120%); 3781 pointer-events: none; 3782 transition-delay: calc((2 - var(--ods-quick-i, 0)) * 70ms); 3783 } 3784 3785 .ods-support-chip:hover { 3786 border-color: #2563eb; 3787 color: #1d4ed8; 3788 } 3789 3790 .ods-support-form { 3791 display: flex; 3792 gap: 8px; 3793 padding: 0 14px 10px; 3794 align-items: flex-end; 3795 } 3796 3797 .ods-support-input { 3798 flex: 1; 3799 min-height: 44px; 3800 max-height: 96px; 3801 resize: vertical; 3802 border: 1px solid #cbd5e1; 3803 border-radius: 8px; 3804 padding: 8px 10px; 3805 font-size: 13px; 3806 line-height: 1.4; 3807 } 3808 3809 .ods-support-input:focus { 3810 outline: none; 3811 border-color: #2563eb; 3812 box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.15); 3813 } 3814 3815 .ods-support-send { 3816 border: none; 3817 background: #2563eb; 3818 color: #fff; 3819 border-radius: 8px; 3820 padding: 10px 14px; 3821 font-size: 13px; 3822 font-weight: 600; 3823 cursor: pointer; 3824 white-space: nowrap; 3825 } 3826 3827 .ods-support-send:disabled { 3828 opacity: 0.55; 3829 cursor: not-allowed; 3830 } 3831 3832 .ods-support-footer { 3833 padding: 8px 14px 12px; 3834 border-top: 1px solid var(--ali-border, #e2e8f0); 3835 font-size: 11px; 3836 color: #64748b; 3837 background: #f8fafc; 3838 } 3839 3840 @media (max-width: 782px) { 3841 .ods-support-assistant { 3842 right: 16px; 3843 bottom: 16px; 3844 } 3845 } -
ods-ournest-dropship/trunk/includes/ajax/ajax-mapping.php
r3757662 r3765411 827 827 828 828 // ────────────────────────────────────────── 829 // Save default logistics for a mapped variation830 // ──────────────────────────────────────────831 add_action(832 'wp_ajax_ournest_dropship_save_mapping_logistics',833 function (): void {834 Settings::verify_request();835 836 $product_id = ournest_dropship_post_int( 'product_id', 0 );837 $variation_id = ournest_dropship_post_int( 'variation_id', 0 );838 $service = ournest_dropship_post_text( 'logistics_service', '' );839 $company = ournest_dropship_post_text( 'logistics_company', '' );840 $ae_product_id = ournest_dropship_post_text( 'ae_product_id', '' );841 $ae_sku_id = ournest_dropship_post_text( 'ae_sku_id', '' );842 $ae_sku_title = ournest_dropship_post_text( 'ae_sku_title', '' );843 $ae_sku_img = esc_url_raw( ournest_dropship_post_unslash_string( 'ae_sku_img' ) );844 $ae_sku_path = ournest_dropship_post_text( 'ae_sku_path', '' );845 846 if ( ! $variation_id ) {847 wp_send_json_error( array( 'message' => __( 'Variation ID is required.', 'ods-ournest-dropship' ) ) );848 }849 if ( ! $product_id ) {850 wp_send_json_error( array( 'message' => __( 'Product ID is required.', 'ods-ournest-dropship' ) ) );851 }852 853 $product = wc_get_product( $product_id );854 if ( ! $product ) {855 wp_send_json_error( array( 'message' => __( 'Product not found.', 'ods-ournest-dropship' ) ) );856 }857 if ( $product->is_type( 'variable' ) ) {858 $children = array_map( 'intval', $product->get_children() );859 if ( ! in_array( $variation_id, $children, true ) ) {860 wp_send_json_error( array( 'message' => __( 'Variation does not belong to this product.', 'ods-ournest-dropship' ) ) );861 }862 } elseif ( $variation_id !== $product_id ) {863 wp_send_json_error( array( 'message' => __( 'Variation does not belong to this product.', 'ods-ournest-dropship' ) ) );864 }865 866 $existing = Product_Mapper::get_variation_mapping( $variation_id );867 if ( ! $existing ) {868 if ( $ae_product_id === '' || $ae_sku_id === '' ) {869 wp_send_json_error( array( 'message' => __( 'Map an AliExpress SKU before saving logistics.', 'ods-ournest-dropship' ) ) );870 }871 Product_Mapper::map_variation(872 $product_id,873 $variation_id,874 $ae_product_id,875 $ae_sku_id,876 $ae_sku_title,877 $ae_sku_img,878 $ae_sku_path879 );880 Product_Mapper::auto_maintain_suppliers( $product_id );881 } elseif ( $ae_sku_id !== '' && (string) ( $existing['ae_sku_id'] ?? '' ) !== $ae_sku_id ) {882 // Draft SKU changed before Save Mapping — sync then clear stale logistics via map.883 Product_Mapper::map_variation(884 $product_id,885 $variation_id,886 $ae_product_id !== '' ? $ae_product_id : (string) ( $existing['ae_product_id'] ?? '' ),887 $ae_sku_id,888 $ae_sku_title !== '' ? $ae_sku_title : (string) ( $existing['ae_sku_title'] ?? '' ),889 $ae_sku_img !== '' ? $ae_sku_img : (string) ( $existing['ae_sku_img'] ?? '' ),890 $ae_sku_path !== '' ? $ae_sku_path : (string) ( $existing['ae_sku_path'] ?? '' )891 );892 }893 894 $result = Product_Mapper::save_mapping_logistics( $variation_id, $service, $company );895 if ( is_wp_error( $result ) ) {896 wp_send_json_error( array( 'message' => $result->get_error_message() ) );897 }898 899 wp_send_json_success(900 array(901 'message' => __( 'Logistics saved.', 'ods-ournest-dropship' ),902 'logistics_service' => $service,903 'logistics_company' => $company,904 )905 );906 }907 );908 909 // ──────────────────────────────────────────910 829 // Add supplier to a WC product 911 830 // ────────────────────────────────────────── -
ods-ournest-dropship/trunk/includes/class-i18n.php
r3757662 r3765411 352 352 'completedProgress' => __( '%1$d / %2$d completed', 'ods-ournest-dropship' ), 353 353 'dismissFailed' => __( 'Failed to dismiss', 'ods-ournest-dropship' ), 354 355 // Support assistant 356 'supportOpen' => __( 'Help', 'ods-ournest-dropship' ), 357 'supportClose' => __( 'Close', 'ods-ournest-dropship' ), 358 'supportTitle' => __( 'ODS Assistant', 'ods-ournest-dropship' ), 359 'supportSubtitle' => __( 'Operator help from the ODS manual', 'ods-ournest-dropship' ), 360 'supportPlaceholder' => __( 'Ask how to connect, map, or place orders…', 'ods-ournest-dropship' ), 361 'supportSend' => __( 'Send', 'ods-ournest-dropship' ), 362 'supportHuman' => __( 'Need a human?', 'ods-ournest-dropship' ), 363 'supportThinking' => __( 'Looking up the manual…', 'ods-ournest-dropship' ), 364 'supportEmptyAnswer' => __( 'No answer returned.', 'ods-ournest-dropship' ), 365 'supportError' => __( 'Something went wrong. Please try again.', 'ods-ournest-dropship' ), 366 'supportCitations' => __( 'From the manual:', 'ods-ournest-dropship' ), 367 'supportFallbackHint' => __( 'If this does not help, email', 'ods-ournest-dropship' ), 368 /* translators: %s: HTML link labeled "operator manual". */ 369 'supportWelcome' => __( 'Ask an ODS how-to question. Answers follow the %s.', 'ods-ournest-dropship' ), 370 'supportManualLink' => __( 'operator manual', 'ods-ournest-dropship' ), 371 'supportWelcomeDisconnected' => __( 'You can ask how to connect AliExpress even before authorization. Connect for fulfillment details.', 'ods-ournest-dropship' ), 372 'supportQuickConnect' => __( 'How do I connect AliExpress?', 'ods-ournest-dropship' ), 373 'supportQuickMapping' => __( 'How do I map product SKUs?', 'ods-ournest-dropship' ), 374 'supportQuickPlace' => __( 'Place order failed — what should I check?', 'ods-ournest-dropship' ), 354 375 ); 355 376 } -
ods-ournest-dropship/trunk/includes/class-order-handler.php
r3760832 r3765411 49 49 $list['counts'] = self::compute_tab_counts( $search_ids, $buckets ); 50 50 return $list; 51 }52 53 /**54 * @return array{orders: array, total: int, pages: int}55 */56 public static function get_wc_orders( string $tab = 'paid', string $keyword = '', int $page = 1, int $per_page = 20 ): array {57 $page = max( 1, $page );58 $per_page = max( 1, min( 100, $per_page ) );59 60 $search_ids = null;61 if ( $keyword !== '' ) {62 $search_ids = array_map( 'absint', wc_order_search( $keyword ) );63 if ( empty( $search_ids ) ) {64 return array(65 'orders' => array(),66 'total' => 0,67 'pages' => 0,68 );69 }70 }71 72 return self::query_orders_for_tab( $tab, $search_ids, $page, $per_page, self::place_order_display_buckets() );73 }74 75 /**76 * Order counts per display-status tab (same filter rules as get_wc_orders).77 *78 * @return array<string,int>79 */80 public static function get_tab_counts( string $keyword = '' ): array {81 $search_ids = null;82 if ( $keyword !== '' ) {83 $search_ids = array_map( 'absint', wc_order_search( $keyword ) );84 if ( empty( $search_ids ) ) {85 return array_fill_keys(86 array( 'pending', 'paid', 'processing', 'shipping', 'fulfilled', 'cancelled', 'failed' ),87 088 );89 }90 }91 92 return self::compute_tab_counts( $search_ids, self::place_order_display_buckets() );93 51 } 94 52 -
ods-ournest-dropship/trunk/ournest-dropship.php
r3760832 r3765411 11 11 * Plugin URI: https://anest.top/ods/ 12 12 * Description: AliExpress dropshipping for WooCommerce by OurNest (ODS). Browse, import, map SKUs, and fulfill orders from your WordPress store. 13 * Version: 1. 2.013 * Version: 1.3.0 14 14 * Requires at least: 6.0 15 15 * Requires PHP: 8.0 … … 30 30 // Constants 31 31 // ────────────────────────────────────────────── 32 define( 'OURNEST_DROPSHIP_VERSION', '1. 2.0' );32 define( 'OURNEST_DROPSHIP_VERSION', '1.3.0' ); 33 33 define( 'OURNEST_DROPSHIP_PATH', plugin_dir_path( __FILE__ ) ); 34 34 define( 'OURNEST_DROPSHIP_URL', plugin_dir_url( __FILE__ ) ); … … 47 47 if ( ! defined( 'OURNEST_DROPSHIP_SERVER_URL' ) ) { 48 48 define( 'OURNEST_DROPSHIP_SERVER_URL', 'https://api.anest.top' ); 49 } 50 // Shared with ae-server [support].service_key — PHP only, never localize to JS. 51 if ( ! defined( 'OURNEST_DROPSHIP_SUPPORT_KEY' ) ) { 52 define( 'OURNEST_DROPSHIP_SUPPORT_KEY', 'd7c8cc25fc2d63f637a9371cf2c247fbd363795912cb7c50cb427f097608e798' ); 49 53 } 50 54 … … 375 379 ? \Ournest\Dropship\Settings::is_api_key_valid() 376 380 : false, 377 'countries' => $needs_countries && function_exists( 'ournest_dropship_countries' ) 381 'current_page' => $page, 382 'support_email' => 'support@anest.top', 383 'docs_url' => 'https://anest.top/ods/help', 384 'countries' => $needs_countries && function_exists( 'ournest_dropship_countries' ) 378 385 ? ournest_dropship_countries() 379 386 : array(), 380 387 'i18n' => class_exists( '\\Ournest\Dropship\\I18n' ) ? \Ournest\Dropship\I18n::js_strings() : array(), 381 388 ) 389 ); 390 wp_enqueue_script( 391 'ournest-dropship-support-assistant', 392 OURNEST_DROPSHIP_URL . 'assets/js/support-assistant.js', 393 array( $common_handle ), 394 ournest_dropship_asset_ver( 'assets/js/support-assistant.js' ), 395 true 382 396 ); 383 397 … … 490 504 require_once $ournest_dropship_onboarding_ajax; 491 505 } 506 507 $ournest_dropship_support_ajax = OURNEST_DROPSHIP_PATH . 'includes/ajax/ajax-support.php'; 508 if ( file_exists( $ournest_dropship_support_ajax ) ) { 509 require_once $ournest_dropship_support_ajax; 510 } -
ods-ournest-dropship/trunk/readme.txt
r3760832 r3765411 9 9 WC requires at least: 8.0 10 10 WC tested up to: 9.8 11 Stable tag: 1. 2.011 Stable tag: 1.3.0 12 12 License: GPLv2 or later 13 13 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 38 38 * Apply optional USD exchange rates in pricing rules 39 39 * Optional daily AliExpress stock sync with per-product exclusion 40 * Floating smart assistant for operator how-to questions (manual-based) 40 41 41 42 = How It Works = … … 140 141 141 142 == Changelog == 143 144 = 1.3.0 = 145 146 * Smart assistant: floating help on all ODS admin pages for operator how-to questions. 147 * Smart assistant: quick prompts with staggered show/hide; answers cite the operator manual. 148 * Smart assistant: “operator manual” links to https://anest.top/ods/help . 149 * Smart assistant: works before AliExpress is connected (how-to connect still available). 150 * Removed unused order-list helpers and an unused mapping-logistics AJAX endpoint. 142 151 143 152 = 1.2.0 = … … 246 255 == Upgrade Notice == 247 256 257 = 1.3.0 = 258 Adds a floating smart assistant for ODS operator how-to questions, with manual citations and docs link. Recommended update for all stores. 259 248 260 = 1.2.0 = 249 261 Improves My Orders compatibility with WooCommerce 11, links Order # to Woo edit, and shows AE SKU image/title in place-order and AE drawers. Recommended update for all stores.
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)