راهنمای جامع شخصی‌سازی و توسعه وبسایت وردپرس

مقدمه

وردپرس به عنوان یک سیستم مدیریت محتوای انعطاف‌پذیر، امکان توسعه و شخصی‌سازی در سطوح مختلف را فراهم می‌کند. در این راهنمای پیشرفته، تکنیک‌های حرفه‌ای برای سفارشی‌سازی و توسعه وبسایت وردپرس را بررسی می‌کنیم.

بخش 1: شخصی‌سازی پیشرفته ظاهر

1.1 ایجاد تم سفارشی با Underscores

// ایجاد تم از پایه با استفاده از _s (Underscores)
function my_theme_setup() {
    // پشتیبانی از عنوان داینامیک
    add_theme_support('title-tag');

    // پشتیبانی از تصاویر شاخص
    add_theme_support('post-thumbnails');

    // ثبت منوها
    register_nav_menus(array(
        'primary' => __('منوی اصلی', 'my-theme'),
        'footer'  => __('منوی فوتر', 'my-theme')
    ));
}
add_action('after_setup_theme', 'my_theme_setup');

تشریح کد ایجاد تم سفارشی:

این کد یک تابع پایه‌ای برای راه‌اندازی اولیه یک تم وردپرس ایجاد می‌کند که معمولاً در فایل functions.php تم قرار می‌گیرد. بیایید بخش‌های مختلف این کد را به طور دقیق بررسی کنیم:

1. تعریف تابع my_theme_setup()

function my_theme_setup() {
    ...
}

این تابع شامل تمام تنظیمات اولیه و ویژگی‌هایی است که تم شما از آنها پشتیبانی می‌کند.

2. افزودن پشتیبانی از عنوان داینامیک

add_theme_support('title-tag');
  • این خط کد به وردپرس می‌گوید که تم شما از تگ <title> داینامیک پشتیبانی می‌کند.
  • قبل از وردپرس 4.1، توسعه‌دهندگان مجبور بودند تگ title را به صورت دستی در فایل header.php قرار دهند.
  • با این تابع، وردپرس به طور خودکار عنوان مناسب را برای هر صفحه تولید می‌کند.

3. افزودن پشتیبانی از تصاویر شاخص (Featured Image)

add_theme_support('post-thumbnails');
  • این امکان را فراهم می‌کند که برای هر پست یا صفحه یک تصویر شاخص تعیین کنید.
  • پس از فعال شدن این ویژگی، در ویرایشگر پست/صفحه بخشی برای انتخاب تصویر شاخص ظاهر می‌شود.
  • می‌توانید این تصاویر را در قالب خود با تابع the_post_thumbnail() نمایش دهید.

4. ثبت منوهای ناوبری

register_nav_menus(array(
    'primary' => __('منوی اصلی', 'my-theme'),
    'footer'  => __('منوی فوتر', 'my-theme')
));
  • این کد دو موقعیت منو را برای تم شما ثبت می‌کند:
  • منوی اصلی (primary)
  • منوی فوتر (footer)
  • __() یک تابع ترجمه در وردپرس است که امکان چندزبانه کردن تم را فراهم می‌کند.
  • پس از این تنظیم، در پیشخوان وردپرس (بخش نمایش > منوها) می‌توانید منوها را به این موقعیت‌ها اختصاص دهید.
  • در قالب می‌توانید این منوها را با تابع wp_nav_menu() نمایش دهید.

5. ثبت هوک (Hook)

add_action('after_setup_theme', 'my_theme_setup');
  • این خط تابع my_theme_setup را به هوک after_setup_theme متصل می‌کند.
  • after_setup_theme یکی از اولین هوک‌هایی است که وردپرس بعد از بارگذاری تم اجرا می‌کند.
  • با این کار مطمئن می‌شویم که ویژگی‌های تم قبل از هر چیز دیگری بارگذاری شده‌اند.

