# better-payment/2.4.0/includes/Campaign/Elements/ProElementSchemas.php

Better Payment – Instant Payments, Donations, Fundraising with Subscriptions &amp; More, version 2.4.0. 483 lines.

- Page: https://pluginprobe.com/plugins/better-payment/2.4.0/code/includes/Campaign/Elements/ProElementSchemas.php
- Raw: https://pluginprobe.com/plugins/better-payment/2.4.0/raw/includes/Campaign/Elements/ProElementSchemas.php
- Modified: 2026-09-24T10:14:42+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/better-payment/2.4.0/code/includes/Campaign/Elements/ProElementSchemas.php#L10-L20`.

```php
<?php

namespace Better_Payment\Lite\Campaign\Elements;

use Better_Payment\Lite\Classes\ProCompatibility;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Transitional copy for Better Payment Pro <= 1.4.3; delete when
 * ProCompatibility::MIN_PRO_VERSION >= 1.4.4.
 * Pro copy: better-payment-pro/includes/Campaign/ProElementSchemas.php.
 * Slug: campaign_pro_element_schemas.
 *
 * Control schemas and default settings for the three Pro-only campaign elements
 * — Donors Wall, FAQ and Video. Pro 1.4.3 and earlier register renderers only and
 * rely on Lite for these, so Lite still serves them to an active Pro that does not
 * declare {@see self::FEATURE}, through {@see self::apply_lite_copy()}. A free
 * install never receives them: it gets {@see ProElementStubs}, and a current Pro
 * registers its own copy.
 *
 * Deleting this file at step 3 also means deleting the `add_filter()` line in
 * {@see CampaignElements::register_pro_elements()} and the three contract symbols
 * below from tests/Unit/ProCouplingContractTest.php (Pro 1.4.4 no longer calls them).
 *
 * The public constants and {@see self::default_video_url()} are part of the Pro
 * coupling contract: Pro 1.4.3's `BuilderElements` aliases them.
 */
class ProElementSchemas {

    /**
     * Feature slug Pro declares on `better_payment/pro_provides` once it ships
     * these schemas itself.
     */
    const FEATURE = 'campaign_pro_element_schemas';

    /**
     * The video a newly added Video element starts with, so a freshly dropped
     * element isn't a blank box.
     *
     * Pro 1.4.3's `BuilderElements::DEFAULT_VIDEO_URL` aliases this constant.
     */
    const DEFAULT_VIDEO_URL = 'https://www.youtube.com/watch?v=jeXG-4SOlZE';

    /**
     * Seconds into {@see self::DEFAULT_VIDEO_URL} that playback starts.
     */
    const DEFAULT_VIDEO_START = 2;

    /**
     * Filterable default video URL.
     *
     * @return string
     */
    public static function default_video_url(): string {
        return (string) apply_filters( 'better_payment/campaign/default_video_url', self::DEFAULT_VIDEO_URL );
    }

    /**
     * Callback for `better_payment/campaign_elements` (priority 5): replace the lock
     * stubs with the full definitions, for an older active Pro only.
     *
     * @param mixed $elements Registered elements, keyed by type.
     * @return mixed
     */
    public static function apply_lite_copy( $elements ) {
        if ( ! is_array( $elements ) || ! ProCompatibility::lite_copy_applies( self::FEATURE ) ) {
            return $elements;
        }

        foreach ( self::get_all() as $type => $schema ) {
            $elements[ $type ] = array_merge( $schema, [ 'type' => $type, 'pro' => true ] );
        }

        return $elements;
    }

    /**
     * All three schemas, keyed by element type.
     *
     * @return array<string, array>
     */
    public static function get_all(): array {
        return [
            'donors_wall' => self::donors_wall(),
            'faq'         => self::faq(),
            'video'       => self::video(),
        ];
    }

    /**
     * @return array
     */
    public static function donors_wall(): array {
        return [
            'label'           => __( 'Donors Wall', 'better-payment' ),
            'icon'            => 'groups',
            'defaultSettings' => [
                'headline'       => __( 'Recent Donors', 'better-payment' ),
                'layout'         => 'list',
                'columns'        => 2,
                'number_to_show' => 10,
                'order_by'       => 'date',
                'order'          => 'desc',
                'hide_if_empty'  => false,
                'show_summary'   => true,
                'show_name'      => true,
                'show_amount'    => true,
                'show_avatar'    => true,
                'show_date'      => true,
                'accent_color'   => '',
                'width'          => 100,
                'align'          => 'left',
            ],
            'settingsSchema'  => [
                [
                    'key'         => 'headline',
                    'label'       => __( 'Headline', 'better-payment' ),
                    'type'        => 'text',
                    'placeholder' => __( 'Recent Donors', 'better-payment' ),
                ],
                [
                    'key'     => 'layout',
                    'label'   => __( 'Layout', 'better-payment' ),
                    'type'    => 'select',
                    'options' => [
                        [ 'value' => 'list',   'label' => __( 'List (vertical)', 'better-payment' ) ],
                        [ 'value' => 'grid',   'label' => __( 'Grid', 'better-payment' ) ],
                        [ 'value' => 'ticker', 'label' => __( 'Ticker (auto-scroll)', 'better-payment' ) ],
                    ],
                ],
                // A select, not a range: three discrete values are chosen, not
                // dialled. It was a slider whose value read "4%" — the builder's
                // range control used to assume every range was a percentage.
                // Shown only for the grid, where columns mean anything at all.
                [
                    'key'          => 'columns',
                    'label'        => __( 'Grid Columns', 'better-payment' ),
                    'type'         => 'select',
                    'defaultValue' => 2,
                    'condition'    => [ 'layout' => 'grid' ],
                    'options'      => [
                        [ 'value' => 2, 'label' => __( '2 columns', 'better-payment' ) ],
                        [ 'value' => 3, 'label' => __( '3 columns', 'better-payment' ) ],
                        [ 'value' => 4, 'label' => __( '4 columns', 'better-payment' ) ],
                    ],
                ],
                [
                    'key'          => 'number_to_show',
                    'label'        => __( 'Number of Donors To Show', 'better-payment' ),
                    'type'         => 'number',
                    'min'          => 0,
                    'max'          => 100,
                    'defaultValue' => 10,
                    'info'         => __( 'Set to 0 to hide the donor list.', 'better-payment' ),
                ],
                [
                    'key'     => 'order_by',
                    'label'   => __( 'Order By', 'better-payment' ),
                    'type'    => 'select',
                    'options' => [
                        [ 'value' => 'date',   'label' => __( 'Date', 'better-payment' ) ],
                        [ 'value' => 'amount', 'label' => __( 'Amount', 'better-payment' ) ],
                    ],
                ],
                // Two variants of the same `order` control, gated on `order_by`,
                // so the direction labels read naturally for what's being sorted.
                // Both write the same `order` key with the same `desc`/`asc`
                // values — the renderer is unchanged and the chosen value survives
                // switching Order By. Only one is ever visible (isControlVisible).
                [
                    'key'       => 'order',
                    'label'     => __( 'Order', 'better-payment' ),
                    'type'      => 'select',
                    'condition' => [ 'order_by' => 'amount' ],
                    'options'   => [
                        [ 'value' => 'desc', 'label' => __( 'High to Low', 'better-payment' ) ],
                        [ 'value' => 'asc',  'label' => __( 'Low to High', 'better-payment' ) ],
                    ],
                ],
                [
                    'key'       => 'order',
                    'label'     => __( 'Order', 'better-payment' ),
                    'type'      => 'select',
                    'condition' => [ 'order_by' => 'date' ],
                    'options'   => [
                        [ 'value' => 'desc', 'label' => __( 'Newest First', 'better-payment' ) ],
                        [ 'value' => 'asc',  'label' => __( 'Oldest First', 'better-payment' ) ],
                    ],
                ],
                [
                    'key'   => 'hide_if_empty',
                    'label' => __( 'Hide If No Donors', 'better-payment' ),
                    'type'  => 'switch',
                ],
                [
                    'key'   => '_donor_info_label',
                    'label' => __( 'Donor Information', 'better-payment' ),
                    'type'  => 'section_label',
                ],
                [
                    'key'   => 'show_summary',
                    'label' => __( 'Show Totals Summary', 'better-payment' ),
                    'type'  => 'switch',
                ],
                [
                    'key'   => 'show_name',
                    'label' => __( 'Show Name', 'better-payment' ),
                    'type'  => 'switch',
                ],
                [
                    'key'   => 'show_amount',
                    'label' => __( 'Show Amount', 'better-payment' ),
                    'type'  => 'switch',
                ],
                [
                    'key'   => 'show_avatar',
                    'label' => __( 'Show Avatar', 'better-payment' ),
                    'type'  => 'switch',
                ],
                [
                    'key'   => 'show_date',
                    'label' => __( 'Show Time', 'better-payment' ),
                    'type'  => 'switch',
                ],
                [
                    'key'   => '_style_label',
                    'label' => __( 'Style', 'better-payment' ),
                    'type'  => 'section_label',
                ],
                [
                    'key'   => 'accent_color',
                    'label' => __( 'Accent Color', 'better-payment' ),
                    'type'  => 'color',
                    'info'  => __( 'Leave empty to inherit the campaign color.', 'better-payment' ),
                ],
                [
                    'key'          => 'width',
                    'label'        => __( 'Width', 'better-payment' ),
                    'type'         => 'range',
                    'min'          => 10,
                    'max'          => 100,
                    'step'         => 1,
                    'unit'         => '%',
                    'defaultValue' => 100,
                ],
                [
                    'key'   => 'align',
                    'label' => __( 'Align', 'better-payment' ),
                    'type'  => 'align',
                ],
            ],
        ];
    }

    /**
     * @return array
     */
    public static function faq(): array {
        return [
            'label'           => __( 'FAQ', 'better-payment' ),
            'icon'            => 'editor-help',
            'defaultSettings' => [
                'heading'      => __( 'Frequently Asked Questions', 'better-payment' ),
                'items'        => [
                    [
                        'question' => __( 'How will my donation help?', 'better-payment' ),
                        'answer'   => __( 'Your donation will directly support the goals of this campaign and help make a meaningful difference for the people or cause it aims to support.', 'better-payment' ),
                    ],
                    [
                        'question' => __( 'Is my donation secure?', 'better-payment' ),
                        'answer'   => __( 'Yes. Donations are processed through a secure payment system to help keep your payment information safe.', 'better-payment' ),
                    ],
                    [
                        'question' => __( 'Can I donate any amount?', 'better-payment' ),
                        'answer'   => __( 'Yes. Every contribution matters, regardless of the amount. You can donate an amount that feels comfortable for you.', 'better-payment' ),
                    ],
                    [
                        'question' => __( 'Can I share this campaign with others?', 'better-payment' ),
                        'answer'   => __( 'Absolutely! Sharing the campaign with your friends, family, and social network is a great way to help spread awareness and support the cause.', 'better-payment' ),
                    ],
                ],
                'style'        => 'accordion',
                'icon_style'   => 'chevron',
                'single_open'  => true,
                'first_open'   => true,
                'accent_color' => '',
                'width'        => 100,
                'align'        => 'left',
            ],
            'settingsSchema'  => [
                [
                    'key'         => 'heading',
                    'label'       => __( 'Heading', 'better-payment' ),
                    'type'        => 'text',
                    'placeholder' => __( 'Frequently Asked Questions', 'better-payment' ),
                ],
                [
                    'key'        => 'items',
                    'label'      => __( 'FAQ Items', 'better-payment' ),
                    'type'       => 'repeater',
                    'itemLabel'  => __( 'Question', 'better-payment' ),
                    'titleField' => 'question',
                    'addLabel'   => __( 'Add Question', 'better-payment' ),
                    'max'        => 30,
                    'fields'     => [
                        [
                            'key'         => 'question',
                            'label'       => __( 'Question', 'better-payment' ),
                            'type'        => 'text',
                            'placeholder' => __( 'Enter a question', 'better-payment' ),
                        ],
                        [
                            'key'         => 'answer',
                            'label'       => __( 'Answer', 'better-payment' ),
                            'type'        => 'textarea',
                            'rows'        => 3,
                            'placeholder' => __( 'Enter the answer', 'better-payment' ),
                        ],
                        [
                            'key'   => 'open',
                            'label' => __( 'Open by default?', 'better-payment' ),
                            'type'  => 'switch',
                        ],
                    ],
                ],
                [
                    'key'     => 'style',
                    'label'   => __( 'Style', 'better-payment' ),
                    'type'    => 'select',
                    'options' => [
                        [ 'value' => 'accordion', 'label' => __( 'Accordion (collapsible)', 'better-payment' ) ],
                        [ 'value' => 'list',      'label' => __( 'Open list', 'better-payment' ) ],
                    ],
                ],
                [
                    'key'       => 'icon_style',
                    'label'     => __( 'Toggle Icon', 'better-payment' ),
                    'type'      => 'select',
                    // Accordion-only: the open-list style shows every answer, so
                    // there is no collapse toggle to put an icon on.
                    'condition' => [ 'style' => 'accordion' ],
                    'options'   => [
                        [ 'value' => 'chevron', 'label' => __( 'Chevron', 'better-payment' ) ],
                        [ 'value' => 'plus',    'label' => __( 'Plus / Minus', 'better-payment' ) ],
                        [ 'value' => 'none',    'label' => __( 'No icon', 'better-payment' ) ],
                    ],
                ],
                [
                    'key'       => 'single_open',
                    'label'     => __( 'Open One At A Time', 'better-payment' ),
                    'type'      => 'switch',
                    // Accordion-only: an open list has nothing to close.
                    'condition' => [ 'style' => 'accordion' ],
                    'info'      => __( 'Opening a question closes the others (accordion only).', 'better-payment' ),
                ],
                [
                    'key'       => 'first_open',
                    'label'     => __( 'Open First Item By Default', 'better-payment' ),
                    'type'      => 'switch',
                    // Accordion-only: open-list items are all expanded already.
                    'condition' => [ 'style' => 'accordion' ],
                ],
                [
                    'key'   => 'accent_color',
                    'label' => __( 'Accent Color', 'better-payment' ),
                    'type'  => 'color',
                    'info'  => __( 'Leave empty to inherit the campaign color.', 'better-payment' ),
                ],
                [
                    'key'          => 'width',
                    'label'        => __( 'Width', 'better-payment' ),
                    'type'         => 'range',
                    'min'          => 10,
                    'max'          => 100,
                    'step'         => 1,
                    'unit'         => '%',
                    'defaultValue' => 100,
                ],
                [
                    'key'   => 'align',
                    'label' => __( 'Align', 'better-payment' ),
                    'type'  => 'align',
                ],
            ],
        ];
    }

    /**
     * @return array
     */
    public static function video(): array {
        return [
            'label'           => __( 'Video', 'better-payment' ),
            'icon'            => 'format-video',
            'defaultSettings' => [
                'url'          => self::default_video_url(),
                'aspect_ratio' => '16-9',
                'autoplay'     => false,
                'muted'        => false,
                'loop'         => false,
                'controls'     => true,
                'start_time'   => self::DEFAULT_VIDEO_START,
                'width'        => 100,
                'align'        => 'center',
            ],
            'settingsSchema'  => [
                [
                    'key'         => 'url',
                    'label'       => __( 'Video URL', 'better-payment' ),
                    'type'        => 'url',
                    // Renders a Media Library button beside the field (Lite's
                    // `url` control), so an uploaded video can be chosen without
                    // leaving the builder to copy its URL.
                    'mediaType'   => 'video',
                    'placeholder' => 'https://www.youtube.com/watch?v=…',
                    'info'        => __( 'Paste a YouTube or Vimeo link, or choose an uploaded video from your Media Library.', 'better-payment' ),
                ],
                [
                    'key'     => 'aspect_ratio',
                    'label'   => __( 'Aspect Ratio', 'better-payment' ),
                    'type'    => 'select',
                    'options' => [
                        [ 'value' => '16-9', 'label' => '16:9' ],
                        [ 'value' => '4-3',  'label' => '4:3' ],
                        [ 'value' => '1-1',  'label' => '1:1' ],
                        [ 'value' => '21-9', 'label' => '21:9' ],
                    ],
                ],
                [
                    'key'   => '_playback_label',
                    'label' => __( 'Playback', 'better-payment' ),
                    'type'  => 'section_label',
                ],
                [
                    'key'   => 'autoplay',
                    'label' => __( 'Autoplay', 'better-payment' ),
                    'type'  => 'switch',
                ],
                [
                    'key'   => 'muted',
                    'label' => __( 'Muted', 'better-payment' ),
                    'type'  => 'switch',
                ],
                [
                    'key'   => 'loop',
                    'label' => __( 'Loop', 'better-payment' ),
                    'type'  => 'switch',
                ],
                [
                    'key'   => 'controls',
                    'label' => __( 'Show Controls', 'better-payment' ),
                    'type'  => 'switch',
                ],
                [
                    'key'          => 'start_time',
                    'label'        => __( 'Start Time (seconds)', 'better-payment' ),
                    'type'         => 'number',
                    'min'          => 0,
                    'defaultValue' => 0,
                ],
                [
                    'key'          => 'width',
                    'label'        => __( 'Width', 'better-payment' ),
                    'type'         => 'range',
                    'min'          => 10,
                    'max'          => 100,
                    'step'         => 1,
                    'unit'         => '%',
                    'defaultValue' => 100,
                ],
                [
                    'key'   => 'align',
                    'label' => __( 'Align', 'better-payment' ),
                    'type'  => 'align',
                ],
            ],
        ];
    }
}

```
