مجله ایرانیکاسرورآموزش سرور، هاست، وردپرس و شبکه
آموزشی

چطور در ووکامرس فاکتور PDF خودکار بسازیم و برای مشتری ارسال کنیم؟

اگر فروشگاه ووکامرسی دارید و می‌خواهید بعد از خرید، برای هر سفارش یک فایل PDF مرتب و قابل دانلود بسازید، این آموزش برای همین کار است. در پایان مقاله یک افزونه سبک اختصاصی خواهید…

چطور در ووکامرس فاکتور PDF خودکار بسازیم و برای مشتری ارسال کنیم؟
خلاصه سریع این آموزش

اگر فروشگاه ووکامرسی دارید و می‌خواهید بعد از خرید، برای هر سفارش یک فایل PDF مرتب و قابل دانلود بسازید، این آموزش برای همین کار است. در پایان مقاله یک…

۱۷ دقیقه مطالعه ۰ دیدگاه ۱۸ مهر ۱۴۰۵ آخرین به‌روزرسانی

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

مسیر این آموزش بر پایه APIهای خود ووکامرس نوشته شده است؛ یعنی برای گرفتن اطلاعات سفارش سراغ جدول‌های قدیمی wp_posts و wp_postmeta نمی‌رویم. این انتخاب مهم است، چون WooCommerce در نسخه‌های جدید از HPOS برای ذخیره سفارش‌ها استفاده می‌کند و کدی که مستقیماً به ساختار دیتابیس وابسته باشد ممکن است بعداً خراب شود.

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

فهرست مطالب

فاکتور PDF ووکامرس چیست و چه فرقی با صفحه سفارش دارد؟

خود WooCommerce اطلاعات سفارش را در پیشخوان و حساب مشتری نمایش می‌دهد، اما این صفحه یک فایل قابل ذخیره یا ارسال نیست. فاکتور PDF همان اطلاعات مهم را در قالب یک سند مستقل A4 قرار می‌دهد تا مشتری بتواند آن را دانلود، بایگانی یا چاپ کند.

در این مقاله از عبارت «فاکتور» برای سند سفارش استفاده می‌کنیم. اگر کسب‌وکار شما به فاکتور رسمی مالیاتی، شماره سریال قانونی، شناسه مالیاتی یا سامانه‌های قانونی خاص نیاز دارد، منطق شماره‌گذاری و فیلدهای حقوقی باید جداگانه با حسابدار یا الزامات قانونی کسب‌وکار تنظیم شوند. شماره سفارش ووکامرس را نباید بدون بررسی به‌عنوان شماره فاکتور رسمی در نظر گرفت.

چرا برای PDF فارسی از mPDF استفاده می‌کنیم؟

برای ساخت PDF در PHP کتابخانه‌های مختلفی وجود دارد، اما در این آموزش mPDF انتخاب شده است؛ چون از HTML مبتنی بر UTF-8 استفاده می‌کند و برای زبان‌های راست‌به‌چپ از جمله فارسی امکانات مناسبی دارد. در نتیجه عنوان‌ها، نام مشتری، آدرس و جدول کالاها را می‌توان راست‌چین و خوانا تولید کرد.

نصب رسمی mPDF از طریق Composer انجام می‌شود. Composer ابزار مدیریت کتابخانه‌های PHP است؛ یعنی وابستگی‌های لازم را دریافت می‌کند و فایل autoload را می‌سازد تا لازم نباشد فایل‌های کتابخانه را دستی یکی‌یکی بارگذاری کنیم.

📌 مقاله مرتبط

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

ساختار افزونه‌ای که می‌سازیم

به‌جای ریختن کد داخل فایل functions.php قالب، یک افزونه کوچک می‌سازیم. مزیت این کار این است که با تغییر یا به‌روزرسانی قالب، قابلیت صدور فاکتور از بین نمی‌رود.

فایل‌ها و نقش هر بخش
مسیر کاربرد
iranica-woo-pdf-invoice.php کد اصلی افزونه، تولید PDF، دکمه دانلود و پیوست ایمیل
composer.json تعریف کتابخانه mPDF
vendor/ کتابخانه mPDF و وابستگی‌هایی که Composer نصب می‌کند

پیش‌نیازها