نکات تکمیلی:

  1. استفاده از Underscores: این کد معمولاً در تم‌های مبتنی بر _s (Underscores) که یک تم پایه برای توسعه است استفاده می‌شود.
  2. امنیت: در یک تم حرفه‌ای، بهتر است قبل از تعریف تابع بررسی کنید که آیا از قبل تعریف نشده است:
   if (!function_exists('my_theme_setup')) {
       function my_theme_setup() {
           ...
       }
   }
  1. اضافه کردن ویژگی‌های بیشتر: می‌توانید ویژگی‌های دیگری نیز به این تابع اضافه کنید مانند:
   // پشتیبانی از HTML5
   add_theme_support('html5', array('comment-list', 'comment-form', 'search-form', 'gallery', 'caption'));

   // پشتیبانی از واسط نوشتن ریسپانسیو
   add_theme_support('responsive-embeds');
  1. اندازه‌های تصویر شاخص: بعد از فعال کردن پست تامبنیل‌ها، می‌توانید اندازه‌های سفارشی تعریف کنید:
   add_image_size('custom-size', 800, 400, true);

این کد پایه‌ای برای شروع توسعه یک تم وردپرس است و می‌تواند بسته به نیازهای پروژه گسترش یابد.

1.2 طراحی ریسپانسیو پیشرفته با CSS Grid و Flexbox

/* ساختار صفحه اصلی با CSS Grid */
.homepage {
    display: grid;
    grid-template-columns: 1fr 3fr;
    grid-gap: 2rem;
}

/* کارت‌های محصول با Flexbox */
.product-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    justify-content: space-between;
}

.product-card {
    flex: 1 1 300px;
    max-width: 350px;
}

تشریح کد CSS برای ساختار صفحه و کارت‌های محصول

این کد CSS دو بخش اصلی از طراحی یک صفحه وب را پیاده‌سازی می‌کند: ساختار صفحه اصلی با CSS Grid و کارت‌های محصول با Flexbox. بیایید هر بخش را به تفکیک بررسی کنیم.

بخش اول: ساختار صفحه اصلی با CSS Grid

.homepage {
    display: grid;
    grid-template-columns: 1fr 3fr;
    grid-gap: 2rem;
}

توضیحات:

  1. display: grid;:
  • این ویژگی یک کانتینر گرید ایجاد می‌کند.
  • تمام فرزندان مستقیم این عنصر به صورت خودکار آیتم‌های گرید (grid items) می‌شوند.
  1. grid-template-columns: 1fr 3fr;:
  • ساختار ستون‌های گرید را تعریف می‌کند.
  • fr واحد کسری (fractional unit) است که فضای موجود را تقسیم می‌کند.
  • در اینجا صفحه به دو ستون تقسیم می‌شود:
    • ستون اول: 1 واحد (معمولاً برای سایدبار)
    • ستون دوم: 3 واحد (معمولاً برای محتوای اصلی)
  • نسبت عرض ستون‌ها 1 به 3 خواهد بود.
  1. grid-gap: 2rem;:
  • فاصله بین ردیف‌ها و ستون‌های گرید را تعیین می‌کند.
  • 2rem حدود 32 پیکسل (با فرض font-size پایه 16px) فاصله ایجاد می‌کند.
  • (توجه: grid-gap نام قدیمی است و بهتر است از gap استفاده شود)

کاربرد:

این ساختار برای صفحاتی مناسب است که نیاز به یک سایدبار (ستون باریک) و یک بخش محتوای اصلی (ستون عریض) دارند، مثل صفحه اصلی یک وبلاگ یا فروشگاه.

بخش دوم: کارت‌های محصول با Flexbox

.product-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    justify-content: space-between;
}

.product-card {
    flex: 1 1 300px;
    max-width: 350px;
}

توضیحات برای .product-cards:

  1. display: flex;:
  • یک کانتینر فلکس ایجاد می‌کند.
  • فرزندان مستقیم به صورت افقی (به طور پیش‌فرض) چیده می‌شوند.
  1. flex-wrap: wrap;:
  • اگر آیتم‌ها در یک سطر جا نشوند، به سطر بعد منتقل می‌شوند.
  • بدون این ویژگی، آیتم‌ها برای ماندن در یک سطر فشرده می‌شوند.
  1. gap: 1.5rem;:
  • فاصله بین آیتم‌های فلکس را تنظیم می‌کند (حدود 24 پیکسل).
  1. justify-content: space-between;:
  • آیتم‌ها را به طور یکنواخت در طول محور اصلی توزیع می‌کند.
  • اولین آیتم در ابتدا و آخرین آیتم در انتها قرار می‌گیرد.
  • فاصله بین آیتم‌ها برابر است.

