欢迎光临好主题官网!致力于 WordPress 企业主题定制开发及 WP外贸模板下载。

Elementor + ACF 实现产品附件下载:提交表单后自动下载并关闭弹窗

文章目录

一、需求背景

在使用 WordPress 搭建企业展示型网站时,产品详情页经常需要提供 PDF 产品手册、产品目录、技术参数表、安装说明书等资料供访客下载。

如果直接在产品详情页放置附件下载链接,访客无需填写任何信息即可获取资料,企业很难收集潜在客户的联系方式。

一种比较实用的方案是:用户点击下载按钮后,先填写 Elementor 原生表单,提交成功后自动下载当前产品对应的附件,并关闭弹窗。

本文介绍如何使用 Elementor、ACF(Advanced Custom Fields)以及少量 PHP 和 JavaScript 实现这一功能,无需额外安装专门的表单插件。

二、应用场景

这种方案适合以下网站类型:

  • 工业制造企业网站: 下载产品目录、技术参数、产品说明书。
  • 外贸企业网站: 下载产品宣传册、PDF 产品手册和技术文档。
  • 机械设备网站: 下载设备规格书、操作手册和安装指南。
  • 电子元器件网站: 下载产品 Datasheet、规格书和技术资料。
  • 企业解决方案网站: 下载白皮书、行业报告和解决方案文档。

例如,一个工业设备网站有 100 个产品,每个产品都有不同的 PDF 技术资料。通过 ACF 为每个产品单独设置附件,就可以使用同一套 Elementor 弹窗和表单完成所有产品的资料下载,无需为每个产品单独创建下载表单。

三、技术方案与实现原理

本方案使用以下技术:

技术 主要用途
WordPress 网站基础框架
Elementor Pro 产品详情页、弹窗及原生表单
ACF 为每个产品配置独立附件
PHP 获取附件 URL、处理 AJAX 请求
JavaScript / jQuery 传递产品 ID、监听表单提交、触发下载及关闭弹窗

整体流程如下:

  1. 用户进入产品详情页。
  2. 点击 Download Leaflet 按钮,打开 Elementor 弹窗。
  3. JavaScript 获取当前产品 ID,并写入表单隐藏字段。
  4. 用户填写姓名、邮箱、联系方式等信息并提交表单。
  5. Elementor 完成表单验证和配置的提交操作。
  6. JavaScript 监听提交成功事件,向 WordPress AJAX 接口请求附件地址。
  7. PHP 根据产品 ID 读取 ACF 的 product_file 字段。
  8. 浏览器触发文件下载。
  9. 下载操作触发后,自动关闭 Elementor 弹窗。

需要注意,Elementor 表单的提交成功事件与 AJAX 获取附件地址是两个不同的过程。只有表单提交成功后,才开始获取附件并触发下载。

四、第一步:使用 ACF 创建产品附件字段

首先,在 ACF 中创建一个文件字段。

建议设置如下:

配置项 设置值
Field Label Product File
Field Name product_file
Field Type File
Return Format File URL
Location 对应的产品文章类型

如果产品使用 WooCommerce,可以将字段关联到产品(Product);如果使用自定义文章类型,也可以关联到对应的 CPT。

设置完成后,进入产品编辑页面,为不同产品上传对应的 PDF 文件。

例如:

  • 产品 A → product-a.pdf
  • 产品 B → product-b.pdf
  • 产品 C → product-c.pdf

这样,同一套模板就能根据当前产品动态获取不同附件。

由于字段返回格式设置为 URL,PHP 可以直接使用:

$file_url = get_field( 'product_file', $product_id );

这里返回的是文件 URL 字符串,而不是包含 URL、标题和文件 ID 的数组。

五、第二步:创建 Elementor 弹窗

在 Elementor Pro 的弹窗功能中创建一个下载弹窗。

可以放置以下内容:

  • 标题:Download Product Brochure
  • 提示文字:Please submit the form below. Your download will start automatically after successful submission.
  • Elementor 原生 Form 表单

表单字段可以根据业务需求配置:

  • Name
  • Email
  • Phone / WhatsApp / WeChat
  • Message

对于工业品和外贸网站,邮箱通常是比较重要的客户线索字段。可以根据实际情况设置必填规则。

配置表单提交操作

在 Actions After Submit 中保留需要的操作,例如:

  • Email:发送客户信息通知。
  • Collect Submissions:保存提交记录(如已启用)。

不要配置会提前跳转到其他页面的 Redirect 操作,否则可能影响后续下载流程。

六、第三步:给下载按钮和表单设置标识

为了让 JavaScript 准确找到目标按钮与表单,需要设置 CSS 类和 CSS ID。

1. 下载按钮

