: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
namespace WPForms\Admin\Payments\Views;
use WPForms\Admin\Payments\ScreenOptions;
use WPForms\Admin\Payments\Views\Overview\Helpers;
use WPForms\Db\Payments\ValueValidator;
use WPForms_Field_Layout;
* Payments Overview Page class.
class Single implements PaymentsViewsInterface {
* Abort. Bail on proceeding to process the page.
* The human readable error message.
* Subscription object, if applicable.
* Subscription meta, if applicable.
private $subscription_meta;
* Subscription renewal payments, if applicable.
* This is an array of payment objects.
private function hooks() {
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
public function get_tab_label() {
* Enqueue scripts and styles.
public function enqueue_assets() {
$min = wpforms_get_min_suffix();
WPFORMS_PLUGIN_URL . 'assets/lib/jquery.tooltipster/jquery.tooltipster.min.css',
WPFORMS_PLUGIN_URL . 'assets/lib/jquery.tooltipster/jquery.tooltipster.min.js',
'wpforms-admin-payments-single',
WPFORMS_PLUGIN_URL . "assets/js/admin/payments/single{$min}.js",
'wpforms-admin-payments-single',
'wpforms_admin_payments_single',
'payment_delete_confirm' => esc_html__( 'Are you sure you want to delete this payment and all its information (details, notes, etc.)?', 'wpforms-lite' ),
'payment_refund_confirm' => esc_html__( 'Are you sure you want to refund this payment?', 'wpforms-lite' ),
'payment_cancel_confirm' => esc_html__( 'Are you sure you want to cancel this subscription?', 'wpforms-lite' ),
'payment_refund_success' => esc_html__( 'Payment was successfully refunded!', 'wpforms-lite' ),
'payment_cancel_success' => esc_html__( 'Subscription was successfully canceled!', 'wpforms-lite' ),
private function setup() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$payment_id = ! empty( $_GET['payment_id'] ) ? absint( $_GET['payment_id'] ) : 0;
$this->abort_message = esc_html__( 'It looks like the provided payment ID is not valid.', 'wpforms-lite' );
$this->payment = wpforms()->get( 'payment' )->get( $payment_id );
if ( empty( $this->payment ) ) {
$this->abort_message = esc_html__( 'It looks like the payment you are trying to access is no longer available.', 'wpforms-lite' );
if ( ! $this->payment->is_published ) {
$this->abort_message = esc_html__( "You can't edit this payment because it's in the trash.", 'wpforms-lite' );
$this->payment_meta = wpforms()->get( 'payment_meta' )->get_all( $payment_id );
// Retrieve the subscription renewal payments, if applicable.
if ( ! empty( $this->payment->subscription_id ) ) {
// Assign renewals to reduce queries and reuse later.
list( $this->subscription, $this->renewals ) = wpforms()->get( 'payment_queries' )->get_subscription_payment_history( $this->payment->subscription_id, $this->payment->currency );
if ( ! empty( $this->subscription ) ) {
$this->subscription_meta = wpforms()->get( 'payment_meta' )->get_all( $this->subscription->id );
* Check if the current user has the capability to view the page.
public function current_user_can() {
return wpforms_current_user_can();
public function heading() {
$payment_prev = wpforms()->get( 'payment_queries' )->get_prev( $this->payment->id, [ 'mode' => $this->payment->mode ] );
$payment_next = wpforms()->get( 'payment_queries' )->get_next( $this->payment->id, [ 'mode' => $this->payment->mode ] );
$prev_url = ! empty( $payment_prev ) ? add_query_arg(
'page' => 'wpforms-payments',
'payment_id' => (int) $payment_prev->id,
$next_url = ! empty( $payment_next ) ? add_query_arg(
'page' => 'wpforms-payments',
'payment_id' => (int) $payment_next->id,
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'admin/payments/single/heading-navigation',
'count' => (int) wpforms()->get( 'payment_queries' )->count_all( [ 'mode' => $this->payment->mode ] ),
'prev_count' => (int) wpforms()->get( 'payment_queries' )->get_prev_count( $this->payment->id, [ 'mode' => $this->payment->mode ] ),
'prev_class' => empty( $payment_prev ) ? 'inactive' : '',
'next_class' => empty( $payment_next ) ? 'inactive' : '',
'overview_url' => add_query_arg(
'page' => 'wpforms-payments',
public function display() {
echo '<div class="wpforms-admin-content">';
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'admin/payments/single/no-payment',
'message' => $this->abort_message,
$screen_options = ScreenOptions::get_single_page_options();
echo '<div id="poststuff"><div id="post-body" class="metabox-holder columns-2">';
echo '<div id="post-body-content">';
$this->payment_details();
$this->education_details();
$this->subscription_details();
$this->subscription_payment_history();
if ( ! empty( $screen_options['advanced'] ) ) {
$this->advanced_details();
echo '<div id="postbox-container-1" class="postbox-container">';
if ( ! empty( $screen_options['log'] ) ) {
echo '</div></div></div>';
* Payment details output.
private function payment_details() {
$payment_type_class = ! empty( $this->payment->subscription_id ) ? 'subscription' : 'one-time';
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'admin/payments/single/payment-details',
'id' => 'wpforms-payment-info',
'class' => 'payment-details',
'title' => __( 'Payment Details', 'wpforms-lite' ),
'payment_id' => "#{$this->payment->id}",
'gateway_link' => $this->get_gateway_transaction_link(),
'gateway_text' => sprintf( /* translators: %s - payment gateway name. */
__( 'View in %s', 'wpforms-lite' ),
$this->get_gateway_name()
'gateway_name' => $this->payment->gateway,
'gateway_action_text' => __( 'Refund', 'wpforms-lite' ),
'gateway_action_slug' => 'refund',
'gateway_action_link' => $this->get_gateway_action_link( 'refund' ),
'payment_id_raw' => $this->payment->id,
'status' => $this->payment->status,
'status_label' => $this->get_status_label(),
'disabled' => $this->payment->status === 'refunded',
'label' => esc_html__( 'Total', 'wpforms-lite' ),
'value' => wpforms_format_amount( wpforms_sanitize_amount( $this->payment->total_amount, $this->payment->currency ), true, $this->payment->currency ),
'label' => esc_html__( 'Type', 'wpforms-lite' ),
'value' => $this->get_payment_type(),
'label' => esc_html__( 'Method', 'wpforms-lite' ),
'value' => $this->get_payment_method(),
'tooltip' => $this->get_payment_method_details(),
'label' => esc_html__( 'Coupon', 'wpforms-lite' ),
'value' => $this->get_coupon_value(),
'tooltip' => nl2br( $this->get_coupon_info() ),
* Subscription details output.
private function subscription_details() {
if ( empty( $this->subscription ) ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'admin/payments/single/payment-details',
'id' => 'wpforms-subscription-details',
'class' => 'subscription-details',
'title' => __( 'Subscription Details', 'wpforms-lite' ),
'gateway_link' => $this->get_gateway_subscription_link(),
'gateway_text' => sprintf( /* translators: %s - payment gateway name. */
__( 'View in %s', 'wpforms-lite' ),
$this->get_gateway_name()
'gateway_name' => $this->payment->gateway,
'gateway_action_text' => __( 'Cancel', 'wpforms-lite' ),
'gateway_action_slug' => 'cancel',
'gateway_action_link' => $this->get_gateway_action_link( 'cancel' ),
'payment_id_raw' => $this->subscription->id,
'status' => $this->subscription->subscription_status,
'status_label' => ValueValidator::get_allowed_subscription_statuses()[ $this->subscription->subscription_status ],
'disabled' => $this->subscription->subscription_status === 'cancelled',
'label' => esc_html__( 'Lifetime Total', 'wpforms-lite' ),
'value' => $this->get_subscription_lifetime_total(),
'label' => esc_html__( 'Billing Cycle', 'wpforms-lite' ),
'value' => $this->get_subscription_cycle(),
'label' => esc_html__( 'Times Billed', 'wpforms-lite' ),
'value' => $this->get_subscription_times_billed(),
'label' => esc_html__( 'Renewal Date', 'wpforms-lite' ),
'value' => $this->get_renewal_date(),
* Subscription payment history output.
private function subscription_payment_history() {
// Early bail if no subscription ID.
if ( empty( $this->payment->subscription_id ) ) {
// Early bail if no subscription or renewals found.
// "$this->renewals" is set in the "setup" method.
if ( empty( $this->renewals ) ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'admin/payments/single/payment-history',
'title' => __( 'Payment History', 'wpforms-lite' ),
'renewals' => $this->renewals,
'types' => ValueValidator::get_allowed_subscription_types(),
'statuses' => ValueValidator::get_allowed_statuses(),
'placeholder_na_text' => Helpers::get_placeholder_na_text( false ),
'single_url' => add_query_arg(
'page' => 'wpforms-payments',
* Get Subscription cycle.
private function get_subscription_cycle() {