PluginProbe
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More / 2.4.1
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More v2.4.1
2.4.1 2.4.0 2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.2 2.2.1 2.2.0 2.1.2 2.1.1 trunk 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.0.7 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 All 68 releases
← All changes | includes/Campaign/Elements/ProElementPreview.php +95 -40 2.3.0 → 2.4.1 View file →
@@ -11,11 +11,17 @@
11 11 * for sites without Better Payment Pro.
12 12 *
13 13 * Replaces the old flat "PRO" banner. A banner told a free user nothing about
14 14 * what the element does; this paints a realistic approximation so they can see
15 - * the widget, watch it react to the (disabled) controls beside it, and judge
16 - * whether Pro is worth buying.
15 + * the widget and judge whether Pro is worth buying.
17 16 *
17 + * A free install registers only a lock stub for these elements
18 + * ({@see ProElementStubs}: no schema, no default settings), so a freshly dropped
19 + * element reaches here with `[]` settings and every mock must look complete from
20 + * built-in sample content alone. Settings that ARE present — a campaign built
21 + * while Pro was active — are still honoured, so a downgraded campaign shows the
22 + * author's own configuration.
23 + *
18 24 * ── The one rule that matters ────────────────────────────────────────────────
19 25 * **This NEVER renders on the public frontend.** Every method here fabricates
20 26 * data — invented donor names, invented amounts. On a live fundraising page that
21 27 * is not a cosmetic bug, it is a lie about who gave money. Two independent gates
@@ -174,9 +180,11 @@
174 180 $show_amount = ! isset( $settings['show_amount'] ) || $settings['show_amount'];
175 181 $show_avatar = ! isset( $settings['show_avatar'] ) || $settings['show_avatar'];
176 182 $show_date = ! isset( $settings['show_date'] ) || $settings['show_date'];
177 183
178 - $headline = isset( $settings['headline'] ) ? (string) $settings['headline'] : '';
184 + // Unset (a stub-registered element) takes the sample heading; an emptied
185 + // heading stays empty.
186 + $headline = isset( $settings['headline'] ) ? (string) $settings['headline'] : __( 'Recent Donors', 'better-payment' );
179 187 $accent = self::safe_color( isset( $settings['accent_color'] ) ? $settings['accent_color'] : '' );
180 188
181 189 $donors = array_slice( self::sample_donors(), 0, $limit );
182 190
@@ -251,10 +259,12 @@
251 259 return (string) ob_get_clean();
252 260 }
253 261
254 262 /**
255 - * The FAQ mock renders the author's OWN items, not invented ones — the
256 - * questions are already in the saved settings and are not Pro data. Only the
263 + * The FAQ mock renders the author's OWN items when the saved settings carry
264 + * any (a campaign built while Pro was active) — those questions are not Pro
265 + * data. Otherwise it shows {@see self::sample_faq_items()}: placeholder copy
266 + * that describes the widget and states nothing about the campaign. Only the
257 267 * accordion's interactivity is missing, so every item is shown open.
258 268 *
259 269 * @param array $settings
260 270 * @return string
@@ -259,14 +269,18 @@
259 269 * @param array $settings
260 270 * @return string
261 271 */
262 272 private static function faq( array $settings ): string {
263 - $heading = isset( $settings['heading'] ) ? (string) $settings['heading'] : '';
273 + $heading = isset( $settings['heading'] ) ? (string) $settings['heading'] : __( 'Frequently Asked Questions', 'better-payment' );
264 274 $accent = self::safe_color( isset( $settings['accent_color'] ) ? $settings['accent_color'] : '' );
265 275
266 276 $items = ( isset( $settings['items'] ) && is_array( $settings['items'] ) ) ? $settings['items'] : [];
267 277 $items = array_slice( $items, 0, 30 );
268 278
279 + if ( ! self::has_faq_content( $items ) ) {
280 + $items = self::sample_faq_items();
281 + }
282 +
269 283 ob_start();
270 284 ?>
271 285 <div>
272 286 <?php if ( '' !== $heading ) : ?>
@@ -274,38 +288,32 @@
274 288 <?php echo esc_html( $heading ); ?>
275 289 </h4>
276 290 <?php endif; ?>
277 291
278 - <?php if ( empty( $items ) ) : ?>
279 - <p style="margin:0;font-size:12px;color:#787c82;">
280 - <?php esc_html_e( 'No questions added yet.', 'better-payment' ); ?>
281 - </p>
282 - <?php else : ?>
283 - <div style="display:flex;flex-direction:column;gap:8px;">
284 - <?php foreach ( $items as $item ) :
285 - $question = isset( $item['question'] ) ? (string) $item['question'] : '';
286 - $answer = isset( $item['answer'] ) ? (string) $item['answer'] : '';
292 + <div style="display:flex;flex-direction:column;gap:8px;">
293 + <?php foreach ( $items as $item ) :
294 + $question = isset( $item['question'] ) ? (string) $item['question'] : '';
295 + $answer = isset( $item['answer'] ) ? (string) $item['answer'] : '';
287 296
288 - if ( '' === $question && '' === $answer ) {
289 - continue;
290 - }
291 - ?>
292 - <div style="border:1px solid #f0f0f1;border-radius:6px;padding:10px 12px;">
293 - <div style="display:flex;align-items:flex-start;gap:8px;">
294 - <span style="flex:0 0 auto;color:<?php echo esc_attr( $accent ); ?>;font-weight:700;line-height:1.4;">+</span>
295 - <span style="flex:1 1 auto;font-size:13px;font-weight:600;color:#1a1a2e;line-height:1.4;">
296 - <?php echo esc_html( $question ); ?>
297 - </span>
298 - </div>
299 - <?php if ( '' !== $answer ) : ?>
300 - <p style="margin:6px 0 0 18px;font-size:12px;line-height:1.6;color:#50575e;">
301 - <?php echo esc_html( $answer ); ?>
302 - </p>
303 - <?php endif; ?>
297 + if ( '' === $question && '' === $answer ) {
298 + continue;
299 + }
300 + ?>
301 + <div style="border:1px solid #f0f0f1;border-radius:6px;padding:10px 12px;">
302 + <div style="display:flex;align-items:flex-start;gap:8px;">
303 + <span style="flex:0 0 auto;color:<?php echo esc_attr( $accent ); ?>;font-weight:700;line-height:1.4;">+</span>
304 + <span style="flex:1 1 auto;font-size:13px;font-weight:600;color:#1a1a2e;line-height:1.4;">
305 + <?php echo esc_html( $question ); ?>
306 + </span>
304 307 </div>
305 - <?php endforeach; ?>
306 - </div>
307 - <?php endif; ?>
308 + <?php if ( '' !== $answer ) : ?>
309 + <p style="margin:6px 0 0 18px;font-size:12px;line-height:1.6;color:#50575e;">
310 + <?php echo esc_html( $answer ); ?>
311 + </p>
312 + <?php endif; ?>
313 + </div>
314 + <?php endforeach; ?>
315 + </div>
308 316 </div>
309 317 <?php
310 318 return (string) ob_get_clean();
311 319 }
@@ -310,8 +318,55 @@
310 318 return (string) ob_get_clean();
311 319 }
312 320
313 321 /**
322 + * Whether any FAQ row carries a question or an answer.
323 + *
324 + * @param array $items Saved FAQ rows.
325 + * @return bool
326 + */
327 + private static function has_faq_content( array $items ): bool {
328 + foreach ( $items as $item ) {
329 + if ( ! is_array( $item ) ) {
330 + continue;
331 + }
332 + $question = isset( $item['question'] ) ? (string) $item['question'] : '';
333 + $answer = isset( $item['answer'] ) ? (string) $item['answer'] : '';
334 + if ( '' !== $question || '' !== $answer ) {
335 + return true;
336 + }
337 + }
338 +
339 + return false;
340 + }
341 +
342 + /**
343 + * Sample FAQ rows for a mock with no saved questions.
344 + *
345 + * The questions are the generic ones any donor asks; the answers describe the
346 + * widget, not the campaign, so nothing here can be read as a claim about how a
347 + * real campaign spends its money.
348 + *
349 + * @return array<int, array<string, string>>
350 + */
351 + private static function sample_faq_items(): array {
352 + return [
353 + [
354 + 'question' => __( 'How will my donation be used?', 'better-payment' ),
355 + 'answer' => __( 'Your own answer appears here. Add the questions donors ask most, each with a short, direct answer.', 'better-payment' ),
356 + ],
357 + [
358 + 'question' => __( 'Is my payment secure?', 'better-payment' ),
359 + 'answer' => __( 'Sample answer. Each question opens and closes on your live campaign.', 'better-payment' ),
360 + ],
361 + [
362 + 'question' => __( 'Can I donate any amount?', 'better-payment' ),
363 + 'answer' => __( 'Sample answer. Add, remove and reorder questions as your campaign needs.', 'better-payment' ),
364 + ],
365 + ];
366 + }
367 +
368 + /**
314 369 * A poster frame, never a real embed.
315 370 *
316 371 * Rendering the actual `<iframe>` would mean Lite reproducing Pro's URL
317 372 * parsing and, for self-hosted files, its oEmbed HTTP call — exactly the
@@ -422,34 +477,34 @@
422 477 private static function sample_donors(): array {
423 478 return [
424 479 [
425 480 'name' => __( 'Jordan A.', 'better-payment' ),
426 - 'amount' => '$250.00',
481 + 'amount' => '$250',
427 482 'when' => __( '2 hours ago', 'better-payment' ),
428 483 ],
429 484 [
430 485 'name' => __( 'Priya S.', 'better-payment' ),
431 - 'amount' => '$100.00',
486 + 'amount' => '$100',
432 487 'when' => __( '5 hours ago', 'better-payment' ),
433 488 ],
434 489 [
435 490 'name' => __( 'Marco B.', 'better-payment' ),
436 - 'amount' => '$75.00',
491 + 'amount' => '$75',
437 492 'when' => __( 'Yesterday', 'better-payment' ),
438 493 ],
439 494 [
440 495 'name' => __( 'Anonymous', 'better-payment' ),
441 - 'amount' => '$50.00',
496 + 'amount' => '$50',
442 497 'when' => __( 'Yesterday', 'better-payment' ),
443 498 ],
444 499 [
445 500 'name' => __( 'Lena K.', 'better-payment' ),
446 - 'amount' => '$40.00',
501 + 'amount' => '$40',
447 502 'when' => __( '2 days ago', 'better-payment' ),
448 503 ],
449 504 [
450 505 'name' => __( 'Sam O.', 'better-payment' ),
451 - 'amount' => '$25.00',
506 + 'amount' => '$25',
452 507 'when' => __( '3 days ago', 'better-payment' ),
453 508 ],
454 509 ];
455 510 }