buy-now-button/buy-now-button.php
2025-08-24 04:39:13 +06:00

568 lines
25 KiB
PHP

<?php
/**
* Plugin Name: Woo Buy Now Button
* Description: Adds a “Buy Now” button to product cards and single product pages for direct checkout with AJAX. Includes a settings page to customize colors (normal/hover/active), text color, animation (hover or always), border radius (archive + single), button text, and text alignment.
* Version: 1.6.0
* Author: absoftlab
* Author URI: https://absoftlab.com
* License: MIT
* Update URI: https://absoftlab.com/woo-buy-now-button
* Text Domain: ab-buy-now-button-customizable
*/
if (! defined('ABSPATH')) exit;
define('ABB_BN_VERSION', '1.6.0');
define('ABB_BN_FILE', __FILE__);
define('ABB_BN_URL', plugin_dir_url(__FILE__));
define('ABB_BN_PATH', plugin_dir_path(__FILE__));
/** WooCommerce check notice */
add_action('admin_notices', function () {
if (current_user_can('activate_plugins') && ! class_exists('WooCommerce')) {
echo '<div class="notice notice-error"><p><strong>Buy Now Button for WooCommerce:</strong> WooCommerce is not active. Please install/activate WooCommerce.</p></div>';
}
});
/** Defaults */
function abb_bn_default_settings() {
return [
'color_normal' => '#1e40af',
'color_hover' => '#1d4ed8',
'color_active' => '#1e3a8a',
'text_color' => '#ffffff',
'radius' => 8, // archive/shop default
'radius_single' => 8, // NEW: single product page
'animation' => 'none', // none|pulse|bounce|wiggle|shake|glow|ripple
'animation_state' => 'hover', // hover|normal
'button_text' => 'Buy Now',
'text_align' => 'center', // left|center|right
];
}
/** Get settings */
function abb_bn_get_settings() {
$defaults = abb_bn_default_settings();
$saved = get_option('abb_bn_settings', []);
if (! is_array($saved)) $saved = [];
return wp_parse_args($saved, $defaults);
}
/** Sanitize */
function abb_bn_sanitize_settings($input) {
$defaults = abb_bn_default_settings();
$out = [];
// Colors (accept #RGB, #RRGGBB, #RRGGBBAA, rgb/rgba)
foreach (['color_normal','color_hover','color_active','text_color'] as $key) {
$val = isset($input[$key]) ? trim($input[$key]) : '';
if (preg_match('/^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/', $val)
|| preg_match('/^rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}(?:\s*,\s*(0|0?\.\d+|1))?\s*\)$/', $val)) {
$out[$key] = $val;
} else {
$out[$key] = $defaults[$key];
}
}
// Radii: 0-64
$radius = isset($input['radius']) ? intval($input['radius']) : $defaults['radius'];
$radius_single = isset($input['radius_single']) ? intval($input['radius_single']) : $defaults['radius_single'];
$out['radius'] = min(64, max(0, $radius));
$out['radius_single'] = min(64, max(0, $radius_single));
// Animation
$allowed_anims = ['none','pulse','bounce','wiggle','shake','glow','ripple'];
$anim = isset($input['animation']) ? sanitize_text_field($input['animation']) : $defaults['animation'];
$out['animation'] = in_array($anim, $allowed_anims, true) ? $anim : 'none';
$state = isset($input['animation_state']) ? sanitize_text_field($input['animation_state']) : $defaults['animation_state'];
$out['animation_state'] = in_array($state, ['hover','normal'], true) ? $state : 'hover';
// Text + align
$txt = isset($input['button_text']) ? sanitize_text_field($input['button_text']) : $defaults['button_text'];
$out['button_text'] = ($txt === '') ? $defaults['button_text'] : $txt;
$align = isset($input['text_align']) ? sanitize_text_field($input['text_align']) : $defaults['text_align'];
$out['text_align'] = in_array($align, ['left','center','right'], true) ? $align : 'center';
return $out;
}
/** Settings & menu */
add_action('admin_init', function () {
register_setting('abb_bn_settings_group', 'abb_bn_settings', [
'type' => 'array',
'sanitize_callback' => 'abb_bn_sanitize_settings',
'default' => abb_bn_default_settings(),
]);
});
add_action('admin_menu', function () {
$parent_slug = class_exists('WooCommerce') ? 'woocommerce' : 'options-general.php';
add_submenu_page(
$parent_slug,
__('Buy Now Button', 'buy-now-button-customizable'),
__('Buy Now Button', 'buy-now-button-customizable'),
'manage_options',
'buy-now-button',
'abb_bn_render_settings_page'
);
});
/** Admin assets */
add_action('admin_enqueue_scripts', function ($hook) {
if ($hook === 'woocommerce_page_buy-now-button' || $hook === 'settings_page_buy-now-button') {
wp_enqueue_style('wp-color-picker');
wp_enqueue_script('abb-bn-admin', ABB_BN_URL . 'assets/js/admin.js', ['jquery','wp-color-picker'], ABB_BN_VERSION, true);
wp_enqueue_style('abb-bn-admin-css', ABB_BN_URL . 'assets/css/admin.css', [], ABB_BN_VERSION);
}
});
/** Settings UI */
function abb_bn_render_settings_page() {
if (! current_user_can('manage_options')) return;
$opts = abb_bn_get_settings();
$logo_url = '';
if (file_exists(ABB_BN_PATH.'assets/img/logo.svg')) {
$logo_url = ABB_BN_URL.'assets/img/logo.svg';
} elseif (file_exists(ABB_BN_PATH.'assets/img/logo.png')) {
$logo_url = ABB_BN_URL.'assets/img/logo.png';
}
?>
<div class="wrap abb-bn-wrap">
<div class="abb-bn-head">
<?php if ($logo_url): ?>
<img class="abb-bn-logo" src="<?php echo esc_url($logo_url); ?>" alt="<?php esc_attr_e('Brand logo','buy-now-button-customizable'); ?>" />
<?php endif; ?>
<span class="abb-version-badge">-v<?php echo esc_html(ABB_BN_VERSION); ?></span>
</div>
<form method="post" action="options.php" class="abb-bn-form">
<?php settings_fields('abb_bn_settings_group'); ?>
<div class="abb-bn-layout">
<div class="abb-bn-panel">
<div class="abb-bn-card">
<h2 class="abb-bn-card-title"><?php esc_html_e('Button Text','buy-now-button-customizable'); ?></h2>
<label class="abb-bn-field">
<span class="abb-bn-label"><?php esc_html_e('Text','buy-now-button-customizable'); ?></span>
<input type="text" class="regular-text abb-bn-input" name="abb_bn_settings[button_text]" id="abb-bn-button-text" value="<?php echo esc_attr($opts['button_text']); ?>" />
</label>
<label class="abb-bn-field">
<span class="abb-bn-label"><?php esc_html_e('Text Align','buy-now-button-customizable'); ?></span>
<select name="abb_bn_settings[text_align]" id="abb-bn-text-align" class="abb-bn-select">
<option value="left" <?php selected($opts['text_align'],'left'); ?>><?php esc_html_e('Left','buy-now-button-customizable'); ?></option>
<option value="center" <?php selected($opts['text_align'],'center'); ?>><?php esc_html_e('Center','buy-now-button-customizable'); ?></option>
<option value="right" <?php selected($opts['text_align'],'right'); ?>><?php esc_html_e('Right','buy-now-button-customizable'); ?></option>
</select>
</label>
</div>
<div class="abb-bn-card">
<h2 class="abb-bn-card-title"><?php esc_html_e('Button Color','buy-now-button-customizable'); ?></h2>
<div class="abb-bn-grid2">
<label class="abb-bn-field">
<span class="abb-bn-label"><?php esc_html_e('Normal','buy-now-button-customizable'); ?></span>
<input type="text" class="abb-color-field abb-bn-input" name="abb_bn_settings[color_normal]" id="abb-bn-color-normal" value="<?php echo esc_attr($opts['color_normal']); ?>" data-default-color="#1e40af" />
<span class="abb-hex-hint">#RRGGBB / rgba()</span>
</label>
<label class="abb-bn-field">
<span class="abb-bn-label"><?php esc_html_e('Hover','buy-now-button-customizable'); ?></span>
<input type="text" class="abb-color-field abb-bn-input" name="abb_bn_settings[color_hover]" id="abb-bn-color-hover" value="<?php echo esc_attr($opts['color_hover']); ?>" data-default-color="#1d4ed8" />
<span class="abb-hex-hint">#RRGGBB / rgba()</span>
</label>
<label class="abb-bn-field">
<span class="abb-bn-label"><?php esc_html_e('Active','buy-now-button-customizable'); ?></span>
<input type="text" class="abb-color-field abb-bn-input" name="abb_bn_settings[color_active]" id="abb-bn-color-active" value="<?php echo esc_attr($opts['color_active']); ?>" data-default-color="#1e3a8a" />
<span class="abb-hex-hint">#RRGGBB / rgba()</span>
</label>
<label class="abb-bn-field" style="grid-column: 1 / -1;">
<span class="abb-bn-label"><?php esc_html_e('Text Color','buy-now-button-customizable'); ?></span>
<input type="text" class="abb-color-field abb-bn-input" name="abb_bn_settings[text_color]" id="abb-bn-text-color" value="<?php echo esc_attr($opts['text_color']); ?>" data-default-color="#ffffff" />
<span class="abb-hex-hint">#RRGGBB / rgba()</span>
</label>
<label class="abb-bn-field">
<span class="abb-bn-label"><?php esc_html_e('Border Radius (Archive) px','buy-now-button-customizable'); ?></span>
<input type="number" min="0" max="64" class="abb-bn-input" name="abb_bn_settings[radius]" id="abb-bn-radius" value="<?php echo esc_attr($opts['radius']); ?>" />
</label>
<label class="abb-bn-field">
<span class="abb-bn-label"><?php esc_html_e('Border Radius (Single) px','buy-now-button-customizable'); ?></span>
<input type="number" min="0" max="64" class="abb-bn-input" name="abb_bn_settings[radius_single]" id="abb-bn-radius-single" value="<?php echo esc_attr($opts['radius_single']); ?>" />
</label>
</div>
</div>
<div class="abb-bn-card">
<h2 class="abb-bn-card-title"><?php esc_html_e('Button Animation','buy-now-button-customizable'); ?></h2>
<div class="abb-bn-grid2">
<label class="abb-bn-field">
<span class="abb-bn-label"><?php esc_html_e('Type','buy-now-button-customizable'); ?></span>
<select name="abb_bn_settings[animation]" id="abb-bn-animation" class="abb-bn-select">
<?php
$animations = [
'none' => __('None','buy-now-button-customizable'),
'pulse' => __('Pulse','buy-now-button-customizable'),
'bounce' => __('Bounce','buy-now-button-customizable'),
'wiggle' => __('Wiggle','buy-now-button-customizable'),
'shake' => __('Shake','buy-now-button-customizable'),
'glow' => __('Glow','buy-now-button-customizable'),
'ripple' => __('Ripple (on click)','buy-now-button-customizable'),
];
foreach ($animations as $slug => $label) {
printf('<option value="%1$s" %3$s>%2$s</option>', esc_attr($slug), esc_html($label), selected($opts['animation'],$slug,false));
}
?>
</select>
</label>
<label class="abb-bn-field">
<span class="abb-bn-label"><?php esc_html_e('Trigger','buy-now-button-customizable'); ?></span>
<select name="abb_bn_settings[animation_state]" id="abb-bn-animation-state" class="abb-bn-select">
<option value="hover" <?php selected($opts['animation_state'],'hover'); ?>><?php esc_html_e('Apply on Hover','buy-now-button-customizable'); ?></option>
<option value="normal" <?php selected($opts['animation_state'],'normal'); ?>><?php esc_html_e('Apply Always (Normal)','buy-now-button-customizable'); ?></option>
</select>
</label>
</div>
</div>
<div class="abb-bn-actions">
<?php submit_button(__('Save Changes','buy-now-button-customizable'),'primary','submit',false); ?>
</div>
</div>
<!-- Right: Preview -->
<div class="abb-bn-preview">
<div class="abb-bn-card">
<h2 class="abb-bn-card-title"><?php esc_html_e('Preview','buy-now-button-customizable'); ?></h2>
<div class="abb-bn-preview-toolbar">
<label><input type="radio" name="abb-bn-state" value="normal" checked> <?php esc_html_e('Normal','buy-now-button-customizable'); ?></label>
<label><input type="radio" name="abb-bn-state" value="hover"> <?php esc_html_e('Hover','buy-now-button-customizable'); ?></label>
<label><input type="radio" name="abb-bn-state" value="active"> <?php esc_html_e('Active','buy-now-button-customizable'); ?></label>
</div>
<div class="abb-bn-preview-stage">
<a href="#" id="abb-bn-demo" class="button buy-now-button"><?php echo esc_html($opts['button_text']); ?></a>
</div>
<p class="description"><?php esc_html_e('Simulates color states, text color, and animations; frontend reflects your saved settings.','buy-now-button-customizable'); ?></p>
</div>
<!-- Your extra card left as-is -->
<div class="abb-extra">
<article class="card" aria-labelledby="title">
<div class="card-inner">
<div class="logo" role="img" aria-label="Brand logo">
<img height="100%" width="100%" src="<?php echo esc_url(plugins_url('assets/img/profile.png', __FILE__)); ?>" alt="Profile">
</div>
<div>
<h1 id="title">absoftlab - Is a Web Development Agency</h1>
<p class="desc">If you need a super fast ecommerce website or something like that, we are here to help you. We also offer a wide range of other web development services. like custom plugin development, theme customization, and performance optimization.</p>
<div class="meta" aria-label="Contact methods">
<a class="chip" href="mailto:example@gmail.com" aria-label="Email example at gmail dot com">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M3 7.5A2.5 2.5 0 0 1 5.5 5h13A2.5 2.5 0 0 1 21 7.5v9A2.5 2.5 0 0 1 18.5 19h-13A2.5 2.5 0 0 1 3 16.5v-9Z" stroke="currentColor" stroke-width="1.6" />
<path d="m4 7 8 6 8-6" stroke="currentColor" stroke-width="1.6" />
</svg>
absoftlab@gmail.com
</a>
<a class="chip" href="https://wa.me/+8801762675353" target="_blank" rel="noopener" aria-label="WhatsApp number 01762675353">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M20.5 11.5A8.5 8.5 0 1 1 6.8 19.8L3.5 21l1.2-3.3A8.5 8.5 0 0 1 20.5 11.5Z" stroke="currentColor" stroke-width="1.6"/>
<path d="M8.5 8.8c0 4.1 3.4 7.5 7.5 7.5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
</svg>
01762675353
</a>
</div>
</div>
</div>
<footer class="footer">
<a class="btn" href="mailto:absoftlab@gmail.com">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M4 12h14" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/>
<path d="m14 6 6 6-6 6" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Email Me
</a>
<a class="btn" href="tel:+8801762675353">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M6.5 4A2.5 2.5 0 0 1 9 6.5v1A2.5 2.5 0 0 1 6.5 10 10.5 10.5 0 0 0 17 20.5 2.5 2.5 0 0 1 19.5 18h1A2.5 2.5 0 0 1 23 20.5v.3A3.2 3.2 0 0 1 20 24C10.6 24 2.9 16.3 2.9 6.9A3.2 3.2 0 0 1 6.2 3h.3z" stroke="currentColor" stroke-width="1.4"/>
</svg>
Call / WhatsApp
</a>
</footer>
</article>
</div>
</div>
</div>
</form>
</div>
<?php
}
/** Build dynamic CSS (separate radius for archive vs single) */
function abb_bn_build_dynamic_css() {
$opts = abb_bn_get_settings();
$def = abb_bn_default_settings();
foreach (['color_normal','color_hover','color_active','text_color'] as $k) {
$v = trim((string)$opts[$k]);
if (!preg_match('/^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/', $v)
&& !preg_match('/^rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}(?:\s*,\s*(0|0?\.\d+|1))?\s*\)$/', $v)) {
$opts[$k] = $def[$k];
}
}
$normal = $opts['color_normal'];
$hover = $opts['color_hover'];
$active = $opts['color_active'];
$text_color = $opts['text_color'];
$radius_archive = intval($opts['radius']);
$radius_single = intval($opts['radius_single']);
$align = in_array($opts['text_align'], ['left','center','right'], true) ? $opts['text_align'] : 'center';
$justify = $align === 'left' ? 'flex-start' : ($align === 'right' ? 'flex-end' : 'center');
$archive_selectors = [
'.woocommerce ul.products li.product a.button.buy-now-button',
'.woocommerce ul.products li.product .button.buy-now-button',
'.woocommerce .products .product a.button.buy-now-button',
'ul.products li.product a.button.buy-now-button',
'.shop .products .product a.button.buy-now-button',
'.woocommerce a.button.add_to_cart_button.buy-now-button',
'.products .product a.add_to_cart_button.buy-now-button',
'.buy-now-button', // fallback
];
$single_selectors = [
'button.button.buy-now-button-single',
'.single-product .summary .buy-now-button-single',
'.buy-now-button-single',
];
$archive_sel = implode(',', $archive_selectors);
$single_sel = implode(',', $single_selectors);
$block = function($selectors, $radius) use($normal,$hover,$active,$text_color,$align,$justify){
return "
$selectors{
background: {$normal} !important;
background-color: {$normal} !important;
border-color: {$normal} !important;
color: {$text_color} !important;
border-radius: {$radius}px !important;
border: 1px solid {$normal} !important;
display: inline-flex !important;
align-items: center !important;
justify-content: {$justify} !important;
text-align: {$align} !important;
text-decoration: none !important;
transition: all .2s ease-in-out !important;
padding: 10px 16px !important;
cursor: pointer !important;
}
$selectors:hover{
background: {$hover} !important;
background-color: {$hover} !important;
border-color: {$hover} !important;
color: {$text_color} !important;
}
$selectors:active,
$selectors.is-active{
background: {$active} !important;
background-color: {$active} !important;
border-color: {$active} !important;
color: {$text_color} !important;
}
";
};
return $block($archive_sel, $radius_archive) . $block($single_sel, $radius_single);
}
/** Front-end assets + dynamic CSS */
add_action('wp_enqueue_scripts', function () {
// Ensure a style handle exists
if (! wp_style_is('abb-bn-css', 'registered')) {
$css_path = ABB_BN_PATH . 'assets/css/buy-now.css';
if (file_exists($css_path)) {
wp_enqueue_style('abb-bn-css', ABB_BN_URL . 'assets/css/buy-now.css', [], ABB_BN_VERSION);
} else {
wp_register_style('abb-bn-css', false, [], ABB_BN_VERSION);
wp_enqueue_style('abb-bn-css');
}
} else {
wp_enqueue_style('abb-bn-css');
}
// JS
wp_enqueue_script('abb-bn-js', ABB_BN_URL . 'assets/js/buy-now.js', ['jquery'], ABB_BN_VERSION, true);
$opts = abb_bn_get_settings();
wp_localize_script('abb-bn-js', 'abbBnVars', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('abb_bn_nonce'),
'anim' => $opts['animation'],
]);
// Inline CSS early
wp_add_inline_style('abb-bn-css', abb_bn_build_dynamic_css());
});
/** Also print CSS very late to beat aggressive themes */
add_action('wp_head', function () {
echo '<style id="abb-bn-inline-head-late">'.abb_bn_build_dynamic_css().'</style>';
}, 9999);
add_action('wp_footer', function () {
echo '<style id="abb-bn-inline-footer-late">'.abb_bn_build_dynamic_css().'</style>';
}, 99);
/** Inline style helper (context-aware radius) */
function abb_bn_inline_button_style($opts, $is_single = false) {
$align = in_array($opts['text_align'], ['left','center','right'], true) ? $opts['text_align'] : 'center';
$justify = $align === 'left' ? 'flex-start' : ($align === 'right' ? 'flex-end' : 'center');
$normal = esc_attr($opts['color_normal']);
$text_color = esc_attr($opts['text_color']);
$radius = intval($is_single ? $opts['radius_single'] : $opts['radius']);
return "background: {$normal} !important; background-color: {$normal} !important; border-color: {$normal} !important; color: {$text_color} !important; border-radius: {$radius}px !important; border:1px solid {$normal} !important; display:inline-flex !important; align-items:center !important; justify-content: {$justify} !important; text-align: {$align} !important; padding:10px 16px !important;";
}
/** Single product button */
add_action('woocommerce_after_add_to_cart_button', function () {
global $product; if (! $product) return;
$opts = abb_bn_get_settings();
$classes = '';
if ($opts['animation'] !== 'none') {
$classes .= ' bn-anim-'.esc_attr($opts['animation']);
if ($opts['animation_state'] === 'normal') $classes .= ' bn-anim-normal';
}
$style = abb_bn_inline_button_style($opts, true); // use single radius
printf(
'<button class="button alt buy-now-button-single%1$s" data-product_id="%2$d" type="button" style="%3$s margin-left:8px;"
data-color-normal="%4$s" data-color-hover="%5$s" data-color-active="%6$s" data-text-color="%7$s">%8$s</button>',
$classes,
absint($product->get_id()),
esc_attr($style),
esc_attr($opts['color_normal']),
esc_attr($opts['color_hover']),
esc_attr($opts['color_active']),
esc_attr($opts['text_color']),
esc_html($opts['button_text'])
);
}, 20);
/** Archive button (simple products only) */
add_action('woocommerce_after_shop_loop_item', function () {
global $product; if (! $product || ! $product->is_type('simple')) return;
$opts = abb_bn_get_settings();
$classes = '';
if ($opts['animation'] !== 'none') {
$classes .= ' bn-anim-'.esc_attr($opts['animation']);
if ($opts['animation_state'] === 'normal') $classes .= ' bn-anim-normal';
}
$style = abb_bn_inline_button_style($opts, false); // use archive radius
printf(
'<a href="#" class="button buy-now-button%1$s" data-product_id="%2$d" style="%3$s margin-top:8px;"
data-color-normal="%4$s" data-color-hover="%5$s" data-color-active="%6$s" data-text-color="%7$s">%8$s</a>',
$classes,
absint($product->get_id()),
esc_attr($style),
esc_attr($opts['color_normal']),
esc_attr($opts['color_hover']),
esc_attr($opts['color_active']),
esc_attr($opts['text_color']),
esc_html($opts['button_text'])
);
}, 15);
/** AJAX handler */
function abb_bn_ajax_buy_now() {
check_ajax_referer('abb_bn_nonce', 'nonce');
if (! class_exists('WooCommerce')) wp_send_json_error(['message'=>'WooCommerce not active'], 400);
$product_id = isset($_POST['product_id']) ? absint($_POST['product_id']) : 0;
$qty = isset($_POST['quantity']) ? max(1, absint($_POST['quantity'])) : 1;
$variation_id = isset($_POST['variation_id']) ? absint($_POST['variation_id']) : 0;
$attributes = [];
if (isset($_POST['attributes']) && is_array($_POST['attributes'])) {
foreach ($_POST['attributes'] as $k => $v) $attributes[ wc_clean($k) ] = wc_clean( wp_unslash($v) );
}
if ($product_id <= 0) wp_send_json_error(['message'=>'Invalid product'], 400);
if (function_exists('WC') && WC()->cart) {
// WC()->cart->empty_cart(); // optional replace mode
$item_key = WC()->cart->add_to_cart($product_id, $qty, $variation_id, $attributes);
if (! $item_key) wp_send_json_error(['message'=>'Could not add to cart'], 400);
wp_send_json_success(['redirect' => wc_get_checkout_url()]);
}
wp_send_json_error(['message'=>'Cart unavailable'], 500);
}
add_action('wp_ajax_abb_bn_buy_now', 'abb_bn_ajax_buy_now');
add_action('wp_ajax_nopriv_abb_bn_buy_now', 'abb_bn_ajax_buy_now');
/** Non-JS fallback */
add_action('template_redirect', function () {
if (! isset($_GET['buy_now_add'])) return;
if (! class_exists('WooCommerce')) return;
$product_id = absint($_GET['buy_now_add']);
if ($product_id <= 0) return;
$qty = isset($_GET['quantity']) ? max(1, absint($_GET['quantity'])) : 1;
$variation_id = isset($_GET['variation_id']) ? absint($_GET['variation_id']) : 0;
$variations = [];
foreach ($_GET as $key => $val) {
if (strpos($key, 'attribute_') === 0) $variations[ wc_clean($key) ] = wc_clean( wp_unslash($val) );
}
if (function_exists('WC') && WC()->cart) {
WC()->cart->add_to_cart($product_id, $qty, $variation_id, $variations);
wp_safe_redirect( wc_get_checkout_url() );
exit;
}
});
/** Override the "View details" modal for this plugin only */
add_filter('plugins_api', function ($result, $action, $args) {
if ($action !== 'plugin_information') return $result;
$my_slug = basename(dirname(ABB_BN_FILE));
$alt_slug = 'ab-buy-now-button-customizable';
if (empty($args->slug) || ($args->slug !== $my_slug && $args->slug !== $alt_slug)) return $result;
$info = (object) [
'name' => 'Woo Buy Now Button',
'slug' => $my_slug,
'version' => ABB_BN_VERSION,
'author' => '<a href="https://absoftlab.com">absoftlab</a>',
'homepage' => 'https://absoftlab.com',
'requires' => '5.8',
'requires_php' => '7.2',
'tested' => '6.6',
'last_updated' => gmdate('Y-m-d'),
'sections' => [
'description' => wpautop('A lightweight WooCommerce plugin that adds a **Buy Now** button to single products and archives with instant checkout redirect. Includes color, text, alignment, animation, and per-context radius customization.'),
'installation' => wpautop("1. Upload the plugin folder to `wp-content/plugins/`.\n2. Activate in **Plugins**.\n3. Go to **WooCommerce → Buy Now Button** to configure."),
'changelog' => wp_kses_post('
<h4>1.5.4</h4>
<ul><li>Added separate Border Radius for Single Product button.</li></ul>
<h4>1.5.3</h4>
<ul><li>Added Text Color option; preview reflects animation instantly.</li></ul>
<h4>1.5.2</h4>
<ul><li>Force custom colors even when themes inject late CSS.</li></ul>
'),
],
'external' => true,
];
return $info;
}, 10, 3);