قبل از شروع، WooCommerce باید فعال باشد و شما باید به فایل‌های وردپرس دسترسی داشته باشید. بهترین حالت، دسترسی SSH است؛ ولی در هاست‌هایی که SSH ندارند می‌توانید افزونه و پوشه vendor را روی رایانه یا محیط توسعه بسازید و بعد با File Manager یا SFTP آپلود کنید.

mPDF به PHP و افزونه‌های PHP مثل mbstring و gd نیاز دارد. قبل از نصب، نسخه PHP هاست را با نسخه mPDF که Composer انتخاب می‌کند تطبیق دهید.

مرحله ۱: پوشه افزونه را بسازید

در مسیر افزونه‌های وردپرس یعنی wp-content/plugins/ یک پوشه با نام زیر بسازید:

iranica-woo-pdf-invoice

اگر با SSH کار می‌کنید، ابتدا وارد ریشه وردپرس شوید و بعد دستورهای زیر را اجرا کنید:

cd wp-content/plugins
mkdir iranica-woo-pdf-invoice
cd iranica-woo-pdf-invoice

مرحله ۲: mPDF را نصب کنید

دستور زیر را داخل همان پوشه افزونه اجرا کنید. Composer نسخه‌ای سازگار با محیط PHP شما را انتخاب و پوشه vendor را ایجاد می‌کند:

composer require mpdf/mpdf

بعد از پایان نصب باید فایل vendor/autoload.php وجود داشته باشد. اگر این فایل ساخته نشده، ادامه آموزش اجرا نخواهد شد.

⚠️ نکته: پوشه vendor را از یک پروژه نامرتبط کپی نکنید. Composer باید وابستگی‌های mPDF را برای همین پروژه نصب کند. قبل از تغییر روی سایت اصلی نیز بکاپ بگیرید.

مرحله ۳: فایل اصلی افزونه را بسازید

در پوشه iranica-woo-pdf-invoice فایلی با نام iranica-woo-pdf-invoice.php بسازید و کل کد زیر را داخل آن قرار دهید. این کد چهار کار انجام می‌دهد: اطلاعات سفارش را از WooCommerce می‌گیرد، PDF می‌سازد، دانلود امن را به حساب مشتری اضافه می‌کند و PDF را به ایمیل سفارش پیوست می‌کند.

<?php
/**
 * Plugin Name: Iranica Woo PDF Invoice
 * Description: ساخت فاکتور PDF فارسی برای سفارش‌های WooCommerce
 * Version: 1.0.0
 */

defined( 'ABSPATH' ) || exit;

function iranica_pdf_autoload() {
    $autoload = __DIR__ . '/vendor/autoload.php';

    if ( file_exists( $autoload ) ) {
        require_once $autoload;
        return true;
    }

    return false;
}

