PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.12.3
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.12.3
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 / compat / class-charitable-polylang-compat.php

class-charitable-polylang-compat.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.12.3, at includes/compat/class-charitable-polylang-compat.php

536 lines 15.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * A class to resolve compatibility issues with Polylang.
4 *
5 * @package Charitable/Classes/Charitable_Polylang_Compat
6 * @author David Bisset
7 * @copyright Copyright (c) 2023, WP Charitable LLC
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.6.42
10 * @version 1.6.57
11 */
12
13 // Exit if accessed directly.
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 if ( ! class_exists( 'Charitable_Polylang_Compat' ) ) :
19
20 /**
21 * Charitable_Polylang_Compat
22 *
23 * @since 1.6.42
24 */
25 class Charitable_Polylang_Compat {
26
27 /**
28 * Create class object.
29 *
30 * @since 1.6.42
31 */
32 public function __construct() {
33 /* Load Donation & Campaign field translations late */
34 add_action( 'wp', array( $this, 'load_late_translations' ) );
35
36 /* Filter the amount donated to include any translations of the campaign. */
37 add_filter( 'charitable_campaign_donated_amount', array( $this, 'get_donated_amount' ), 5, 3 );
38
39 /* Filter the donor count to include any translations of the campaign. */
40 add_filter( 'charitable_campaign_donor_count', array( $this, 'get_donor_count' ), 5, 2 );
41
42 /* Handle Polylang translation of user dashboard menu */
43 add_action( 'wp_update_nav_menu', array( $this, 'flush_menu_object_cache' ) );
44 add_action( 'wp_update_nav_menu_item', array( $this, 'flush_menu_object_cache' ) );
45 add_filter( 'transient_charitable_user_dashboard_objects', array( $this, 'get_user_dashboard_objects' ) );
46 add_filter( 'pre_set_transient_charitable_user_dashboard_objects', array( $this, 'set_user_dashboard_objects' ) );
47
48 /* Profile Page */
49 add_filter( 'charitable_permalink_profile_page', array( $this, 'get_profile_page_url' ), 10, 2 );
50 add_filter( 'charitable_is_page_profile_page', array( $this, 'is_profile_page' ), 10, 2 );
51
52 /* Login Page */
53 add_filter( 'charitable_permalink_login_page', array( $this, 'get_login_page_url' ), 10, 2 );
54 add_filter( 'charitable_is_page_login_page', array( $this, 'is_login_page' ), 10, 2 );
55
56 /* Registration Page */
57 add_filter( 'charitable_permalink_registration_page', array( $this, 'get_registration_page_url' ), 10, 2 );
58 add_filter( 'charitable_is_page_registration_page', array( $this, 'is_registration_page' ), 10, 2 );
59
60 /* Donation Receipt Page */
61 add_filter( 'charitable_permalink_donation_receipt_page', array( $this, 'get_donation_receipt_page_url' ), 10, 2 );
62 add_filter( 'charitable_is_page_donation_receipt_page', array( $this, 'is_donation_receipt_page' ), 10, 2 );
63
64 /* Terms & Conditions and Privacy Policy */
65 add_filter( 'charitable_option_terms_conditions_page', array( $this, 'get_polylang_page_id' ) );
66 add_filter( 'charitable_option_privacy_policy_page', array( $this, 'get_polylang_page_id' ) );
67
68 /* Disable pre_get_posts filter added by Polylang */
69 add_action( 'charitable_donation_stats_before', array( $this, 'disable_polylang_pre_get_posts_filter' ) );
70 add_action( 'charitable_donation_stats_after', array( $this, 'reenable_polylang_pre_get_posts_filter' ) );
71
72 /**
73 * Do something with this class instance.
74 *
75 * @since 1.6.42
76 *
77 * @param Charitable_Polylang_Compat $helper Polylang compatibility class instance.
78 */
79 do_action( 'charitable_polylang_compat', $this );
80 }
81
82 /**
83 * When Polylang picks up the language from the content, it translates
84 * content late, on the 'wp' hook. This is after Charitable's donation
85 * and campaign fields are loaded, which results in their labels, options
86 * and help text not being translated.
87 *
88 * To overcome this, with pick up the fields on the 'wp' hook and loop
89 * over them all to ensure Polylang translates them.
90 *
91 * @see https://github.com/polylang/polylang/issues/507#issuecomment-634640027
92 *
93 * @since 1.6.42
94 *
95 * @return void
96 */
97 public function load_late_translations() {
98 $options = get_option( 'polylang' );
99
100 /* We only have to do this if the language is picked up from the content. */
101 if ( 0 !== $options['force_lang'] ) {
102 return;
103 }
104
105 $field_apis = array(
106 array(
107 'fields' => charitable()->donation_fields(),
108 'forms' => array( 'donation_form', 'admin_form' ),
109 ),
110 array(
111 'fields' => charitable()->campaign_fields(),
112 'forms' => array( 'campaign_form', 'admin_form' ),
113 ),
114 );
115
116 $translateable_form_fields = array( 'label', 'placeholder' );
117
118 foreach ( $field_apis as $api ) {
119 $fields = $api['fields'];
120
121 foreach ( $fields->get_fields() as $field ) {
122
123 /* Update the field label. */
124 $field->label = pll__( $field->label );
125
126 foreach ( $api['forms'] as $form ) {
127 $form_settings = $field->$form;
128
129 if ( ! is_array( $form_settings ) ) {
130 continue;
131 }
132
133 /* Translate form label and placeholder. */
134 foreach ( $translateable_form_fields as $form_field ) {
135 if ( array_key_exists( $form_field, $form_settings ) ) {
136 $field->set( $form, $form_field, pll__( $form_settings[ $form_field ] ) );
137 }
138 }
139
140 /* Translate options */
141 if ( array_key_exists( 'options', $form_settings ) && is_array( $form_settings['options'] ) ) {
142 $options = $form_settings['options'];
143
144 foreach ( $options as $key => $value ) {
145 $options[ $key ] = pll__( $value );
146 }
147
148 if ( in_array( $field->field, array( 'country', 'state' ) ) ) {
149 asort( $options );
150 }
151
152 $field->set( $form, 'options', $options );
153 }
154 }
155 }
156 }
157 }
158
159 /**
160 * Return a list of campaign IDs that are translations of the
161 * given campaign.
162 *
163 * @since 1.6.43
164 *
165 * @param Charitable_Campaign $campaign
166 * @return array
167 */
168 public function get_campaign_translations( Charitable_Campaign $campaign ) {
169 return array_values( pll_get_post_translations( $campaign->ID ) );
170 }
171
172 /**
173 * Filter the amount donated to a campaign to include any translations of the same campaign.
174 *
175 * @since 1.6.43
176 *
177 * @param string $amount The default amount donated.
178 * @param Charitable_Campaign $campaign The campaign to get the donated amount for.
179 * @param boolean $sanitize Whether to sanitize the amount. False by default.
180 * @return string
181 */
182 public function get_donated_amount( $amount, Charitable_Campaign $campaign, $sanitize = false ) {
183 $campaigns = $this->get_campaign_translations( $campaign );
184
185 if ( empty( $campaigns ) ) {
186 return $amount;
187 }
188
189 $amount = charitable_get_table( 'campaign_donations' )->get_campaign_donated_amount( $campaigns );
190
191 if ( $sanitize ) {
192 $amount = charitable_sanitize_amount( $amount );
193 }
194
195 return $amount;
196 }
197
198 /**
199 * Return the number of donors, including any donations to campaign locale variations.
200 *
201 * @since 1.6.43
202 *
203 * @param int $count The default number of donors.
204 * @param Charitable_Campaign $campaign The campaign object.
205 * @return int
206 */
207 public function get_donor_count( $count, Charitable_Campaign $campaign ) {
208 $campaigns = $this->get_campaign_translations( $campaign );
209
210 if ( empty( $campaigns ) ) {
211 return $count;
212 }
213
214 return charitable_get_table( 'campaign_donations' )->count_campaign_donors( $campaigns );
215 }
216
217 /**
218 * Returns the user dashboard menus, including any Polylang
219 * translation versions.
220 *
221 * @since 1.6.42
222 *
223 * @return array
224 */
225 public function get_user_dashboard_menus() {
226 $dashboard_menus = array();
227
228 /* Get all nav menu locations. */
229 $locations = get_nav_menu_locations();
230
231 foreach ( $locations as $location => $assigned_menu ) {
232 if ( 'charitable-dashboard' === substr( $location, 0, 20 ) ) {
233 $dashboard_menus[] = wp_get_nav_menu_object( $assigned_menu );
234 }
235 }
236
237 return $dashboard_menus;
238 }
239
240 /**
241 * Flush the object cache when a menu assigned to the user dashboard
242 * location (in any language) is edited.
243 *
244 * @since 1.6.42
245 *
246 * @param int $menu_id The menu id.
247 * @return void
248 */
249 public function flush_menu_object_cache( $menu_id ) {
250 $dashboard_menus = $this->get_user_dashboard_menus();
251
252 if ( empty( $dashboard_menus ) ) {
253 delete_transient( 'charitable_user_dashboard_objects' );
254 }
255
256 if ( in_array( $menu_id, wp_list_pluck( $dashboard_menus, 'term_id' ) ) ) {
257 delete_transient( 'charitable_user_dashboard_objects' );
258 }
259 }
260
261 /**
262 * Get the user dashboard objects for the current language.
263 *
264 * @since 1.6.42
265 *
266 * @return array
267 */
268 public function get_user_dashboard_objects( $objects ) {
269 $language = pll_current_language();
270
271 if ( false === $objects ) {
272 return false;
273 }
274
275 if ( ! array_key_exists( $language, $objects ) ) {
276 return false;
277 }
278
279 return $objects[ $language ];
280 }
281
282 /**
283 * When saving the user dashboard objects, include any objects in Polylang
284 * locations of the user dashboard menu.
285 *
286 * @since 1.6.42
287 *
288 * @return array
289 */
290 public function set_user_dashboard_objects( $menu_items ) {
291 $language = pll_current_language();
292
293 /* Temporarily switch off our filter. */
294 remove_filter( 'transient_charitable_user_dashboard_objects', array( $this, 'get_user_dashboard_objects' ) );
295
296 $all_menu_items = get_transient( 'charitable_user_dashboard_objects' );
297
298 if ( ! is_array( $all_menu_items ) ) {
299 $all_menu_items = array();
300 }
301
302 if ( ! array_key_exists( $language, $all_menu_items ) ) {
303 $all_menu_items[ $language ] = $menu_items;
304 }
305
306 /* Temporarily switch off our filter. */
307 add_filter( 'transient_charitable_user_dashboard_objects', array( $this, 'get_user_dashboard_objects' ) );
308
309 return $all_menu_items;
310 }
311
312 /**
313 * Get the current language version of the specified endpoint,
314 * or return the default.
315 *
316 * @since 1.6.42
317 *
318 * @param string $endpoint_id The endpoint ID.
319 * @param string $default The endpoint's URL.
320 * @param array $args Mixed set of arguments.
321 * @return string
322 */
323 public function get_polylang_page_url( $page_option, $default, $args ) {
324 if ( empty( $default ) ) {
325 return $default;
326 }
327
328 /* Prevent Polylang override. */
329 if ( array_key_exists( 'polylang_override', $args ) && ! $args['polylang_override'] ) {
330 return $default;
331 }
332
333 $page_id = charitable_get_option( $page_option, false );
334
335 if ( in_array( $page_id, array( 'wp', 'auto' ) ) ) {
336 return $default;
337 }
338
339 return get_permalink( pll_get_post( $page_id ) );
340 }
341
342 /**
343 * Checks whether this is the specified page.
344 *
345 * @since 1.6.42
346 *
347 * @param string $page_option The option key used to record the page ID.
348 * @param boolean $is_page Whether we are currently on the page.
349 * @param array $args Mixed arguments.
350 * @return string
351 */
352 public function is_polylang_page( $page_option, $is_page, $args ) {
353 /* We've already determined it's the current page. */
354 if ( $is_page ) {
355 return $is_page;
356 }
357
358 /* Prevent Polylang override. */
359 if ( array_key_exists( 'polylang_override', $args ) && ! $args['polylang_override'] ) {
360 return $is_page;
361 }
362
363 global $post, $wp_query;
364
365 if ( is_null( $post ) || ! $wp_query->is_main_query() ) {
366 return $is_page;
367 }
368
369 $page_id = charitable_get_option( $page_option, false );
370
371 if ( in_array( $page_id, array( 'wp', 'auto' ) ) ) {
372 return $is_page;
373 }
374
375 $pll_page = pll_get_post( $page_id );
376
377 return $pll_page && $pll_page === $post->ID;
378 }
379
380 /**
381 * Get the profile page URL.
382 *
383 * @since 1.6.42
384 *
385 * @param string $default The endpoint's URL.
386 * @param array $args Mixed set of arguments.
387 * @return string
388 */
389 public function get_profile_page_url( $default, $args ) {
390 return $this->get_polylang_page_url( 'profile_page', $default, $args );
391 }
392
393 /**
394 * Check whether we are currently on the profile page.
395 *
396 * @since 1.6.42
397 *
398 * @param boolean $is_page Whether we are currently on the profile page.
399 * @param array $args Mixed arguments.
400 * @return boolean
401 */
402 public function is_profile_page( $is_page, $args ) {
403 return $this->is_polylang_page( 'profile_page', $is_page, $args );
404 }
405
406 /**
407 * Get the login page URL.
408 *
409 * @since 1.6.42
410 *
411 * @param string $default The endpoint's URL.
412 * @param array $args Mixed set of arguments.
413 * @return string
414 */
415 public function get_login_page_url( $default, $args ) {
416 return $this->get_polylang_page_url( 'login_page', $default, $args );
417 }
418
419 /**
420 * Check whether we are currently on the login page.
421 *
422 * @since 1.6.42
423 *
424 * @param boolean $is_page Whether we are currently on the login page.
425 * @param array $args Mixed arguments.
426 * @return boolean
427 */
428 public function is_login_page( $is_page, $args ) {
429 return $this->is_polylang_page( 'login_page', $is_page, $args );
430 }
431
432 /**
433 * Get the registration page URL.
434 *
435 * @since 1.6.42
436 *
437 * @param string $default The endpoint's URL.
438 * @param array $args Mixed set of arguments.
439 * @return string
440 */
441 public function get_registration_page_url( $default, $args ) {
442 return $this->get_polylang_page_url( 'registration_page', $default, $args );
443 }
444
445 /**
446 * Check whether we are currently on the registration page.
447 *
448 * @since 1.6.42
449 *
450 * @param boolean $is_page Whether we are currently on the registration page.
451 * @param array $args Mixed arguments.
452 * @return boolean
453 */
454 public function is_registration_page( $is_page, $args ) {
455 return $this->is_polylang_page( 'registration_page', $is_page, $args );
456 }
457
458 /**
459 * Get the donation receipt page URL.
460 *
461 * @since 1.6.42
462 *
463 * @param string $default The endpoint's URL.
464 * @param array $args Mixed set of arguments.
465 * @return string
466 */
467 public function get_donation_receipt_page_url( $default, $args ) {
468 $pll_url = $this->get_polylang_page_url( 'donation_receipt_page', $default, $args );
469
470 if ( $pll_url !== $default ) {
471 $donation_id = isset( $args['donation_id'] ) ? $args['donation_id'] : get_the_ID();
472 $pll_url = esc_url_raw( add_query_arg( array( 'donation_id' => $donation_id ), $pll_url ) );
473 }
474
475 return $pll_url;
476 }
477
478 /**
479 * Check whether we are currently on the donation receipt page.
480 *
481 * @since 1.6.42
482 *
483 * @param boolean $is_page Whether we are currently on the donation_receipt page.
484 * @param array $args Mixed arguments.
485 * @return boolean
486 */
487 public function is_donation_receipt_page( $is_page, $args ) {
488 return $this->is_polylang_page( 'donation_receipt_page', $is_page, $args );
489 }
490
491 /**
492 * Get the page ID of a specific page, returning the Polylang
493 * translation if applicable.
494 *
495 * @since 1.6.42
496 *
497 * @param int|string $page_id The set page id.
498 * @return int|string
499 */
500 public function get_polylang_page_id( $page_id ) {
501 if ( empty( $page_id ) || 0 == $page_id ) {
502 return $page_id;
503 }
504
505 return pll_get_post( $page_id );
506 }
507
508 /**
509 * Disable the Polylang auto translate pre_get_posts filter.
510 *
511 * @since 1.6.57
512 *
513 * @return void
514 */
515 public function disable_polylang_pre_get_posts_filter() {
516 if ( method_exists( \PLL(), 'auto_translate' ) ) {
517 remove_action( 'pre_get_posts', array( \PLL()->auto_translate(), 'pre_get_posts' ) );
518 }
519 }
520
521 /**
522 * Re-enable the Polylang auto translate pre_get_posts filter.
523 *
524 * @since 1.6.57
525 *
526 * @return void
527 */
528 public function reenable_polylang_pre_get_posts_filter() {
529 if ( method_exists( \PLL(), 'auto_translate' ) ) {
530 add_action( 'pre_get_posts', array( \PLL()->auto_translate(), 'pre_get_posts' ) );
531 }
532 }
533 }
534
535 endif;
536