$fields Stored fields as label/value/group entries.
* @return string Rendered markup, or '' when there is nothing to show.
* @since 1.5.1
*/
public static function render_submitted_fields( $fields ) {
if ( empty( $fields ) || ! is_array( $fields ) ) {
return '';
}
$rows_html = '';
foreach ( $fields as $field ) {
if ( ! is_array( $field ) ) {
continue;
}
$label = self::get_string_value( $field['label'] ?? '' );
$value = self::format_checkbox_field_value( $field['value'] ?? '' );
$group = self::get_string_value( $field['group'] ?? '' );
if ( '' === $label && '' === $value ) {
continue;
}
// Sub-fields (e.g. the Address block's parts) are stored with their
// parent block's label as the group; prefix it so "Street Address"
// reads as "Address: Street Address" rather than losing its context.
if ( '' !== $group ) {
// str_replace (not sprintf) because the format is translator
// editable and this runs inside the gateway webhook handlers — a
// stray literal % would make sprintf throw a ValueError on PHP 8,
// 500 the webhook and trigger gateway retries. Same rule as
// Field_Validation's message formatting.
$label = str_replace(
[ '%1$s', '%2$s' ],
[ $group, $label ],
/* translators: 1: parent field label, 2: sub-field label. */
_x( '%1$s: %2$s', 'parent field label: sub-field label', 'suredonation' )
);
}
$rows_html .= sprintf(
'%1$s%2$s
',
esc_html( $label ),
esc_html( $value )
);
}
if ( '' === $rows_html ) {
return '';
}
return sprintf(
'',
esc_html__( 'Form Details', 'suredonation' ),
$rows_html
);
}
/**
* Default confirmation message template (receipt layout with smart tags).
*
* @return string Message HTML template.
* @since 1.0.0
*/
public static function get_default_confirmation_message() {
return '{success_badge}
'
. ''
/* translators: {donor_name} is a smart tag replaced with the donor's name. */
. esc_html__( 'Thank you {donor_name} for your Donation', 'suredonation' )
. '
'
. ''
. esc_html__( 'Your contribution means a lot. We have sent a confirmation email to your registered address with the details of your donation.', 'suredonation' )
. '
{donation_receipt}';
}
/**
* Build the rendered confirmation/thank-you HTML for a donation.
*
* Resolves the form's confirmation message template against the donation's
* real data (smart tags) so the frontend can display the receipt. The
* billing interval is lifted out of the nested donation_data column, which
* is the only field of the set that is not stored as a column of its own.
*
* @param int $donation_id Donation ID.
* @param array|null $donation Donation row to render from.
* Defaults to reading it. Pass one
* when the caller already holds the
* row, or when the row on disk does
* not yet reflect the state being
* reported to the donor.
* @return string Sanitized confirmation HTML, or '' on failure.
* @since 1.0.0
*/
public static function render_confirmation_message( $donation_id, $donation = null ) {
if ( ! is_array( $donation ) ) {
$donation = Donations::get( $donation_id );
}
if ( ! is_array( $donation ) ) {
return '';
}
$form_id = isset( $donation['form_id'] ) ? absint( $donation['form_id'] ) : 0;
$campaign_id = isset( $donation['campaign_id'] ) ? absint( $donation['campaign_id'] ) : 0;
$settings = self::get_form_confirmation_settings( $form_id );
$template = ! empty( $settings['message'] ) ? $settings['message'] : self::get_default_confirmation_message();
// The billing interval is the one field the donation row does not carry
// as a column; it is written a level down inside donation_data, so it
// has to be lifted out before the tag map can see it.
$stored = $donation['donation_data'] ?? [];
if ( is_string( $stored ) && '' !== $stored ) {
$stored = json_decode( $stored, true );
}
$stored = is_array( $stored ) ? $stored : [];
$donation_data = [
'id' => $donation_id,
'donor_name' => $donation['donor_name'] ?? '',
'donor_email' => $donation['donor_email'] ?? '',
'amount' => $donation['amount'] ?? 0,
'fees_covered' => $donation['fees_covered'] ?? 0,
'currency' => $donation['currency'] ?? Payment_Helper::get_currency(),
'gateway' => $donation['gateway'] ?? '',
'payment_status' => $donation['payment_status'] ?? '',
'transaction_id' => $donation['transaction_id'] ?? '',
'donation_type' => $donation['donation_type'] ?? 'one-time',
// Recurring donations resolve these two; a one-time donation has
// neither, and the tag map already renders a missing value as empty.
'subscription_id' => $donation['subscription_id'] ?? '',
'subscription_interval' => $stored['subscription_interval'] ?? '',
];
$campaign = $campaign_id ? get_post( $campaign_id ) : null;
$rendered = Email_Handler::process_smart_tags( $template, $donation_data, $campaign );
return wp_kses_post( $rendered );
}
/**
* Check whether the OttoKit (formerly SureTriggers) plugin is active and
* authenticated with the OttoKit SaaS.
*
* @return bool True when OttoKit is installed, active and connected.
* @since 1.2.0
*/
public static function is_suretriggers_ready() {
if ( ! defined( 'SURE_TRIGGERS_FILE' ) ) {
// Plugin is deactivated or not installed at all.
return false;
}
$suretriggers_data = get_option( 'suretrigger_options', [] );
if ( ! is_array( $suretriggers_data ) || empty( $suretriggers_data['secret_key'] ) || ! is_string( $suretriggers_data['secret_key'] ) ) {
// OttoKit is not authenticated yet.
return false;
}
return true;
}
/**
* Get OttoKit (formerly SureTriggers) integration metadata.
*
* Shared by the admin app and the donation form editor so both surface the
* same install/activate/connect state.
*
* @return array Integration metadata.
* @since 1.2.0
*/
public static function get_ottokit_integration() {
$plugin_file = 'suretriggers/suretriggers.php';
if ( ! function_exists( 'is_plugin_active' ) ) {
include_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$status = 'Install';
if ( is_plugin_active( $plugin_file ) ) {
$status = 'Activated';
} elseif ( array_key_exists( $plugin_file, get_plugins() ) ) {
$status = 'Installed';
}
return [
'title' => 'OttoKit',
'slug' => 'suretriggers',
'path' => $plugin_file,
'status' => $status,
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Filter is owned by the OttoKit plugin.
'connected' => apply_filters( 'suretriggers_is_user_connected', '' ),
'connection_url' => admin_url( 'admin.php?page=suretriggers' ),
];
}
}