function iranica_pdf_invoice_html( WC_Order $order ) {
    $order_number = $order->get_order_number();
    $created      = $order->get_date_created();
    $date         = $created ? wc_format_datetime( $created, 'Y/m/d H:i' ) : '';

    $billing_name = trim(
        $order->get_billing_first_name() . ' ' .
        $order->get_billing_last_name()
    );

    $billing_address = $order->get_formatted_billing_address();
    $billing_phone   = $order->get_billing_phone();
    $billing_email   = $order->get_billing_email();

    $rows = '';

    foreach ( $order->get_items() as $item ) {
        if ( ! $item instanceof WC_Order_Item_Product ) {
            continue;
        }

        $product = $item->get_product();
        $sku     = $product ? $product->get_sku() : '';

        $rows .= '<tr>';
        $rows .= '<td>' . esc_html( $item->get_name() ) . '</td>';
        $rows .= '<td>' . esc_html( $sku ?: '-' ) . '</td>';
        $rows .= '<td>' . esc_html( $item->get_quantity() ) . '</td>';
        $rows .= '<td>' . wp_kses_post(
            wc_price(
                $item->get_total(),
                array( 'currency' => $order->get_currency() )
            )
        ) . '</td>';
        $rows .= '</tr>';
    }

    $totals_html = '';

    foreach ( $order->get_order_item_totals() as $total ) {
        $totals_html .= '<tr>';
        $totals_html .= '<th colspan="3">' . esc_html(
            wp_strip_all_tags( $total['label'] )
        ) . '</th>';
        $totals_html .= '<td>' . wp_kses_post( $total['value'] ) . '</td>';
        $totals_html .= '</tr>';
    }

    $payment_method = $order->get_payment_method_title();

    return '
    <div lang="fa" dir="rtl" style="direction:rtl; text-align:right;">
        <h1 style="text-align:center; font-size:22px; margin-bottom:18px;">
            فاکتور سفارش شماره ' . esc_html( $order_number ) . '
        </h1>

        <table style="width:100%; border-collapse:collapse; margin-bottom:18px;">
            <tr>
                <td style="padding:7px; border:1px solid #cccccc;">
                    تاریخ سفارش
                </td>
                <td style="padding:7px; border:1px solid #cccccc;">' .
                    esc_html( $date ) .
                '</td>
            </tr>
            <tr>
                <td style="padding:7px; border:1px solid #cccccc;">
                    روش پرداخت
                </td>
                <td style="padding:7px; border:1px solid #cccccc;">' .
                    esc_html( $payment_method ?: '-' ) .
                '</td>
            </tr>
        </table>

        <h2 style="font-size:17px;">مشخصات خریدار</h2>

        <p>
            <strong>نام:</strong> ' . esc_html( $billing_name ?: '-' ) . '<br>
            <strong>تلفن:</strong> ' . esc_html( $billing_phone ?: '-' ) . '<br>
            <strong>ایمیل:</strong> ' . esc_html( $billing_email ?: '-' ) . '<br>
            <strong>آدرس:</strong> ' .
                wp_kses_post( $billing_address ?: '-' ) .
        '</p>

        <h2 style="font-size:17px;">اقلام سفارش</h2>

        <table style="width:100%; border-collapse:collapse;">
            <thead>
                <tr>
                    <th style="padding:7px; border:1px solid #cccccc;">کالا</th>
                    <th style="padding:7px; border:1px solid #cccccc;">کد کالا</th>
                    <th style="padding:7px; border:1px solid #cccccc;">تعداد</th>
                    <th style="padding:7px; border:1px solid #cccccc;">مبلغ</th>
                </tr>
            </thead>
            <tbody>' .
                $rows .
                $totals_html .
            '</tbody>
        </table>

        <p style="margin-top:20px; font-size:11px; color:#555555;">
            این فایل به‌صورت خودکار از اطلاعات سفارش WooCommerce ساخته شده است.
        </p>
    </div>';
}

function iranica_generate_pdf_invoice( WC_Order $order ) {
    if ( ! iranica_pdf_autoload() ) {
        throw new RuntimeException( 'mPDF autoload file not found.' );
    }

    $temp_dir = trailingslashit( get_temp_dir() ) . 'iranica-mpdf';

    if ( ! is_dir( $temp_dir ) ) {
        wp_mkdir_p( $temp_dir );
    }

    if ( ! is_dir( $temp_dir ) || ! is_writable( $temp_dir ) ) {
        throw new RuntimeException( 'mPDF temp directory is not writable.' );
    }

    $mpdf = new \Mpdf\Mpdf(
        array(
            'mode'         => 'utf-8',
            'format'       => 'A4',
            'default_font' => 'dejavusans',
            'margin_top'   => 12,
            'margin_right' => 12,
            'margin_bottom'=> 12,
            'margin_left'  => 12,
            'tempDir'      => $temp_dir,
        )
    );

    $mpdf->SetDirectionality( 'rtl' );
    $mpdf->WriteHTML( iranica_pdf_invoice_html( $order ) );

    return $mpdf->Output(
        '',
        \Mpdf\Output\Destination::STRING_RETURN
    );
}

function iranica_invoice_filename( WC_Order $order ) {
    return 'invoice-order-' .
        sanitize_file_name( $order->get_order_number() ) .
        '.pdf';
}

add_filter(
    'woocommerce_my_account_my_orders_actions',
    function( $actions, $order ) {
        if ( ! $order instanceof WC_Order ) {
            return $actions;
        }

        if ( ! $order->is_paid() ) {
            return $actions;
        }

        $url = wp_nonce_url(
            add_query_arg(
                array(
                    'iranica_pdf_invoice' => 1,
                    'order_id'            => $order->get_id(),
                ),
                home_url( '/' )
            ),
            'iranica_pdf_invoice_' . $order->get_id()
        );

        $actions['iranica_pdf_invoice'] = array(
            'url'  => $url,
            'name' => 'دانلود فاکتور PDF',
        );

        return $actions;
    },
    20,
    2
);

