WordpressLập Trình

Hướng Dẫn Chức Năng Quảng Cáo Trong Bài Viết

Quảng cáo bài viết là một phương thức hiệu quả giúp nội dung của bạn nổi bật hơn giữa hàng nghìn nội dung khác. Nếu bạn là quản trị viên website WordPress, việc tích hợp một hệ thống quản lý quảng cáo bài viết ngay trong trang quản trị sẽ giúp bạn chủ động kiểm soát và gia tăng giá trị cho nội dung trên website.

Tính năng nổi bật của hệ thống quản lý quảng cáo bài viết

Hệ thống quản lý quảng cáo bài viết (MTWPGR QCP) là một module dành riêng cho WordPress với nhiều chức năng vượt trội giúp việc quản lý quảng cáo trở nên dễ dàng và chuyên nghiệp hơn:

1. Thêm thông tin quảng cáo ngay tại giao diện chỉnh sửa bài viết

Khi biên tập bài viết, bạn có thể nhanh chóng cấu hình thông tin quảng cáo bao gồm:

  • Loại quảng cáo: Theo giờ, theo ngày, theo tháng, hoặc theo năm.
  • Thời gian bắt đầu và kết thúc.
  • Trạng thái quảng cáo: Chờ duyệt, đang chạy, hết hạn, từ chối.

Việc sử dụng meta box giúp mọi thao tác trở nên trực quan và tiện lợi.

Thêm thông tin quảng cáo ngay tại giao diện chỉnh sửa bài viết

2. Tự động sắp xếp bài viết quảng cáo hiển thị lên đầu trang

Trên trang chủ, hệ thống tự động ưu tiên hiển thị các bài viết đang trong thời gian quảng cáo hợp lệ và có trạng thái “đã duyệt”. Điều này giúp bài viết được tiếp cận nhiều hơn từ người dùng.

3. Dashboard quản trị quảng cáo chuyên nghiệp

Trong phần quản trị, bạn có thể truy cập vào mục “Quảng cáo Bài viết” để:

  • Xem danh sách tất cả bài viết có quảng cáo.
  • Lọc theo trạng thái (chờ duyệt, đã duyệt, hết hạn, từ chối).
  • Tìm kiếm bài viết theo tiêu đề.
  • Duyệt hoặc từ chối quảng cáo chỉ với một cú nhấp chuột.

4. Tự động kiểm tra và xử lý quảng cáo hết hạn

Hệ thống sử dụng cron job chạy mỗi giờ để kiểm tra các bài viết quảng cáo đã hết hạn. Khi một quảng cáo hết hạn:

  • Trạng thái sẽ được cập nhật tự động.
  • Một email thông báo được gửi đến người dùng.

5. Biểu mẫu đăng ký quảng cáo bài viết ngay trên frontend

Người dùng đã đăng nhập có thể đăng ký quảng cáo bài viết qua shortcode [mtwpgr_qcp_ad_form]:

  • Chọn bài viết muốn quảng cáo.
  • Chọn loại hình quảng cáo.
  • Nhập thời lượng quảng cáo.
  • Xem chi phí ước tính ngay lập tức.

6. Thông báo qua email

Người dùng sẽ nhận email thông báo sau khi:

  • Gửi yêu cầu quảng cáo.
  • Quảng cáo được duyệt hoặc từ chối.
  • Quảng cáo hết hạn.

Hệ thống đảm bảo việc truyền tải thông tin đầy đủ và kịp thời đến người dùng.

7. Bảng giá quảng cáo rõ ràng

Bảng giá được định nghĩa theo từng loại thời gian:

  • Quảng cáo theo giờ: 1.000 đ/giờ
  • Quảng cáo theo ngày: 15.000 đ/ngày
  • Quảng cáo theo tháng: 300.000 đ/tháng

Người dùng có thể xem bảng giá qua shortcode [mtwpgr_qcp_pricing].

