get( \Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled() ? wc_get_page_screen_id( 'shop-order' ) : 'shop_order'; add_meta_box( 'ordercourier_order_actions', __( 'OrderCourier Actions', 'ordercourier' ), array( $this, 'render_order_metabox' ), $screen, 'side', 'default' ); } /** * Render order metabox. * * @param \WP_Post|\WC_Order $post_or_order Post or order object. */ public function render_order_metabox( $post_or_order ) { $order = $post_or_order instanceof \WC_Order ? $post_or_order : wc_get_order( $post_or_order->ID ); if ( ! $order ) { return; } $channel = $order->get_meta( '_oc_channel' ); if ( 'chat' !== $channel ) { echo '

' . esc_html__( 'This is not a chat order.', 'ordercourier' ) . '

'; return; } $agent_id = $order->get_meta( '_oc_agent_id' ); $agent_phone = $order->get_meta( '_oc_agent_phone' ); $sent_at = $order->get_meta( '_oc_sent_at' ); // Display agent name or phone. if ( $agent_id ) { $agent_name = get_the_title( $agent_id ); } elseif ( $agent_phone ) { $agent_name = $agent_phone; } else { $agent_name = __( 'Default', 'ordercourier' ); } ?>

$template ) { $url = \Prologic365\OrderCourier\Order_Manager::get_order_message_url( $order->get_id(), 'order' ); ?>

is_plugin_screen( $hook ) ) { wp_enqueue_style( 'ordercourier-admin', ORDERCOURIER_URL . 'assets/css/admin.css', array(), ORDERCOURIER_VERSION ); wp_enqueue_script( 'ordercourier-admin', ORDERCOURIER_URL . 'assets/js/admin.js', array( 'jquery' ), ORDERCOURIER_VERSION, true ); /** * Action for PRO and other add-ons to enqueue their admin assets. * * @since 1.0.0 * @param string $hook Current admin page hook. */ do_action( 'ordercourier_admin_enqueue_scripts', $hook ); } } /** * Whether the current admin screen is one where this plugin shows UI. * * That is the OrderCourier tab in WooCommerce settings and the order edit screen * (both the classic post screen and the HPOS orders screen). * * @param string $hook Admin page hook. * @return bool */ public function is_plugin_screen( $hook ) { if ( 'woocommerce_page_wc-settings' === $hook ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only reads which settings tab is open. $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : ''; return 'ordercourier' === $tab; } $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( ! $screen ) { return false; } $order_screens = array( 'shop_order' ); if ( function_exists( 'wc_get_page_screen_id' ) ) { $order_screens[] = wc_get_page_screen_id( 'shop-order' ); } return in_array( $screen->id, $order_screens, true ); } /** * Add category phone field (add form). * * @param string $taxonomy Taxonomy slug. */ public function add_category_phone_field_new( $taxonomy ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found wp_nonce_field( 'ordercourier_save_term', 'ordercourier_term_nonce' ); ?>

term_id, '_oc_agent_phone', true ); ?>

validate( $phone ) ) { // Invalid phone, don't save and show error via transient. set_transient( 'ordercourier_phone_validation_error_' . get_current_user_id(), 'category', 10 ); return; } // Normalize to digits only (E.164 without +). $normalized_phone = $validator->normalize( $phone ); $normalized_phone = ltrim( $normalized_phone, '+' ); update_term_meta( $term_id, '_oc_agent_phone', $normalized_phone ); } else { delete_term_meta( $term_id, '_oc_agent_phone' ); } } } /** * Add product phone field. */ public function add_product_phone_field() { global $post; echo '
'; wp_nonce_field( 'ordercourier_save_product', 'ordercourier_product_nonce' ); woocommerce_wp_text_input( array( 'id' => '_oc_agent_phone', 'label' => __( 'OrderCourier Phone', 'ordercourier' ), 'placeholder' => '+1234567890', 'desc_tip' => true, 'description' => __( 'Override the default phone number for this product (E.164 format).', 'ordercourier' ), 'value' => get_post_meta( $post->ID, '_oc_agent_phone', true ), ) ); woocommerce_wp_checkbox( array( 'id' => '_oc_quote_only', 'label' => __( 'Quote Only', 'ordercourier' ), 'description' => __( 'The chat button asks for a price instead of sending an order. The product price is still visible to customers.', 'ordercourier' ), 'value' => get_post_meta( $post->ID, '_oc_quote_only', true ), ) ); woocommerce_wp_checkbox( array( 'id' => '_oc_disable', 'label' => __( 'Hide Chat Button', 'ordercourier' ), 'description' => __( 'Hide the chat button for this product.', 'ordercourier' ), 'value' => get_post_meta( $post->ID, '_oc_disable', true ), ) ); echo '
'; } /** * Save product phone field. * * @param int $post_id Product ID. */ public function save_product_phone_field( $post_id ) { if ( ! isset( $_POST['ordercourier_product_nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['ordercourier_product_nonce'] ) ), 'ordercourier_save_product' ) ) { return; } // Verify user capabilities. if ( ! current_user_can( 'edit_post', $post_id ) ) { return; } // Save quote only checkbox. if ( isset( $_POST['_oc_quote_only'] ) ) { update_post_meta( $post_id, '_oc_quote_only', 'yes' ); } else { delete_post_meta( $post_id, '_oc_quote_only' ); } // Save disable button checkbox. if ( isset( $_POST['_oc_disable'] ) ) { update_post_meta( $post_id, '_oc_disable', 'yes' ); } else { delete_post_meta( $post_id, '_oc_disable' ); } if ( isset( $_POST['_oc_agent_phone'] ) ) { $phone = sanitize_text_field( wp_unslash( $_POST['_oc_agent_phone'] ) ); if ( ! empty( $phone ) ) { // Validate and normalize phone number. $validator = new \Prologic365\OrderCourier\Phone_Validator(); if ( ! $validator->validate( $phone ) ) { // Invalid phone, don't save and show error via transient. set_transient( 'ordercourier_phone_validation_error_' . get_current_user_id(), 'product', 10 ); return; } // Normalize to digits only (E.164 without +). $normalized_phone = $validator->normalize( $phone ); $normalized_phone = ltrim( $normalized_phone, '+' ); update_post_meta( $post_id, '_oc_agent_phone', $normalized_phone ); } else { delete_post_meta( $post_id, '_oc_agent_phone' ); } } } /** * Display phone validation error notice. */ public function display_phone_validation_error() { // Only on the product and product category screens, where the phone field is saved. $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( ! $screen || 'product' !== $screen->post_type || ! in_array( $screen->base, array( 'post', 'edit-tags', 'term' ), true ) ) { return; } $user_id = get_current_user_id(); $error_type = get_transient( 'ordercourier_phone_validation_error_' . $user_id ); if ( $error_type ) { delete_transient( 'ordercourier_phone_validation_error_' . $user_id ); $message = sprintf( /* translators: %s: error context (product or category) */ __( 'OrderCourier: Invalid phone number format for %s. Please use E.164 format (e.g., +1234567890). The number was not saved.', 'ordercourier' ), $error_type ); echo '

' . esc_html( $message ) . '

'; } } }