توضیحات برای .product-card:

  1. flex: 1 1 300px;:
  • این shorthand برای سه ویژگی است:
    • flex-grow: 1: می‌تواند در صورت نیاز رشد کند.
    • flex-shrink: 1: می‌تواند در صورت نیاز کوچک شود.
    • flex-basis: 300px: اندازه پایه 300 پیکسل دارد.
  • یعنی هر کارت حداقل 300px عرض دارد، اما می‌تواند بزرگتر شود تا فضای خالی را پر کند.
  1. max-width: 350px;:
  • حداکثر عرض هر کارت را به 350 پیکسل محدود می‌کند.
  • حتی اگر فضای بیشتری موجود باشد، از این مقدار بیشتر نمی‌شود.

رفتار کلی:

  • در صفحه‌های عریض، چندین کارت در یک سطر نمایش داده می‌شوند.
  • هر کارت حداقل 300px و حداکثر 350px عرض دارد.
  • اگر فضای کافی برای 300px نباشد، کارت‌ها به سطر بعد منتقل می‌شوند.
  • فاصله بین کارت‌ها 1.5rem است و به طور یکنواخت توزیع می‌شوند.

نکات تکمیلی:

  1. تفاوت Grid و Flexbox:
  • Grid برای طرح‌بندی دو بعدی (ردیف و ستون) مناسب است.
  • Flexbox برای طرح‌بندی یک بعدی (در یک راستا) بهتر عمل می‌کند.
  1. ریسپانسیو بودن:
  • این کد به صورت ذاتی ریسپانسیو است.
  • برای کنترل بیشتر می‌توان از media query استفاده کرد:
    css @media (max-width: 768px) { .homepage { grid-template-columns: 1fr; } }
  1. پشتیبانی مرورگرها:
  • gap برای Flexbox در مرورگرهای جدیدتر پشتیبانی می‌شود.
  • برای پشتیبانی از مرورگرهای قدیمی‌تر می‌توان از margin استفاده کرد.
  1. بهینه‌سازی:
  • برای کارت‌های محصول، می‌توان aspect-ratio را برای حفظ تناسب تصاویر اضافه کرد.
  • افزودن transition برای افکت‌های hover می‌تواند تجربه کاربری را بهبود بخشد.

بخش 2: توسعه پلاگین‌های سفارشی

2.1 ایجاد سیستم عضویت پیشرفته

class Membership_System {
    public function __construct() {
        // ثبت نقش کاربری جدید
        add_action('init', array($this, 'register_member_role'));

        // افزودن فیلدهای سفارشی به پروفایل کاربر
        add_action('show_user_profile', array($this, 'add_custom_profile_fields'));
        add_action('edit_user_profile', array($this, 'add_custom_profile_fields'));

        // ذخیره فیلدهای سفارشی
        add_action('personal_options_update', array($this, 'save_custom_profile_fields'));
        add_action('edit_user_profile_update', array($this, 'save_custom_profile_fields'));
    }

    public function register_member_role() {
        add_role('premium_member', 'عضو ویژه', array(
            'read' => true,
            'edit_posts' => true,
            'upload_files' => true
        ));
    }

    public function add_custom_profile_fields($user) {
        ?>
        <h3>اطلاعات عضویت</h3>
        <table class="form-table">
            <tr>
                <th><label for="membership_number">شماره عضویت</label></th>
                <td>
                    <input type="text" name="membership_number" id="membership_number" 
                           value="<?php echo esc_attr(get_user_meta($user->ID, 'membership_number', true)); ?>" 
                           class="regular-text">
                </td>
            </tr>
        </table>
        <?php
    }

    public function save_custom_profile_fields($user_id) {
        if (!current_user_can('edit_user', $user_id)) {
            return false;
        }

        update_user_meta($user_id, 'membership_number', sanitize_text_field($_POST['membership_number']));
    }
}

new Membership_System();

2.2 ایجاد ویجت‌های سفارشی

class Custom_Recent_Posts_Widget extends WP_Widget {
    public function __construct() {
        parent::__construct(
            'custom_recent_posts',
            'مطالب اخیر پیشرفته',
            array('description' => 'نمایش مطالب اخیر با امکانات اضافه')
        );
    }

