: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$allowed_intervals = ValueValidator::get_allowed_subscription_intervals();
if ( isset( $this->subscription_meta['subscription_period']->value, $allowed_intervals[ $this->subscription_meta['subscription_period']->value ] ) ) {
$amount = wpforms_format_amount( wpforms_sanitize_amount( $this->payment->total_amount, $this->payment->currency ), true, $this->payment->currency );
$interval = $allowed_intervals[ $this->subscription_meta['subscription_period']->value ];
return "{$amount} / {$interval}";
return Helpers::get_placeholder_na_text( false );
* Get Subscription lifetime total.
private function get_subscription_lifetime_total() {
return wpforms_format_amount( (float) $this->subscription->total_amount + array_sum( array_column( $this->renewals, 'total_amount' ) ), true, $this->payment->currency );
* Get Subscription times billed.
private function get_subscription_times_billed() {
// Display "N/A", in case no subscription ID is found.
if ( empty( $this->payment->subscription_id ) ) {
return Helpers::get_placeholder_na_text( false );
// Add the initial subscription payment object to the renewal array.
// The "+1" has to be added, because the initial subscription payment is not included in the renewals array.
if ( ! empty( $this->subscription ) ) {
$this->renewals[] = $this->subscription;
return count( $this->renewals );
* Get Subscription renewal date.
private function get_renewal_date() {
$this->payment->subscription_status === 'cancelled'
|| $this->is_renewal_of_cancelled_subscription()
return Helpers::get_placeholder_na_text( false );
'quarterly' => '+3 month',
'semiyearly' => '+6 month',
if ( ! isset( $this->subscription_meta['subscription_period']->value, $converted_periods[ $this->subscription_meta['subscription_period']->value ] ) ) {
return gmdate( 'M d, Y', strtotime( $this->payment->date_updated_gmt . $converted_periods[ $this->subscription_meta['subscription_period']->value ] ) );
* Is renewal of cancelled subscription.
private function is_renewal_of_cancelled_subscription() {
return $this->payment->type === 'renewal'
&& $this->subscription->subscription_status === 'cancelled';
* i.e. One-time, Subscription, etc.
private function get_payment_type() {
if ( isset( $this->payment->type ) && ValueValidator::is_valid( $this->payment->type, 'type' ) ) {
return ValueValidator::get_allowed_types()[ $this->payment->type ];
return Helpers::get_placeholder_na_text( false );
* Get payment method type.
private function get_payment_method() {
$method = isset( $this->payment_meta['credit_card_method'] ) ? ucfirst( $this->payment_meta['credit_card_method']->value ) : '';
return isset( $this->payment_meta['method_type'] ) ? ucfirst( $this->payment_meta['method_type']->value ) : Helpers::get_placeholder_na_text( false );
* Get payment method details.
private function get_payment_method_details() {
! isset( $this->payment_meta['method_type'] ) ||
$this->payment_meta['method_type']->value !== 'card' ||
empty( $this->payment_meta['credit_card_last4'] ) ||
empty( $this->payment_meta['credit_card_expires'] )
$credit_card_last = 'xxxx xxxx xxxx ' . $this->payment_meta['credit_card_last4']->value;
$expires_in = sprintf( /* translators: %s - credit card expiry date. */
__( 'Expires %s', 'wpforms-lite' ),
$this->payment_meta['credit_card_expires']->value
if ( ! empty( $this->payment_meta['credit_card_name'] ) ) {
$output .= '<span>' . esc_html( $this->payment_meta['credit_card_name']->value ) . '</span></br>';
$output .= '<span>' . esc_html( $credit_card_last ) . '</span></br>';
$output .= '<span>' . esc_html( $expires_in ) . '</span>';
private function get_coupon_info() {
$coupon_info = ! empty( $this->payment_meta['coupon_info']->value ) ? $this->payment_meta['coupon_info']->value : '';
* Allow modifying coupon info.
* @param string $coupon_info Coupon info.
* @param object $payment Payment object.
* @param array $payment_meta Payment meta.
return apply_filters( 'wpforms_admin_payments_views_single_get_coupon_info', $coupon_info, $this->payment, $this->payment_meta );
private function get_coupon_value() {
return ! empty( $this->payment_meta['coupon_value']->value ) ? sprintf( '-%s', $this->payment_meta['coupon_value']->value ) : '';
* Education notice for lite users output.
private function education_details() {
if ( in_array( wpforms_get_license_type(), [ 'pro', 'elite', 'agency', 'ultimate' ], true ) ) {
$dismissed = get_user_meta( get_current_user_id(), 'wpforms_dismissed', true );
if ( ! empty( $dismissed['edu-single-payment'] ) ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo wpforms_render( 'education/admin/payments/single-page' );
* Advanced details output.
private function advanced_details() {
* Allow to modify a single payment page advanced details list.
* @param array $list Advanced details to show.
* @param object $payment Payment object.
$details_list = (array) apply_filters(
'wpforms_admin_payments_views_single_advanced_details_list',
'label' => __( 'Transaction ID', 'wpforms-lite' ),
'link' => $this->get_gateway_transaction_link(),
'value' => $this->payment->transaction_id,
'label' => __( 'Subscription ID', 'wpforms-lite' ),
'link' => $this->get_gateway_subscription_link(),
'value' => $this->payment->subscription_id,
'label' => __( 'Customer ID', 'wpforms-lite' ),
'link' => $this->get_gateway_customer_link(),
'value' => $this->payment->customer_id,
'label' => __( 'Customer IP Address', 'wpforms-lite' ),
'value' => ! empty( $this->payment_meta['ip_address']->value ) ? $this->payment_meta['ip_address']->value : false,
'label' => __( 'Payment Method', 'wpforms-lite' ),
'value' => $this->get_payment_method_details(),
'label' => __( 'Coupon', 'wpforms-lite' ),
'value' => $this->get_coupon_info(),
$details_list = array_filter(
static function ( $item ) {
return ! empty( $item['value'] );
// Return early if there are no details.
if ( empty( $details_list ) ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'admin/payments/single/advanced-details',
'details_list' => $details_list,
private function entry_details() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
// Grab submitted values from the entry if it exists.
if ( ! empty( $this->payment->entry_id ) && wpforms()->is_pro() ) {
$entry = wpforms()->get( 'entry' )->get( $this->payment->entry_id );
$fields = wpforms_decode( $entry->fields );
$entry_id_title .= "#{$this->payment->entry_id}";
$entry_status = $entry->status;
// Otherwise, grab submitted values from the payment meta if it exists.
if ( empty( $fields ) && ! empty( $this->payment_meta['fields'] ) ) {
$fields = wpforms_decode( $this->payment_meta['fields']->value );
// Bail early if there are submitted values.
if ( empty( $fields ) ) {
* Allow modifying the form data before rendering the entry details.
* @param array $form_data Form data.
* @param array $fields Entry fields.
$form_data = apply_filters(
'wpforms_admin_payments_views_single_form_data',
wpforms()->get( 'form' )->get( $this->payment->form_id, [ 'content_only' => true ] ),
add_filter( 'wp_kses_allowed_html', [ $this, 'modify_allowed_tags_payment_field_value' ], 10, 2 );
* Allow modifying the entry fields before rendering the entry details.
* @param array $entry_fields Entry fields.
* @param array $form_data Form data.
$entry_fields = apply_filters(
'wpforms_admin_payments_views_single_fields',
$this->prepare_entry_fields( $fields, $form_data ),
$entry_output = wpforms_render(
'admin/payments/single/entry-details',
'entry_fields' => $entry_fields,
'form_data' => $form_data,
'entry_id_title' => $entry_id_title,
'entry_id' => $this->payment->entry_id,
'entry_status' => $entry_status,
'entry_url' => add_query_arg(
'page' => 'wpforms-entries',
'entry_id' => $this->payment->entry_id,
remove_filter( 'wp_kses_allowed_html', [ $this, 'modify_allowed_tags_payment_field_value' ] );
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
* @param array $fields Entry fields.
* @param array $form_data Form data.
private function prepare_entry_fields( $fields, $form_data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.MaxExceeded, Generic.Metrics.CyclomaticComplexity.TooHigh
if ( empty( $form_data['fields'] ) || empty( $fields ) ) {
// Display the fields and their values.
foreach ( $form_data['fields'] as $key => $field_data ) {
if ( empty( $field_data['type'] ) ) {
$field_type = $field_data['type'];
// Add repeater fields as is.
if ( $field_type === 'repeater' && wpforms()->is_pro() ) {
$prepared_fields[ $key ] = $field_data;
$field = $fields[ $field_data['id'] ] ?? [];
// phpcs:disable WPForms.PHP.ValidateHooks.InvalidHookName
/** This filter is documented in /src/Pro/Admin/Entries/Edit.php */
if ( $this->payment->entry_id && ! (bool) apply_filters( "wpforms_pro_admin_entries_edit_is_field_displayable_{$field_type}", true, $field, $form_data ) ) {
$field_value = isset( $field['value'] ) ? $field['value'] : '';
/** This filter is documented in src/SmartTags/SmartTag/FieldHtmlId.php.*/
$prepared_fields[ $key ]['field_value'] = apply_filters( 'wpforms_html_field_value', wp_strip_all_tags( $field_value ), $field, $form_data, 'payment-single' );
// phpcs:enable WPForms.PHP.ValidateHooks.InvalidHookName
$prepared_fields[ $key ]['field_class'] = sanitize_html_class( 'wpforms-field-' . $field_type );
$prepared_fields[ $key ]['type'] = $field_type;
$prepared_fields[ $key ]['id'] = $field_data['id'];
$prepared_fields[ $key ]['field_name'] = ! empty( $field['name'] )
: sprintf( /* translators: %d - field ID. */
esc_html__( 'Field ID #%d', 'wpforms-lite' ),
$is_empty_value = wpforms_is_empty_string( $field_value );
$is_empty_quantity = isset( $field['quantity'] ) && ! $field['quantity'];
$prepared_fields[ $key ]['field_value'] = esc_html__( 'Empty', 'wpforms-lite' );
if ( $is_empty_value || $is_empty_quantity ) {
$prepared_fields[ $key ]['field_class'] .= ' empty';
* Allow additional tags for the wp_kses_post function.
* @param array $allowed_html List of allowed HTML.
* @param string $context Context name.
public function modify_allowed_tags_payment_field_value( $allowed_html, $context ) {
if ( $context !== 'post' ) {
$allowed_html['iframe'] = [
* Details metabox output.
private function details() {
$form_edit_link = $this->get_form_edit_link();
$date = sprintf( /* translators: %1$s - date, %2$s - time when item was created, e.g. "Oct 22, 2022 at 11:11 am". */
__( '%1$s at %2$s', 'wpforms-lite' ),
wpforms_date_format( $this->payment->date_created_gmt, 'M j, Y', true ),
wpforms_time_format( $this->payment->date_created_gmt, '', true )
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'admin/payments/single/details',