feat: Implement upsell functionality with repository and service layers
This commit is contained in:
53
public/hooks/analytics-hooks.php
Normal file
53
public/hooks/analytics-hooks.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// Prevent direct access
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
use Sodino\Repositories\EventRepository;
|
||||
use Sodino\Services\TrackingService;
|
||||
|
||||
function sodino_get_tracking_service() {
|
||||
static $service = null;
|
||||
|
||||
if ($service === null) {
|
||||
$eventRepository = new EventRepository();
|
||||
$service = new TrackingService($eventRepository);
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
add_action('template_redirect', 'sodino_track_product_view');
|
||||
add_action('woocommerce_add_to_cart', 'sodino_track_add_to_cart', 10, 6);
|
||||
add_action('woocommerce_before_checkout_form', 'sodino_track_checkout_start');
|
||||
add_action('woocommerce_thankyou', 'sodino_track_purchase', 10, 1);
|
||||
|
||||
function sodino_track_product_view() {
|
||||
if (is_admin() || !is_singular('product')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$product_id = get_the_ID();
|
||||
if (!$product_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
sodino_get_tracking_service()->trackProductView($product_id);
|
||||
}
|
||||
|
||||
function sodino_track_add_to_cart($cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data) {
|
||||
sodino_get_tracking_service()->trackAddToCart($product_id, $variation_id, $quantity);
|
||||
}
|
||||
|
||||
function sodino_track_checkout_start() {
|
||||
if (is_admin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
sodino_get_tracking_service()->trackCheckoutStart();
|
||||
}
|
||||
|
||||
function sodino_track_purchase($order_id) {
|
||||
sodino_get_tracking_service()->trackPurchase($order_id);
|
||||
}
|
||||
@@ -5,12 +5,16 @@ if (!defined('ABSPATH')) {
|
||||
}
|
||||
|
||||
use Sodino\Services\PricingService;
|
||||
use Sodino\Services\TrackingService;
|
||||
use Sodino\Repositories\RuleRepository;
|
||||
use Sodino\Repositories\EventRepository;
|
||||
|
||||
// Initialize pricing service
|
||||
global $sodino_pricing_service;
|
||||
$ruleRepository = new RuleRepository();
|
||||
$sodino_pricing_service = new PricingService($ruleRepository);
|
||||
$eventRepository = new EventRepository();
|
||||
$trackingService = new TrackingService($eventRepository);
|
||||
$sodino_pricing_service = new PricingService($ruleRepository, $trackingService);
|
||||
|
||||
// Hook into WooCommerce price filter
|
||||
add_filter('woocommerce_product_get_price', 'sodino_apply_dynamic_pricing', 10, 2);
|
||||
|
||||
91
public/hooks/upsell-hooks.php
Normal file
91
public/hooks/upsell-hooks.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
// Prevent direct access
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
use Sodino\Repositories\UpsellRepository;
|
||||
use Sodino\Services\UpsellService;
|
||||
|
||||
global $sodino_upsell_service;
|
||||
$upsellRepository = new UpsellRepository();
|
||||
$sodino_upsell_service = new UpsellService($upsellRepository);
|
||||
|
||||
add_action('woocommerce_before_cart', 'sodino_render_upsell_suggestions');
|
||||
|
||||
function sodino_render_upsell_suggestions() {
|
||||
if (is_admin() || !is_cart()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = wp_parse_args(get_option('sodino_settings', []), [
|
||||
'upsell_enabled' => 1,
|
||||
]);
|
||||
|
||||
if (empty($settings['upsell_enabled'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $sodino_upsell_service;
|
||||
if (!isset($sodino_upsell_service)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cart = WC()->cart;
|
||||
if (!$cart || $cart->is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$upsells = $sodino_upsell_service->getMatchingUpsells($cart);
|
||||
if (empty($upsells)) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<div class="sodino-upsell-panel bg-white rounded-2xl border border-gray-200 p-6 mb-8 shadow-sm">';
|
||||
echo '<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">';
|
||||
echo '<div>';
|
||||
echo '<p class="text-sm font-semibold text-blue-600">' . esc_html__('پیشنهاد ویژه آپسل', 'sodino') . '</p>';
|
||||
echo '<h2 class="mt-2 text-xl font-bold text-gray-900">' . esc_html__('این محصول را همراه خرید خود با تخفیف ویژه دریافت کنید', 'sodino') . '</h2>';
|
||||
echo '</div>';
|
||||
echo '<span class="inline-flex items-center rounded-full bg-blue-50 px-3 py-1 text-sm font-medium text-blue-700">' . count($upsells) . ' ' . esc_html__('پیشنهاد فعال', 'sodino') . '</span>';
|
||||
echo '</div>';
|
||||
echo '<div class="mt-6 grid gap-4 lg:grid-cols-'.min(2, count($upsells)).'">';
|
||||
|
||||
foreach ($upsells as $upsell) {
|
||||
$product = wc_get_product($upsell->target_product_id);
|
||||
if (!$product) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$discountedPrice = $sodino_upsell_service->applyUpsellDiscount($product, $upsell);
|
||||
$originalPrice = floatval($product->get_price());
|
||||
$priceHtml = wc_price($discountedPrice);
|
||||
if ($discountedPrice < $originalPrice) {
|
||||
$priceHtml .= ' <span class="mr-2 text-sm text-gray-500 line-through">' . wc_price($originalPrice) . '</span>';
|
||||
}
|
||||
|
||||
$addToCartUrl = esc_url(add_query_arg('add-to-cart', $product->get_id(), wc_get_cart_url()));
|
||||
$image = $product->get_image('woocommerce_thumbnail', ['class' => 'h-20 w-20 rounded-xl object-cover']);
|
||||
|
||||
echo '<div class="rounded-2xl border border-gray-200 p-5 bg-gray-50">';
|
||||
echo '<div class="flex gap-4">';
|
||||
echo '<div class="flex-shrink-0">' . $image . '</div>';
|
||||
echo '<div class="flex-1">';
|
||||
echo '<p class="text-sm font-medium text-gray-700">' . esc_html($upsell->title) . '</p>';
|
||||
echo '<h3 class="mt-2 text-lg font-semibold text-gray-900">' . esc_html($product->get_name()) . '</h3>';
|
||||
echo '<div class="mt-3 flex items-center gap-3">';
|
||||
echo '<span class="rounded-full bg-green-50 px-3 py-1 text-sm font-medium text-green-700">' . esc_html($sodino_upsell_service->getDiscountLabel($upsell)) . '</span>';
|
||||
echo '<span class="text-sm text-gray-600">' . esc_html($sodino_upsell_service->getTriggerLabel($upsell)) . '</span>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
echo '<div class="mt-5 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">';
|
||||
echo '<div class="text-lg font-semibold text-gray-900">' . $priceHtml . '</div>';
|
||||
echo '<a href="' . $addToCartUrl . '" class="inline-flex items-center justify-center rounded-full bg-blue-600 px-5 py-3 text-sm font-semibold text-white hover:bg-blue-700">' . esc_html__('افزودن به سبد', 'sodino') . '</a>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
Reference in New Issue
Block a user