| @@ -6,39 +6,30 @@ | ||
| 6 | 6 | exit; |
| 7 | 7 | } |
| 8 | 8 | |
| 9 | 9 | /** |
| 10 | - * Control schemas for the three Pro-only campaign elements — Donors Wall, FAQ | |
| 11 | - * and Video. | |
| 10 | + * Fatal guard for Better Payment Pro 1.4.3 and older. Holds no schema. | |
| 12 | 11 | * |
| 13 | - * These live in Lite, not Pro, on purpose. Lite has to render the *complete* | |
| 14 | - * control set for a Pro element (disabled, with a locked banner) so a free user | |
| 15 | - * can see exactly what Pro buys them. That needs the schema, and a schema is | |
| 16 | - * pure declarative data — labels, control types, option lists. It carries no | |
| 17 | - * business logic, no data access and no markup, so nothing sensitive crosses the | |
| 18 | - * boundary by living here. | |
| 12 | + * The Donors Wall, FAQ and Video schemas and default settings ship with Pro | |
| 13 | + * (better-payment-pro/includes/Campaign/ProElementSchemas.php); a free install gets | |
| 14 | + * {@see ProElementStubs}. Lite's transitional copy of the schemas was deleted when | |
| 15 | + * ProCompatibility::MIN_PRO_VERSION reached 1.4.4. | |
| 19 | 16 | * |
| 20 | - * Keeping it here also means there is exactly ONE copy. When Pro owned these and | |
| 21 | - * overwrote Lite's stubs, Lite could only show an empty panel; giving Lite its | |
| 22 | - * own copy instead would have created two 350-line arrays that drift the first | |
| 23 | - * time someone adds a control to Pro and forgets Lite — at which point the free | |
| 24 | - * preview quietly misrepresents the product. | |
| 17 | + * What stays is only what Pro 1.4.3 reads directly: its `BuilderElements` aliases | |
| 18 | + * these constants at class-constant time and calls {@see self::default_video_url()}, | |
| 19 | + * so removing them would fatal every campaign render on a site that updated Lite | |
| 20 | + * before Pro. Pro 1.4.4+ reads its own class. Pinned by | |
| 21 | + * tests/Unit/ProCouplingContractTest.php; delete this file once no supported site | |
| 22 | + * can run Pro 1.4.3. | |
| 25 | 23 | * |
| 26 | - * What stays in Pro: every renderer, the donor queries, oEmbed/HTTP, the view | |
| 27 | - * templates. See `Better_Payment\Pro\Campaign\BuilderElements`. | |
| 28 | - * | |
| 29 | - * The `pro => true` flag is attached by {@see CampaignElements::register_pro_elements()}, | |
| 30 | - * not here, and is kept on the schema whether or not Pro is active — the live | |
| 31 | - * `better_payment/pro_enabled` filter is what decides locking, never a stored value. | |
| 24 | + * @deprecated Kept only so Better Payment Pro <= 1.4.3 does not fatal. | |
| 32 | 25 | */ |
| 33 | 26 | class ProElementSchemas { |
| 34 | 27 | |
| 35 | 28 | /** |
| 36 | - * The video a newly added Video element starts with, so a freshly dropped | |
| 37 | - * element isn't a blank box. | |
| 29 | + * The video a newly added Video element starts with. | |
| 38 | 30 | * |
| 39 | - * Lives here rather than in Pro because it is part of `defaultSettings`, | |
| 40 | - * which is part of the schema. Pro keeps a back-compat alias. | |
| 31 | + * Pro 1.4.3's `BuilderElements::DEFAULT_VIDEO_URL` aliases this constant. | |
| 41 | 32 | */ |
| 42 | 33 | const DEFAULT_VIDEO_URL = 'https://www.youtube.com/watch?v=jeXG-4SOlZE'; |
| 43 | 34 | |
| 44 | 35 | /** |
| @@ -52,409 +43,6 @@ | ||
| 52 | 43 | * @return string |
| 53 | 44 | */ |
| 54 | 45 | public static function default_video_url(): string { |
| 55 | 46 | return (string) apply_filters( 'better_payment/campaign/default_video_url', self::DEFAULT_VIDEO_URL ); |
| 56 | - } | |
| 57 | - | |
| 58 | - /** | |
| 59 | - * All three schemas, keyed by element type. | |
| 60 | - * | |
| 61 | - * @return array<string, array> | |
| 62 | - */ | |
| 63 | - public static function get_all(): array { | |
| 64 | - return [ | |
| 65 | - 'donors_wall' => self::donors_wall(), | |
| 66 | - 'faq' => self::faq(), | |
| 67 | - 'video' => self::video(), | |
| 68 | - ]; | |
| 69 | - } | |
| 70 | - | |
| 71 | - /** | |
| 72 | - * @return array | |
| 73 | - */ | |
| 74 | - public static function donors_wall(): array { | |
| 75 | - return [ | |
| 76 | - 'label' => __( 'Donors Wall', 'better-payment' ), | |
| 77 | - 'icon' => 'groups', | |
| 78 | - 'defaultSettings' => [ | |
| 79 | - 'headline' => __( 'Recent Donors', 'better-payment' ), | |
| 80 | - 'layout' => 'list', | |
| 81 | - 'columns' => 2, | |
| 82 | - 'number_to_show' => 10, | |
| 83 | - 'order_by' => 'date', | |
| 84 | - 'order' => 'desc', | |
| 85 | - 'hide_if_empty' => false, | |
| 86 | - 'show_summary' => true, | |
| 87 | - 'show_name' => true, | |
| 88 | - 'show_amount' => true, | |
| 89 | - 'show_avatar' => true, | |
| 90 | - 'show_date' => true, | |
| 91 | - 'accent_color' => '', | |
| 92 | - 'width' => 100, | |
| 93 | - 'align' => 'left', | |
| 94 | - ], | |
| 95 | - 'settingsSchema' => [ | |
| 96 | - [ | |
| 97 | - 'key' => 'headline', | |
| 98 | - 'label' => __( 'Headline', 'better-payment' ), | |
| 99 | - 'type' => 'text', | |
| 100 | - 'placeholder' => __( 'Recent Donors', 'better-payment' ), | |
| 101 | - ], | |
| 102 | - [ | |
| 103 | - 'key' => 'layout', | |
| 104 | - 'label' => __( 'Layout', 'better-payment' ), | |
| 105 | - 'type' => 'select', | |
| 106 | - 'options' => [ | |
| 107 | - [ 'value' => 'list', 'label' => __( 'List (vertical)', 'better-payment' ) ], | |
| 108 | - [ 'value' => 'grid', 'label' => __( 'Grid', 'better-payment' ) ], | |
| 109 | - [ 'value' => 'ticker', 'label' => __( 'Ticker (auto-scroll)', 'better-payment' ) ], | |
| 110 | - ], | |
| 111 | - ], | |
| 112 | - // A select, not a range: three discrete values are chosen, not | |
| 113 | - // dialled. It was a slider whose value read "4%" — the builder's | |
| 114 | - // range control used to assume every range was a percentage. | |
| 115 | - // Shown only for the grid, where columns mean anything at all. | |
| 116 | - [ | |
| 117 | - 'key' => 'columns', | |
| 118 | - 'label' => __( 'Grid Columns', 'better-payment' ), | |
| 119 | - 'type' => 'select', | |
| 120 | - 'defaultValue' => 2, | |
| 121 | - 'condition' => [ 'layout' => 'grid' ], | |
| 122 | - 'options' => [ | |
| 123 | - [ 'value' => 2, 'label' => __( '2 columns', 'better-payment' ) ], | |
| 124 | - [ 'value' => 3, 'label' => __( '3 columns', 'better-payment' ) ], | |
| 125 | - [ 'value' => 4, 'label' => __( '4 columns', 'better-payment' ) ], | |
| 126 | - ], | |
| 127 | - ], | |
| 128 | - [ | |
| 129 | - 'key' => 'number_to_show', | |
| 130 | - 'label' => __( 'Number of Donors To Show', 'better-payment' ), | |
| 131 | - 'type' => 'number', | |
| 132 | - 'min' => 0, | |
| 133 | - 'max' => 100, | |
| 134 | - 'defaultValue' => 10, | |
| 135 | - 'info' => __( 'Set to 0 to hide the donor list.', 'better-payment' ), | |
| 136 | - ], | |
| 137 | - [ | |
| 138 | - 'key' => 'order_by', | |
| 139 | - 'label' => __( 'Order By', 'better-payment' ), | |
| 140 | - 'type' => 'select', | |
| 141 | - 'options' => [ | |
| 142 | - [ 'value' => 'date', 'label' => __( 'Date', 'better-payment' ) ], | |
| 143 | - [ 'value' => 'amount', 'label' => __( 'Amount', 'better-payment' ) ], | |
| 144 | - ], | |
| 145 | - ], | |
| 146 | - // Two variants of the same `order` control, gated on `order_by`, | |
| 147 | - // so the direction labels read naturally for what's being sorted. | |
| 148 | - // Both write the same `order` key with the same `desc`/`asc` | |
| 149 | - // values — the renderer is unchanged and the chosen value survives | |
| 150 | - // switching Order By. Only one is ever visible (isControlVisible). | |
| 151 | - [ | |
| 152 | - 'key' => 'order', | |
| 153 | - 'label' => __( 'Order', 'better-payment' ), | |
| 154 | - 'type' => 'select', | |
| 155 | - 'condition' => [ 'order_by' => 'amount' ], | |
| 156 | - 'options' => [ | |
| 157 | - [ 'value' => 'desc', 'label' => __( 'High to Low', 'better-payment' ) ], | |
| 158 | - [ 'value' => 'asc', 'label' => __( 'Low to High', 'better-payment' ) ], | |
| 159 | - ], | |
| 160 | - ], | |
| 161 | - [ | |
| 162 | - 'key' => 'order', | |
| 163 | - 'label' => __( 'Order', 'better-payment' ), | |
| 164 | - 'type' => 'select', | |
| 165 | - 'condition' => [ 'order_by' => 'date' ], | |
| 166 | - 'options' => [ | |
| 167 | - [ 'value' => 'desc', 'label' => __( 'Newest First', 'better-payment' ) ], | |
| 168 | - [ 'value' => 'asc', 'label' => __( 'Oldest First', 'better-payment' ) ], | |
| 169 | - ], | |
| 170 | - ], | |
| 171 | - [ | |
| 172 | - 'key' => 'hide_if_empty', | |
| 173 | - 'label' => __( 'Hide If No Donors', 'better-payment' ), | |
| 174 | - 'type' => 'switch', | |
| 175 | - ], | |
| 176 | - [ | |
| 177 | - 'key' => '_donor_info_label', | |
| 178 | - 'label' => __( 'Donor Information', 'better-payment' ), | |
| 179 | - 'type' => 'section_label', | |
| 180 | - ], | |
| 181 | - [ | |
| 182 | - 'key' => 'show_summary', | |
| 183 | - 'label' => __( 'Show Totals Summary', 'better-payment' ), | |
| 184 | - 'type' => 'switch', | |
| 185 | - ], | |
| 186 | - [ | |
| 187 | - 'key' => 'show_name', | |
| 188 | - 'label' => __( 'Show Name', 'better-payment' ), | |
| 189 | - 'type' => 'switch', | |
| 190 | - ], | |
| 191 | - [ | |
| 192 | - 'key' => 'show_amount', | |
| 193 | - 'label' => __( 'Show Amount', 'better-payment' ), | |
| 194 | - 'type' => 'switch', | |
| 195 | - ], | |
| 196 | - [ | |
| 197 | - 'key' => 'show_avatar', | |
| 198 | - 'label' => __( 'Show Avatar', 'better-payment' ), | |
| 199 | - 'type' => 'switch', | |
| 200 | - ], | |
| 201 | - [ | |
| 202 | - 'key' => 'show_date', | |
| 203 | - 'label' => __( 'Show Time', 'better-payment' ), | |
| 204 | - 'type' => 'switch', | |
| 205 | - ], | |
| 206 | - [ | |
| 207 | - 'key' => '_style_label', | |
| 208 | - 'label' => __( 'Style', 'better-payment' ), | |
| 209 | - 'type' => 'section_label', | |
| 210 | - ], | |
| 211 | - [ | |
| 212 | - 'key' => 'accent_color', | |
| 213 | - 'label' => __( 'Accent Color', 'better-payment' ), | |
| 214 | - 'type' => 'color', | |
| 215 | - 'info' => __( 'Leave empty to inherit the campaign color.', 'better-payment' ), | |
| 216 | - ], | |
| 217 | - [ | |
| 218 | - 'key' => 'width', | |
| 219 | - 'label' => __( 'Width', 'better-payment' ), | |
| 220 | - 'type' => 'range', | |
| 221 | - 'min' => 10, | |
| 222 | - 'max' => 100, | |
| 223 | - 'step' => 1, | |
| 224 | - 'unit' => '%', | |
| 225 | - 'defaultValue' => 100, | |
| 226 | - ], | |
| 227 | - [ | |
| 228 | - 'key' => 'align', | |
| 229 | - 'label' => __( 'Align', 'better-payment' ), | |
| 230 | - 'type' => 'align', | |
| 231 | - ], | |
| 232 | - ], | |
| 233 | - ]; | |
| 234 | - } | |
| 235 | - | |
| 236 | - /** | |
| 237 | - * @return array | |
| 238 | - */ | |
| 239 | - public static function faq(): array { | |
| 240 | - return [ | |
| 241 | - 'label' => __( 'FAQ', 'better-payment' ), | |
| 242 | - 'icon' => 'editor-help', | |
| 243 | - 'defaultSettings' => [ | |
| 244 | - 'heading' => __( 'Frequently Asked Questions', 'better-payment' ), | |
| 245 | - 'items' => [ | |
| 246 | - [ | |
| 247 | - 'question' => __( 'How will my donation help?', 'better-payment' ), | |
| 248 | - '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' ), | |
| 249 | - ], | |
| 250 | - [ | |
| 251 | - 'question' => __( 'Is my donation secure?', 'better-payment' ), | |
| 252 | - 'answer' => __( 'Yes. Donations are processed through a secure payment system to help keep your payment information safe.', 'better-payment' ), | |
| 253 | - ], | |
| 254 | - [ | |
| 255 | - 'question' => __( 'Can I donate any amount?', 'better-payment' ), | |
| 256 | - 'answer' => __( 'Yes. Every contribution matters, regardless of the amount. You can donate an amount that feels comfortable for you.', 'better-payment' ), | |
| 257 | - ], | |
| 258 | - [ | |
| 259 | - 'question' => __( 'Can I share this campaign with others?', 'better-payment' ), | |
| 260 | - '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' ), | |
| 261 | - ], | |
| 262 | - ], | |
| 263 | - 'style' => 'accordion', | |
| 264 | - 'icon_style' => 'chevron', | |
| 265 | - 'single_open' => true, | |
| 266 | - 'first_open' => true, | |
| 267 | - 'accent_color' => '', | |
| 268 | - 'width' => 100, | |
| 269 | - 'align' => 'left', | |
| 270 | - ], | |
| 271 | - 'settingsSchema' => [ | |
| 272 | - [ | |
| 273 | - 'key' => 'heading', | |
| 274 | - 'label' => __( 'Heading', 'better-payment' ), | |
| 275 | - 'type' => 'text', | |
| 276 | - 'placeholder' => __( 'Frequently Asked Questions', 'better-payment' ), | |
| 277 | - ], | |
| 278 | - [ | |
| 279 | - 'key' => 'items', | |
| 280 | - 'label' => __( 'FAQ Items', 'better-payment' ), | |
| 281 | - 'type' => 'repeater', | |
| 282 | - 'itemLabel' => __( 'Question', 'better-payment' ), | |
| 283 | - 'titleField' => 'question', | |
| 284 | - 'addLabel' => __( 'Add Question', 'better-payment' ), | |
| 285 | - 'max' => 30, | |
| 286 | - 'fields' => [ | |
| 287 | - [ | |
| 288 | - 'key' => 'question', | |
| 289 | - 'label' => __( 'Question', 'better-payment' ), | |
| 290 | - 'type' => 'text', | |
| 291 | - 'placeholder' => __( 'Enter a question', 'better-payment' ), | |
| 292 | - ], | |
| 293 | - [ | |
| 294 | - 'key' => 'answer', | |
| 295 | - 'label' => __( 'Answer', 'better-payment' ), | |
| 296 | - 'type' => 'textarea', | |
| 297 | - 'rows' => 3, | |
| 298 | - 'placeholder' => __( 'Enter the answer', 'better-payment' ), | |
| 299 | - ], | |
| 300 | - [ | |
| 301 | - 'key' => 'open', | |
| 302 | - 'label' => __( 'Open by default?', 'better-payment' ), | |
| 303 | - 'type' => 'switch', | |
| 304 | - ], | |
| 305 | - ], | |
| 306 | - ], | |
| 307 | - [ | |
| 308 | - 'key' => 'style', | |
| 309 | - 'label' => __( 'Style', 'better-payment' ), | |
| 310 | - 'type' => 'select', | |
| 311 | - 'options' => [ | |
| 312 | - [ 'value' => 'accordion', 'label' => __( 'Accordion (collapsible)', 'better-payment' ) ], | |
| 313 | - [ 'value' => 'list', 'label' => __( 'Open list', 'better-payment' ) ], | |
| 314 | - ], | |
| 315 | - ], | |
| 316 | - [ | |
| 317 | - 'key' => 'icon_style', | |
| 318 | - 'label' => __( 'Toggle Icon', 'better-payment' ), | |
| 319 | - 'type' => 'select', | |
| 320 | - // Accordion-only: the open-list style shows every answer, so | |
| 321 | - // there is no collapse toggle to put an icon on. | |
| 322 | - 'condition' => [ 'style' => 'accordion' ], | |
| 323 | - 'options' => [ | |
| 324 | - [ 'value' => 'chevron', 'label' => __( 'Chevron', 'better-payment' ) ], | |
| 325 | - [ 'value' => 'plus', 'label' => __( 'Plus / Minus', 'better-payment' ) ], | |
| 326 | - [ 'value' => 'none', 'label' => __( 'No icon', 'better-payment' ) ], | |
| 327 | - ], | |
| 328 | - ], | |
| 329 | - [ | |
| 330 | - 'key' => 'single_open', | |
| 331 | - 'label' => __( 'Open One At A Time', 'better-payment' ), | |
| 332 | - 'type' => 'switch', | |
| 333 | - // Accordion-only: an open list has nothing to close. | |
| 334 | - 'condition' => [ 'style' => 'accordion' ], | |
| 335 | - 'info' => __( 'Opening a question closes the others (accordion only).', 'better-payment' ), | |
| 336 | - ], | |
| 337 | - [ | |
| 338 | - 'key' => 'first_open', | |
| 339 | - 'label' => __( 'Open First Item By Default', 'better-payment' ), | |
| 340 | - 'type' => 'switch', | |
| 341 | - // Accordion-only: open-list items are all expanded already. | |
| 342 | - 'condition' => [ 'style' => 'accordion' ], | |
| 343 | - ], | |
| 344 | - [ | |
| 345 | - 'key' => 'accent_color', | |
| 346 | - 'label' => __( 'Accent Color', 'better-payment' ), | |
| 347 | - 'type' => 'color', | |
| 348 | - 'info' => __( 'Leave empty to inherit the campaign color.', 'better-payment' ), | |
| 349 | - ], | |
| 350 | - [ | |
| 351 | - 'key' => 'width', | |
| 352 | - 'label' => __( 'Width', 'better-payment' ), | |
| 353 | - 'type' => 'range', | |
| 354 | - 'min' => 10, | |
| 355 | - 'max' => 100, | |
| 356 | - 'step' => 1, | |
| 357 | - 'unit' => '%', | |
| 358 | - 'defaultValue' => 100, | |
| 359 | - ], | |
| 360 | - [ | |
| 361 | - 'key' => 'align', | |
| 362 | - 'label' => __( 'Align', 'better-payment' ), | |
| 363 | - 'type' => 'align', | |
| 364 | - ], | |
| 365 | - ], | |
| 366 | - ]; | |
| 367 | - } | |
| 368 | - | |
| 369 | - /** | |
| 370 | - * @return array | |
| 371 | - */ | |
| 372 | - public static function video(): array { | |
| 373 | - return [ | |
| 374 | - 'label' => __( 'Video', 'better-payment' ), | |
| 375 | - 'icon' => 'format-video', | |
| 376 | - 'defaultSettings' => [ | |
| 377 | - 'url' => self::default_video_url(), | |
| 378 | - 'aspect_ratio' => '16-9', | |
| 379 | - 'autoplay' => false, | |
| 380 | - 'muted' => false, | |
| 381 | - 'loop' => false, | |
| 382 | - 'controls' => true, | |
| 383 | - 'start_time' => self::DEFAULT_VIDEO_START, | |
| 384 | - 'width' => 100, | |
| 385 | - 'align' => 'center', | |
| 386 | - ], | |
| 387 | - 'settingsSchema' => [ | |
| 388 | - [ | |
| 389 | - 'key' => 'url', | |
| 390 | - 'label' => __( 'Video URL', 'better-payment' ), | |
| 391 | - 'type' => 'url', | |
| 392 | - // Renders a Media Library button beside the field (Lite's | |
| 393 | - // `url` control), so an uploaded video can be chosen without | |
| 394 | - // leaving the builder to copy its URL. | |
| 395 | - 'mediaType' => 'video', | |
| 396 | - 'placeholder' => 'https://www.youtube.com/watch?v=…', | |
| 397 | - 'info' => __( 'Paste a YouTube or Vimeo link, or choose an uploaded video from your Media Library.', 'better-payment' ), | |
| 398 | - ], | |
| 399 | - [ | |
| 400 | - 'key' => 'aspect_ratio', | |
| 401 | - 'label' => __( 'Aspect Ratio', 'better-payment' ), | |
| 402 | - 'type' => 'select', | |
| 403 | - 'options' => [ | |
| 404 | - [ 'value' => '16-9', 'label' => '16:9' ], | |
| 405 | - [ 'value' => '4-3', 'label' => '4:3' ], | |
| 406 | - [ 'value' => '1-1', 'label' => '1:1' ], | |
| 407 | - [ 'value' => '21-9', 'label' => '21:9' ], | |
| 408 | - ], | |
| 409 | - ], | |
| 410 | - [ | |
| 411 | - 'key' => '_playback_label', | |
| 412 | - 'label' => __( 'Playback', 'better-payment' ), | |
| 413 | - 'type' => 'section_label', | |
| 414 | - ], | |
| 415 | - [ | |
| 416 | - 'key' => 'autoplay', | |
| 417 | - 'label' => __( 'Autoplay', 'better-payment' ), | |
| 418 | - 'type' => 'switch', | |
| 419 | - ], | |
| 420 | - [ | |
| 421 | - 'key' => 'muted', | |
| 422 | - 'label' => __( 'Muted', 'better-payment' ), | |
| 423 | - 'type' => 'switch', | |
| 424 | - ], | |
| 425 | - [ | |
| 426 | - 'key' => 'loop', | |
| 427 | - 'label' => __( 'Loop', 'better-payment' ), | |
| 428 | - 'type' => 'switch', | |
| 429 | - ], | |
| 430 | - [ | |
| 431 | - 'key' => 'controls', | |
| 432 | - 'label' => __( 'Show Controls', 'better-payment' ), | |
| 433 | - 'type' => 'switch', | |
| 434 | - ], | |
| 435 | - [ | |
| 436 | - 'key' => 'start_time', | |
| 437 | - 'label' => __( 'Start Time (seconds)', 'better-payment' ), | |
| 438 | - 'type' => 'number', | |
| 439 | - 'min' => 0, | |
| 440 | - 'defaultValue' => 0, | |
| 441 | - ], | |
| 442 | - [ | |
| 443 | - 'key' => 'width', | |
| 444 | - 'label' => __( 'Width', 'better-payment' ), | |
| 445 | - 'type' => 'range', | |
| 446 | - 'min' => 10, | |
| 447 | - 'max' => 100, | |
| 448 | - 'step' => 1, | |
| 449 | - 'unit' => '%', | |
| 450 | - 'defaultValue' => 100, | |
| 451 | - ], | |
| 452 | - [ | |
| 453 | - 'key' => 'align', | |
| 454 | - 'label' => __( 'Align', 'better-payment' ), | |
| 455 | - 'type' => 'align', | |
| 456 | - ], | |
| 457 | - ], | |
| 458 | - ]; | |
| 459 | 47 | } |
| 460 | 48 | } |