براتی طراح سایت

افزونه مدیریت پروژه در وردپرس

مشخصات مقاله:
بروزرسانی: شهریور ۱۴۰۴
افزونه مدیریت پروژه در وردپرس
فهرست مطالب

خلاصه:

پیشخوان وردپرس را به یک مرکز فرماندهی شخصی کنید تا به شما کمک کند وظایف روزانه، یادداشت‌های مهم و برنامه‌ریزی‌ هارا انجام بدهد.

بهترین افزونه مدیریت پروژه در وردپرس 

دفترچه یادداشت هوشمند وردپرس

در دنیای پرشتاب مدیریت وب‌سایت، پیشخوان وردپرس به خانه‌ی دوم مدیران، نویسندگان و توسعه‌دهندگان تبدیل شده است. اما این خانه، گاهی می‌تواند به فضایی بی‌نظم و آشفته برای مدیریت کارها تبدیل شود. جابجایی مداوم بین نرم‌افزارهای مدیریت وظایف، تقویم‌ها و یادداشت‌ها، تمرکز را از بین برده و بهره‌وری را کاهش می‌دهد. اما راه‌حل چیست؟ یک افزونه مدیریت پروژه در وردپرس که تمام ابزارهای مورد نیاز شما را به صورت یکپارچه در اختیارتان قرار دهد.

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

افزونه Notex نوتکس

اهمیت سازماندهی وظایف در پیشخوان وردپرس

مدیریت زمان و وظایف، کلید موفقیت هر پروژه‌ای است. وقتی تمام ابزارهای شما در یک مکان متمرکز باشند، اتفاقات زیر رخ می‌دهد:

  • افزایش تمرکز: دیگر نیازی به خروج از محیط وردپرس برای چک کردن لیست کارها یا ثبت یک ایده جدید ندارید. همه چیز درست در مقابل چشمان شماست.

  • کاهش اتلاف وقت: زمان ارزشمندی که صرف باز و بسته کردن اپلیکیشن‌های مختلف می‌شد، اکنون برای انجام کارهای مهم‌تر ذخیره می‌شود.

  • دسترسی سریع: ایده‌ها و وظایف به محض خطور به ذهن، در سریع‌ترین زمان ممکن ثبت و سازماندهی می‌شوند.

  • یکپارچگی با محیط کار: مدیریت وظایف در همان محیطی که محتوا تولید یا سایت را مدیریت می‌کنید، یکپارچگی بی‌نظیری در گردش کار شما ایجاد می‌کند.

افزونه مدیریت پروژه در وردپرس

معرفی افزونه دفترچه یادداشت وردپرس

فراتر از یک ابزار ساده

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

دانلود نسخه پرو افزونه نوتکس NoteX

امکانات کلیدی برای بهبود گردش کار شما

این افزونه با درک نیازهای کاربران وردپرس، ویژگی‌های متنوع و کارآمدی را ارائه می‌دهد که در ادامه به بررسی مهم‌ترین آن‌ها می‌پردازیم.

سیستم یادداشت‌برداری و مدیریت وظایف پیشرفته

هسته‌ی اصلی این افزونه، سیستم مدیریت یادداشت و وظایف آن است. شما می‌توانید:

  • ایجاد و ویرایش یادداشت: به راحتی یادداشت‌های خود را با محتوای نامحدود ثبت و در هر زمان ویرایش کنید.

  • تعیین اولویت: هر وظیفه یا یادداشت می‌تواند یکی از سه سطح اولویت (بالا، متوسط، کم) را داشته باشد. این ویژگی به شما کمک می‌کند تا روی مهم‌ترین کارها متمرکز شوید.

  • مشخص کردن وضعیت: وظایف خود را با وضعیت‌های «در حال انجام»، «تمام شده» یا «بدون تغییر» دسته‌بندی کنید تا تصویر واضحی از پیشرفت کارها داشته باشید.

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

افزودن یادداشت به وردپرس

ابزارهای جانبی برای برنامه‌ریزی روزانه

یکی از مزیت‌های بزرگ این افزونه، تجمیع ابزارهای کاربردی روزمره در کنار سیستم مدیریت وظایف است:

  • ساعت و تقویم دقیق: نمایش ساعت دیجیتال به همراه تاریخ کامل شمسی و میلادی، به شما کمک می‌کند تا همیشه زمان را در اختیار داشته باشید.

  • تقویم شمسی-میلادی : یک تقویم ساده و زیبا که روزهای ماه شمسی را به همزاه معادل میلادی و مشخص کردن روز جاری نمایش می‌دهد.

  • وضعیت آب و هوا: با انتخاب شهر خود از لیست کامل مراکز استان‌های ایران، می‌توانید دمای لحظه‌ای شهر مورد نظر را مستقیماً در پیشخوان وردپرس مشاهده کنید.

  • اوقات شرعی: این افزونه با دریافت اطلاعات دقیق، اوقات شرعی روز را برای شهر انتخابی شما به نمایش می‌گذارد.

نسحه رایگان افزونه دفترچه یادداشت

