| @@ -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,41 +288,82 @@ | ||
| 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(); |
| 319 | + } | |
| 320 | + | |
| 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 | + ]; | |
| 311 | 366 | } |
| 312 | 367 | |
| 313 | 368 | /** |
| 314 | 369 | * A poster frame, never a real embed. |