motayeb/functions.php
Kazem Alghasi c16648678d - install local Tailwind
- fix more problems
2026-09-23 00:32:16 +03:30

864 lines
40 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* توابع اختصاصی تم مطیب
*
* @package Motayeb
* @version 1.0.1
*
* تغییرات نسخه ۱.۰.۱:
* - رفع ارورهای CSP/CORB با چک کردن وجود فایل پیش از enqueue
* - استفاده از filemtime برای cache-busting به جای نسخه تم
* - حذف وابستگی غیرضروری به jQuery
* - جایگزینی WP_Query با wc_get_products در جستجوی Ajax
* - افزودن defer به اسکریپت‌ها برای بهبود بارگذاری
* - guard کردن تمام فراخوانی wc_get_* در برابر غیرفعال بودن ووکامرس
* - اعتبارسنجی rating در comment_post
* - sanitize_key روی کوکی دارک‌مود
* - بررسی revision در save_post
*/
// جلوگیری از دسترسی مستقیم
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// ============================================================
// ثابت‌های کمکی
// ============================================================
define( 'MOTAYEB_VERSION', '1.0.1' );
define( 'MOTAYEB_NONCE_ACTION', 'motayeb_nonce' );
// ============================================================
// ۱. تنظیمات اولیه تم (Theme Setup)
// ============================================================
function motayeb_theme_setup() {
add_theme_support( 'title-tag' );
add_theme_support( 'post-thumbnails' );
add_theme_support( 'custom-logo', array(
'height' => 60,
'width' => 200,
'flex-height' => true,
'flex-width' => true,
'header-text' => array( 'site-title', 'site-description' ),
) );
add_theme_support( 'woocommerce' );
add_theme_support( 'wc-product-gallery-zoom' );
add_theme_support( 'wc-product-gallery-lightbox' );
add_theme_support( 'wc-product-gallery-slider' );
add_theme_support( 'html5', array(
'search-form', 'comment-form', 'comment-list', 'gallery', 'caption', 'style', 'script',
) );
add_theme_support( 'align-wide' );
add_theme_support( 'responsive-embeds' );
register_nav_menus( array(
'primary' => esc_html__( 'منوی اصلی', 'motayeb' ),
'footer' => esc_html__( 'منوی فوتر', 'motayeb' ),
) );
add_image_size( 'motayeb-product-grid', 400, 400, true );
add_image_size( 'motayeb-product-single', 600, 600, true );
}
add_action( 'after_setup_theme', 'motayeb_theme_setup' );
// ============================================================
// ۲. بارگذاری فایل‌های استایل و اسکریپت (Enqueue) — اصلاح‌شده
// ============================================================
/**
* تابع کمکی: enqueue امن برای استایل — فقط اگه فایل وجود داشته باشه.
* از filemtime برای cache-busting استفاده می‌کنه تا با هر تغییر، کش مرورگر بشکنه.
*/
function motayeb_enqueue_style_safe( $handle, $rel_path, $deps = array(), $media = 'all' ) {
$path = get_theme_file_path( $rel_path );
if ( ! $path || ! file_exists( $path ) || 0 === filesize( $path ) ) {
return false;
}
wp_enqueue_style(
$handle,
get_theme_file_uri( $rel_path ),
$deps,
filemtime( $path ),
$media
);
return true;
}
/**
* تابع کمکی: enqueue امن برای اسکریپت — فقط اگه فایل وجود داشته باشه.
* jQuery به‌صورت پیش‌فرض بارگذاری نمی‌شه؛ اگه واقعاً لازم بود، deps بده.
*/
function motayeb_enqueue_script_safe( $handle, $rel_path, $deps = array(), $in_footer = true ) {
$path = get_theme_file_path( $rel_path );
if ( ! $path || ! file_exists( $path ) || 0 === filesize( $path ) ) {
return false;
}
wp_enqueue_script(
$handle,
get_theme_file_uri( $rel_path ),
$deps,
filemtime( $path ),
$in_footer
);
return true;
}
function motayeb_scripts() {
$ver = MOTAYEB_VERSION;
// ۱. استایل اصلی تم (style.css در ریشه)
wp_enqueue_style( 'motayeb-style', get_stylesheet_uri(), array(), $ver );
// ۲. استایل Tailwind ساخته‌شده (پس از build استاتیک جایگزین Play CDN می‌شه)
motayeb_enqueue_style_safe( 'motayeb-tailwind', '/assets/css/tailwind.css', array( 'motayeb-style' ) );
// ۳. استایل ووکامرس — فقط اگه فایل واقعاً وجود داشت و خالی نبود
if ( class_exists( 'WooCommerce' ) ) {
motayeb_enqueue_style_safe( 'motayeb-woocommerce', '/assets/css/woocommerce.css', array( 'motayeb-style' ) );
}
// ۴. استایل ریسپانسیو
motayeb_enqueue_style_safe( 'motayeb-responsive', '/assets/css/responsive.css', array( 'motayeb-style' ) );
// ۵. اسکریپت اصلی (بدون jQuery — فرض بر اینه که با vanilla JS نوشته شده)
$main_loaded = motayeb_enqueue_script_safe( 'motayeb-main', '/assets/js/main.js' );
// ۶. پاس دادن متغیرها به JS — با guard ووکامرس
if ( $main_loaded ) {
$localize_data = array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( MOTAYEB_NONCE_ACTION ),
'home_url' => home_url( '/' ),
);
if ( class_exists( 'WooCommerce' ) ) {
$localize_data['checkout_url'] = wc_get_checkout_url();
$localize_data['cart_url'] = wc_get_cart_url();
}
wp_localize_script( 'motayeb-main', 'motayeb_ajax', $localize_data );
}
// ۷. اسکریپت ووکامرس — فقط روی صفحات فروشگاهی و اگه فایل پر بود
if ( class_exists( 'WooCommerce' ) ) {
if ( is_woocommerce() || is_cart() || is_checkout() || is_account_page() ) {
motayeb_enqueue_script_safe( 'motayeb-woocommerce', '/assets/js/woocommerce.js', array( 'motayeb-main' ) );
}
}
// ۸. اسکریپت دارک‌مود
motayeb_enqueue_script_safe( 'motayeb-darkmode', '/assets/js/darkmode.js' );
// ۹. اسکریپت‌های پیش‌فرض ووکامرس روی صفحات مربوطه
if ( class_exists( 'WooCommerce' ) ) {
if ( is_product() ) { wp_enqueue_script( 'wc-single-product' ); }
if ( is_cart() ) { wp_enqueue_script( 'wc-cart' ); }
if ( is_checkout() ) { wp_enqueue_script( 'wc-checkout' ); }
}
}
add_action( 'wp_enqueue_scripts', 'motayeb_scripts' );
/**
* افزودن `defer` به اسکریپت‌های خودمان برای بهبود بارگذاری.
* این کار parsing HTML رو مسدود نمی‌کنه.
*/
function motayeb_script_loader_tag( $tag, $handle ) {
$defer_handles = array( 'motayeb-main', 'motayeb-darkmode', 'motayeb-woocommerce' );
if ( in_array( $handle, $defer_handles, true ) ) {
return str_replace( ' src', ' defer src', $tag );
}
return $tag;
}
add_filter( 'script_loader_tag', 'motayeb_script_loader_tag', 10, 2 );
// ============================================================
// ۳. ثبت ناحیه‌های ویجت (Widget Areas)
// ============================================================
function motayeb_widgets_init() {
register_sidebar( array(
'name' => esc_html__( 'سایدبار اصلی', 'motayeb' ),
'id' => 'sidebar-main',
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
) );
if ( class_exists( 'WooCommerce' ) ) {
register_sidebar( array(
'name' => esc_html__( 'سایدبار فروشگاه', 'motayeb' ),
'id' => 'sidebar-shop',
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
) );
}
for ( $i = 1; $i <= 4; $i++ ) {
register_sidebar( array(
'name' => esc_html__( 'فوتر - ستون ' . $i, 'motayeb' ),
'id' => 'footer-' . $i,
'before_widget' => '<div id="%1$s" class="footer-widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h4 class="footer-widget-title">',
'after_title' => '</h4>',
) );
}
}
add_action( 'widgets_init', 'motayeb_widgets_init' );
// ============================================================
// ۴. توابع کمکی ووکامرس
// ============================================================
add_filter( 'loop_shop_columns', function() { return 4; } );
add_filter( 'loop_shop_per_page', function() { return 12; } );
function motayeb_body_classes( $classes ) {
if ( class_exists( 'WooCommerce' ) ) {
if ( is_product() ) { $classes[] = 'motayeb-product-page'; }
if ( is_shop() ) { $classes[] = 'motayeb-shop-page'; }
}
// کوکی با sanitize_key بررسی می‌شه تا فقط 'on' یا '' قبول بشه
if ( isset( $_COOKIE['motayeb_darkmode'] ) && 'on' === sanitize_key( wp_unslash( $_COOKIE['motayeb_darkmode'] ) ) ) {
$classes[] = 'dark-mode';
}
return $classes;
}
add_filter( 'body_class', 'motayeb_body_classes' );
// ============================================================
// ۵. کلاس‌های Walker برای منو
// ============================================================
class Motayeb_Desktop_Walker extends Walker_Nav_Menu {
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$output .= '<ul class="absolute top-full right-0 min-w-[200px] bg-white dark:bg-dark-card shadow-xl rounded-xl p-2 mt-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-300 border border-cream-200 dark:border-dark-border">';
}
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$classes = 'relative group';
if ( $depth === 0 ) {
$classes .= ' nav-link text-sm font-medium text-earth-400 dark:text-dark-text hover:text-forest-500 dark:hover:text-forest-300 transition';
}
$output .= '<li class="' . esc_attr( $classes ) . '">';
$output .= '<a href="' . esc_url( $item->url ) . '" class="block px-1 py-2">' . esc_html( $item->title ) . '</a>';
}
public function end_el( &$output, $item, $depth = 0, $args = array() ) {
$output .= '</li>';
}
}
class Motayeb_Mobile_Walker extends Walker_Nav_Menu {
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$output .= '<a href="' . esc_url( $item->url ) . '" onclick="closeMobileMenu()" class="flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-forest-50 dark:hover:bg-forest-900/30 transition">';
$output .= '<iconify-icon icon="lucide:chevron-left" width="20" class="text-forest-500 dark:text-forest-300"></iconify-icon>';
$output .= '<span class="font-medium">' . esc_html( $item->title ) . '</span>';
$output .= '</a>';
}
public function end_el( &$output, $item, $depth = 0, $args = array() ) {}
}
// ============================================================
// ۶. توابع Ajax برای جستجو و دریافت محصولات — اصلاح‌شده
// ============================================================
/**
* دریافت اطلاعات یک محصول با ID.
* فقط روی محصولات منتشرشده کار می‌کنه.
*/
function motayeb_ajax_get_product_data() {
check_ajax_referer( MOTAYEB_NONCE_ACTION, 'nonce' );
if ( ! class_exists( 'WooCommerce' ) ) {
wp_send_json_error( 'ووکامرس فعال نیست' );
}
$product_id = isset( $_GET['id'] ) ? intval( $_GET['id'] ) : 0;
if ( ! $product_id ) {
wp_send_json_error( 'شناسه محصول نامعتبر است' );
}
$product = wc_get_product( $product_id );
if ( ! $product || 'publish' !== $product->get_status() ) {
wp_send_json_error( 'محصول یافت نشد' );
}
$image = wp_get_attachment_image_src( $product->get_image_id(), 'thumbnail' );
wp_send_json_success( array(
'id' => $product->get_id(),
'name' => $product->get_name(),
'price' => $product->get_price() !== '' ? floatval( $product->get_price() ) : 0,
'img' => $image ? $image[0] : '',
'stock' => $product->get_stock_quantity(),
'permalink' => $product->get_permalink(),
) );
}
add_action( 'wp_ajax_get_product_data', 'motayeb_ajax_get_product_data' );
add_action( 'wp_ajax_nopriv_get_product_data', 'motayeb_ajax_get_product_data' );
/**
* جستجوی زنده محصولات — از wc_get_products استفاده می‌کنه تا
* visibility ووکامرسی (محصولات hidden از کاتالوگ) رعایت بشه.
*/
function motayeb_ajax_search_products() {
check_ajax_referer( MOTAYEB_NONCE_ACTION, 'nonce' );
if ( ! class_exists( 'WooCommerce' ) ) {
wp_send_json_error( 'ووکامرس فعال نیست' );
}
$term = isset( $_GET['term'] ) ? sanitize_text_field( wp_unslash( $_GET['term'] ) ) : '';
if ( strlen( $term ) < 2 ) {
wp_send_json_success( array() );
}
$products = wc_get_products( array(
'status' => 'publish',
'limit' => 6,
'paginate' => false,
's' => $term,
) );
$results = array();
foreach ( $products as $product ) {
$image = wp_get_attachment_image_src( $product->get_image_id(), 'thumbnail' );
$terms = wp_get_post_terms( $product->get_id(), 'product_cat', array( 'fields' => 'names' ) );
$results[] = array(
'id' => $product->get_id(),
'name' => $product->get_name(),
'price' => $product->get_price() !== '' ? floatval( $product->get_price() ) : 0,
'image' => $image ? $image[0] : '',
'category' => ! empty( $terms ) ? $terms[0] : '',
'permalink' => $product->get_permalink(),
);
}
wp_send_json_success( $results );
}
add_action( 'wp_ajax_search_products', 'motayeb_ajax_search_products' );
add_action( 'wp_ajax_nopriv_search_products', 'motayeb_ajax_search_products' );
// ============================================================
// ۷. متاباکس‌های سفارشی برای محصولات
// ============================================================
function motayeb_add_product_metaboxes() {
add_meta_box( 'motayeb_ingredients', 'ترکیبات محصول', 'motayeb_ingredients_metabox_callback', 'product', 'normal', 'high' );
add_meta_box( 'motayeb_health_benefits', 'خواص سلامت (هر آیتم در یک خط + آیکون انتخابی)', 'motayeb_health_benefits_metabox_callback', 'product', 'normal', 'high' );
}
add_action( 'add_meta_boxes', 'motayeb_add_product_metaboxes' );
function motayeb_ingredients_metabox_callback( $post ) {
wp_nonce_field( 'motayeb_save_ingredients', 'motayeb_ingredients_nonce' );
$value = get_post_meta( $post->ID, '_ingredients', true );
echo '<p><label for="ingredients_field">متن ترکیبات را وارد کنید (می‌توانید از تگ‌های HTML ساده استفاده کنید):</label></p>';
wp_editor( $value, 'ingredients_field', array(
'textarea_name' => 'ingredients_field', 'textarea_rows' => 8, 'media_buttons' => false, 'teeny' => true, 'quicktags' => true
) );
}
function motayeb_health_benefits_metabox_callback( $post ) {
wp_nonce_field( 'motayeb_save_health_benefits', 'motayeb_health_benefits_nonce' );
$benefits = get_post_meta( $post->ID, '_health_benefits', true );
if ( ! is_array( $benefits ) ) { $benefits = array(); }
$benefits_title = get_post_meta( $post->ID, '_health_benefits_title', true );
$icon_list = array( 'heart-pulse' => '❤️ تپش قلب', 'flame' => '🔥 شعله', 'stomach' => '🫀 معده', 'sparkles' => '✨ جرقه', 'shield-check' => '🛡️ سپر', 'droplets' => '💧 قطره', 'leaf' => '🍃 برگ', 'sun' => '☀️ خورشید', 'zap' => '⚡ برق', 'moon' => '🌙 ماه', 'star' => '⭐ ستاره', 'smile' => '😊 لبخند' );
$color_list = array( 'text-red-400' => 'قرمز', 'text-orange-400' => 'نارنجی', 'text-green-400' => 'سبز', 'text-purple-400' => 'بنفش', 'text-blue-400' => 'آبی', 'text-amber-400' => 'عنبری', 'text-emerald-400' => 'زمردی', 'text-rose-400' => 'گل‌بهی', 'text-pink-400' => 'صورتی', 'text-indigo-400' => 'نیلی' );
?>
<div id="motayeb-benefits-wrapper">
<p><label for="benefits_title_field"><strong>عنوان این بخش (در تب محصول):</strong></label>
<input type="text" id="benefits_title_field" name="benefits_title_field" value="<?php echo esc_attr( $benefits_title ); ?>" style="width:100%;max-width:400px;" placeholder="مثلاً: خواص سلامت، مزایا، ویژگی‌ها..."></p>
<hr>
<p>هر آیتم شامل عنوان، توضیحات، آیکون و رنگ است. برای افزودن آیتم جدید، دکمه زیر را بزنید.</p>
<div id="motayeb-benefits-container">
<?php if ( empty( $benefits ) ) : ?>
<div class="motayeb-benefit-item">
<p><label>عنوان: <input type="text" name="benefit_title[]" value="" /></label></p>
<p><label>توضیحات: <textarea name="benefit_desc[]" rows="2"></textarea></label></p>
<p><label>آیکون: <select name="benefit_icon[]"><?php foreach ( $icon_list as $value => $label ) { echo '<option value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>'; } ?></select></label></p>
<p><label>رنگ: <select name="benefit_color[]"><?php foreach ( $color_list as $value => $label ) { echo '<option value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>'; } ?></select></label></p>
<button type="button" class="button remove-benefit">حذف این آیتم</button>
</div>
<?php else : ?>
<?php foreach ( $benefits as $item ) : ?>
<div class="motayeb-benefit-item">
<p><label>عنوان: <input type="text" name="benefit_title[]" value="<?php echo esc_attr( $item['title'] ); ?>" /></label></p>
<p><label>توضیحات: <textarea name="benefit_desc[]" rows="2"><?php echo esc_textarea( $item['description'] ); ?></textarea></label></p>
<p><label>آیکون: <select name="benefit_icon[]"><?php foreach ( $icon_list as $value => $label ) { echo '<option value="' . esc_attr( $value ) . '" ' . selected( $item['icon'], $value, false ) . '>' . esc_html( $label ) . '</option>'; } ?></select></label></p>
<p><label>رنگ: <select name="benefit_color[]"><?php foreach ( $color_list as $value => $label ) { echo '<option value="' . esc_attr( $value ) . '" ' . selected( $item['color'], $value, false ) . '>' . esc_html( $label ) . '</option>'; } ?></select></label></p>
<button type="button" class="button remove-benefit">حذف این آیتم</button>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<button type="button" id="add-benefit" class="button button-primary">افزودن آیتم جدید</button>
</div>
<style>
.motayeb-benefit-item { background: #f9f9f9; padding: 15px; margin-bottom: 10px; border: 1px solid #ddd; border-radius: 4px; }
.motayeb-benefit-item input[type="text"], .motayeb-benefit-item textarea { width: 100%; }
.motayeb-benefit-item select { max-width: 300px; }
</style>
<script>
jQuery(document).ready(function($) {
$('#add-benefit').on('click', function() {
var html = '<div class="motayeb-benefit-item">' +
'<p><label>عنوان: <input type="text" name="benefit_title[]" value="" /></label></p>' +
'<p><label>توضیحات: <textarea name="benefit_desc[]" rows="2"></textarea></label></p>' +
'<p><label>آیکون: <select name="benefit_icon[]"><?php foreach ( $icon_list as $value => $label ) { echo '<option value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>'; } ?></select></label></p>' +
'<p><label>رنگ: <select name="benefit_color[]"><?php foreach ( $color_list as $value => $label ) { echo '<option value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>'; } ?></select></label></p>' +
'<button type="button" class="button remove-benefit">حذف این آیتم</button>' +
'</div>';
$('#motayeb-benefits-container').append(html);
});
$(document).on('click', '.remove-benefit', function() {
if (confirm('آیا از حذف این آیتم اطمینان دارید؟')) { $(this).closest('.motayeb-benefit-item').remove(); }
});
});
</script>
<?php
}
/**
* ذخیره متاباکس‌ها — با بررسی revision، nonce مجزا برای هر اکشن، و unslash.
*/
function motayeb_save_product_metaboxes( $post_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; }
if ( wp_is_post_revision( $post_id ) ) { return; }
if ( ! current_user_can( 'edit_post', $post_id ) ) { return; }
// ذخیره ترکیبات
if (
isset( $_POST['motayeb_ingredients_nonce'] )
&& wp_verify_nonce( $_POST['motayeb_ingredients_nonce'], 'motayeb_save_ingredients' )
&& isset( $_POST['ingredients_field'] )
) {
update_post_meta( $post_id, '_ingredients', wp_kses_post( wp_unslash( $_POST['ingredients_field'] ) ) );
}
// ذخیره خواص سلامت
if (
isset( $_POST['motayeb_health_benefits_nonce'] )
&& wp_verify_nonce( $_POST['motayeb_health_benefits_nonce'], 'motayeb_save_health_benefits' )
) {
if ( isset( $_POST['benefits_title_field'] ) ) {
update_post_meta( $post_id, '_health_benefits_title', sanitize_text_field( wp_unslash( $_POST['benefits_title_field'] ) ) );
}
$titles = isset( $_POST['benefit_title'] ) ? array_map( 'sanitize_text_field', wp_unslash( (array) $_POST['benefit_title'] ) ) : array();
$descs = isset( $_POST['benefit_desc'] ) ? array_map( 'sanitize_textarea_field', wp_unslash( (array) $_POST['benefit_desc'] ) ) : array();
$icons = isset( $_POST['benefit_icon'] ) ? array_map( 'sanitize_key', wp_unslash( (array) $_POST['benefit_icon'] ) ) : array();
$colors = isset( $_POST['benefit_color'] ) ? array_map( 'sanitize_key', wp_unslash( (array) $_POST['benefit_color'] ) ) : array();
$benefits = array();
foreach ( $titles as $index => $title ) {
if ( ! empty( $title ) && isset( $descs[ $index ] ) ) {
$benefits[] = array(
'title' => $title,
'description' => $descs[ $index ],
'icon' => isset( $icons[ $index ] ) ? $icons[ $index ] : 'heart-pulse',
'color' => isset( $colors[ $index ] ) ? $colors[ $index ] : 'text-red-400',
);
}
}
update_post_meta( $post_id, '_health_benefits', $benefits );
}
}
add_action( 'save_post_product', 'motayeb_save_product_metaboxes' );
// ============================================================
// ۸. ذخیره امتیاز دیدگاه‌ها — با اعتبارسنجی محدوده ۱ تا ۵
// ============================================================
function motayeb_save_rating_field( $comment_id ) {
if ( isset( $_POST['rating'] ) ) {
$rating = intval( $_POST['rating'] );
if ( $rating >= 1 && $rating <= 5 ) {
update_comment_meta( $comment_id, 'rating', $rating );
}
}
}
add_action( 'comment_post', 'motayeb_save_rating_field' );
// ============================================================
// ۹. تنظیمات تم مطیب (با استفاده از Settings API)
// ============================================================
function motayeb_add_admin_menu() {
add_options_page(
'تنظیمات تم مطیب',
'تنظیمات مطیب',
'manage_options',
'motayeb_settings',
'motayeb_settings_page_callback'
);
}
add_action( 'admin_menu', 'motayeb_add_admin_menu' );
function motayeb_admin_scripts( $hook ) {
if ( 'settings_page_motayeb_settings' !== $hook ) {
return;
}
wp_enqueue_media();
wp_enqueue_script( 'jquery' );
}
add_action( 'admin_enqueue_scripts', 'motayeb_admin_scripts' );
function motayeb_register_settings() {
add_settings_section(
'motayeb_shop_section',
'تنظیمات صفحه فروشگاه',
'motayeb_shop_section_callback',
'motayeb_settings'
);
add_settings_field(
'motayeb_shop_banner',
'عکس بنر فروشگاه',
'motayeb_shop_banner_callback',
'motayeb_settings',
'motayeb_shop_section'
);
register_setting( 'motayeb_settings', 'motayeb_shop_banner', 'esc_url_raw' );
for ( $i = 1; $i <= 4; $i++ ) {
add_settings_field(
'motayeb_feature_' . $i . '_icon',
'آیکون ویژگی ' . $i . ' (مثلاً: lucide:leaf)',
'motayeb_text_field_callback',
'motayeb_settings',
'motayeb_shop_section',
array( 'id' => 'motayeb_feature_' . $i . '_icon', 'default' => 'lucide:leaf' )
);
register_setting( 'motayeb_settings', 'motayeb_feature_' . $i . '_icon', 'sanitize_text_field' );
add_settings_field(
'motayeb_feature_' . $i . '_text',
'متن ویژگی ' . $i,
'motayeb_text_field_callback',
'motayeb_settings',
'motayeb_shop_section',
array( 'id' => 'motayeb_feature_' . $i . '_text', 'default' => 'ویژگی ' . $i )
);
register_setting( 'motayeb_settings', 'motayeb_feature_' . $i . '_text', 'sanitize_text_field' );
}
}
add_action( 'admin_init', 'motayeb_register_settings' );
function motayeb_shop_section_callback() {
echo '<p>تنظیمات بنر و ویژگی‌های نمایش داده شده در صفحه فروشگاه را در اینجا مدیریت کنید.</p>';
}
function motayeb_shop_banner_callback() {
$value = get_option( 'motayeb_shop_banner', '' );
?>
<div class="motayeb-media-uploader">
<input type="text" id="motayeb_shop_banner" name="motayeb_shop_banner" value="<?php echo esc_attr( $value ); ?>" style="width: 70%;" class="regular-text" placeholder="آدرس تصویر را وارد کنید یا انتخاب کنید">
<button type="button" class="button motayeb-upload-btn" data-target="motayeb_shop_banner">انتخاب تصویر</button>
<br><br>
<img src="<?php echo esc_attr( $value ); ?>" style="max-width: 300px; height: auto; display: <?php echo empty( $value ) ? 'none' : 'block'; ?>;" id="preview-motayeb_shop_banner" alt="" />
</div>
<script>
jQuery(document).ready(function($){
$('.motayeb-upload-btn').click(function(e) {
e.preventDefault();
var button = $(this);
var targetId = button.data('target');
var customUploader = wp.media({
title: 'انتخاب تصویر بنر',
button: { text: 'استفاده از این تصویر' },
multiple: false
}).on('select', function() {
var attachment = customUploader.state().get('selection').first().toJSON();
$('#' + targetId).val(attachment.url);
$('#preview-' + targetId).attr('src', attachment.url).show();
}).open();
});
});
</script>
<?php
}
function motayeb_text_field_callback( $args ) {
$id = $args['id'];
$default = $args['default'];
$value = get_option( $id, $default );
echo '<input type="text" id="' . esc_attr( $id ) . '" name="' . esc_attr( $id ) . '" value="' . esc_attr( $value ) . '" style="width: 100%; max-width: 400px;" />';
}
function motayeb_settings_page_callback() {
?>
<div class="wrap">
<h1>تنظیمات تم مطیب</h1>
<form method="post" action="options.php">
<?php
settings_fields( 'motayeb_settings' );
do_settings_sections( 'motayeb_settings' );
submit_button();
?>
</form>
</div>
<?php
}
// ============================================================
// ۱۰. غیرفعال کردن استایل‌های پیش‌فرض ووکامرس
// ============================================================
add_filter( 'woocommerce_enqueue_styles', '__return_empty_array' );
// ============================================================
// ۱۱. نمایش ستاره‌های امتیاز (تابع کمکی برای صفحه محصول)
// ============================================================
function motayeb_get_rating_html( $rating, $count = 0 ) {
if ( $rating <= 0 ) {
return '<span class="text-xs text-cream-400 dark:text-dark-muted">بدون امتیاز</span>';
}
$rating = floatval( $rating );
$full_stars = floor( $rating );
$half_star = ( $rating - $full_stars ) >= 0.5 ? 1 : 0;
$empty_stars = 5 - $full_stars - $half_star;
$html = '<span class="flex items-center gap-0.5 text-honey-400 text-sm" aria-label="' . esc_attr( sprintf( __( 'امتیاز %s از ۵', 'motayeb' ), number_format_i18n( $rating, 1 ) ) ) . '">';
for ( $i = 0; $i < $full_stars; $i++ ) {
$html .= '★';
}
if ( $half_star ) {
$html .= '<span class="relative">★<span class="absolute inset-0 overflow-hidden" style="width:50%;color:#D4A574;">★</span></span>';
}
for ( $i = 0; $i < $empty_stars; $i++ ) {
$html .= '<span class="text-cream-300 dark:text-dark-muted">★</span>';
}
if ( $count > 0 ) {
$html .= ' <span class="text-xs text-cream-400 dark:text-dark-muted mr-1">(' . esc_html( number_format_i18n( $count ) ) . ')</span>';
}
$html .= '</span>';
return $html;
}
// ============================================================
// ۱۲. پاک‌سازی transient cache هنگام ذخیره محصول/دسته‌بندی
// ============================================================
function motayeb_clear_home_transients( $post_id ) {
if ( 'product' === get_post_type( $post_id ) ) {
delete_transient( 'motayeb_home_bestsellers' );
// پاک کردن کش شمارش دسته‌بندی‌ها
$terms = wp_get_post_terms( $post_id, 'product_cat', array( 'fields' => 'ids' ) );
if ( ! is_wp_error( $terms ) ) {
foreach ( $terms as $term_id ) {
delete_transient( 'motayeb_cat_count_' . $term_id );
}
}
}
}
add_action( 'save_post_product', 'motayeb_clear_home_transients' );
add_action( 'woocommerce_product_set_stock_status', 'motayeb_clear_home_transients' );
// پاک‌سازی هنگام ویرایش دسته‌بندی
function motayeb_clear_category_transients( $term_id, $taxonomy = '' ) {
if ( 'product_cat' === $taxonomy || empty( $taxonomy ) ) {
delete_transient( 'motayeb_home_categories' );
delete_transient( 'motayeb_cat_count_' . $term_id );
}
}
add_action( 'edited_product_cat', 'motayeb_clear_category_transients', 10, 2 );
add_action( 'created_product_cat', 'motayeb_clear_category_transients', 10, 2 );
add_action( 'delete_product_cat', 'motayeb_clear_category_transients', 10, 2 );
// اضافه کردن فیلد آیکون به صفحه افزودن/ویرایش دسته‌بندی محصول
function motayeb_add_category_icon_field( $term = null ) {
$icon = $term ? get_term_meta( $term->term_id, 'motayeb_icon', true ) : '';
$color = $term ? get_term_meta( $term->term_id, 'motayeb_color', true ) : '';
?>
<div class="form-field">
<label for="motayeb_icon">آیکون (Iconify)</label>
<input type="text" name="motayeb_icon" id="motayeb_icon" value="<?php echo esc_attr( $icon ); ?>" placeholder="lucide:hexagon">
<p>نام آیکون از سایت <a href="https://icon-sets.iconify.design" target="_blank">Iconify</a></p>
</div>
<div class="form-field">
<label for="motayeb_color">کلاس رنگ Tailwind</label>
<input type="text" name="motayeb_color" id="motayeb_color" value="<?php echo esc_attr( $color ); ?>" placeholder="bg-honey-50 dark:bg-honey-900/20 text-honey-400">
</div>
<?php
}
add_action( 'product_cat_add_form_fields', 'motayeb_add_category_icon_field' );
add_action( 'product_cat_edit_form_fields', 'motayeb_add_category_icon_field' );
function motayeb_save_category_icon( $term_id ) {
if ( isset( $_POST['motayeb_icon'] ) ) {
update_term_meta( $term_id, 'motayeb_icon', sanitize_text_field( $_POST['motayeb_icon'] ) );
}
if ( isset( $_POST['motayeb_color'] ) ) {
update_term_meta( $term_id, 'motayeb_color', sanitize_text_field( $_POST['motayeb_color'] ) );
}
}
add_action( 'created_product_cat', 'motayeb_save_category_icon' );
add_action( 'edited_product_cat', 'motayeb_save_category_icon' );
// ============================================================
// ۹.۱ افزودن فیلدهای تنظیمات تماس و شبکه‌های اجتماعی
// ============================================================
function motayeb_register_contact_settings() {
// بخش تنظیمات تماس
add_settings_section(
'motayeb_contact_section',
'اطلاعات تماس',
'motayeb_contact_section_callback',
'motayeb_settings'
);
// فیلدهای تماس
$contact_fields = array(
'motayeb_contact_phone' => 'شماره تماس',
'motayeb_contact_email' => 'ایمیل',
'motayeb_contact_address' => 'آدرس',
);
foreach ( $contact_fields as $id => $label ) {
add_settings_field(
$id,
$label,
'motayeb_text_field_callback',
'motayeb_settings',
'motayeb_contact_section',
array( 'id' => $id, 'default' => '' )
);
register_setting( 'motayeb_settings', $id, 'sanitize_text_field' );
}
// بخش شبکه‌های اجتماعی
add_settings_section(
'motayeb_social_section',
'شبکه‌های اجتماعی',
'motayeb_social_section_callback',
'motayeb_settings'
);
$social_fields = array(
'motayeb_social_instagram' => 'لینک اینستاگرام',
'motayeb_social_telegram' => 'لینک تلگرام',
'motayeb_social_twitter' => 'لینک توییتر',
);
foreach ( $social_fields as $id => $label ) {
add_settings_field(
$id,
$label,
'motayeb_text_field_callback',
'motayeb_settings',
'motayeb_social_section',
array( 'id' => $id, 'default' => '' )
);
register_setting( 'motayeb_settings', $id, 'esc_url_raw' );
}
// بخش نمادهای اعتماد
add_settings_section(
'motayeb_badges_section',
'نمادهای اعتماد',
'motayeb_badges_section_callback',
'motayeb_settings'
);
$badge_fields = array(
'motayeb_enamad_url' => 'لینک نماد اعتماد الکترونیکی',
'motayeb_samandehi_url'=> 'لینک ساماندهی',
);
foreach ( $badge_fields as $id => $label ) {
add_settings_field(
$id,
$label,
'motayeb_text_field_callback',
'motayeb_settings',
'motayeb_badges_section',
array( 'id' => $id, 'default' => '' )
);
register_setting( 'motayeb_settings', $id, 'esc_url_raw' );
}
// بخش انتخاب صفحات خدمات مشتریان
add_settings_section(
'motayeb_pages_section',
'صفحات خدمات مشتریان',
'motayeb_pages_section_callback',
'motayeb_settings'
);
$page_fields = array(
'motayeb_page_faq' => 'صفحه سوالات متداول',
'motayeb_page_return' => 'صفحه شرایط بازگشت',
'motayeb_page_shipping' => 'صفحه نحوه ارسال',
'motayeb_page_privacy' => 'صفحه حریم خصوصی',
'motayeb_page_terms' => 'صفحه قوانین و مقررات',
'motayeb_page_about' => 'صفحه درباره ما',
'motayeb_page_contact' => 'صفحه تماس با ما',
);
foreach ( $page_fields as $id => $label ) {
add_settings_field(
$id,
$label,
'motayeb_page_select_callback',
'motayeb_settings',
'motayeb_pages_section',
array( 'id' => $id )
);
register_setting( 'motayeb_settings', $id, 'intval' );
}
}
add_action( 'admin_init', 'motayeb_register_contact_settings' );
function motayeb_contact_section_callback() {
echo '<p>اطلاعاتی که در فوتر سایت نمایش داده می‌شود را وارد کنید.</p>';
}
function motayeb_social_section_callback() {
echo '<p>لینک شبکه‌های اجتماعی فروشگاه خود را وارد کنید. برای مخفی کردن یک شبکه، فیلد آن را خالی بگذارید.</p>';
}
function motayeb_badges_section_callback() {
echo '<p>لینک صفحه نماد اعتماد و ساماندهی خود را وارد کنید. اگه خالی باشند، نمایش داده نمی‌شوند.</p>';
}
function motayeb_pages_section_callback() {
echo '<p>صفحات وردپرس که برای خدمات مشتریان استفاده می‌شوند را انتخاب کنید.</p>';
}
// Callback برای انتخاب صفحه
function motayeb_page_select_callback( $args ) {
$id = $args['id'];
$current = get_option( $id, 0 );
wp_dropdown_pages( array(
'name' => $id,
'id' => $id,
'selected' => $current,
'show_option_none' => '— انتخاب کنید —',
'option_none_value'=> 0,
) );
}
// ============================================================
// ۱۳. شمارش محصولات در دسته شامل زیردسته‌ها (با cache)
// ============================================================
function motayeb_count_category_products( $term_id ) {
$transient_key = 'motayeb_cat_count_' . $term_id;
$count = get_transient( $transient_key );
if ( false === $count ) {
$terms = get_terms( array(
'taxonomy' => 'product_cat',
'child_of' => $term_id,
'hide_empty' => false,
'fields' => 'ids',
) );
$all_ids = array_merge( array( $term_id ), ( is_array( $terms ) ? $terms : array() ) );
$query = new WP_Query( array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => -1,
'fields' => 'ids',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'terms' => $all_ids,
),
),
) );
$count = $query->found_posts;
wp_reset_postdata();
set_transient( $transient_key, $count, DAY_IN_SECONDS );
}
return $count;
}
// عدد فارسی برای شمارش
function motayeb_fa_count( $n ) {
return number_format_i18n( intval( $n ) );
}