选中产品详情页中的 Download Leaflet 按钮,在 Advanced → CSS Classes 中填写:

hzt-download-trigger

如果原来已经有 CSS 类,只需要追加这个类名,不要删除原有类名。

2. Elementor 表单

选中弹窗中的 Form 组件,在 Advanced → CSS ID 中填写:

hzt-download-form

注意,这是表单组件的 CSS ID,不是表单字段 ID。

3. 添加隐藏字段

在 Elementor Form 中新增一个 Hidden 字段:

配置项 设置值
Type Hidden
Label Product ID
ID product_id
Default Value 留空

隐藏字段用于记录当前产品 ID。访客无需手动填写,JavaScript 会在打开弹窗时自动设置其值。

七、第四步:编写 PHP 后端代码

将以下代码添加到子主题的 functions.php,或放入自己的功能插件中。

如果这项功能需要在多个企业主题中复用,建议放入独立插件或主题核心插件,避免后续切换主题时丢失功能。

1. 注册脚本并传递当前产品 ID

add_action( 'wp_enqueue_scripts', function () {

    if ( ! is_singular() ) {
        return;
    }

    wp_register_script(
        'hzt-product-download',
        false,
        array( 'jquery' ),
        '1.0.0',
        true
    );

    wp_enqueue_script( 'hzt-product-download' );

    wp_localize_script(
        'hzt-product-download',
        'hztProductDownload',
        array(
            'ajaxUrl'   => admin_url( 'admin-ajax.php' ),
            'nonce'     => wp_create_nonce( 'hzt_product_download' ),
            'productId' => get_queried_object_id(),
        )
    );

    wp_add_inline_script(
        'hzt-product-download',
        hzt_product_download_script()
    );
} );

这段代码完成以下工作:

  • 注册前端 JavaScript。
  • 获取 WordPress AJAX 接口地址。
  • 生成用于请求校验的 nonce。
  • 将当前查询对象 ID 传递给前端。

2. 创建 AJAX 接口

add_action(
    'wp_ajax_hzt_get_product_download_url',
    'hzt_get_product_download_url'
);

add_action(
    'wp_ajax_nopriv_hzt_get_product_download_url',
    'hzt_get_product_download_url'
);

function hzt_get_product_download_url() {

    check_ajax_referer(
        'hzt_product_download',
        'nonce'
    );

    $product_id = isset( $_POST['product_id'] )
        ? absint( $_POST['product_id'] )
        : 0;

    if ( ! $product_id ) {
        wp_send_json_error(
            array( 'message' => 'Invalid product.' ),
            400
        );
    }

    $product = get_post( $product_id );

    if (
        ! $product ||
        'publish' !== $product->post_status
    ) {
        wp_send_json_error(
            array( 'message' => 'Product not found.' ),
            404
        );
    }

    if ( ! function_exists( 'get_field' ) ) {
        wp_send_json_error(
            array( 'message' => 'ACF is unavailable.' ),
            500
        );
    }

    $file_url = get_field(
        'product_file',
        $product_id
    );

    if (
        ! is_string( $file_url ) ||
        '' === $file_url
    ) {
        wp_send_json_error(
            array(
                'message' => 'No download file is configured.'
            ),
            404
        );
    }

    $file_url = esc_url_raw( $file_url );

    $file_host = wp_parse_url(
        $file_url,
        PHP_URL_HOST
    );

    $site_host = wp_parse_url(
        home_url(),
        PHP_URL_HOST
    );

    $file_scheme = wp_parse_url(
        $file_url,
        PHP_URL_SCHEME
    );

    if (
        ! $file_host ||
        ! $site_host ||
        strtolower( $file_host ) !== strtolower( $site_host ) ||
        ! in_array(
            $file_scheme,
            array( 'http', 'https' ),
            true
        )
    ) {
        wp_send_json_error(
            array(
                'message' => 'Invalid download file URL.'
            ),
            400
        );
    }

    $filename = wp_basename(
        (string) wp_parse_url(
            $file_url,
            PHP_URL_PATH
        )
    );

    wp_send_json_success(
        array(
            'url'      => $file_url,
            'filename' => $filename,
        )
    );
}

这里主要有三个关键点。

第一,获取当前产品的附件。

$file_url = get_field( 'product_file', $product_id );

根据传入的产品 ID,读取该产品对应的 ACF 文件字段。

第二,处理没有附件的情况。

当产品没有设置文件时,接口返回明确的错误信息:

No download file is configured.

前端可以据此显示友好的英文提示,而不是直接触发无效下载。

第三,检查附件 URL。

示例代码限制附件地址为本站同域名的 HTTP 或 HTTPS URL,避免接口被用于返回任意外部链接。

