PDF Download Tracker

If you want to know how many people open/download/view your pdf file, follow below

Classes

Insert this class in your button wrap - pdf-tracker

Snippets

/**
 * PDF Download Tracker
 * Tracks PDF clicks and provides an admin dashboard
 * with the ability to delete/reset individual records.
 */


/* =========================================================
 * 1. AJAX CLICK TRACKING
 * ========================================================= */

add_action('wp_ajax_track_pdf_download', 'my_pdf_track_download');
add_action('wp_ajax_nopriv_track_pdf_download', 'my_pdf_track_download');

function my_pdf_track_download() {

    if (empty($_POST['url'])) {
        wp_die();
    }

    $url = esc_url_raw(wp_unslash($_POST['url']));
    $path = parse_url($url, PHP_URL_PATH);

    // Only track PDF files
    if (strtolower(pathinfo($path, PATHINFO_EXTENSION)) !== 'pdf') {
        wp_die();
    }

    // Unique ID based on PDF URL
    $id = md5($url);

    $key = 'pdf_tracker_' . $id;

    // Get existing data
    $data = get_option($key, array());

    if (!is_array($data)) {
        $data = array();
    }

    // Extract readable filename
    $filename = basename($path);
    $filename = urldecode($filename);

    // Update data
    $data['filename'] = sanitize_text_field($filename);
    $data['url']      = $url;

    /*
     * NEW PDF STARTING COUNT
     *
     * Currently set so that the FIRST click shows as 101.
     * Change 101 to 1 if you ever want normal counting.
     */
    $data['count'] = isset($data['count'])
        ? (int) $data['count'] + 1
        : 101;

    $data['last_click'] = current_time('mysql');

    update_option($key, $data, false);

    wp_die();
}


/* =========================================================
 * 2. FRONT-END CLICK DETECTION
 * ========================================================= */

add_action('wp_footer', function () {
    ?>
    <script>
    document.addEventListener('click', function(e) {

        const link = e.target.closest('a');

        if (!link) return;

        // Works whether the class is on <a> or its parent/wrapper
        const shouldTrack =
            link.classList.contains('track-pdf-download') ||
            link.closest('.track-pdf-download');

        if (!shouldTrack) return;

        const pdfUrl = link.href;

        if (!pdfUrl) return;

        try {

            const url = new URL(pdfUrl);

            // Only track PDF files
            if (!url.pathname.toLowerCase().endsWith('.pdf')) {
                return;
            }

        } catch (error) {
            return;
        }

        const data = new FormData();

        data.append('action', 'track_pdf_download');
        data.append('url', pdfUrl);

        if (navigator.sendBeacon) {

            navigator.sendBeacon(
                '<?php echo esc_url(admin_url('admin-ajax.php')); ?>',
                data
            );

        } else {

            fetch(
                '<?php echo esc_url(admin_url('admin-ajax.php')); ?>',
                {
                    method: 'POST',
                    body: data,
                    keepalive: true
                }
            );

        }

    });
    </script>
    <?php
});


/* =========================================================
 * 3. WORDPRESS ADMIN MENU
 * ========================================================= */

add_action('admin_menu', function () {

    add_menu_page(
        'PDF Downloads',
        'PDF Downloads',
        'manage_options',
        'pdf-downloads',
        'my_pdf_download_dashboard',
        'dashicons-media-document',
        30
    );

});


/* =========================================================
 * 4. DELETE PDF TRACKING RECORD
 * ========================================================= */

add_action('admin_post_delete_pdf_tracking', 'my_delete_pdf_tracking');

function my_delete_pdf_tracking() {

    // Only administrators / users with this capability
    if (!current_user_can('manage_options')) {
        wp_die('You do not have permission to do this.');
    }

    // Make sure ID exists
    if (empty($_GET['pdf_id'])) {
        wp_die('Invalid PDF tracking record.');
    }

    $pdf_id = sanitize_text_field(wp_unslash($_GET['pdf_id']));

    // MD5 IDs must contain exactly 32 hexadecimal characters
    if (!preg_match('/^[a-f0-9]{32}$/', $pdf_id)) {
        wp_die('Invalid PDF ID.');
    }

    // Security check
    check_admin_referer(
        'delete_pdf_tracking_' . $pdf_id
    );

    // Delete tracking record
    delete_option(
        'pdf_tracker_' . $pdf_id
    );

    // Return to dashboard
    wp_safe_redirect(
        add_query_arg(
            'pdf_deleted',
            '1',
            admin_url('admin.php?page=pdf-downloads')
        )
    );

    exit;
}