    public function widget($args, $instance) {
        $title = apply_filters('widget_title', $instance['title']);
        $number = (!empty($instance['number'])) ? absint($instance['number']) : 5;

        echo $args['before_widget'];

        if (!empty($title)) {
            echo $args['before_title'] . $title . $args['after_title'];
        }

        $query = new WP_Query(array(
            'posts_per_page' => $number,
            'post_status' => 'publish',
            'ignore_sticky_posts' => true
        ));

        if ($query->have_posts()) {
            echo '<ul class="custom-recent-posts">';
            while ($query->have_posts()) {
                $query->the_post();
                echo '<li>';
                echo '<a href="' . get_permalink() . '">' . get_the_title() . '</a>';
                echo '<span class="post-date">' . get_the_date() . '</span>';
                echo '</li>';
            }
            echo '</ul>';
            wp_reset_postdata();
        }

        echo $args['after_widget'];
    }

    public function form($instance) {
        $title = isset($instance['title']) ? $instance['title'] : 'مطالب اخیر';
        $number = isset($instance['number']) ? absint($instance['number']) : 5;
        ?>
        <p>
            <label for="<?php echo $this->get_field_id('title'); ?>">عنوان:</label>
            <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" 
                   name="<?php echo $this->get_field_name('title'); ?>" 
                   type="text" value="<?php echo esc_attr($title); ?>">
        </p>
        <p>
            <label for="<?php echo $this->get_field_id('number'); ?>">تعداد مطالب:</label>
            <input id="<?php echo $this->get_field_id('number'); ?>" 
                   name="<?php echo $this->get_field_name('number'); ?>" 
                   type="number" value="<?php echo esc_attr($number); ?>" size="3">
        </p>
        <?php
    }

    public function update($new_instance, $old_instance) {
        $instance = array();
        $instance['title'] = sanitize_text_field($new_instance['title']);
        $instance['number'] = absint($new_instance['number']);
        return $instance;
    }
}

function register_custom_widgets() {
    register_widget('Custom_Recent_Posts_Widget');
}
add_action('widgets_init', 'register_custom_widgets');

بخش 3: بهینه‌سازی پیشرفته

3.1 کش‌گذاری سطح بالا

// پیاده‌سازی کش شیء با Redis
function get_cached_data($key, $callback, $expiration = 3600) {
    if (class_exists('Redis')) {
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);

        if ($data = $redis->get($key)) {
            return unserialize($data);
        }

        $data = $callback();
        $redis->setex($key, $expiration, serialize($data));
        return $data;
    }

    // Fallback to WordPress transients
    $data = get_transient($key);

    if (false === $data) {
        $data = $callback();
        set_transient($key, $data, $expiration);
    }

    return $data;
}

3.2 بهینه‌سازی تصاویر پیشرفته

// تبدیل خودکار تصاویر به WebP
function convert_to_webp($file_path) {
    if (!function_exists('imagewebp')) {
        return false;
    }

    $extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
    $webp_path = preg_replace('/\.(jpg|jpeg|png)$/', '.webp', $file_path);

    switch ($extension) {
        case 'jpg':
        case 'jpeg':
            $image = imagecreatefromjpeg($file_path);
            break;
        case 'png':
            $image = imagecreatefrompng($file_path);
            break;
        default:
            return false;
    }

    if (imagewebp($image, $webp_path, 80)) {
        imagedestroy($image);
        return $webp_path;
    }

    imagedestroy($image);
    return false;
}

// فیلتر برای جایگزینی تصاویر با نسخه WebP
function webp_replace($content) {
    if (strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== false) {
        $content = preg_replace_callback('/<img[^>]+\.(jpg|jpeg|png)[^>]*>/i', function($matches) {
            $webp_url = preg_replace('/\.(jpg|jpeg|png)$/i', '.webp', $matches[0]);
            return str_replace($matches[1], 'webp', $webp_url);
        }, $content);
    }
    return $content;
}
add_filter('the_content', 'webp_replace');

بخش 4: امنیت پیشرفته

4.1 سیستم احراز هویت دو مرحله‌ای

class Two_Factor_Auth {
    public function __construct() {
        add_action('login_form', array($this, 'add_2fa_field'));
        add_filter('authenticate', array($this, 'verify_2fa_code'), 30, 3);
        add_action('wp_login', array($this, 'send_2fa_code'), 10, 2);
    }

    public function send_2fa_code($user_login, $user) {
        $code = rand(100000, 999999);
        update_user_meta($user->ID, '2fa_code', $code);

        // ارسال کد از طریق SMS یا ایمیل
        wp_mail(
            $user->user_email,
            'کد تأیید دو مرحله‌ای',
            'کد تأیید شما: ' . $code
        );
    }