这只是基础校验。如果网站存在多个合法媒体域名或使用 CDN,需要根据实际部署调整域名白名单。

八、第五步:编写 JavaScript,实现表单提交后自动下载

下面的代码负责三个主要功能:

  1. 点击下载按钮时写入产品 ID。
  2. 表单提交成功后请求附件地址。
  3. 下载触发后关闭 Elementor 弹窗。

将此函数与前面的 PHP 注册代码配合使用。

function hzt_product_download_script() {

    return <<<'JS'
jQuery(function ($) {

    /**
     * 点击下载按钮,写入当前产品 ID
     */
    $(document).on(
        'click',
        '.hzt-download-trigger',
        function () {

            var productId =
                hztProductDownload.productId;

            var $form = $(
                '#hzt-download-form'
            ).find('form');

            var $field = $form.find(
                'input[name="form_fields[product_id]"]'
            );

            if ($field.length) {
                $field
                    .val(productId)
                    .trigger('input')
                    .trigger('change');
            }
        }
    );

    /**
     * 表单提交成功后获取附件
     */
    $(document).on(
        'submit_success',
        function (event) {

            var $form = $(
                '#hzt-download-form'
            ).find('form');

            if (!$form.length) {
                return;
            }

            if (
                event.target &&
                event.target.tagName === 'FORM' &&
                !$(event.target).is($form)
            ) {
                return;
            }

            var productId = $form.find(
                'input[name="form_fields[product_id]"]'
            ).val();

            if (!productId) {
                productId =
                    hztProductDownload.productId;
            }

            $.ajax({
                url: hztProductDownload.ajaxUrl,
                type: 'POST',
                dataType: 'json',
                data: {
                    action:
                        'hzt_get_product_download_url',
                    nonce:
                        hztProductDownload.nonce,
                    product_id: productId
                }
            }).done(function (response) {

                if (
                    !response.success ||
                    !response.data ||
                    !response.data.url
                ) {

                    var message =
                        response.data &&
                        response.data.message ===
                        'No download file is configured.'
                            ? 'No attachment is currently available for this product. Please contact us to obtain the file manually or try again later.'
                            : (
                                response.data &&
                                response.data.message
                                    ? response.data.message
                                    : 'Unable to retrieve the file. Please try again.'
                            );

                    alert(message);
                    return;
                }

                /**
                 * 触发浏览器下载
                 */
                var link =
                    document.createElement('a');

                link.href = response.data.url;

                link.download =
                    response.data.filename || '';

                link.style.display = 'none';

                document.body.appendChild(link);

                link.click();

                link.remove();

                /**
                 * 开始触发下载后关闭弹窗
                 */
                setTimeout(function () {

                    var $popup = $form.closest(
                        '.elementor-popup-modal'
                    );

                    if (
                        $popup.length &&
                        window.elementorProFrontend
                    ) {

                        var popupId =
                            $popup.attr(
                                'data-elementor-id'
                            );

                        if (popupId) {
                            elementorProFrontend
                                .modules
                                .popup
                                .closePopup({
                                    id: popupId
                                });
                        }
                    }

                }, 500);

            }).fail(function () {

                alert(
                    'Unable to retrieve the file. Please try again.'
                );

            });

        }
    );

});
JS;
}

为什么要监听 submit_success?

Elementor 原生表单有自己的前端验证和提交机制。直接监听按钮点击并下载,可能导致用户还没有完成提交,就已经获取附件。

通过 submit_success 事件,可以将下载流程安排在表单成功提交之后。

此外,附件请求使用独立的 WordPress AJAX 接口,不需要让表单提交本身承担文件下载任务,两者职责更清晰。

为什么要延迟关闭弹窗?

在触发 link.click() 后延迟约 500 毫秒关闭弹窗,可以避免弹窗在触发下载之前就关闭。

但需要明确:浏览器的下载触发并不等于文件已经完整下载。此处关闭弹窗只是让用户体验更流畅,并不代表下载完成。

九、第六步:设置表单提示文字

为了让访客清楚了解操作流程,可以在 Elementor Form 上方添加 Text Editor 组件。

推荐英文提示:

Please submit the form below. Your download will start automatically after successful submission.

中文含义:请填写并提交以下表单,提交成功后将自动开始下载。

如果想强调这是产品手册下载,也可以使用:

Please submit the form to download the leaflet. The download will start automatically.

第一种表达更加通用,适合产品手册、技术资料和 PDF 文件等不同下载场景。

十、第七步:测试没有附件时的提示

在实际网站中,并非所有产品都一定有可供下载的文件。

如果 ACF 字段 product_file 为空,后端接口会返回:

No download file is configured.

前端将它转换为用户友好的提示:

No attachment is currently available for this product. Please contact us to obtain the file manually or try again later.

这样既能告知用户当前无法下载,也为潜在客户提供了后续联系渠道。

其他网络错误或接口异常则继续显示通用提示:

Unable to retrieve the file. Please try again.

这两种提示需要区分处理,避免将所有异常都误认为产品没有附件。

十一、第八步:清理缓存并进行完整测试

如果网站使用 WP Rocket、服务器页面缓存或 CDN,修改代码后应清理相关缓存。

建议按以下清单逐项测试:

  • 点击 Download Leaflet,能够正常打开 Elementor 弹窗。
  • 表单必填字段验证正常。
  • 未完成必填字段时,不能进入下载流程。
  • 提交成功后,能够下载当前产品对应的附件。
  • 不同产品能够下载各自配置的文件,而不是同一个固定文件。
  • 成功触发下载后,弹窗能够自动关闭。
  • 没有设置附件的产品能够显示正确的英文提示。
  • 表单邮件通知和提交记录功能正常。
  • 桌面端与移动端都能够正常操作。

建议至少选择两个附件不同的产品进行测试,再测试一个没有附件的产品。

十二、常见问题

1. 所有产品都下载同一个文件怎么办?

首先检查隐藏字段是否正确传入当前产品 ID。

确认 Elementor 表单中的隐藏字段 ID 是 product_id,下载按钮包含 hzt-download-trigger,表单组件的 CSS ID 为 hzt-download-form。

同时确认产品详情页中的查询对象 ID 与实际产品 ID 一致。对于标准 WordPress 单篇页面和产品详情页,get_queried_object_id() 通常可以正确获取当前对象。

2. 表单提交成功,但没有开始下载怎么办?

可以检查以下项目:

  • 浏览器控制台是否存在 JavaScript 错误。
  • 网络请求中的 admin-ajax.php 是否成功返回 JSON。
  • ACF 字段是否已经保存文件 URL。
  • 当前页面是否正确加载 hztProductDownload 配置。
  • Elementor Pro 是否正常触发表单的 submit_success 事件。
  • 浏览器是否因为跨域或文件响应方式而忽略下载属性。

3. 为什么某些 PDF 文件会直接在浏览器中打开?

浏览器对 PDF 等文件的处理取决于响应头、同源策略和服务器配置。

对于本站同域名的文件,a.download 通常可以提示浏览器下载;但它不是强制下载指令。

如果业务要求始终下载文件,可以进一步改为 PHP 受控下载接口,通过 Content-Disposition: attachment 和 Content-Type 等响应头返回文件。

4. 这种方式能否防止访客绕过表单直接下载?

不能。

当前方案通过表单提交流程引导用户下载,但 ACF 返回的媒体库 URL 仍然是公开地址。知道该地址的人可能直接访问文件。

如果附件涉及内部资料、付费文档或必须收集授权信息后才能访问的文件,应将附件存储在非公开目录,通过 PHP 校验访问权限后再输出文件内容。

5. 是否需要为每个产品单独制作弹窗?

通常不需要。

只要产品详情页使用统一模板,按钮和弹窗的 CSS 标识一致,且每个产品都配置了正确的 ACF 文件字段,就可以让多个产品复用同一套下载流程。

十三、总结

通过 Elementor、ACF、PHP 和 JavaScript,可以在 WordPress 企业网站中构建完整的产品资料下载流程。

这种方案的核心不是简单地给按钮添加附件链接,而是将产品数据、表单提交和文件下载三个环节连接起来:

  • ACF 负责维护每个产品对应的附件。
  • Elementor 负责产品页面、弹窗和客户信息收集。
  • PHP 负责读取附件、验证请求并返回下载地址。
  • JavaScript 负责产品 ID 传递、提交成功后的下载触发和弹窗关闭。

对于产品数量较多的工业企业网站或外贸网站,这种实现方式便于复用、维护和扩展。后续还可以进一步增加下载次数统计、客户线索关联、附件权限校验以及不同语言的提示信息。

需要注意的是,前端触发下载并不意味着文件已经完整下载,公开媒体库 URL 也不构成真正的访问权限控制。若涉及敏感资料,应使用受控下载接口,而不是直接向浏览器公开文件地址。

本文由 好主题 原创整理,致力于分享实用的 WordPress 建站知识与主题开发经验。 我们专注于提供高质量的 WordPress企业主题 资源,帮助中小企业轻松构建专业网站。 转载请注明来源,并保留原文链接,感谢您的支持与理解。

联系我们

教程看不懂?联系我们免费为您解答!免费助力个人,小企站点!

客服微信
相关文章
主题推荐

会员注册

成为会员,获得更多专属优惠!

验证码: 加载中... =

已有账号?
还没有账号?