برای دانلود نسخه رایگان افزونه دفترچه یادداشت وردپرس برای تست کافیست کدهای زیر را درون یک فولدر زیپ قرار دهید ودر افزونه ها اپلود کنید. یا در افزونه wp code یک php snippet بسازید 

افزونه براحتی فعال میشود 

<?php
/*
Plugin Name: دفترچه یادداشت وردپرس
Plugin URI: https://Mrbarati.com
Description: ویجت پیشخوان: یادداشت، آب و هوا، اوقات شرعی و تقویم ساده — نسخه نهایی با تنظیمات کاربر.
Version: 1.0.0
Author: مهندس براتی
Author URI: https://Mrbarati.com
License: GPLv2 or later
*/

if (!defined('ABSPATH')) exit;

class Notex_Tools_Wp_Free {

    private $cities_data = [];

    public function __construct() {
        $this->cities_data = [
            'Arak' => 'اراک', 'Ardabil' => 'اردبیل', 'Urmia' => 'ارومیه', 'Isfahan' => 'اصفهان',
            'Ahvaz' => 'اهواز', 'Ilam' => 'ایلام', 'Bojnurd' => 'بجنورد', 'BandarAbbas' => 'بندرعباس',
            'Bushehr' => 'بوشهر', 'Birjand' => 'بیرجند', 'Tabriz' => 'تبریز', 'Tehran' => 'تهران',
            'Khorramabad' => 'خرم‌آباد', 'Rasht' => 'رشت', 'Zahedan' => 'زاهدان', 'Zanjan' => 'زنجان',
            'Sari' => 'ساری', 'Semnan' => 'سمنان', 'Sanandaj' => 'سنندج', 'Shahrekord' => 'شهرکرد',
            'Shiraz' => 'شیراز', 'Qazvin' => 'قزوین', 'Qom' => 'قم', 'Karaj' => 'کرج',
            'Kerman' => 'کرمان', 'Kermanshah' => 'کرمانشاه', 'Gorgan' => 'گرگان', 'Mashhad' => 'مشهد',
            'Hamedan' => 'همدان', 'Yasuj' => 'یاسوج', 'Yazd' => 'یزد'
        ];

        add_action('wp_dashboard_setup', array($this, 'add_dashboard_widget'));
        add_action('wp_ajax_notex_tools_wp_action', array($this, 'handle_ajax_actions'));
        register_activation_hook(__FILE__, array($this, 'activate_plugin'));
        register_uninstall_hook(__FILE__, array('Notex_Tools_Wp_Free', 'uninstall_plugin'));
    }

    public function activate_plugin() {
        global $wpdb;
        $table_name = $wpdb->prefix . 'notex_tools_wp_notes';
        $charset_collate = $wpdb->get_charset_collate();
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta("CREATE TABLE {$table_name} (
            id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
            created_at DATETIME NOT NULL,
            note_content LONGTEXT NOT NULL,
            priority VARCHAR(20) NOT NULL DEFAULT 'medium',
            status VARCHAR(20) NOT NULL DEFAULT 'no_change',
            PRIMARY KEY (id)
        ) {$charset_collate};");
    }

    public static function uninstall_plugin() {
        global $wpdb;
        $table_name = $wpdb->prefix . 'notex_tools_wp_notes';
        $wpdb->query("DROP TABLE IF EXISTS {$table_name}");
    }

    private function gregorian_to_jalali($g_y,$g_m,$g_d) {
        $g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
        $j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
        $gy = $g_y - 1600; $gm = $g_m - 1; $gd = $g_d - 1;
        $g_day_no = 365 * $gy + floor(($gy + 3) / 4) - floor(($gy + 99) / 100) + floor(($gy + 399) / 400);
        for ($i = 0; $i < $gm; ++$i) $g_day_no += $g_days_in_month[$i];
        if ($gm > 1 && (($g_y % 4 == 0 && $g_y % 100 != 0) || ($g_y % 400 == 0))) $g_day_no++;
        $g_day_no += $gd; $j_day_no = $g_day_no - 79;
        $j_np = floor($j_day_no / 12053); $j_day_no %= 12053;
        $jy = 979 + 33 * $j_np + 4 * floor($j_day_no / 1461); $j_day_no %= 1461;
        if ($j_day_no >= 366) { $jy += floor(($j_day_no - 1) / 365); $j_day_no = ($j_day_no - 1) % 365; }
        for ($i = 0; $i < 11 && $j_day_no >= $j_days_in_month[$i]; ++$i) $j_day_no -= $j_days_in_month[$i];
        $jm = $i + 1; $jd = $j_day_no + 1;
        return array($jy, $jm, $jd);
    }