    public function add_2fa_field() {
        echo '<p>
            <label for="2fa_code">کد تأیید دو مرحله‌ای<br>
            <input type="text" name="2fa_code" id="2fa_code" class="input" size="20">
            </label>
        </p>';
    }

    public function verify_2fa_code($user, $username, $password) {
        if (!empty($_POST['2fa_code'])) {
            $stored_code = get_user_meta($user->ID, '2fa_code', true);

            if ($_POST['2fa_code'] != $stored_code) {
                return new WP_Error('invalid_2fa', '<strong>خطا</strong>: کد تأیید نامعتبر است.');
            }

            delete_user_meta($user->ID, '2fa_code');
            return $user;
        }

        return $user;
    }
}

new Two_Factor_Auth();

4.2 محافظت در برابر حملات DDoS

// محدود کردن درخواست‌های API
function limit_api_requests() {
    $ip = $_SERVER['REMOTE_ADDR'];
    $transient_name = 'api_limit_' . $ip;
    $requests = get_transient($transient_name) ?: 0;

    if ($requests > 100) {
        wp_die('تعداد درخواست‌های شما بیش از حد مجاز است. لطفاً 1 ساعت دیگر تلاش کنید.', 429);
    }

    set_transient($transient_name, $requests + 1, HOUR_IN_SECONDS);
}
add_action('rest_api_init', 'limit_api_requests', 1);

بخش 5: یکپارچه‌سازی با سرویس‌های خارجی

5.1 یکپارچه‌سازی با سیستم CRM

class CRM_Integration {
    private $api_key;
    private $api_url = 'https://crm.example.com/api/v1/';

    public function __construct($api_key) {
        $this->api_key = $api_key;

        // همگام‌سازی کاربران جدید
        add_action('user_register', array($this, 'sync_user_to_crm'));

        // همگام‌سازی سفارشات
        add_action('woocommerce_new_order', array($this, 'sync_order_to_crm'));
    }

    public function sync_user_to_crm($user_id) {
        $user = get_userdata($user_id);

        $data = array(
            'email' => $user->user_email,
            'name' => $user->display_name,
            'meta' => array(
                'wordpress_id' => $user_id
            )
        );

        $this->make_api_request('contacts', $data);
    }

    public function sync_order_to_crm($order_id) {
        $order = wc_get_order($order_id);
        $user = $order->get_user();

        $data = array(
            'order_id' => $order_id,
            'customer_id' => $user ? $user->ID : null,
            'amount' => $order->get_total(),
            'items' => array()
        );

        foreach ($order->get_items() as $item) {
            $data['items'][] = array(
                'product_id' => $item->get_product_id(),
                'quantity' => $item->get_quantity(),
                'price' => $item->get_total()
            );
        }

        $this->make_api_request('orders', $data);
    }

    private function make_api_request($endpoint, $data) {
        $args = array(
            'headers' => array(
                'Authorization' => 'Bearer ' . $this->api_key,
                'Content-Type' => 'application/json'
            ),
            'body' => json_encode($data),
            'timeout' => 15
        );

        $response = wp_remote_post($this->api_url . $endpoint, $args);

        if (is_wp_error($response)) {
            error_log('CRM Integration Error: ' . $response->get_error_message());
            return false;
        }

        return json_decode(wp_remote_retrieve_body($response), true);
    }
}

// مقداردهی اولیه با کلید API
new CRM_Integration('YOUR_CRM_API_KEY');

نتیجه‌گیری

شخصی‌سازی و توسعه وردپرس در سطح پیشرفته نیازمند درک عمیق از معماری وردپرس، APIهای آن و اصول برنامه‌نویسی شیءگرا است. با استفاده از تکنیک‌های ارائه شده در این راهنما می‌توانید:

  1. تم‌های کاملاً سفارشی ایجاد کنید
  2. پلاگین‌های قدرتمند با قابلیت‌های منحصر به فرد توسعه دهید
  3. عملکرد سایت را به میزان قابل توجهی بهینه کنید
  4. امنیت سایت را در سطح حرفه‌ای افزایش دهید
  5. با سرویس‌های خارجی یکپارچه شوید

همواره به یاد داشته باشید که قبل از اعمال تغییرات اساسی در سایت زنده، تغییرات را در محیط توسعه تست کنید و از اطلاعات خود نسخه پشتیبان تهیه نمایید.

سبد خرید
پیمایش به بالا