add_action(
    'template_redirect',
    function() {
        if ( empty( $_GET['iranica_pdf_invoice'] ) ) {
            return;
        }

        if ( ! is_user_logged_in() ) {
            wp_die( 'برای دانلود فاکتور ابتدا وارد حساب کاربری شوید.' );
        }

        $order_id = isset( $_GET['order_id'] )
            ? absint( $_GET['order_id'] )
            : 0;

        $nonce = isset( $_GET['_wpnonce'] )
            ? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) )
            : '';

        if (
            ! $order_id ||
            ! wp_verify_nonce(
                $nonce,
                'iranica_pdf_invoice_' . $order_id
            )
        ) {
            wp_die( 'درخواست دانلود معتبر نیست.' );
        }

        $order = wc_get_order( $order_id );

        if ( ! $order instanceof WC_Order ) {
            wp_die( 'سفارش پیدا نشد.' );
        }

        $is_owner = (int) $order->get_user_id() === get_current_user_id();
        $is_admin = current_user_can( 'manage_woocommerce' );

        if ( ! $is_owner && ! $is_admin ) {
            wp_die( 'شما اجازه دسترسی به این فاکتور را ندارید.' );
        }

        if ( ! $order->is_paid() && ! $is_admin ) {
            wp_die( 'فاکتور این سفارش هنوز قابل دانلود نیست.' );
        }

        try {
            $pdf = iranica_generate_pdf_invoice( $order );
        } catch ( Throwable $e ) {
            if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
                error_log( 'Iranica PDF Invoice: ' . $e->getMessage() );
            }

            wp_die( 'در ساخت فایل PDF خطایی رخ داد.' );
        }

        nocache_headers();
        header( 'Content-Type: application/pdf' );
        header(
            'Content-Disposition: attachment; filename="' .
            iranica_invoice_filename( $order ) .
            '"'
        );
        header( 'Content-Length: ' . strlen( $pdf ) );

        echo $pdf;
        exit;
    }
);

add_filter(
    'woocommerce_email_attachments',
    function( $attachments, $email_id, $object, $email = null ) {
        $allowed_email_ids = array(
            'customer_processing_order',
            'customer_completed_order',
        );

        if ( ! in_array( $email_id, $allowed_email_ids, true ) ) {
            return $attachments;
        }

        if ( ! $object instanceof WC_Order ) {
            return $attachments;
        }

        if ( ! $object->is_paid() ) {
            return $attachments;
        }

        try {
            $pdf = iranica_generate_pdf_invoice( $object );
        } catch ( Throwable $e ) {
            if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
                error_log( 'Iranica PDF Invoice: ' . $e->getMessage() );
            }

            return $attachments;
        }

        $tmp_file = wp_tempnam( iranica_invoice_filename( $object ) );

        if ( ! $tmp_file ) {
            return $attachments;
        }

        if ( false === file_put_contents( $tmp_file, $pdf ) ) {
            @unlink( $tmp_file );
            return $attachments;
        }

        $attachments[] = $tmp_file;

        register_shutdown_function(
            static function() use ( $tmp_file ) {
                if ( file_exists( $tmp_file ) ) {
                    @unlink( $tmp_file );
                }
            }
        );

        return $attachments;
    },
    20,
    4
);

این کد دقیقاً چه کاری انجام می‌دهد؟

تابع iranica_pdf_invoice_html() اطلاعات را از شیء WC_Order می‌گیرد. این شیء رابط استاندارد WooCommerce برای دسترسی به سفارش است و به همین دلیل لازم نیست بدانیم اطلاعات سفارش داخل کدام جدول دیتابیس ذخیره شده است.

تابع iranica_generate_pdf_invoice() همان HTML را به mPDF می‌دهد، جهت سند را راست‌به‌چپ می‌کند و PDF را به‌صورت رشته باینری برمی‌گرداند. فایل دائمی داخل پوشه عمومی سایت ذخیره نمی‌شود؛ این تصمیم خطر افشای اطلاعات مشتری از طریق URL مستقیم فایل را کمتر می‌کند.