Lợi ích cho quản trị viên và người dùng

Đối với quản trị viên:

  • Dễ dàng kiểm duyệt và kiểm soát trạng thái quảng cáo.
  • Tăng doanh thu từ hình thức quảng cáo bài viết.
  • Nâng cao chất lượng và uy tín website thông qua sự chuyên nghiệp.

Đối với người dùng:

  • Tự do lựa chọn bài viết muốn quảng cáo.
  • Biết trước chi phí dự kiến.
  • Quản lý lịch sử quảng cáo hiệu quả.

Tích hợp dễ dàng và mở rộng linh hoạt

Plugin này được xây dựng bằng mã nguồn chuẩn WordPress với:

  • Các hookfilter và shortcode giúp dễ mở rộng.
  • Không gây ảnh hưởng đến các plugin hoặc theme hiện có.
  • Bảo mật cao, tuân thủ nguyên tắc xử lý form và quyền truy cập người dùng.
// ====== Khởi tạo class chính ======
class MTWPGR_QCP_Manager {
    public function __construct() {
        add_action('add_meta_boxes', [$this, 'mtwpgr_qcp_add_ad_meta_box']);
        add_action('save_post', [$this, 'mtwpgr_qcp_save_ad_meta_box']);
        add_filter('the_posts', [$this, 'mtwpgr_qcp_prioritize_ad_posts'], 10, 2);
        add_action('admin_post_mtwpgr_qcp_approve_ad', [$this, 'mtwpgr_qcp_approve_ad']);
        add_action('admin_post_mtwpgr_qcp_reject_ad', [$this, 'mtwpgr_qcp_reject_ad']);
    }

    public function mtwpgr_qcp_add_ad_meta_box() {
        add_meta_box(
            'mtwpgr_qcp_ad_box',
            'Quảng cáo Bài viết (mtwpgr-qcp)',
            [$this, 'mtwpgr_qcp_render_ad_meta_box'],
            'post',
            'side',
            'high'
        );
    }

    public function mtwpgr_qcp_render_ad_meta_box($post) {
        wp_nonce_field('mtwpgr_qcp_save_ad_data', 'mtwpgr_qcp_nonce');
        $ad_type = get_post_meta($post->ID, '_mtwpgr_qcp_ad_type', true);
        $start_date = get_post_meta($post->ID, '_mtwpgr_qcp_start_date', true);
        $end_date = get_post_meta($post->ID, '_mtwpgr_qcp_end_date', true);
        $ad_status = get_post_meta($post->ID, '_mtwpgr_qcp_ad_status', true);
        ?>
        <p>
            <label for="mtwpgr_qcp_ad_type">Loại quảng cáo:</label><br>
            <select name="mtwpgr_qcp_ad_type" id="mtwpgr_qcp_ad_type">
                <option value="">-- Chọn loại --</option>
                <option value="hourly" <?php selected($ad_type, 'hourly'); ?>>Theo giờ</option>
                <option value="daily" <?php selected($ad_type, 'daily'); ?>>Theo ngày</option>
                <option value="monthly" <?php selected($ad_type, 'monthly'); ?>>Theo tháng</option>
                <option value="yearly" <?php selected($ad_type, 'yearly'); ?>>Theo năm</option>
            </select>
        </p>
        <p>
            <label for="mtwpgr_qcp_start_date">Bắt đầu:</label><br>
            <input type="datetime-local" name="mtwpgr_qcp_start_date" value="<?php echo esc_attr($start_date); ?>" />
        </p>
        <p>
            <label for="mtwpgr_qcp_end_date">Kết thúc:</label><br>
            <input type="datetime-local" name="mtwpgr_qcp_end_date" value="<?php echo esc_attr($end_date); ?>" />
        </p>
        <p>
            <label>Trạng thái quảng cáo:</label><br>
            <strong>
                <?php
                switch ($ad_status) {
                    case 'pending': echo '⏳ Chờ duyệt'; break;
                    case 'approved': echo '✅ Đang chạy'; break;
                    case 'expired': echo '⏱ Hết hạn'; break;
                    case 'rejected': echo '❌ Từ chối'; break;
                    default: echo 'Không có quảng cáo';
                }
                ?>
            </strong>
        </p>
        <?php
    }