/* =========================================================
 * 5. PDF DOWNLOAD DASHBOARD
 * ========================================================= */

function my_pdf_download_dashboard() {

    global $wpdb;

    if (!current_user_can('manage_options')) {
        return;
    }

    $results = $wpdb->get_results(
        "SELECT option_name, option_value
         FROM {$wpdb->options}
         WHERE option_name LIKE 'pdf_tracker_%'"
    );

    $downloads = array();

    foreach ($results as $row) {

        $data = maybe_unserialize($row->option_value);

        if (!is_array($data)) {
            continue;
        }

        // Extract the PDF ID from the option name
        $data['pdf_id'] = str_replace(
            'pdf_tracker_',
            '',
            $row->option_name
        );

        $downloads[] = $data;
    }


    // Highest downloads first
    usort($downloads, function ($a, $b) {

        return ($b['count'] ?? 0) <=> ($a['count'] ?? 0);

    });

    ?>

    <div class="wrap">

        <h1>PDF Downloads</h1>


        <?php
        /* Success message after deleting a record */
        if (
            isset($_GET['pdf_deleted']) &&
            $_GET['pdf_deleted'] === '1'
        ) :
        ?>

            <div class="notice notice-success is-dismissible">
                <p>
                    PDF tracking record deleted successfully.
                </p>
            </div>

        <?php endif; ?>


        <p>
            PDF button clicks recorded by your website.
        </p>


        <table class="widefat striped">

            <thead>

                <tr>

                    <th>PDF File</th>

                    <th style="width:120px;">
                        Downloads
                    </th>

                    <th style="width:220px;">
                        Last Click
                    </th>

                    <th style="width:120px;">
                        Action
                    </th>

                </tr>

            </thead>


            <tbody>

            <?php if (!empty($downloads)) : ?>


                <?php foreach ($downloads as $data) : ?>

                    <tr>


                        <!-- PDF FILE -->

                        <td>

                            <?php if (!empty($data['url'])) : ?>

                                <a
                                    href="<?php echo esc_url($data['url']); ?>"
                                    target="_blank"
                                    rel="noopener"
                                >

                                    <strong>

                                        <?php
                                        echo esc_html(
                                            $data['filename'] ?? 'Unknown PDF'
                                        );
                                        ?>

                                    </strong>

                                </a>

                            <?php else : ?>

                                <?php
                                echo esc_html(
                                    $data['filename'] ?? 'Unknown PDF'
                                );
                                ?>

                            <?php endif; ?>

                        </td>



                        <!-- DOWNLOAD COUNT -->

                        <td>

                            <strong>

                                <?php
                                echo number_format_i18n(
                                    (int) ($data['count'] ?? 0)
                                );
                                ?>

                            </strong>

                        </td>



                        <!-- LAST CLICK -->

                        <td>

                            <?php

                            if (!empty($data['last_click'])) {

                                echo esc_html(
                                    mysql2date(
                                        get_option('date_format') . ' ' .
                                        get_option('time_format'),
                                        $data['last_click']
                                    )
                                );

                            } else {

                                echo '—';

                            }

                            ?>

                        </td>



                        <!-- DELETE BUTTON -->

                        <td>

                            <?php

                            $delete_url = wp_nonce_url(

                                admin_url(
                                    'admin-post.php?action=delete_pdf_tracking&pdf_id=' .
                                    urlencode($data['pdf_id'])
                                ),

                                'delete_pdf_tracking_' . $data['pdf_id']

                            );

                            ?>

                            <a
                                href="<?php echo esc_url($delete_url); ?>"
                                class="button button-small"
                                style="color:#b32d2e;"
                                onclick="return confirm('Are you sure you want to delete this PDF tracking record? The download count will be removed.');"
                            >
                                Delete
                            </a>

                        </td>


                    </tr>

                <?php endforeach; ?>


            <?php else : ?>

                <tr>

                    <td colspan="4">

                        No PDF downloads have been recorded yet.

                    </td>

                </tr>

            <?php endif; ?>

            </tbody>

        </table>

    </div>

    <?php
}
Copyright © 2026 Siam Naulak.
magnifiercrossmenu