برای دانلود، URL با Nonce ساخته می‌شود. Nonce یک توکن امنیتی کوتاه‌عمر وردپرس است که کمک می‌کند یک لینک ساختگی نتواند به‌سادگی برای دریافت فاکتور استفاده شود. علاوه بر آن، کد بررسی می‌کند سفارش متعلق به کاربر واردشده باشد یا کاربر دسترسی مدیریت WooCommerce داشته باشد.

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

مرحله ۴: افزونه را فعال کنید

بعد از ذخیره فایل، وارد پیشخوان وردپرس شوید و از بخش «افزونه‌ها» افزونه Iranica Woo PDF Invoice را فعال کنید.

اگر هنگام فعال‌سازی خطای سفید یا Fatal Error دیدید، ابتدا وجود فایل زیر را بررسی کنید:

wp-content/plugins/iranica-woo-pdf-invoice/vendor/autoload.php

نبودن این فایل معمولاً یعنی دستور Composer در مسیر اشتباه اجرا شده یا پوشه vendor هنگام آپلود جا افتاده است.

فروشگاه ووکامرسی دارید و منابع هاست کم می‌آورد؟

تولید PDF، پردازش سفارش، ایمیل‌های ووکامرس و افزونه‌های فروشگاهی همگی از PHP و RAM استفاده می‌کنند. اگر فروشگاه هم‌زمان سفارش زیادی پردازش می‌کند، هنگام انتخاب میزبانی فقط فضای دیسک را نبینید؛ نسخه PHP، حافظه قابل استفاده، محدودیت پردازش و سرعت دیتابیس نیز مهم‌اند.

تماس با پشتیبانی ایرانیکاسرور: 021-91302467

مرحله ۵: دانلود PDF را آزمایش کنید

یک سفارش آزمایشی ایجاد کنید و آن را واقعاً در وضعیت پرداخت‌شده قرار دهید. سپس با همان حساب مشتری وارد شوید و به مسیر «حساب کاربری ← سفارش‌ها» بروید. کنار سفارش باید دکمه دانلود فاکتور PDF دیده شود.

با کلیک روی آن باید مرورگر یک فایل با نامی شبیه نمونه زیر دانلود کند:

invoice-order-1426.pdf

داخل فایل نام مشتری، آدرس صورتحساب، اقلام، تعداد و جمع سفارش را بررسی کنید. اگر فارسی درست ولی فونت ظاهری دلخواه شما نیست، در مرحله بعد می‌توانید فونت اختصاصی فارسی را به mPDF معرفی کنید.

مرحله ۶: ارسال فاکتور همراه ایمیل سفارش را تست کنید

کدی که ساختیم PDF را برای دو ایمیل مشتری اضافه می‌کند: ایمیل سفارش در حال پردازش و ایمیل سفارش تکمیل‌شده. دلیل انتخاب هر دو این است که بعضی سفارش‌ها بعد از پرداخت وارد Processing می‌شوند و بعضی محصولات مجازی یا جریان‌های سفارشی ممکن است مستقیم Completed شوند.

اگر نمی‌خواهید مشتری در هر دو ایمیل فاکتور دریافت کند، آرایه زیر را در کد پیدا کنید و فقط شناسه ایمیل موردنظر را نگه دارید:

$allowed_email_ids = array(
    'customer_processing_order',
    'customer_completed_order',
);

برای فروشگاه کالای فیزیکی معمولاً ایمیل Processing زمان منطقی‌تری است؛ برای برخی فروشگاه‌ها ممکن است Completed مناسب‌تر باشد. این تصمیم باید با فرایند واقعی فروشگاه هماهنگ شود.

چطور لوگو و مشخصات فروشگاه را به فاکتور اضافه کنیم؟

در نمونه پایه عمداً لوگو و اطلاعات ثابت فروشنده را وارد نکردیم تا کد برای همه فروشگاه‌ها قابل استفاده باشد. برای شخصی‌سازی، داخل تابع iranica_pdf_invoice_html() و بالای عنوان فاکتور می‌توانید نام فروشگاه، تلفن، آدرس و شناسه‌های موردنیاز خودتان را اضافه کنید.

اگر لوگو اضافه می‌کنید، بهتر است از مسیر فایل محلی استفاده شود نه URL بیرونی. این کار وابستگی تولید PDF به اینترنت یا درخواست HTTP اضافه را کم می‌کند. مسیر فایل باید واقعی باشد و mPDF اجازه خواندن آن را داشته باشد.

