PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13.1 1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 All 212 releases
charitable / includes / public / charitable-template-helpers.php

charitable-template-helpers.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.13, at includes/public/charitable-template-helpers.php

481 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Charitable Template Helpers.
4 *
5 * Functions used to assist with rendering templates.
6 *
7 * @package Charitable/Functions/Templates
8 * @author David Bisset
9 * @copyright Copyright (c) 2023, WP Charitable LLC
10 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
11 * @since 1.0.0
12 * @version 1.8.13
13 */
14
15 // Exit if accessed directly.
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit;
18 }
19
20 /**
21 * Displays a template.
22 *
23 * @since 1.0.0
24 * @since 1.5.2 Added $classname parameter.
25 *
26 * @param string|string[] $template_name A single template name or an ordered array of template.
27 * @param mixed[] $args Optional array of arguments to pass to the view.
28 * @param string $classname Template class name. Allows for extensions to use charitable_template().
29 * @return Charitable_Template
30 */
31 function charitable_template( $template_name, array $args = array(), $classname = 'Charitable_Template' ) {
32 $classname = apply_filters( 'charitable_template_class_name', $classname, $template_name, $args );
33
34 if ( ! class_exists( $classname ) ) {
35 $classname = 'Charitable_Template';
36 }
37
38 $class = class_exists( $classname ) ? $classname : 'Charitable_Template';
39 if ( empty( $args ) ) {
40 $template = new $classname( $template_name );
41 } else {
42 $template = new $classname( $template_name, false );
43 $template->set_view_args( $args );
44 $template->render();
45 }
46
47 return $template;
48 }
49
50 /**
51 * When a session-reliant template is displayed without a session ID being
52 * set, wrap the output in a wrapper that tells our client-side session
53 * handler to fetch content via AJAX.
54 *
55 * @since 1.5.0
56 *
57 * @param string|string[] $template_name A single template name or an ordered array of template.
58 * @param mixed[] $args Array of arguments to pass to the view.
59 * @param string $template_key A key representing the template, which will be passed
60 * as one of the arguments in the AJAX request.
61 * @param array $wrapper_args A mixed set of arguments that need to be passed along
62 * in the AJAX request.
63 * @param string $classname Template class name. Allows for extensions to use charitable_template().
64 * @return void Content is echoed.
65 */
66 function charitable_template_from_session( $template_name, array $args, $template_key, $wrapper_args = array(), $classname = 'Charitable_Template' ) {
67 ob_start();
68
69 charitable_template( $template_name, $args, $classname );
70
71 echo charitable_template_from_session_content( $template_key, $wrapper_args, ob_get_clean() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
72 }
73
74 /**
75 * Returns a piece of content or an empty string, wrapped in the correct markup
76 * for on-demand session content retrieval.
77 *
78 * @since 1.5.0
79 *
80 * @param string $template_key A key representing the template, which will be passed
81 * as one of the arguments in the AJAX request.
82 * @param array $wrapper_args A mixed set of arguments that need to be passed along
83 * in the AJAX request.
84 * @param string $default The default content to be displayed if no content is
85 * returned from the AJAX request, or the user does not
86 * have Javascript enabled.
87 * @return string
88 */
89 function charitable_template_from_session_content( $template_key, $wrapper_args = array(), $default = '' ) {
90 /* When we have a session ID, we just print the default. */
91 if ( charitable_get_session()->has_session_id() ) {
92 return $default;
93 }
94
95 $content = '<div class="charitable-session-content" data-template="' . esc_attr( $template_key ) . '" data-args="' . esc_attr( wp_json_encode( $wrapper_args ) ) . '" style="display: none;">' . $default . '</div>';
96 $content .= '<noscript>' . $default . '</noscript>';
97
98 return $content;
99 }
100
101 /**
102 * Return the template path if the template exists. Otherwise, return default.
103 *
104 * @since 1.0.0
105 *
106 * @param string|string[] $template The template to load.
107 * @param string $default The default to load if the template file doesn't exist.
108 * @return string The template path if the template exists. Otherwise, return default.
109 */
110 function charitable_get_template_path( $template, $default = '' ) {
111 $t = new Charitable_Template( $template, false );
112 $path = $t->locate_template();
113
114 if ( ! file_exists( $path ) ) {
115 $path = $default;
116 }
117
118 return $path;
119 }
120
121 /**
122 * Insert a particular template into an array of templates.
123 *
124 * @since 1.5.0
125 *
126 * @param string $template The template to be inserted.
127 * @param array $templates The default set of templates.
128 * @param int $index The position at which to insert the template.
129 * @return array
130 */
131 function charitable_splice_template( $template, $templates, $index = 1 ) {
132 if ( empty( $template ) ) {
133 return $templates;
134 }
135
136 array_splice( $templates, $index, 0, $template );
137
138 return $templates;
139 }
140
141 /**
142 * Simple CSS compression.
143 *
144 * Removes all comments, removes spaces after colons and strips out all the whitespace.
145 *
146 * Based on http://manas.tungare.name/software/css-compression-in-php/
147 *
148 * @since 1.2.0
149 *
150 * @param string $css The block of CSS to be compressed.
151 * @return string The compressed CSS
152 */
153 function charitable_compress_css( $css ) {
154 /* 1. Remove comments */
155 $css = preg_replace( '!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css );
156
157 /* 2. Remove space after colons */
158 $css = str_replace( ': ', ':', $css );
159
160 /* 3. Remove whitespace */
161 $css = str_replace( array( "\r\n", "\r", "\n", "\t", ' ', ' ', ' ' ), '', $css );
162
163 return $css;
164 }
165
166 /**
167 * Provides arguments passed to campaigns within the loop.
168 *
169 * @since 1.2.3
170 *
171 * @param mixed[] $view_args Optional. If called by the shortcode, this will contain the arguments passed to the shortcode.
172 * @return mixed[]
173 */
174 function charitable_campaign_loop_args( $view_args = array() ) {
175 $defaults = array(
176 'button' => 'donate',
177 );
178
179 $args = wp_parse_args( $view_args, $defaults );
180
181 return apply_filters( 'charitable_campaign_loop_args', $args );
182 }
183
184 /**
185 * Provides arguments passed to campaigns within the loop.
186 *
187 * @since 1.5.7
188 *
189 * @param mixed[] $view_args Optional. If called by the shortcode, this will contain the arguments passed to the shortcode.
190 * @return mixed[]
191 */
192 function charitable_campaign_loop_class( $view_args = array() ) {
193 $classes = array( 'campaign-loop' );
194
195 if ( $view_args['columns'] > 1 ) {
196 $classes = array_merge( $classes, array( 'campaign-grid campaign-grid-' . $view_args['columns'] ) );
197
198 if ( $view_args['masonry'] ) {
199 $classes[] = 'masonry';
200 }
201 } else {
202 $classes[] = 'campaign-list';
203 }
204
205 /**
206 * Filter the classes to be applied to the campaign loop.
207 *
208 * @since 1.5.7
209 *
210 * @param array $classes Array of classes.
211 * @param array $view_args View args.
212 */
213 $classes = apply_filters( 'charitable_campaign_loop_classes', $classes, $view_args );
214
215 return implode( ' ', $classes );
216 }
217
218 /**
219 * Processes arbitrary form attributes into HTML-safe key/value pairs
220 *
221 * @since 1.3.0
222 *
223 * @param array $field Array defining the form field attributes.
224 * @return string The formatted HTML-safe attributes.
225 */
226 function charitable_get_arbitrary_attributes( $field ) {
227 if ( ! isset( $field['attrs'] ) ) {
228 $field['attrs'] = array();
229 }
230
231 /* Add backwards compatibility support for placeholder, min, max, step, pattern, rows and required. */
232 foreach ( array( 'placeholder', 'min', 'max', 'step', 'pattern', 'rows', 'required' ) as $attr ) {
233
234 /* Skip if the attribute is not defined in the field, or is explicitly set in the 'attrs' property. */
235 if ( ! array_key_exists( $attr, $field ) || array_key_exists( $attr, $field['attrs'] ) ) {
236 continue;
237 }
238
239 if ( 'required' == $attr ) {
240 /* Skip required attribute if it's not true. */
241 if ( ! $field['required'] ) {
242 continue;
243 }
244
245 $field['attrs'][ $attr ] = 'required';
246 } else {
247 $field['attrs'][ $attr ] = $field[ $attr ];
248 }
249 }
250
251 $output = '';
252
253 foreach ( $field['attrs'] as $key => $value ) {
254 $escaped_value = esc_attr( $value );
255 $output .= " $key=\"$escaped_value\" ";
256 }
257
258 return apply_filters( 'charitable_arbitrary_field_attributes', $output );
259 }
260
261 /**
262 * Checks whether we are currently in the main loop on a singular page.
263 *
264 * This should be used in any functions run on the_content hook, to prevent
265 * Charitable's filters touching other the_content instances outside the main
266 * loop.
267 *
268 * @since 1.4.11
269 * @since 1.8.1 added 'charitable_is_main_loop' filter.
270 *
271 * @return boolean
272 */
273 function charitable_is_main_loop() {
274 $is_main_loop = is_single() && in_the_loop() && is_main_query();
275 return apply_filters( 'charitable_is_main_loop', $is_main_loop );
276 }
277
278 /**
279 * Re-encodes a raw query string so that every key and value is percent-encoded.
280 *
281 * The query string arrives from the request untrusted and unencoded. Rebuilding it
282 * pair by pair guarantees the result contains no character that could break out of
283 * the HTML attribute, JavaScript string or URL context it is later printed into --
284 * including HTML entities such as `&apos;` that survive esc_url() and are decoded
285 * back into a quote by the browser's HTML parser.
286 *
287 * Query strings are application/x-www-form-urlencoded, so urldecode()/urlencode()
288 * is the correct pair here: it round-trips `+` as a space the way the request did.
289 *
290 * @since 1.8.13
291 *
292 * @param string $query_string Raw query string, without the leading '?'.
293 * @return string Re-encoded query string, or an empty string if nothing usable remains.
294 */
295 function charitable_sanitize_query_string( $query_string ) {
296 $pairs = array();
297
298 foreach ( explode( '&', (string) $query_string ) as $pair ) {
299 if ( '' === $pair ) {
300 continue;
301 }
302
303 $parts = explode( '=', $pair, 2 );
304 $key = urlencode( urldecode( $parts[0] ) );
305
306 if ( '' === $key ) {
307 continue;
308 }
309
310 $pairs[] = isset( $parts[1] ) ? $key . '=' . urlencode( urldecode( $parts[1] ) ) : $key;
311 }
312
313 return implode( '&', $pairs );
314 }
315
316 /**
317 * Returns the current URL.
318 *
319 * @see https://gist.github.com/leereamsnyder/fac3b9ccb6b99ab14f36
320 *
321 * @since 1.0.0
322 * @since 1.8.13 The path and query string are both percent-encoded instead of being
323 * reflected raw, and the trailing slash is applied to the path rather
324 * than to the end of the query string.
325 *
326 * @global WP $wp
327 * @return string
328 */
329 function charitable_get_current_url() {
330 global $wp;
331
332 $path = isset( $wp->request ) ? (string) $wp->request : '';
333
334 /*
335 * The requested path is reflected here too, and WordPress hands it over exactly as
336 * it arrived: any %XX escapes are already inert, but characters that arrived
337 * literally are not. Encoding '&' closes off every HTML entity form at once
338 * (&apos;, &#39;, &#x27;, &quot;, ...), which is what a URL escaper cannot do
339 * because those entities are made of characters it considers legal; the quotes and
340 * angle brackets cover the literal cases. Only these five are touched, so existing
341 * %XX escapes and ordinary slugs pass through unchanged and the result is idempotent.
342 */
343 $path = str_replace(
344 array( '&', "'", '"', '<', '>' ),
345 array( '%26', '%27', '%22', '%3C', '%3E' ),
346 $path
347 );
348
349 $url = trailingslashit( home_url( $path ) );
350
351 if ( empty( $_SERVER['QUERY_STRING'] ) ) {
352 return $url;
353 }
354
355 $query_string = charitable_sanitize_query_string( wp_unslash( $_SERVER['QUERY_STRING'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
356
357 if ( '' === $query_string ) {
358 return $url;
359 }
360
361 return $url . '?' . $query_string;
362 }
363
364 /**
365 * Returns the URL to which the user should be redirected after signing on or registering an account.
366 *
367 * @since 1.0.0
368 *
369 * @return string
370 */
371 function charitable_get_login_redirect_url() {
372 if ( isset( $_REQUEST['redirect_to'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
373 $redirect = $_REQUEST['redirect_to']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
374 } elseif ( charitable_get_permalink( 'profile_page' ) ) {
375 $redirect = charitable_get_permalink( 'profile_page' );
376 } else {
377 $redirect = home_url();
378 }
379
380 return apply_filters( 'charitable_signon_redirect_url', $redirect );
381 }
382
383 /**
384 * Displays a table.
385 *
386 * @since 1.5.0
387 *
388 * @param array $columns The set of table columns.
389 * @param array $data The data to display in the table.
390 * @param array $args Optional set of extra arguments.
391 * @return void
392 */
393 function charitable_table_template( array $columns, array $data, $args = array() ) {
394 $table = new Charitable_Table_Helper( $columns, $data, $args );
395 $table->render();
396 }
397
398 /**
399 * Return the email verification link.
400 *
401 * @since 1.5.0
402 * @since 1.6.32 Added $force_send argument.
403 *
404 * @param WP_User $user An instance of `WP_User`.
405 * @param string|false $redirect_url The URL to redirect to after verification.
406 * @param boolean $force_send Whether the link should include an argument to force
407 * resending the email, even if it was sent recently.
408 * @return string
409 */
410 function charitable_get_email_verification_link( WP_User $user, $redirect_url = false, $force_send = false ) {
411 return add_query_arg(
412 array(
413 'charitable_action' => 'verify_email',
414 'user' => $user->ID,
415 'redirect_url' => $redirect_url,
416 'force_send' => (int) $force_send,
417 )
418 );
419 }
420
421 /**
422 * Get the button classes for a Charitable button.
423 *
424 * @since 1.6.29
425 * @version 1.8.3.6 Added $disabled parameter.
426 *
427 * @param string $button Which button we're showing.
428 * @return string
429 */
430 function charitable_get_button_class( $button, $disabled = false ) {
431 $classes = [ 'button', 'charitable-button' ];
432
433 switch ( $button ) {
434 case 'donate':
435 $classes[] = 'donate-button';
436 $classes[] = 'button-primary';
437 break;
438
439 default:
440 $classes[] = $button . '-button';
441 }
442
443 if ( $disabled ) {
444 $classes[] = 'charitable-disabled';
445 }
446
447 /**
448 * Filter the button classes.
449 *
450 * @since 1.6.29
451 *
452 * @param array $classes The button classes.
453 * @param string $button The specific button we're showing.
454 */
455 $classes = apply_filters( 'charitable_button_class', $classes, $button );
456
457 return implode( ' ', $classes );
458 }
459
460 /**
461 * Get a unique donation form ID.
462 *
463 * @since 1.6.57
464 *
465 * @return string
466 */
467 function charitable_get_donation_form_id() {
468 static $form_number;
469
470 if ( ! isset( $form_number ) ) {
471 $form_id = 'charitable-donation-form';
472 $form_number = 1;
473 } else {
474 $form_id = 'charitable-donation-form-' . $form_number;
475 $form_number += 1;
476 }
477
478 // $form_number = ;
479
480 return $form_id;
481 }