    private function jalali_to_gregorian($j_y, $j_m, $j_d) {
        $j_y = intval($j_y); $j_m = intval($j_m); $j_d = intval($j_d);
        $jy = $j_y - 979; $jm = $j_m - 1; $jd = $j_d - 1;
        $j_day_no = 365 * $jy + intval($jy / 33) * 8 + intval((($jy % 33) + 3) / 4);
        $j_days_in_month = [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29];
        for ($i = 0; $i < $jm; ++$i) $j_day_no += $j_days_in_month[$i];
        $j_day_no += $jd;
        $g_day_no = $j_day_no + 79;
        $gy = 1600 + 400 * intval($g_day_no / 146097);
        $g_day_no = $g_day_no % 146097;
        $leap = true;
        if ($g_day_no >= 36525) {
            $g_day_no--;
            $gy += 100 * intval($g_day_no / 36524);
            $g_day_no = $g_day_no % 36524;
            if ($g_day_no >= 365) $g_day_no++;
            else $leap = false;
        }
        $gy += 4 * intval($g_day_no / 1461);
        $g_day_no %= 1461;
        if ($g_day_no >= 366) {
            $leap = false;
            $g_day_no--;
            $gy += intval($g_day_no / 365);
            $g_day_no = $g_day_no % 365;
        }
        $g_days_in_month = [31, ($leap ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
        for ($i = 0; $g_day_no >= $g_days_in_month[$i]; $i++) $g_day_no -= $g_days_in_month[$i];
        $gm = $i + 1;
        $gd = $g_day_no + 1;
        return [$gy, $gm, $gd];
    }

    private function format_jalali($jy,$jm,$jd) {
        $map = [1=>'فروردین',۲=>'اردیبهشت',۳=>'خرداد',۴=>'تیر',۵=>'مرداد',۶=>'شهریور',۷=>'مهر',۸=>'آبان',۹=>'آذر',۱۰=>'دی',۱۱=>'بهمن',۱۲=>'اسفند'];
        $week_days = ['یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه'];
        $day_of_week = $week_days[date('w', current_time('timestamp'))];
        return $day_of_week . '، ' . sprintf('%02d %s %04d', $jd, $map[$jm], $jy);
    }

    private function get_time_ir_data() {
        $transient_key = 'notex_time_ir_data';
        $cached_data = get_transient($transient_key);
        if (false !== $cached_data) {
            return $cached_data;
        }
        $response = wp_remote_get('https://time.ir/api/Fa/Time/GetNow', ['timeout' => 10]);
        if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
            return null;
        }
        $data = json_decode(wp_remote_retrieve_body($response), true);
        if (is_array($data) && isset($data['year'])) {
            set_transient($transient_key, $data, 60);
            return $data;
        }
        return null;
    }

    private function excerpt_words($text, $limit = 5) {
        return wp_trim_words(wp_strip_all_tags($text), $limit, '...');
    }

    public function add_dashboard_widget() {
        wp_add_dashboard_widget('notex_tools_wp_dashboard_widget', 'Notex tools wp', array($this, 'render_dashboard_widget'));
    }

    public function render_dashboard_widget() {
        $time_data = $this->get_time_ir_data();
        if ($time_data) {
            $jalali_display = $time_data['fullDate'];
            $gregorian_timestamp = strtotime($time_data['gregorianDate']);
            $gregorian_display_formatted = date('Y - m - d', $gregorian_timestamp);
            $gregorian_day_of_week = $time_data['dayOfWeek'];
            $initial_clock = $time_data['hour'] . ':' . $time_data['minute'] . ':' . $time_data['second'];
        } else {
            $now = current_time('timestamp');
            list($g_y, $g_m, $g_d) = [date('Y', $now), date('n', $now), date('j', $now)];
            list($jy, $jm, $jd) = $this->gregorian_to_jalali($g_y, $g_m, $g_d);
            $jalali_display = $this->format_jalali($jy, $jm, $jd);
            $gregorian_display_formatted = date('Y - m - d', $now);
            $gregorian_day_of_week = date('l', $now);
            $initial_clock = date('H:i:s', $now);
        }
        ?>
        <style>
            #notex_tools_wp_dashboard_widget .hndle,
            #notex_tools_wp_dashboard_widget .handle-order-higher,
            #notex_tools_wp_dashboard_widget .handle-order-lower { display: none !important; }
            #notex_tools_wp_dashboard_widget .inside { margin: 0; padding: 0; }
            .notex-wrapper { display:flex; direction:rtl; background:#f7f3fb; border:1px solid #e3dfe8; border-radius:8px; overflow:hidden; }
            .notex-col { padding:20px; box-sizing:border-box; display:flex; flex-direction:column; }
            .notex-col-main { width: 65%; background:#fff; }
            .notex-col-sidebar { width: 35%; border-left:1px solid #e3dfe8; justify-content: space-between; gap: 20px; text-align: center; }
            .notex-tabs { display:flex; flex-wrap:nowrap; overflow-x: auto; gap:8px; border-bottom:1px solid #e9e6ee; padding-bottom:10px; margin-bottom:12px; }
            .notex-tab-link { padding:8px 12px; background:#f4eef8; border:1px solid #e9e6ee; border-radius:8px; cursor:pointer; white-space: nowrap; }
            .notex-tab-link.active { background:#8a2be2; color:#fff; border-color:#8a2be2; }
            .time-box .clock { font-size:3.2rem; font-weight:800; line-height:1.1; margin-bottom: 10px; }
            .time-box .date { font-size:1rem; color:#333; font-weight:700; line-height: 1.8; }
            .weather-box { background:#fff; border-radius:8px; padding:15px; border:1px solid #e9e6ee; }
            #note-content { width:100%; min-height:160px; padding:12px; border-radius:8px; border:1px solid #e9e6ee; resize:vertical; margin-bottom: 10px;}
            .note-form-dropdowns { display: flex; gap: 10px; margin-bottom: 10px; }
            .note-form-dropdowns select { flex-grow: 1; padding: 10px; border-radius: 8px; border: 1px solid #e9e6ee; background-color: #fff; }
            #save-note-btn { width: 100%; background:#1e88e5; color:#fff; padding:12px; border-radius:8px; border:none; cursor:pointer; font-weight:700; }
            .notes-list .note-list-item { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:10px 6px; border-bottom:1px solid #f0eef3; }
            .note-left { display:flex; align-items:center; gap:10px; min-width:0; flex-grow: 1; }
            .note-text-content { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
            .note-meta { display:flex; gap:8px; align-items:center; direction:ltr; justify-content:flex-end; font-size:0.9em; color:#555; }
            .note-delete { background:#e74c3c; color:#fff; padding:6px 10px; border-radius:6px; text-decoration:none; }
            .note-edit { background:#8a2be2; color:#fff; padding:6px 10px; border-radius:6px; text-decoration:none; }
            .priority-dot { width:12px; height:12px; border-radius:50%; flex-shrink:0; display: inline-block; margin-left: 5px; }
            .priority-dot.high{ background:#e74c3c; } .priority-dot.medium{ background:#f39c12; } .priority-dot.low{ background:#f1c40f; }
            .status-dot { width:12px; height:12px; border-radius:50%; flex-shrink:0; display: inline-block; margin-left: 5px; }
            .status-dot.completed { background: #28a745; }
            #prayer-times-output { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; padding: 20px; text-align: center; }
            #prayer-times-output div { background-color: #f9f9f9; border: 1px solid #eee; border-radius: 8px; padding: 15px; box-shadow: 0 2px 5px rgba(0,0,0,0.05); }
            #prayer-times-output strong { display: block; font-size: 1.2em; color: #8a2be2; margin-bottom: 8px; }
            #prayer-times-output span { font-size: 1.5em; font-weight: bold; color: #333; }
            .simple-calendar { display:grid; grid-template-columns: repeat(7, 1fr); gap:10px; padding:8px; }
            .cal-day { height:50px; border-radius:8px; display:flex; flex-direction:column; align-items:center; justify-content:center; font-size:1rem; line-height:1.2; background: #fff; border: 1px solid #ddd; }
            .cal-day.cal-today { font-weight: bold; border: 2px solid #8a2be2; }
            .cal-day .gregorian-date { font-size: 0.75em; color: #A52A2A; font-weight: normal; }
            .parsidate-notice { font-size: 1em !important; color: #444 !important; }
            .notex-pro-banner { background-color: #ffe5e5; color: #d8000c; padding: 10px; text-align: center; margin-bottom: 15px; border-bottom: 1px solid #e3dfe8; font-weight: bold; }
            .notex-pro-banner a { color: #8a2be2; text-decoration: none; }
        </style>

        <div class="notex-wrapper" id="notex-widget-root">
            <div class="notex-col notex-col-main">
                <div class="notex-pro-banner">محدودیت حداکثر ساخت ۳ یادداشت: <a href="https://mrbarati.com/management-wp" target="_blank">نسخه پرو</a></div>
                <div class="notex-tabs">
                    <button class="notex-tab-link active" data-tab="new-note">نوشتن/ویرایش یادداشت</button>
                    <button class="notex-tab-link" data-tab="all-notes" data-filter="all">نمایش همه</button>
                    <button class="notex-tab-link" data-tab="high-priority-notes" data-filter="high">اولویت بالا</button>
                    <button class="notex-tab-link" data-tab="medium-priority-notes" data-filter="medium">اولویت متوسط</button>
                    <button class="notex-tab-link" data-tab="low-priority-notes" data-filter="low">اولویت کم</button>
                    <button class="notex-tab-link" data-tab="prayer-times">اوقات شرعی</button>
                    <button class="notex-tab-link" data-tab="calendar">تقویم</button>
                </div>
                <div id="new-note" class="notex-tab-content" style="display:block;">
                    <?php wp_nonce_field('notex_tools_wp_nonce_form', 'notex_form_nonce'); ?>
                    <input type="hidden" id="note-id-to-edit" value="">
                    <textarea id="note-content" placeholder="...متن خود را اینجا بنویسید"></textarea>
                    <div class="note-form-dropdowns">
                        <select id="note-priority">
                            <option value="high">اولویت بالا</option>
                            <option value="medium" selected>اولویت متوسط</option>
                            <option value="low">اولویت کم</option>
                        </select>
                         <select id="note-status">
                            <option value="in_progress">در حال انجام</option>
                            <option value="no_change" selected>بدون تغییر</option>
                            <option value="completed">تمام شده</option>
                        </select>
                    </div>
                    <button id="save-note-btn">ذخیره یادداشت</button>
                </div>
                <div id="all-notes" class="notex-tab-content notes-list" style="display:none;"></div>
                <div id="high-priority-notes" class="notex-tab-content notes-list" style="display:none;"></div>
                <div id="medium-priority-notes" class="notex-tab-content notes-list" style="display:none;"></div>
                <div id="low-priority-notes" class="notex-tab-content notes-list" style="display:none;"></div>
                <div id="prayer-times" class="notex-tab-content" style="display:none;"><div id="prayer-times-output"></div></div>
                <div id="calendar" class="notex-tab-content" style="display:none;"><div id="simple-calendar" class="simple-calendar"></div></div>
            </div>

            <div class="notex-col notex-col-sidebar">
                <div class="time-box">
                    <div class="clock" id="notex-clock" data-initial-time="<?php echo esc_attr($initial_clock); ?>">۰۰:۰۰</div>
                    <div class="date">
                        <div><?php echo esc_html($jalali_display); ?></div>
                        <div><?php echo esc_html($gregorian_display_formatted); ?></div>
                        <div><?php echo esc_html($gregorian_day_of_week); ?></div>
                    </div>
                </div>
                <div class="weather-box" id="notex-weather-info">برای نمایش آب و هوا، شهر را انتخاب کنید.</div>
                <div class="sidebar-bottom">
                    <div style="font-weight:700; margin-bottom:8px;">انتخاب شهر (برای آب و هوا)</div>
                    <select id="sidebar-city-selector" style="width:100%; padding:12px; border-radius:8px; border:1px solid #e9e6ee;">
                        <option value="">-- انتخاب کنید --</option>
                        <?php foreach ($this->cities_data as $key => $fa): ?>
                            <option value="<?php echo esc_attr($key); ?>"><?php echo esc_html($fa); ?></option>
                        <?php endforeach; ?>
                    </select>
                    <div class="parsidate-notice" style="margin-top: 10px;">
                        افزونه برای نمایش فارسی به پلاگین <a href="https://wordpress.org/plugins/wp-parsidate/" target="_blank">پارسی دیت</a> نیاز دارد.
                    </div>
                </div>
            </div>
        </div>

        <script>
        (function($){
            $(function() {
                const widget = $('#notex_tools_wp_dashboard_widget');
                if (widget.length) {
                    $('#dashboard-widgets.metabox-holder').prepend(widget);
                    widget.css('margin-bottom', '20px');
                }
            });

            const nonce = '<?php echo wp_create_nonce("notex_tools_wp_nonce"); ?>';
            function doAjax(sub_action, data = {}, cb) {
                $.post(ajaxurl, $.extend({ action: 'notex_tools_wp_action', sub_action: sub_action, _ajax_nonce: nonce }, data), cb, 'json');
            }

            function initializeClock() {
                const clockElement = $('#notex-clock');
                const initialTime = clockElement.data('initial-time');
                let serverTime;
                if (initialTime && initialTime.split(':').length === 3) {
                    const parts = initialTime.split(':');
                    serverTime = new Date();
                    serverTime.setHours(parseInt(parts[0], 10), parseInt(parts[1], 10), parseInt(parts[2], 10));
                } else {
                    serverTime = new Date();
                }
                function updateClock() {
                    serverTime.setSeconds(serverTime.getSeconds() + 1);
                    const h = String(serverTime.getHours()).padStart(2, '0');
                    const m = String(serverTime.getMinutes()).padStart(2, '0');
                    clockElement.text(h + ':' + m);
                }
                updateClock();
                setInterval(updateClock, 1000);
            }
            initializeClock();
            
            $('.notex-tab-link').on('click', function(){
                const tab = $(this).data('tab');
                $('.notex-tab-link').removeClass('active');
                $(this).addClass('active');
                $('.notex-tab-content').hide();
                $('#' + tab).show();
                if ($(this).data('filter')) loadNotes($(this).data('filter'), 1, '#' + tab);
                if (tab === 'calendar') renderCalendar();
            });

            function escapeHtml(text) {
                if (typeof text !== 'string') return '';
                return text.replace(/[&<>"'`=\/]/g, s => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;','`':'&#x60;','=':'&#x3D;','/':'&#x2F;'})[s]);
            }
            
            function buildNoteItemHtml(note, number) {
                let statusDot = note.status === 'completed' ? `<span class="status-dot completed" title="تمام شده"></span>` : '';
                return `<div class="note-list-item">
                    <div class="note-left">
                        <span>${number}.</span>
                        ${statusDot}
                        <span class="priority-dot ${escapeHtml(note.priority)}"></span>
                        <span class="note-text-content" title="${escapeHtml(note.note_content)}">${escapeHtml(note.excerpt)}</span>
                    </div>
                    <div class="note-meta">
                        <a href="#" class="note-edit" data-id="${note.id}" data-content="${escapeHtml(note.note_content)}" data-priority="${note.priority}" data-status="${note.status}">ویرایش</a>
                        <a href="#" class="note-delete" data-id="${note.id}">حذف</a>
                        <span>${note.created_at_display || ''}</span>
                    </div>
                </div>`;
            }

            function loadNotes(filter, page = 1, containerSelector = '#all-notes') {
                $(containerSelector).html('در حال بارگذاری...');
                doAjax('get_notes', { filter, page }, function(res){
                    if (!res || !res.success) { $(containerSelector).html('خطا در دریافت یادداشت‌ها.'); return; }
                    let html = (res.data.notes || []).map((note, idx) => buildNoteItemHtml(note, res.data.offset + idx + 1)).join('');
                    $(containerSelector).html(html || 'یادداشتی یافت نشد.');
                });
            }

            $('body').on('click', '.note-delete', function(e){
                e.preventDefault();
                if (!confirm('آیا از حذف این یادداشت مطمئن هستید؟')) return;
                const id = $(this).data('id');
                doAjax('delete_note', { note_id: id }, function(res){
                    if (res && res.success) $('.notex-tab-link.active').trigger('click');
                    else alert(res.data.message || 'خطا در حذف.');
                });
            });

            $('body').on('click', '.note-edit', function(e){
                e.preventDefault();
                const btn = $(this);
                $('.notex-tab-link[data-tab="new-note"]').trigger('click');
                $('#note-id-to-edit').val(btn.data('id'));
                $('#note-content').val(btn.data('content'));
                $('#note-priority').val(btn.data('priority'));
                $('#note-status').val(btn.data('status'));
                $('#save-note-btn').text('بروزرسانی یادداشت');
            });

            $('#save-note-btn').on('click', function(){
                const noteData = {
                    note_id: $('#note-id-to-edit').val(),
                    content: $('#note-content').val(),
                    priority: $('#note-priority').val(),
                    status: $('#note-status').val(),
                    nonce: $('#notex_form_nonce').val()
                };
                doAjax('save_note', noteData, function(res){
                    if (res && res.success) {
                        $('#note-content').val('');
                        $('#note-id-to-edit').val('');
                        $('#save-note-btn').text('ذخیره یادداشت');
                        $('.notex-tab-link[data-filter="all"]').trigger('click');
                    } else {
                        if (res.data && res.data.message === 'limit_reached') {
                             alert('شما به حداکثر تعداد یادداشت (۳ عدد) در نسخه رایگان رسیده‌اید. برای برداشتن محدودیت، نسخه پرو را تهیه کنید: https://mrbarati.com/management-wp');
                        } else {
                            alert(res.data.message || 'خطا در ذخیره سازی.');
                        }
                    }
                });
            });

            $('#sidebar-city-selector').on('change', function(){
                const city = $(this).val();
                if (!city) return;
                $('#notex-weather-info').html('در حال دریافت...');
                $('#prayer-times-output').html('در حال دریافت...');
                doAjax('get_city_data', { city }, function(res){
                    if (res && res.success) {
                        const w = res.data.weather;
                        const p = res.data.prayer;
                        let weather_html = `<strong>${escapeHtml(w.temp)}°C</strong> — دمای الان`;
                        let prayer_html = Object.entries(p).map(([key, val]) => `<div><strong>${escapeHtml(key)}</strong><span>${escapeHtml(val)}</span></div>`).join('');
                        $('#notex-weather-info').html(weather_html);
                        $('#prayer-times-output').html(prayer_html || 'اوقات شرعی دریافت نشد.');
                    } else {
                         $('#notex-weather-info').html('خطا در دریافت اطلاعات آب و هوا.');
                         $('#prayer-times-output').html('خطا در دریافت اوقات شرعی.');
                    }
                });
            });

            function renderCalendar() {
                $('#simple-calendar').html('در حال بارگذاری تقویم...');
                doAjax('get_calendar_info', {}, function(res){
                    if (!res || !res.success) {
                        $('#simple-calendar').html('خطا در دریافت تقویم.');
                        return;
                    }
                    let html = '';
                    const weekDays = ['ش', 'ی', 'د', 'س', 'چ', 'پ', 'ج'];
                    weekDays.forEach(day => {
                        html += `<div class="cal-day" style="background:#f0eef3; font-weight:bold;">${day}</div>`;
                    });
                    for(let i=0; i < res.data.first_day_offset; i++) html += '<div></div>';
                    (res.data.days || []).forEach(day => {
                        html += `<div class="cal-day ${day.is_today ? 'cal-today' : ''}">
                                    <div>${day.jalali_day}</div>
                                    <div class="gregorian-date">${day.gregorian_str}</div>
                                 </div>`;
                    });
                    $('#simple-calendar').html(html);
                });
            }
            loadNotes('all', 1, '#all-notes');
        })(jQuery);
        </script>
        <?php
    }

    public function handle_ajax_actions() {
        check_ajax_referer('notex_tools_wp_nonce');
        if (!current_user_can('edit_dashboard')) {
            wp_send_json_error(['message' => 'عدم دسترسی.'], ۴۰۳);
        }
        $action = isset($_POST['sub_action']) ? sanitize_key($_POST['sub_action']) : '';
        switch ($action) {
            case 'save_note': $this->ajax_save_note(); break;
            case 'get_notes': $this->ajax_get_notes(); break;
            case 'delete_note': $this->ajax_delete_note(); break;
            case 'get_city_data': $this->ajax_get_city_data(); break;
            case 'get_calendar_info': $this->ajax_get_calendar_info(); break;
            default: wp_send_json_error(['message' => 'عملیات نامعتبر.']);
        }
    }

    private function ajax_save_note() {
        global $wpdb;
        $table_name = $wpdb->prefix . 'notex_tools_wp_notes';
        $note_id = isset($_POST['note_id']) ? intval($_POST['note_id']) : 0;

        if ($note_id === 0) {
            $note_count = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name}");
            if ($note_count >= 3) {
                wp_send_json_error(['message' => 'limit_reached']);
                return;
            }
        }
        
        $content = isset($_POST['content']) ? wp_kses_post($_POST['content']) : '';
        $priority = isset($_POST['priority']) ? sanitize_key($_POST['priority']) : 'medium';
        $status = isset($_POST['status']) ? sanitize_key($_POST['status']) : 'no_change';
        if (empty(trim($content))) wp_send_json_error(['message' => 'متن یادداشت خالی است.']);
        if (!in_array($priority, ['high', 'medium', 'low'])) wp_send_json_error(['message' => 'اولویت نامعتبر است.']);
        if (!in_array($status, ['in_progress', 'no_change', 'completed'])) wp_send_json_error(['message' => 'وضعیت نامعتبر است.']);
        $data = ['note_content' => $content, 'priority' => $priority, 'status' => $status];
        
        if ($note_id > 0) {
            $result = $wpdb->update($table_name, $data, ['id' => $note_id]);
        } else {
            $data['created_at'] = current_time('mysql', 1);
            $result = $wpdb->insert($table_name, $data);
        }

        if ($result !== false) wp_send_json_success();
        else wp_send_json_error(['message' => 'خطا در پایگاه داده.']);
    }
    
    private function ajax_get_notes() {
        global $wpdb;
        $filter = isset($_POST['filter']) && in_array($_POST['filter'], ['all', 'high', 'medium', 'low']) ? sanitize_key($_POST['filter']) : 'all';
        $where = ($filter !== 'all') ? $wpdb->prepare("WHERE priority = %s", $filter) : '';
        $table_name = $wpdb->prefix . 'notex_tools_wp_notes';
        $notes = $wpdb->get_results("SELECT * FROM {$table_name} {$where} ORDER BY created_at DESC LIMIT 20");
        $status_map = ['in_progress' => 'در حال انجام', 'no_change' => 'بدون تغییر', 'completed' => 'تمام شده'];
        $out = [];
        foreach ($notes as $n) {
            $timestamp = strtotime($n->created_at);
            $status_text = isset($status_map[$n->status]) ? $status_map[$n->status] : esc_html($n->status);
            $date_text = function_exists('parsidate') ? parsidate('Y/m/d', $timestamp) : date('Y-m-d', $timestamp);
            $out[] = [
                'id' => intval($n->id),
                'note_content' => wp_kses_post($n->note_content),
                'priority' => esc_html($n->priority),
                'status' => esc_html($n->status),
                'excerpt' => $this->excerpt_words($n->note_content, 5),
                'created_at_display' => $status_text . ' - ' . $date_text,
            ];
        }
        wp_send_json_success(['notes' => $out, 'offset' => 0]);
    }

    private function ajax_delete_note() {
        global $wpdb;
        $note_id = isset($_POST['note_id']) ? intval($_POST['note_id']) : 0;
        if ($note_id > 0) {
            $table_name = $wpdb->prefix . 'notex_tools_wp_notes';
            if ($wpdb->delete($table_name, ['id' => $note_id], ['%d'])) wp_send_json_success();
            else wp_send_json_error(['message' => 'یادداشت یافت نشد یا خطا در حذف.']);
        } else {
            wp_send_json_error(['message' => 'شناسه نامعتبر.']);
        }
    }

    private function ajax_get_city_data() {
        $city = isset($_POST['city']) ? sanitize_text_field($_POST['city']) : '';
        if (empty($city)) wp_send_json_error(['message' => 'نام شهر مشخص نشده است.']);
        $weather_res = wp_remote_get("https://wttr.in/{$city}?format=j1", ['timeout' => 10]);
        $weather_data = ['temp' => 'N/A'];
        if (!is_wp_error($weather_res) && wp_remote_retrieve_response_code($weather_res) === 200) {
            $wt = json_decode(wp_remote_retrieve_body($weather_res), true);
            if (!empty($wt['current_condition'][0])) $weather_data['temp'] = esc_html($wt['current_condition'][0]['temp_C']);
        }
        $prayer_res = wp_remote_get("https://api.aladhan.com/v1/timingsByCity?city={$city}&country=Iran&method=8", ['timeout' => 10]);
        $prayer_times = [];
        if (!is_wp_error($prayer_res) && wp_remote_retrieve_response_code($prayer_res) === 200) {
            $pr_api = json_decode(wp_remote_retrieve_body($prayer_res), true);
            if (!empty($pr_api['data']['timings'])) {
                $map = ['Fajr'=>'اذان صبح','Sunrise'=>'طلوع آفتاب','Dhuhr'=>'اذان ظهر','Maghrib'=>'اذان مغرب','Isha'=>'عشا'];
                foreach ($map as $en => $fa) if (isset($pr_api['data']['timings'][$en])) $prayer_times[esc_html($fa)] = esc_html($pr_api['data']['timings'][$en]);
            }
        }
        wp_send_json_success(['weather' => $weather_data, 'prayer' => $prayer_times]);
    }

    private function generate_calendar_fallback() {
        $now = current_time('timestamp');
        list($g_y, $g_m, $g_d) = [date('Y', $now), date('n', $now), date('j', $now)];
        list($jy, $jm, $jd) = $this->gregorian_to_jalali($g_y, $g_m, $g_d);
        $is_leap = in_array(($jy % 33), [1, 5, 9, 13, 17, 22, 26, 30]);
        $days_in_month = ($jm <= 6) ? 31 : (($jm <= 11) ? 30 : ($is_leap ? 30 : 29));
        $calendar_days = [];
        for ($day = 1; $day <= $days_in_month; $day++) {
            list($cal_g_y, $cal_g_m, $cal_g_d) = $this->jalali_to_gregorian($jy, $jm, $day);
            $calendar_days[] = [
                'jalali_day'    => intval($day),
                'gregorian_str' => sprintf('%02d/%02d', $cal_g_d, $cal_g_m),
                'is_today'      => ($day == $jd),
            ];
        }
        list($first_g_y, $first_g_m, $first_g_d) = $this->jalali_to_gregorian($jy, $jm, 1);
        $php_w = date('w', strtotime("$first_g_y-$first_g_m-$first_g_d"));
        $offset = ($php_w + 1) % 7;
        return ['days' => $calendar_days, 'first_day_offset' => $offset];
    }
    
    private function ajax_get_calendar_info() {
        $time_data = $this->get_time_ir_data();
        if ($time_data) {
            $jy = $time_data['year'];
            $jm = $time_data['month'];
            $jd = $time_data['dayOfMonth'];
            $api_url = "https://time.ir/api/Fa/Month/GetCalender?Year={$jy}&Month={$jm}";
            $response = wp_remote_get($api_url, ['timeout' => 10]);
            if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
                $cal_data = json_decode(wp_remote_retrieve_body($response), true);
                if (isset($cal_data['days']) && isset($cal_data['dayOfWeek'])) {
                    $calendar_days = [];
                    foreach ($cal_data['days'] as $day_data) {
                        $calendar_days[] = [
                            'jalali_day'    => intval($day_data['day']),
                            'gregorian_str' => esc_html($day_data['gregorian']),
                            'is_today'      => (intval($day_data['day']) == $jd),
                        ];
                    }
                    $offset = intval($cal_data['dayOfWeek']);
                    wp_send_json_success(['days' => $calendar_days, 'first_day_offset' => $offset]);
                    return;
                }
            }
        }
        $fallback_data = $this->generate_calendar_fallback();
        wp_send_json_success($fallback_data);
    }
}

new Notex_Tools_Wp_Free();

نقش افزونه به بهبود بهره‌وری

استفاده از یک افزونه مدیریت پروژه در وردپرس مانند این ابزار، نیاز به جابجایی بین اپلیکیشن‌های مختلف را از بین می‌برد و همه چیز را در دسترس شما قرار می‌دهد. تصور کنید در حال نوشتن یک مقاله هستید و ایده‌ای جدید به ذهنتان می‌رسد؛ بدون ترک صفحه، آن را در ویجت یادداشت با اولویت بالا ثبت می‌کنید. یا می‌خواهید برنامه‌ریزی محتوایی هفته آینده را انجام دهید؛ با یک نگاه به تقویم شمسی و لیست وظایف، بهترین تصمیم را می‌گیرید. این یکپارچگی، کلید اصلی افزایش بهره‌وری است.

  1. یکپارچگی و عدم ترک پیشخوان
  2. فارسی ساز شده و ایرانی
  3. سبک و بهینه

نصب افوزنه دفترچه یادداشت وردپرس

نصب این افزونه مانند هر پلاگین استاندارد دیگری در وردپرس انجام می‌شود. پس از فعال‌سازی، ویجت «Notex tools wp» به صورت خودکار به بالای صفحه پیشخوان شما اضافه می‌شود تا بلافاصله قابل استفاده باشد.

دانلود نسخه پرو افزونه نوتکس NoteX

لازم به ذکر است که برای نمایش بهینه تاریخ و اعداد به زبان فارسی، این افزونه با پلاگین محبوب «پارسی دیت» (WP Parsidate) سازگاری کامل دارد و توصیه می‌شود از آن در کنار این ابزار استفاده کنید.

آموزش های رایگان بیشتر : طراحی سایت شرکتی

 

خدمات پشتیبانی سایت وردپرسی
بعد از تکمیل فرم وبررسی اولیه باشما تماس می گیرم

 

۴/۵ - (۵ امتیاز)
Telegram
WhatsApp
Email
LinkedIn
پشتیبان سایت

دیدگاهتان را بنویسید

دوازده + هشت =