شماره فاکتور را چطور مستقل از شماره سفارش کنیم؟

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

برای فروشگاه پرتراکنش، ساخت شماره ترتیبی با خواندن «آخرین شماره + ۱» بدون قفل یا تراکنش می‌تواند باعث شماره تکراری شود؛ چون دو سفارش ممکن است هم‌زمان همان آخرین مقدار را بخوانند. اگر شماره رسمی و ترتیبی برای شما اهمیت دارد، این بخش باید با جدول اختصاصی و محدودیت یکتا طراحی شود.

سازگاری با HPOS

یکی از مهم‌ترین مزیت‌های این پیاده‌سازی این است که اطلاعات سفارش از متدهای WC_Order گرفته می‌شود. یعنی کد برای پیدا کردن نام، مبلغ یا اقلام سفارش Query مستقیم روی جدول‌های قدیمی وردپرس اجرا نمی‌کند.

WooCommerce برای افزونه‌های جدید توصیه می‌کند سفارش‌ها از APIهای خودش خوانده شوند. این کار باعث می‌شود افزونه وابستگی کمتری به محل فیزیکی ذخیره داده داشته باشد و مهاجرت بین Legacy Storage و HPOS آسیب کمتری ایجاد کند.

خطاهای رایج

خطای Class Mpdf not found

این خطا تقریباً همیشه به autoload مربوط است. مسیر vendor/autoload.php را بررسی کنید و مطمئن شوید Composer داخل پوشه همین افزونه اجرا شده است.

PDF ساخته می‌شود ولی فارسی خراب است

اول بررسی کنید فایل PHP و داده‌ها UTF-8 باشند. سپس مطمئن شوید جهت سند RTL است و فونت انتخاب‌شده حروف فارسی را پوشش می‌دهد. در کد نمونه از DejaVu Sans استفاده شده تا برای شروع وابستگی به فونت خارجی نداشته باشیم.

دکمه دانلود نمایش داده نمی‌شود

کد فقط برای سفارش پرداخت‌شده دکمه را نشان می‌دهد. ابتدا وضعیت و مقدار is_paid() سفارش را بررسی کنید. سپس با همان کاربری وارد شوید که سفارش متعلق به اوست.

فاکتور به ایمیل وصل نمی‌شود

بررسی کنید ایمیل موردنظر واقعاً یکی از customer_processing_order یا customer_completed_order باشد. همچنین خطاهای PHP و لاگ ارسال ایمیل را بررسی کنید؛ اگر mPDF هنگام ساخت فایل Exception بدهد، کد برای جلوگیری از خراب‌شدن کل ایمیل، همان ایمیل را بدون PDF ادامه می‌دهد.

خطای نوشتن پوشه موقت mPDF

mPDF برای پردازش به پوشه موقت قابل نوشتن نیاز دارد. کد داخل get_temp_dir() پوشه iranica-mpdf می‌سازد. اگر PHP اجازه ساخت یا نوشتن در این مسیر را ندارد، سطح دسترسی و تنظیمات PHP هاست را بررسی کنید؛ راه‌حل عمومی این خطا دادن مجوز 777 به پوشه‌ها نیست.

نکات امنیتی مهم

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

Nonce به‌تنهایی جای کنترل مالکیت سفارش را نمی‌گیرد. در کد هر دو بررسی انجام شده‌اند: لینک باید Nonce معتبر داشته باشد و Order ID نیز باید متعلق به همان کاربر باشد؛ مدیر WooCommerce استثناست.

اطلاعات مشتری را بی‌دلیل در error_log ننویسید. لاگ خطا بهتر است فقط پیام فنی موردنیاز برای عیب‌یابی را ثبت کند.

آزمایش نهایی قبل از استفاده روی فروشگاه اصلی

سناریوهایی که باید بررسی شوند
آزمایش نتیجه مورد انتظار
سفارش پرداخت‌نشده مشتری دکمه فاکتور نبیند و PDF ایمیل نشود.
سفارش پرداخت‌شده دکمه دانلود ظاهر شود.
دانلود با حساب مشتری دیگر دسترسی رد شود.
سفارش دارای تخفیف و ارسال جمع‌های WooCommerce در PDF کامل نمایش داده شوند.
محصول با نام فارسی متن بدون جداشدگی حروف یا به‌هم‌ریختگی RTL دیده شود.
ایمیل Processing یا Completed فایل PDF سالم به پیام پیوست شود.

