JezK
Edit File: chat-order-buttons.php
<?php /** * Plugin Name: Advaxe Chat & Call Order Buttons * Description: Adds full-width Call, WhatsApp, and Messenger order buttons on WooCommerce single product pages (after the Add to Cart button). Prefills WhatsApp with product title + link. * Version: 1.1.2 * Author: Advaxe * Requires at least: 5.5 * Requires PHP: 7.2 * License: GPLv2 or later */ if ( ! defined( 'ABSPATH' ) ) { exit; } class Advaxe_Chat_Order_Buttons { const OPT_KEY = 'advaxe_chat_order_buttons_opts'; public function __construct() { add_action( 'admin_init', [ $this, 'maybe_set_defaults' ] ); add_action( 'admin_menu', [ $this, 'register_settings_page' ] ); add_action( 'admin_init', [ $this, 'register_settings' ] ); add_action( 'woocommerce_after_add_to_cart_form', [ $this, 'render_buttons' ] ); add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_styles' ] ); } public function maybe_set_defaults() { $opts = get_option( self::OPT_KEY ); if ( ! $opts ) { $defaults = [ 'call_number' => '', 'wa_number' => '', 'fb_username' => '', 'wa_text' => 'হোয়াটসঅ্যাপ', 'call_text' => 'কল করুন', 'fb_text' => 'মেসেঞ্জারে অর্ডার করুন', 'enable_call' => 1, 'enable_wa' => 1, 'enable_fb' => 1, 'desktop_only' => 0, 'mobile_only' => 0, 'show_on_types' => [ 'simple' ], ]; add_option( self::OPT_KEY, $defaults ); } } public function register_settings_page() { add_submenu_page( 'woocommerce', __( 'Chat & Call Buttons', 'advaxe' ), __( 'Chat & Call Buttons', 'advaxe' ), 'manage_woocommerce', 'advaxe-chat-order-buttons', [ $this, 'settings_page_html' ] ); } public function register_settings() { register_setting( 'advaxe_chat_order_buttons_group', self::OPT_KEY, [ $this, 'sanitize_options' ] ); add_settings_section( 'advaxe_main', __( 'Button Settings', 'advaxe' ), function () { echo '<p>' . esc_html__( 'Configure Call, WhatsApp, and Messenger order buttons.', 'advaxe' ) . '</p>'; }, 'advaxe_chat_order_buttons' ); add_settings_field( 'wa_number', __( 'WhatsApp Number', 'advaxe' ), [ $this, 'field_wa_number' ], 'advaxe_chat_order_buttons', 'advaxe_main' ); add_settings_field( 'wa_text', __( 'WhatsApp Button Text', 'advaxe' ), [ $this, 'field_wa_text' ], 'advaxe_chat_order_buttons', 'advaxe_main' ); add_settings_field( 'enable_wa', __( 'Enable WhatsApp Button', 'advaxe' ), [ $this, 'field_enable_wa' ], 'advaxe_chat_order_buttons', 'advaxe_main' ); add_settings_field( 'call_number', __( 'Call Number', 'advaxe' ), [ $this, 'field_call_number' ], 'advaxe_chat_order_buttons', 'advaxe_main' ); add_settings_field( 'call_text', __( 'Call Button Text', 'advaxe' ), [ $this, 'field_call_text' ], 'advaxe_chat_order_buttons', 'advaxe_main' ); add_settings_field( 'enable_call', __( 'Enable Call Button', 'advaxe' ), [ $this, 'field_enable_call' ], 'advaxe_chat_order_buttons', 'advaxe_main' ); add_settings_field( 'fb_username', __( 'Messenger Page/User', 'advaxe' ), [ $this, 'field_fb_username' ], 'advaxe_chat_order_buttons', 'advaxe_main' ); add_settings_field( 'fb_text', __( 'Messenger Button Text', 'advaxe' ), [ $this, 'field_fb_text' ], 'advaxe_chat_order_buttons', 'advaxe_main' ); add_settings_field( 'enable_fb', __( 'Enable Messenger Button', 'advaxe' ), [ $this, 'field_enable_fb' ], 'advaxe_chat_order_buttons', 'advaxe_main' ); add_settings_field( 'visibility', __( 'Visibility', 'advaxe' ), [ $this, 'field_visibility' ], 'advaxe_chat_order_buttons', 'advaxe_main' ); add_settings_field( 'types', __( 'Show on product types', 'advaxe' ), [ $this, 'field_types' ], 'advaxe_chat_order_buttons', 'advaxe_main' ); } public function sanitize_options( $input ) { $output = get_option( self::OPT_KEY, [] ); $output['call_number'] = isset( $input['call_number'] ) ? preg_replace( '/[^0-9+]/', '', $input['call_number'] ) : ''; $output['wa_number'] = isset( $input['wa_number'] ) ? preg_replace( '/[^0-9]/', '', $input['wa_number'] ) : ''; $output['fb_username'] = isset( $input['fb_username'] ) ? sanitize_text_field( $input['fb_username'] ) : ''; $output['call_text'] = isset( $input['call_text'] ) ? sanitize_text_field( $input['call_text'] ) : ''; $output['wa_text'] = isset( $input['wa_text'] ) ? sanitize_text_field( $input['wa_text'] ) : ''; $output['fb_text'] = isset( $input['fb_text'] ) ? sanitize_text_field( $input['fb_text'] ) : ''; $output['enable_call'] = isset( $input['enable_call'] ) ? (int) !! $input['enable_call'] : 0; $output['enable_wa'] = isset( $input['enable_wa'] ) ? (int) !! $input['enable_wa'] : 0; $output['enable_fb'] = isset( $input['enable_fb'] ) ? (int) !! $input['enable_fb'] : 0; $output['desktop_only'] = isset( $input['desktop_only'] ) ? (int) !! $input['desktop_only'] : 0; $output['mobile_only'] = isset( $input['mobile_only'] ) ? (int) !! $input['mobile_only'] : 0; $output['show_on_types'] = isset( $input['show_on_types'] ) && is_array( $input['show_on_types'] ) ? array_values( array_intersect( [ 'simple', 'variable', 'external', 'grouped' ], array_map( 'sanitize_text_field', $input['show_on_types'] ) ) ) : [ 'simple' ]; return $output; } public function field_call_number() { $opts = get_option( self::OPT_KEY ); ?> <input type="text" name="<?php echo esc_attr( self::OPT_KEY ); ?>[call_number]" value="<?php echo esc_attr( $opts['call_number'] ?? '' ); ?>" class="regular-text" placeholder="+8801XXXXXXXXX"> <p class="description"><?php esc_html_e( 'Use international format. Example: +8801XXXXXXXXX', 'advaxe' ); ?></p> <?php } public function field_call_text() { $opts = get_option( self::OPT_KEY ); ?> <input type="text" name="<?php echo esc_attr( self::OPT_KEY ); ?>[call_text]" value="<?php echo esc_attr( $opts['call_text'] ?? '' ); ?>" class="regular-text"> <?php } public function field_enable_call() { $opts = get_option( self::OPT_KEY ); ?> <label><input type="checkbox" name="<?php echo esc_attr( self::OPT_KEY ); ?>[enable_call]" value="1" <?php checked( ! empty( $opts['enable_call'] ) ); ?>> <?php esc_html_e( 'Enable', 'advaxe' ); ?></label> <?php } public function field_wa_number() { $opts = get_option( self::OPT_KEY ); ?> <input type="text" name="<?php echo esc_attr( self::OPT_KEY ); ?>[wa_number]" value="<?php echo esc_attr( $opts['wa_number'] ?? '' ); ?>" class="regular-text" placeholder="8801XXXXXXXXX"> <?php } public function field_wa_text() { $opts = get_option( self::OPT_KEY ); ?> <input type="text" name="<?php echo esc_attr( self::OPT_KEY ); ?>[wa_text]" value="<?php echo esc_attr( $opts['wa_text'] ?? '' ); ?>" class="regular-text"> <?php } public function field_enable_wa() { $opts = get_option( self::OPT_KEY ); ?> <label><input type="checkbox" name="<?php echo esc_attr( self::OPT_KEY ); ?>[enable_wa]" value="1" <?php checked( ! empty( $opts['enable_wa'] ) ); ?>> <?php esc_html_e( 'Enable', 'advaxe' ); ?></label> <?php } public function field_fb_username() { $opts = get_option( self::OPT_KEY ); ?> <input type="text" name="<?php echo esc_attr( self::OPT_KEY ); ?>[fb_username]" value="<?php echo esc_attr( $opts['fb_username'] ?? '' ); ?>" class="regular-text" placeholder="yourpageusername"> <?php } public function field_fb_text() { $opts = get_option( self::OPT_KEY ); ?> <input type="text" name="<?php echo esc_attr( self::OPT_KEY ); ?>[fb_text]" value="<?php echo esc_attr( $opts['fb_text'] ?? '' ); ?>" class="regular-text"> <?php } public function field_enable_fb() { $opts = get_option( self::OPT_KEY ); ?> <label><input type="checkbox" name="<?php echo esc_attr( self::OPT_KEY ); ?>[enable_fb]" value="1" <?php checked( ! empty( $opts['enable_fb'] ) ); ?>> <?php esc_html_e( 'Enable', 'advaxe' ); ?></label> <?php } public function field_visibility() { $opts = get_option( self::OPT_KEY ); ?> <label style="margin-right:1em;"><input type="checkbox" name="<?php echo esc_attr( self::OPT_KEY ); ?>[desktop_only]" value="1" <?php checked( ! empty( $opts['desktop_only'] ) ); ?>> Desktop only</label> <label><input type="checkbox" name="<?php echo esc_attr( self::OPT_KEY ); ?>[mobile_only]" value="1" <?php checked( ! empty( $opts['mobile_only'] ) ); ?>> Mobile only</label> <?php } public function field_types() { $opts = get_option( self::OPT_KEY ); $types = [ 'simple' => 'Simple', 'variable' => 'Variable', 'external' => 'External', 'grouped' => 'Grouped' ]; foreach ( $types as $slug => $label ) : ?> <label style="margin-right:1em;display:inline-block"> <input type="checkbox" name="<?php echo esc_attr( self::OPT_KEY ); ?>[show_on_types][]" value="<?php echo esc_attr( $slug ); ?>" <?php checked( in_array( $slug, $opts['show_on_types'] ?? [], true ) ); ?>> <?php echo esc_html( $label ); ?> </label> <?php endforeach; } public function settings_page_html() { if ( ! current_user_can( 'manage_woocommerce' ) ) return; ?> <div class="wrap"> <h1><?php esc_html_e( 'Advaxe Chat & Call Order Buttons', 'advaxe' ); ?></h1> <form method="post" action="options.php"> <?php settings_fields( 'advaxe_chat_order_buttons_group' ); do_settings_sections( 'advaxe_chat_order_buttons' ); submit_button(); ?> </form> </div> <?php } public function enqueue_styles() { // Google Fonts থেকে Hind Siliguri ইম্পোর্ট করা হলো wp_enqueue_style( 'advaxe-hind-siliguri', 'https://fonts.googleapis.com/css2?family=Hind+Siliguri:wght@600;700&display=swap', [], null ); $css = '.advaxe-chat-order-wrap { margin-top: -10px; display: flex; flex-direction: row; flex-wrap: wrap; gap: 10px; } .advaxe-chat-order-btn { font-family: "Hind Siliguri", sans-serif; display: flex; align-items: center; justify-content: center; gap: 6px; flex: 1; min-width: 140px; text-align: center; padding: 12px 10px; border-radius: 8px; font-weight: 700; font-size: 16px; text-decoration: none; line-height: 1; box-sizing: border-box; transition: all 0.2s ease-in-out; } .advaxe-chat-call { background: #F87315; color: #fff; } .advaxe-chat-wa { background: #25D366; color: #fff; } .advaxe-chat-fb { background: #0084FF; color: #fff; } .advaxe-chat-order-btn:hover { opacity: .9; color: #fff; } .advaxe-chat-order-btn svg { width: 18px; height: 18px; fill: currentColor; }'; wp_register_style( 'advaxe-chat-order-buttons', false ); wp_enqueue_style( 'advaxe-chat-order-buttons' ); wp_add_inline_style( 'advaxe-chat-order-buttons', $css ); } private function device_visible( $opts ) { $is_mobile = wp_is_mobile(); if ( ! empty( $opts['desktop_only'] ) && $is_mobile ) return false; if ( ! empty( $opts['mobile_only'] ) && ! $is_mobile ) return false; return true; } public function render_buttons() { if ( ! function_exists( 'is_product' ) || ! is_product() ) return; global $product; if ( ! $product || ! is_a( $product, 'WC_Product' ) ) return; $opts = get_option( self::OPT_KEY, [] ); if ( empty( $opts ) || ! $this->device_visible( $opts ) ) return; $type = $product->get_type(); $allowed = $opts['show_on_types'] ?? [ 'simple' ]; if ( ! in_array( $type, $allowed, true ) ) return; $title = get_the_title( $product->get_id() ); $link = get_permalink( $product->get_id() ); $buttons_html = ''; $wa_icon = '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51a12.8 12.8 0 00-.57-.01c-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>'; $call_icon = '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20.01 15.38c-1.23 0-2.42-.2-3.53-.56a.977.977 0 00-1.01.24l-1.57 1.97c-2.83-1.35-5.48-3.9-6.89-6.83l1.95-1.66c.27-.28.35-.67.24-1.02-.37-1.11-.56-2.3-.56-3.53 0-.54-.45-.99-.99-.99H4.19C3.65 3 3 3.24 3 3.99 3 13.28 10.73 21 20.01 21c.71 0 .99-.63.99-1.18v-3.45c0-.54-.45-.99-.99-.99z"/></svg>'; $fb_icon = '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 2C6.477 2 2 6.14 2 11.25c0 2.91 1.492 5.513 3.843 7.185V22l3.498-1.923c.85.234 1.742.36 2.659.36 5.523 0 10-4.14 10-9.25S17.523 2 12 2zm1.093 12.35l-2.775-2.955-5.414 2.955 5.952-6.32 2.84 2.956 5.348-2.956-5.951 6.32z"/></svg>'; // 1. WhatsApp (Left Side) if ( ! empty( $opts['enable_wa'] ) && ! empty( $opts['wa_number'] ) ) { $msg = sprintf( __( 'আমি %1$s নিতে চাই। লিংক: %2$s', 'advaxe' ), $title, $link ); $wa_url = 'https://wa.me/' . rawurlencode( $opts['wa_number'] ) . '?text=' . rawurlencode( $msg ); $buttons_html .= sprintf( '<a class="advaxe-chat-order-btn advaxe-chat-wa" href="%1$s" target="_blank" rel="noopener">%2$s %3$s</a>', esc_url( $wa_url ), $wa_icon, esc_html( $opts['wa_text'] ?: 'হোয়াটসঅ্যাপ' ) ); } // 2. Call button (Right Side) if ( ! empty( $opts['enable_call'] ) && ! empty( $opts['call_number'] ) ) { $call_url = 'tel:' . preg_replace( '/[^0-9+]/', '', $opts['call_number'] ); $buttons_html .= sprintf( '<a class="advaxe-chat-order-btn advaxe-chat-call" href="%1$s">%2$s %3$s</a>', esc_url( $call_url ), $call_icon, esc_html( $opts['call_text'] ?: 'কল করুন' ) ); } // 3. Messenger (Optional if enabled) if ( ! empty( $opts['enable_fb'] ) && ! empty( $opts['fb_username'] ) ) { $m_username = trim( $opts['fb_username'] ); $msg_param = rawurlencode( $link ); $fb_web = 'https://m.me/' . rawurlencode( $m_username ) . '?ref=' . $msg_param; $buttons_html .= sprintf( '<a class="advaxe-chat-order-btn advaxe-chat-fb" href="%1$s" target="_blank" rel="noopener">%2$s %3$s</a>', esc_url( $fb_web ), $fb_icon, esc_html( $opts['fb_text'] ?: 'মেসেঞ্জারে অর্ডার করুন' ) ); } if ( $buttons_html ) { echo '<div class="advaxe-chat-order-wrap">' . $buttons_html . '</div>'; } } } new Advaxe_Chat_Order_Buttons();