    public function mtwpgr_qcp_save_ad_meta_box($post_id) {
        if (!isset($_POST['mtwpgr_qcp_nonce']) || !wp_verify_nonce($_POST['mtwpgr_qcp_nonce'], 'mtwpgr_qcp_save_ad_data')) return;
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
        if (!current_user_can('edit_post', $post_id)) return;
        update_post_meta($post_id, '_mtwpgr_qcp_ad_type', sanitize_text_field($_POST['mtwpgr_qcp_ad_type']));
        update_post_meta($post_id, '_mtwpgr_qcp_start_date', sanitize_text_field($_POST['mtwpgr_qcp_start_date']));
        update_post_meta($post_id, '_mtwpgr_qcp_end_date', sanitize_text_field($_POST['mtwpgr_qcp_end_date']));
        update_post_meta($post_id, '_mtwpgr_qcp_ad_status', 'pending');
    }

    public function mtwpgr_qcp_prioritize_ad_posts($posts, $query) {
        if (!is_admin() && $query->is_main_query() && is_home()) {
            usort($posts, function ($a, $b) {
                $a_status = get_post_meta($a->ID, '_mtwpgr_qcp_ad_status', true);
                $b_status = get_post_meta($b->ID, '_mtwpgr_qcp_ad_status', true);
                $a_end = strtotime(get_post_meta($a->ID, '_mtwpgr_qcp_end_date', true));
                $b_end = strtotime(get_post_meta($b->ID, '_mtwpgr_qcp_end_date', true));
                if ($a_status === 'approved' && $b_status !== 'approved') return -1;
                if ($b_status === 'approved' && $a_status !== 'approved') return 1;
                return $b_end - $a_end;
            });
        }
        return $posts;
    }

    public function mtwpgr_qcp_approve_ad() {
        if (!current_user_can('manage_options')) wp_die('No permission');
        $post_id = intval($_GET['post_id']);
        update_post_meta($post_id, '_mtwpgr_qcp_ad_status', 'approved');
        wp_redirect(admin_url('admin.php?page=mtwpgr-qcp-dashboard&msg=approved'));
        exit;
    }
    public function mtwpgr_qcp_reject_ad() {
        if (!current_user_can('manage_options')) wp_die('No permission');
        $post_id = intval($_GET['post_id']);
        update_post_meta($post_id, '_mtwpgr_qcp_ad_status', 'rejected');
        wp_redirect(admin_url('admin.php?page=mtwpgr-qcp-dashboard&msg=rejected'));
        exit;
    }
}
new MTWPGR_QCP_Manager();

// ====== Cron xử lý hết hạn quảng cáo ======
register_activation_hook(__FILE__, 'mtwpgr_qcp_schedule_cron');
function mtwpgr_qcp_schedule_cron() {
    if (!wp_next_scheduled('mtwpgr_qcp_check_expired_ads')) {
        wp_schedule_event(time(), 'hourly', 'mtwpgr_qcp_check_expired_ads');
    }
}
register_deactivation_hook(__FILE__, 'mtwpgr_qcp_unschedule_cron');
function mtwpgr_qcp_unschedule_cron() {
    wp_clear_scheduled_hook('mtwpgr_qcp_check_expired_ads');
}
add_action('mtwpgr_qcp_check_expired_ads', 'mtwpgr_qcp_handle_expired_ads');
function mtwpgr_qcp_handle_expired_ads() {
    $args = [
        'post_type' => 'post',
        'meta_query' => [
            [
                'key' => '_mtwpgr_qcp_end_date',
                'value' => current_time('Y-m-d H:i:s'),
                'compare' => '<=',
                'type' => 'DATETIME'
            ],
            [
                'key' => '_mtwpgr_qcp_ad_status',
                'value' => 'approved',
                'compare' => '='
            ]
        ]
    ];
    $query = new WP_Query($args);
    if ($query->have_posts()) {
        foreach ($query->posts as $post) {
            update_post_meta($post->ID, '_mtwpgr_qcp_ad_status', 'expired');
            mtwpgr_qcp_notify_user_ad_expired($post->ID);
        }
    }
}