پرسش‌های متداول

آیا بدون افزونه آماده می‌توان فاکتور PDF ووکامرس ساخت؟

بله. این آموزش یک افزونه کوچک اختصاصی می‌سازد که از APIهای خود WooCommerce و کتابخانه mPDF استفاده می‌کند و به افزونه تجاری صدور فاکتور وابسته نیست.

آیا کد با HPOS ووکامرس سازگار است؟

منطق اصلی با WC_Order و wc_get_order() کار می‌کند و مستقیم جدول‌های قدیمی سفارش را Query نمی‌کند؛ این همان الگوی مناسب برای کاهش وابستگی به شیوه ذخیره فیزیکی سفارش است.

آیا فاکتور می‌تواند خودکار ایمیل شود؟

بله. فیلتر woocommerce_email_attachments اجازه می‌دهد فایل PDF به ایمیل‌های WooCommerce پیوست شود. در نمونه مقاله فقط ایمیل‌های مشتری برای سفارش پرداخت‌شده هدف قرار گرفته‌اند.

آیا می‌توان لوگو، مهر یا اطلاعات مالیاتی اضافه کرد؟

بله. HTML فاکتور کاملاً قابل تغییر است. لوگو، مشخصات فروشنده، شناسه مالیاتی، توضیحات پرداخت و سایر اطلاعات را می‌توان به قالب PDF اضافه کرد؛ فقط برای اسناد رسمی باید الزامات قانونی کسب‌وکار جداگانه بررسی شوند.

آیا PDF باید روی هاست ذخیره شود؟

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

آیا می‌توان فاکتور را برای سفارش‌های قدیمی هم دانلود کرد؟

بله. چون PDF هنگام درخواست از اطلاعات فعلی WC_Order ساخته می‌شود، سفارش قدیمی پرداخت‌شده نیز می‌تواند فاکتور داشته باشد؛ البته اگر اطلاعات سفارش قدیمی حذف یا تغییر داده شده باشند، PDF همان داده موجود فعلی را نشان می‌دهد.

منابع این آموزش

🔹 مستندات سفارش‌های WooCommerce و wc_get_orders — مرجع رسمی برای خواندن سفارش‌ها بدون وابستگی به Query مستقیم دیتابیس.

🔹 مستندات HPOS ووکامرس — توضیح ساختار جدید ذخیره سفارش و دلیل استفاده از CRUD/API رسمی.

🔹 Code Reference حساب کاربری WooCommerce — مرجع فیلتر اکشن‌های سفارش در My Account.

🔹 Code Reference ایمیل WooCommerce — مرجع فیلتر پیوست‌های ایمیل.

🔹 مخزن رسمی mPDF و راهنمای زبان‌های RTL در mPDF — مرجع نصب با Composer و پشتیبانی متن فارسی و راست‌به‌چپ.

جمع‌بندی

برای ساخت فاکتور PDF ووکامرس لازم نیست مستقیم دیتابیس سفارش‌ها را بخوانید یا فایل‌های حاوی اطلاعات مشتری را در پوشه عمومی نگه دارید. با WC_Order، mPDF، فیلتر اکشن‌های حساب کاربری و فیلتر پیوست ایمیل می‌توان یک مسیر تمیز ساخت که PDF فارسی را هنگام نیاز تولید کند، مالکیت سفارش را بررسی کند و فایل را به ایمیل مشتری وصل کند. بعد از راه‌اندازی نسخه پایه، می‌توانید لوگو، شماره فاکتور مستقل، مشخصات مالیاتی، QR Code و قالب اختصاصی برند را به همین ساختار اضافه کنید.

برای کانفیگ فروشگاه یا سرور کمک می‌خواهید؟

اگر هنگام نصب Composer، فعال‌سازی PHP Extensionها، خطای mPDF یا اجرای افزونه روی سرور با مشکل روبه‌رو شدید، می‌توانید درخواست بررسی و کانفیگ متناسب با سرویس خود را ثبت کنید.

تماس با پشتیبانی ایرانیکاسرور: 021-91302467

اشتراک‌گذاری مقاله
گفت‌وگو درباره آموزش

دیدگاه‌ها (۰)

هنوز دیدگاهی ثبت نشده است.

دیدگاه یا سؤال خود را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *