You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Formidable Form自定义HelloAsso结账时frm_after_create_entry致条目重复

Formidable Form自定义HelloAsso结账动作:条目重复创建问题

我正在为Formidable Form开发自定义动作,实现用户完成HelloAsso结账流程,跳转至感谢页时完成注册。原本计划使用frm_after_create_entry钩子获取已创建的条目ID,并重定向用户到携带该ID作为参数的页面,但现在遇到条目被创建两次的问题。

以下是我的代码:

<?php

require_once __DIR__ . '/../http-query-functions.php';
require_once __DIR__ . '/helloAsso-actions/HelloAssoAuthenticator.php';

class HelloAssoCheckoutAction extends FrmFormAction
{
    private string $user_form_id;
    private string $access_token;
    private string $data_to_send_for_checkout;
    private array $action_parameters;
    private array $user_form_values;

    function __construct()
    {
        $action_ops = array(
            'classes'   => 'dashicons dashicons-format-aside',
            'limit'     => 99,
            'priority'  => 50,
            'event'  => array('create'),
        );

        $this->FrmFormAction('HelloAssoCheckoutAction', __('HelloAsso Checkout', 'formidable'), $action_ops);

        add_filter('frm_validate_entry', array($this, 'prepare_checkout'), 10, 2);
        add_action('frm_after_create_entry', array($this, 'checkout'), 50, 2);
        add_action('init', array($this, 'register_helloasso_shortcodes'));
    }

    function register_helloasso_shortcodes()
    {
        add_shortcode('helloasso_checkout_status', array($this, 'set_checkout_status'));
    }


    function form($form_action, $args = array())
    {
       //... HTML form to set action parameters
    }


    function get_defaults()
    {
        return array(
            'template_name' => '',
            'my_content' => '',
        );
    }

    function prepare_checkout($errors, $values)
    {
        $this->user_form_id = $values['form_id'];
        $form_actions = FrmFormAction::get_action_for_form($this->user_form_id, 'helloassocheckoutaction');
        if (empty($form_actions)) {
            return;
        }
        $form_action = reset($form_actions);

        $this->action_parameters = $form_action->post_content;
        $this->user_form_values = $values;

        $this->connect_to_hello_asso($this->action_parameters['token_endpoint'], $this->action_parameters['client_id'], $this->action_parameters['client_secret']);

        return $errors;
    }

    private function connect_to_hello_asso($token_endpoint, $client_id, $client_secret)
    {
        $helloAsso_ahthenticator = new HelloAssoAuthenticator();
        $this->access_token = $helloAsso_ahthenticator->get_access_token($token_endpoint, $client_id, $client_secret);
    }


    function checkout($entry_id, $form_id)
    {

        $form_actions = FrmFormAction::get_action_for_form($form_id, 'helloassocheckoutaction');
        if (empty($form_actions)) {
            echo 'No action for this form, return errors';
            return;
        }

        $this->set_post_data($entry_id);


        $this->redirect_to_helloAsso_checkout($this->action_parameters['checkout_endpoint'], $this->access_token, $this->data_to_send_for_checkout);
    }

    private function set_post_data($entry_id)
    {
        $this->data_to_send_for_checkout = json_encode(array(
            "totalAmount" => $this->action_parameters['initial_amount'] * 100, // Amount in cents
            "initialAmount" => $this->action_parameters['initial_amount'] * 100,
            "itemName" => $this->action_parameters['campain_name'],
            "backUrl" => sanitize_url($this->action_parameters['back_url']),
            "errorUrl" => sanitize_url($this->action_parameters['error_url']),
            "returnUrl" => sanitize_url($this->action_parameters['success_url'] . "?entry=" . $entry_id),
            "containsDonation" => true,
            "payer" => array(
                "firstName" => sanitize_text_field($this->user_form_values['item_meta'][$this->action_parameters['name_field']]['first']),
                "lastName" => sanitize_text_field($this->user_form_values['item_meta'][$this->action_parameters['name_field']]['last']),
                "email" => sanitize_email($this->user_form_values['item_meta'][$this->action_parameters['mail_field']]),
                "dateOfBirth" => sanitize_text_field($this->user_form_values['item_meta'][$this->action_parameters['birthdate_field']]),
                "address" => sanitize_text_field($this->user_form_values['item_meta'][$this->action_parameters['address_field']]['line1']),
                "city" => sanitize_text_field($this->user_form_values['item_meta'][$this->action_parameters['address_field']]['city']),
                "zipCode" => sanitize_text_field($this->user_form_values['item_meta'][$this->action_parameters['address_field']]['zip']),
                "country" => "FRA"
            )
        ), true);
    }

    private function redirect_to_helloAsso_checkout($checkout_endpoint, $access_token, $form_data_json)
    {
        $response = create_curl_post_and_return_json_response($checkout_endpoint, $form_data_json, array(
            'Content-Type: application/json',
            'Authorization: Bearer ' . $access_token
        ));

        if (isset($response['error'])) {
            throw new Exception($response['error'] . ' ' . $response['message']);
        }

        header('Location: ' . wp_sanitize_redirect($response['redirectUrl']));
    }

    function set_checkout_status($atts)
    {
        if (isset($_GET['entry']) && isset($_GET['orderId']) && isset($_GET['code'])) {
            echo "paiement status for entry " . $_GET['entry'] . " is " . $_GET['code'] . " for order " . $_GET['orderId'];
            //TODO update the entry status 

        } else {
            echo "no entry id or code or order id";
        }
    }
}

为确认问题源于frm_after_create_entry的使用,我进行了以下测试:

  • 移除该钩子后,条目仅保存一次;
  • 保留钩子但移除逻辑仅留占位代码,问题仍存在;
  • 尝试添加条目存在性检查以避免重复,但返回URL中的条目ID不正确。

我已寻找其他可获取条目ID的动作钩子,但未找到合适的替代方案。我并非PHP和WordPress技术栈的开发者,开发过程中大量借助了大语言模型。

内容的提问来源于stack exchange,提问作者Maxime MOHANDI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 23:47:05