// ====== Shortcode form quảng cáo ngoài frontend ======
add_shortcode('mtwpgr_qcp_ad_form', 'mtwpgr_qcp_render_frontend_form');
function mtwpgr_qcp_render_frontend_form() {
    if (!is_user_logged_in()) return '<p>Bạn cần đăng nhập để quảng cáo bài viết.</p>';
    $current_user = wp_get_current_user();
    $args = [
        'author' => $current_user->ID,
        'post_type' => 'post',
        'post_status' => 'publish',
        'posts_per_page' => 20,
        'orderby' => 'date',
        'order' => 'DESC'
    ];
    $user_posts = get_posts($args);
    $ads = [];
    foreach ($user_posts as $post) {
        $ads[$post->ID] = [
            'type' => get_post_meta($post->ID, '_mtwpgr_qcp_ad_type', true),
            'status' => get_post_meta($post->ID, '_mtwpgr_qcp_ad_status', true),
            'end' => get_post_meta($post->ID, '_mtwpgr_qcp_end_date', true),
        ];
    }
    ob_start();
    ?>
    <style>
    .mtwpgr-qcp-form-wrap { max-width: 900px; margin: 30px auto; background: #fff; border-radius: 12px; box-shadow: 0 2px 16px rgba(0,0,0,0.08); padding: 32px 24px; }
    .mtwpgr-qcp-title { font-size: 2rem; font-weight: 700; margin-bottom: 18px; color: #1a202c; }
    .mtwpgr-qcp-list { display: flex; flex-wrap: wrap; gap: 18px; margin-bottom: 24px; }
    .mtwpgr-qcp-post-card { background: #f8fafc; border-radius: 10px; box-shadow: 0 1px 6px rgba(0,0,0,0.04); width: 270px; padding: 16px; display: flex; flex-direction: column; align-items: flex-start; position: relative; transition: box-shadow .2s, border .2s, background .2s; border: 2px solid transparent; cursor: pointer; }
    .mtwpgr-qcp-post-card.selected { border: 2px solid #3182ce; background: #e6f0fa; box-shadow: 0 4px 24px rgba(49,130,206,0.10);}
    .mtwpgr-qcp-thumb { width: 100%; height: 140px; object-fit: cover; border-radius: 7px; margin-bottom: 10px; }
    .mtwpgr-qcp-post-title { font-size: 1.1rem; font-weight: 600; margin-bottom: 6px; color: #222; }
    .mtwpgr-qcp-badge { display: inline-block; padding: 2px 10px; border-radius: 12px; font-size: 0.9em; font-weight: 500; margin-bottom: 7px; }
    .mtwpgr-qcp-badge.pending { background: #fff3cd; color: #856404; }
    .mtwpgr-qcp-badge.approved { background: #d4edda; color: #155724; }
    .mtwpgr-qcp-badge.expired { background: #f8d7da; color: #721c24; }
    .mtwpgr-qcp-badge.rejected { background: #e2e3e5; color: #383d41; }
    .mtwpgr-qcp-actions { margin-top: 10px; display: flex; gap: 8px; }
    .mtwpgr-qcp-btn { background: #3182ce; color: #fff; border: none; border-radius: 6px; padding: 6px 14px; font-size: 0.98em; cursor: pointer; transition: background .2s; }
    .mtwpgr-qcp-btn:hover { background: #225ea8; }
    .mtwpgr-qcp-btn.secondary { background: #e2e8f0; color: #222; }
    .mtwpgr-qcp-btn.secondary:hover { background: #cbd5e1; }
    .mtwpgr-qcp-radio { display: none; }
    .mtwpgr-qcp-form-section { margin-bottom: 18px; }
    .mtwpgr-qcp-total { font-size: 1.2em; font-weight: 600; color: #e53e3e; margin-bottom: 10px; }
    .mtwpgr-qcp-modal-bg { display:none; position:fixed; top:0; left:0; width:100vw; height:100vh; background:rgba(0,0,0,0.35); z-index:9999; }
    .mtwpgr-qcp-modal { background:#fff; border-radius:10px; max-width:500px; margin:60px auto; padding:30px; position:relative; }
    .mtwpgr-qcp-modal-close { position:absolute; top:10px; right:16px; font-size:1.5em; color:#888; cursor:pointer; }
    @media (max-width: 600px) {
        .mtwpgr-qcp-list { flex-direction: column; gap: 10px; }
        .mtwpgr-qcp-post-card { width: 100%; }
    }
    </style>
    <div class="mtwpgr-qcp-form-wrap">
        <div class="mtwpgr-qcp-title">Quảng cáo bài viết của bạn</div>
        <form method="post" id="mtwpgr-qcp-ad-form">
            <div class="mtwpgr-qcp-form-section">
                <label><b>Chọn bài viết để quảng cáo:</b></label>
                <div class="mtwpgr-qcp-list" id="mtwpgr-qcp-list">
                    <?php foreach ($user_posts as $post): 
                        $thumb = get_the_post_thumbnail_url($post->ID, 'medium') ?: 'https://via.placeholder.com/300x180?text=No+Image';
                        $ad = $ads[$post->ID];
                        $status = $ad['status'] ?: 'none';
                        $badge = '';
                        switch ($status) {
                            case 'pending': $badge = '<span class="mtwpgr-qcp-badge pending">⏳ Chờ duyệt</span>'; break;
                            case 'approved': $badge = '<span class="mtwpgr-qcp-badge approved">🔥 Đang chạy</span>'; break;
                            case 'expired': $badge = '<span class="mtwpgr-qcp-badge expired">⏱ Hết hạn</span>'; break;
                            case 'rejected': $badge = '<span class="mtwpgr-qcp-badge rejected">❌ Từ chối</span>'; break;
                        }
                    ?>
                    <label style="margin:0;cursor:pointer;">
                        <input type="radio" class="mtwpgr-qcp-radio" name="mtwpgr_qcp_post_id" value="<?= $post->ID; ?>" required>
                        <div class="mtwpgr-qcp-post-card">
                            <img src="<?= esc_url($thumb); ?>" class="mtwpgr-qcp-thumb" alt="">
                            <div class="mtwpgr-qcp-post-title"><?= esc_html($post->post_title); ?></div>
                            <?= $badge ?>
                            <?php if ($ad['end'] && $status !== 'none'): ?>
                                <div style="font-size:0.95em;color:#666;">Đến: <?= esc_html($ad['end']); ?></div>
                            <?php endif; ?>
                            <div class="mtwpgr-qcp-actions">
                                <button type="button" class="mtwpgr-qcp-btn secondary" onclick="mtwpgrQcpShowModal(<?= $post->ID; ?>);event.stopPropagation();">Xem nhanh</button>
                                <?php if ($status === 'expired'): ?>
                                    <a href="?renew_ad=<?= $post->ID; ?>" class="mtwpgr-qcp-btn">Gia hạn</a>
                                <?php endif; ?>
                                <a href="<?= get_permalink($post->ID); ?>" class="mtwpgr-qcp-btn secondary" target="_blank">Xem bài</a>
                            </div>
                            <div id="mtwpgr-qcp-modal-<?= $post->ID; ?>" class="mtwpgr-qcp-modal-bg">
                                <div class="mtwpgr-qcp-modal">
                                    <span class="mtwpgr-qcp-modal-close" onclick="mtwpgrQcpHideModal(<?= $post->ID; ?>)">×</span>
                                    <h3><?= esc_html($post->post_title); ?></h3>
                                    <div style="font-size:0.95em;color:#888;margin-bottom:8px;">Ngày đăng: <?= get_the_date('', $post->ID); ?></div>
                                    <div><?= wp_trim_words($post->post_content, 60, '...'); ?></div>
                                </div>
                            </div>
                        </div>
                    </label>
                    <?php endforeach; ?>
                </div>
            </div>
            <div class="mtwpgr-qcp-form-section">
                <label><b>Loại quảng cáo:</b></label>
                <select name="mtwpgr_qcp_ad_type" id="mtwpgr_qcp_ad_type" onchange="mtwpgr_qcp_update_price()" required>
                    <option value="hourly">Theo giờ</option>
                    <option value="daily">Theo ngày</option>
                    <option value="monthly">Theo tháng</option>
                </select>
            </div>
            <div class="mtwpgr-qcp-form-section">
                <label><b>Thời gian quảng cáo (số):</b></label>
                <input type="number" name="mtwpgr_qcp_duration" min="1" value="1" id="mtwpgr_qcp_duration" oninput="mtwpgr_qcp_update_price()" required>
            </div>
            <div class="mtwpgr-qcp-total" id="mtwpgr_qcp_total_price"></div>
            <button type="submit" name="mtwpgr_qcp_submit_ad" class="mtwpgr-qcp-btn" style="font-size:1.1em;">Gửi yêu cầu quảng cáo</button>
        </form>
        <hr style="margin:32px 0;">
        <h4>Lịch sử quảng cáo của bạn</h4>
        <ul style="list-style:none;padding:0;">
        <?php
        $args2 = [
            'author' => $current_user->ID,
            'post_type' => 'post',
            'meta_key' => '_mtwpgr_qcp_ad_type',
            'meta_compare' => 'EXISTS',
            'posts_per_page' => -1
        ];
        $ads = get_posts($args2);
        foreach ($ads as $ad) {
            $status = get_post_meta($ad->ID, '_mtwpgr_qcp_ad_status', true);
            $end = get_post_meta($ad->ID, '_mtwpgr_qcp_end_date', true);
            $badge = '';
            switch ($status) {
                case 'pending': $badge = '<span class="mtwpgr-qcp-badge pending">⏳ Chờ duyệt</span>'; break;
                case 'approved': $badge = '<span class="mtwpgr-qcp-badge approved">🔥 Đang chạy</span>'; break;
                case 'expired': $badge = '<span class="mtwpgr-qcp-badge expired">⏱ Hết hạn</span>'; break;
                case 'rejected': $badge = '<span class="mtwpgr-qcp-badge rejected">❌ Từ chối</span>'; break;
            }
            echo '<li style="margin-bottom:10px;"><a href="'.get_permalink($ad->ID).'" style="font-weight:600;">'.esc_html($ad->post_title).'</a> '.$badge;
            if ($end) echo ' <span style="color:#888;font-size:0.95em;">(đến '.$end.')</span>';
            if ($status === 'expired') echo ' <a href="?renew_ad='.$ad->ID.'" class="mtwpgr-qcp-btn" style="padding:2px 10px;font-size:0.95em;">Gia hạn</a>';
            echo '</li>';
        }
        ?>
        </ul>
    </div>
    <script>
    function mtwpgr_qcp_update_price() {
        var type = document.getElementById('mtwpgr_qcp_ad_type').value;
        var duration = document.getElementById('mtwpgr_qcp_duration').value;
        var prices = {hourly: 1000, daily: 15000, monthly: 300000};
        var total = prices[type] * duration;
        document.getElementById('mtwpgr_qcp_total_price').innerHTML = 'Tổng phí: <b>' + total.toLocaleString() + ' đ</b>';
    }
    mtwpgr_qcp_update_price();
    document.addEventListener('DOMContentLoaded', function() {
        var radios = document.querySelectorAll('.mtwpgr-qcp-radio');
        radios.forEach(function(radio) {
            radio.addEventListener('change', function() {
                document.querySelectorAll('.mtwpgr-qcp-post-card').forEach(function(card) {
                    card.classList.remove('selected');
                });
                if (radio.checked) {
                    radio.nextElementSibling.classList.add('selected');
                }
            });
        });
        var checked = document.querySelector('.mtwpgr-qcp-radio:checked');
        if (checked) checked.nextElementSibling.classList.add('selected');
    });
    function mtwpgrQcpShowModal(id) {
        document.getElementById('mtwpgr-qcp-modal-' + id).style.display = 'block';
    }
    function mtwpgrQcpHideModal(id) {
        document.getElementById('mtwpgr-qcp-modal-' + id).style.display = 'none';
    }
    document.getElementById('mtwpgr-qcp-ad-form').addEventListener('submit', function(e){
        if(!confirm('Bạn chắc chắn muốn gửi yêu cầu quảng cáo cho bài viết đã chọn?')) e.preventDefault();
    });
    </script>
    <?php
    return ob_get_clean();
}

// ====== Xử lý form gửi quảng cáo ======
add_action('init', 'mtwpgr_qcp_handle_frontend_form');
function mtwpgr_qcp_handle_frontend_form() {
    if (isset($_POST['mtwpgr_qcp_submit_ad'])) {
        $post_id = intval($_POST['mtwpgr_qcp_post_id']);
        $ad_type = sanitize_text_field($_POST['mtwpgr_qcp_ad_type']);
        $duration = intval($_POST['mtwpgr_qcp_duration']);
        $start = current_time('Y-m-d H:i:s');
        $user_id = get_current_user_id();
        switch ($ad_type) {
            case 'hourly': $end = date('Y-m-d H:i:s', strtotime("+$duration hour")); break;
            case 'daily': $end = date('Y-m-d H:i:s', strtotime("+$duration day")); break;
            case 'monthly': $end = date('Y-m-d H:i:s', strtotime("+$duration month")); break;
            default: $end = $start;
        }
        update_post_meta($post_id, '_mtwpgr_qcp_ad_type', $ad_type);
        update_post_meta($post_id, '_mtwpgr_qcp_start_date', $start);
        update_post_meta($post_id, '_mtwpgr_qcp_end_date', $end);
        update_post_meta($post_id, '_mtwpgr_qcp_ad_status', 'pending');
        wp_mail(get_option('admin_email'), 'Yêu cầu quảng cáo mới', "Bài viết ID $post_id cần duyệt quảng cáo.");
        mtwpgr_qcp_notify_user_ad_submitted($post_id, $user_id, $ad_type, $end);
    }
    if (isset($_GET['renew_ad']) && is_user_logged_in()) {
        $post_id = intval($_GET['renew_ad']);
        $user_id = get_current_user_id();
        $post = get_post($post_id);
        if ($post && $post->post_author == $user_id) {
            $ad_type = get_post_meta($post_id, '_mtwpgr_qcp_ad_type', true);
            $duration = 1;
            $start = current_time('Y-m-d H:i:s');
            switch ($ad_type) {
                case 'hourly': $end = date('Y-m-d H:i:s', strtotime("+$duration hour")); break;
                case 'daily': $end = date('Y-m-d H:i:s', strtotime("+$duration day")); break;
                case 'monthly': $end = date('Y-m-d H:i:s', strtotime("+$duration month")); break;
                default: $end = $start;
            }
            update_post_meta($post_id, '_mtwpgr_qcp_start_date', $start);
            update_post_meta($post_id, '_mtwpgr_qcp_end_date', $end);
            update_post_meta($post_id, '_mtwpgr_qcp_ad_status', 'pending');
            wp_redirect(add_query_arg('renewed', 1, get_permalink()));
            exit;
        }
    }
}

// ====== Hiển thị nhãn quảng cáo ngoài frontend ======
add_filter('the_title', 'mtwpgr_qcp_add_ad_label_to_title', 10, 2);
function mtwpgr_qcp_add_ad_label_to_title($title, $id) {
    if (is_admin()) return $title;
    $ad_status = get_post_meta($id, '_mtwpgr_qcp_ad_status', true);
    if ($ad_status === 'approved') {
        $title .= ' <span style="color:red;">🔥 Quảng cáo</span>';
    } elseif ($ad_status === 'pending') {
        $title .= ' <span style="color:orange;">⏳ Chờ duyệt QC</span>';
    }
    return $title;
}

// ====== Bảng giá quảng cáo theo loại ======
function mtwpgr_qcp_get_price_table() {
    return [
        'hourly' => 1000,
        'daily'  => 15000,
        'monthly'=> 300000,
    ];
}
add_shortcode('mtwpgr_qcp_pricing', function() {
    $prices = mtwpgr_qcp_get_price_table();
    ob_start(); ?>
    <h3>Bảng giá quảng cáo</h3>
    <ul>
        <li>Theo giờ: <?php echo number_format($prices['hourly']); ?> đ/giờ</li>
        <li>Theo ngày: <?php echo number_format($prices['daily']); ?> đ/ngày</li>
        <li>Theo tháng: <?php echo number_format($prices['monthly']); ?> đ/tháng</li>
    </ul>
    <?php return ob_get_clean();
});

// ====== Thông báo cho user khi đăng ký quảng cáo ======
function mtwpgr_qcp_notify_user_ad_submitted($post_id, $user_id, $ad_type, $end_time) {
    $user = get_user_by('id', $user_id);
    $post_title = get_the_title($post_id);
    $message = "Chào bạn {$user->display_name},\n\n"
        . "Bạn đã đăng ký quảng cáo bài viết: \"$post_title\"\n"
        . "Thời hạn quảng cáo đến: $end_time\n"
        . "Trạng thái: Chờ duyệt\n\n"
        . "Cảm ơn bạn đã sử dụng dịch vụ!";
    wp_mail($user->user_email, 'Đăng ký quảng cáo thành công', $message);
}
function mtwpgr_qcp_notify_user_ad_expired($post_id) {
    $author_id = get_post_field('post_author', $post_id);
    $user = get_user_by('id', $author_id);
    $title = get_the_title($post_id);
    $msg = "Chào bạn {$user->display_name},\n\n"
        . "Quảng cáo cho bài viết \"$title\" đã hết hạn.\n"
        . "Bạn có thể đăng ký lại nếu muốn tiếp tục hiển thị ưu tiên.";
    wp_mail($user->user_email, 'Quảng cáo bài viết đã hết hạn', $msg);
}

// ====== Dashboard admin nâng cấp: duyệt, từ chối, lọc, tìm kiếm ======
add_action('admin_menu', 'mtwpgr_qcp_add_admin_dashboard');
function mtwpgr_qcp_add_admin_dashboard() {
    add_menu_page(
        'Quản lý Quảng cáo Bài viết',
        'Quảng cáo Bài viết',
        'manage_options',
        'mtwpgr-qcp-dashboard',
        'mtwpgr_qcp_render_admin_dashboard',
        'dashicons-megaphone',
        30
    );
}

Kết luận

Việc triển khai hệ thống quảng cáo bài viết trên WordPress không chỉ tăng giá trị nội dung mà còn mở ra cơ hội tạo doanh thu từ website. Hệ thống MTWPGR QCP là một giải pháp tối ưu, đơn giản nhưng mạnh mẽ, phù hợp với mọi trang tin tức, blog cá nhân hoặc cổng thông tin chuyên nghiệp.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Back to top button