@@ -433,4 +561,43 @@ get_header();
'https://schema.org',
+ '@type' => 'Organization',
+ 'name' => get_bloginfo( 'name' ),
+ 'url' => home_url( '/' ),
+ 'logo' => get_custom_logo() ? wp_get_attachment_url( get_theme_mod( 'custom_logo' ) ) : '',
+ 'description' => get_bloginfo( 'description' ),
+ 'address' => array(
+ '@type' => 'PostalAddress',
+ 'addressCountry' => 'IR',
+ ),
+ 'contactPoint' => array(
+ '@type' => 'ContactPoint',
+ 'telephone' => '+98-21-12345678',
+ 'contactType' => 'customer service',
+ ),
+);
+
+echo '';
+
+// Schema برای وبسایت با قابلیت جستجو
+ $website_schema = array(
+ '@context' => 'https://schema.org',
+ '@type' => 'WebSite',
+ 'name' => get_bloginfo( 'name' ),
+ 'url' => home_url( '/' ),
+ 'potentialAction' => array(
+ '@type' => 'SearchAction',
+ 'target' => home_url( '/?s={search_term_string}' ),
+ 'query-input' => 'required name=search_term_string',
+ ),
+);
+
+echo '';
+
get_footer();
\ No newline at end of file
diff --git a/functions.php b/functions.php
index 99ff0c3..506f300 100644
--- a/functions.php
+++ b/functions.php
@@ -3,7 +3,18 @@
* توابع اختصاصی تم مطیب
*
* @package Motayeb
- * @version 1.0.0
+ * @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
*/
// جلوگیری از دسترسی مستقیم
@@ -11,6 +22,12 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
+// ============================================================
+// ثابتهای کمکی
+// ============================================================
+define( 'MOTAYEB_VERSION', '1.0.1' );
+define( 'MOTAYEB_NONCE_ACTION', 'motayeb_nonce' );
+
// ============================================================
// ۱. تنظیمات اولیه تم (Theme Setup)
// ============================================================
@@ -43,31 +60,113 @@ function motayeb_theme_setup() {
add_action( 'after_setup_theme', 'motayeb_theme_setup' );
// ============================================================
-// ۲. بارگذاری فایلهای استایل و اسکریپت (Enqueue)
+// ۲. بارگذاری فایلهای استایل و اسکریپت (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() {
- wp_enqueue_style( 'motayeb-style', get_stylesheet_uri(), array(), wp_get_theme()->get( 'Version' ) );
+ $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' ) ) {
- wp_enqueue_style( 'motayeb-woocommerce', get_theme_file_uri( '/assets/css/woocommerce.css' ), array( 'motayeb-style' ), wp_get_theme()->get( 'Version' ) );
+ motayeb_enqueue_style_safe( 'motayeb-woocommerce', '/assets/css/woocommerce.css', array( 'motayeb-style' ) );
}
- wp_enqueue_style( 'motayeb-responsive', get_theme_file_uri( '/assets/css/responsive.css' ), array( 'motayeb-style' ), wp_get_theme()->get( 'Version' ) );
- wp_enqueue_script( 'motayeb-main', get_theme_file_uri( '/assets/js/main.js' ), array( 'jquery' ), wp_get_theme()->get( 'Version' ), true );
+
+ // ۴. استایل ریسپانسیو
+ 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' ) ) {
- wp_enqueue_script( 'motayeb-woocommerce', get_theme_file_uri( '/assets/js/woocommerce.js' ), array( 'jquery', 'motayeb-main' ), wp_get_theme()->get( 'Version' ), true );
+ 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' ); }
}
- wp_enqueue_script( 'motayeb-darkmode', get_theme_file_uri( '/assets/js/darkmode.js' ), array( 'jquery' ), wp_get_theme()->get( 'Version' ), true );
- wp_localize_script( 'motayeb-main', 'motayeb_ajax', array(
- 'ajax_url' => admin_url( 'admin-ajax.php' ),
- 'nonce' => wp_create_nonce( 'motayeb_nonce' ),
- 'checkout_url' => wc_get_checkout_url(),
- 'cart_url' => wc_get_cart_url(),
- ) );
- 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)
// ============================================================
@@ -108,12 +207,14 @@ 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'; }
}
- if ( isset( $_COOKIE['motayeb_darkmode'] ) && 'on' === $_COOKIE['motayeb_darkmode'] ) {
+ // کوکی با sanitize_key بررسی میشه تا فقط 'on' یا '' قبول بشه
+ if ( isset( $_COOKIE['motayeb_darkmode'] ) && 'on' === sanitize_key( wp_unslash( $_COOKIE['motayeb_darkmode'] ) ) ) {
$classes[] = 'dark-mode';
}
return $classes;
@@ -150,46 +251,73 @@ class Motayeb_Mobile_Walker extends Walker_Nav_Menu {
}
// ============================================================
-// ۶. توابع Ajax برای جستجو و دریافت محصولات
+// ۶. توابع Ajax برای جستجو و دریافت محصولات — اصلاحشده
// ============================================================
+
+/**
+ * دریافت اطلاعات یک محصول با ID.
+ * فقط روی محصولات منتشرشده کار میکنه.
+ */
function motayeb_ajax_get_product_data() {
- check_ajax_referer( 'motayeb_nonce', 'nonce' );
+ 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( 'شناسه محصول نامعتبر است' ); }
+ if ( ! $product_id ) {
+ wp_send_json_error( 'شناسه محصول نامعتبر است' );
+ }
$product = wc_get_product( $product_id );
- if ( ! $product ) { wp_send_json_error( 'محصول یافت نشد' ); }
+ 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] : 'default-product',
- 'stock' => $product->get_stock_quantity(),
+ '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', 'nonce' );
- $term = isset( $_GET['term'] ) ? sanitize_text_field( $_GET['term'] ) : '';
- if ( strlen( $term ) < 2 ) { wp_send_json_success( array() ); }
- $args = array( 'post_type' => 'product', 'posts_per_page' => 6, 's' => $term );
- $query = new WP_Query( $args );
+ 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();
- while ( $query->have_posts() ) {
- $query->the_post();
- $product = wc_get_product( get_the_ID() );
- $image = wp_get_attachment_image_src( get_post_thumbnail_id(), 'thumbnail' );
+ 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' => get_the_ID(),
- 'name' => get_the_title(),
- 'price' => $product->get_price() ? floatval( $product->get_price() ) : 0,
- 'image' => $image ? $image[0] : '',
- 'category' => 'محصول',
+ '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_reset_postdata();
wp_send_json_success( $results );
}
add_action( 'wp_ajax_search_products', 'motayeb_ajax_search_products' );
@@ -205,7 +333,7 @@ function motayeb_add_product_metaboxes() {
add_action( 'add_meta_boxes', 'motayeb_add_product_metaboxes' );
function motayeb_ingredients_metabox_callback( $post ) {
- wp_nonce_field( 'motayeb_ingredients_nonce', 'motayeb_ingredients_nonce' );
+ wp_nonce_field( 'motayeb_save_ingredients', 'motayeb_ingredients_nonce' );
$value = get_post_meta( $post->ID, '_ingredients', true );
echo '
';
wp_editor( $value, 'ingredients_field', array(
@@ -214,7 +342,7 @@ function motayeb_ingredients_metabox_callback( $post ) {
}
function motayeb_health_benefits_metabox_callback( $post ) {
- wp_nonce_field( 'motayeb_health_benefits_nonce', 'motayeb_health_benefits_nonce' );
+ 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 );
@@ -228,20 +356,20 @@ function motayeb_health_benefits_metabox_callback( $post ) {
هر آیتم شامل عنوان، توضیحات، آیکون و رنگ است. برای افزودن آیتم جدید، دکمه زیر را بزنید.
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
@@ -249,17 +377,21 @@ function motayeb_health_benefits_metabox_callback( $post ) {
-
+
-
-
-
-
-
-
-
-
+ })();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
>
@@ -248,10 +135,10 @@
-
-
@@ -277,7 +164,7 @@
سبد خرید (0)
-
+
@@ -315,7 +202,7 @@
مطیب
-
+
@@ -334,7 +221,7 @@