← All changes
|
includes/admin/settings/class-charitable-settings.php
+746
-42
1.7.0.3
→
1.8.13
View file →
| @@ -3,9 +3,9 @@ | ||
| 3 | 3 | * Charitable Settings UI. |
| 4 | 4 | * |
| 5 | 5 | * @package Charitable/Classes/Charitable_Settings |
| 6 | 6 | * @author David Bisset |
| 7 | - * @copyright Copyright (c) 2022, WP Charitable LLC | |
| 7 | + * @copyright Copyright (c) 2023, WP Charitable LLC | |
| 8 | 8 | * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License |
| 9 | 9 | * @since 1.0.0 |
| 10 | 10 | * @version 1.0.0 |
| 11 | 11 | */ |
| @@ -56,8 +56,10 @@ | ||
| 56 | 56 | * @since 1.0.0 |
| 57 | 57 | */ |
| 58 | 58 | private function __construct() { |
| 59 | 59 | do_action( 'charitable_admin_settings_start', $this ); |
| 60 | + | |
| 61 | + add_action( 'charitable_after_admin_settings', array( $this, 'settings_cta' ) ); | |
| 60 | 62 | } |
| 61 | 63 | |
| 62 | 64 | /** |
| 63 | 65 | * Returns and/or create the single instance of this class. |
| @@ -84,35 +86,121 @@ | ||
| 84 | 86 | public function get_sections() { |
| 85 | 87 | /** |
| 86 | 88 | * Filter the settings tabs. |
| 87 | 89 | * |
| 88 | - * @since 1.0.0 | |
| 90 | + * @since 1.0.0 | |
| 91 | + * @version 1.8.1.6 removed 'tools' tab | |
| 92 | + * @version 1.8.5.1 added marketing and security tabs depending on addon status. | |
| 89 | 93 | * |
| 90 | 94 | * @param string[] $tabs List of tabs in key=>label format. |
| 91 | 95 | */ |
| 96 | + $tabs = array( | |
| 97 | + 'general' => __( 'General', 'charitable' ), | |
| 98 | + 'gateways' => __( 'Payment Gateways', 'charitable' ), | |
| 99 | + 'emails' => __( 'Emails', 'charitable' ), | |
| 100 | + 'donors' => __( 'Donors', 'charitable' ), | |
| 101 | + 'privacy' => __( 'Privacy', 'charitable' ), | |
| 102 | + 'advanced' => __( 'Advanced', 'charitable' ), | |
| 103 | + ); | |
| 104 | + | |
| 105 | + // Always show marketing tab. Sub-tabs (Newsletters, Conversion Tracking, Google Analytics) | |
| 106 | + // handle the per-feature display: Newsletter Connect addon (which works with Lite) renders | |
| 107 | + // its real UI under the Newsletters sub-tab when active; Conversion Tracking and Google | |
| 108 | + // Analytics always render Pro CTAs in Lite. | |
| 109 | + $tabs = charitable_add_settings_tab( | |
| 110 | + $tabs, | |
| 111 | + 'marketing', | |
| 112 | + __( 'Marketing', 'charitable' ), | |
| 113 | + array( | |
| 114 | + 'index' => 5, | |
| 115 | + ) | |
| 116 | + ); | |
| 117 | + | |
| 118 | + // Always show security tab. | |
| 119 | + // When spam blocker is active, it will handle the settings. | |
| 120 | + // When spam blocker is inactive, core security features will handle the settings. | |
| 121 | + $tabs = charitable_add_settings_tab( | |
| 122 | + $tabs, | |
| 123 | + 'security', | |
| 124 | + __( 'Security', 'charitable' ), | |
| 125 | + array( | |
| 126 | + 'index' => 6, | |
| 127 | + ) | |
| 128 | + ); | |
| 129 | + | |
| 130 | + // Ensure the advanced tab is always last by moving it to the end of the array. | |
| 131 | + if ( isset( $tabs['advanced'] ) ) { | |
| 132 | + $advanced_tab = $tabs['advanced']; | |
| 133 | + unset( $tabs['advanced'] ); | |
| 134 | + $tabs['advanced'] = $advanced_tab; | |
| 135 | + } | |
| 136 | + | |
| 137 | + return apply_filters( 'charitable_settings_tabs', $tabs ); | |
| 138 | + } | |
| 139 | + | |
| 140 | + /** | |
| 141 | + * Return the array of sub tabs used on the Marketing settings page. | |
| 142 | + * | |
| 143 | + * Each label carries an inline "Pro" badge: | |
| 144 | + * - Newsletters: the Newsletter Connect addon works on Lite, but the badge | |
| 145 | + * still appears since the bulk of newsletter functionality is Pro-tier. | |
| 146 | + * - Conversion Tracking / Google Analytics: Pro-only — badge always shown. | |
| 147 | + * | |
| 148 | + * @since 1.8.11.3 | |
| 149 | + * | |
| 150 | + * @return string[] key => label. | |
| 151 | + */ | |
| 152 | + public function get_sub_sections_marketing() { | |
| 153 | + $pro_badge = ' <span class="charitable-pro-badge">' . esc_html__( 'PRO', 'charitable' ) . '</span>'; | |
| 154 | + | |
| 92 | 155 | return apply_filters( |
| 93 | - 'charitable_settings_tabs', | |
| 156 | + 'charitable_settings_sub_tabs_marketing', | |
| 94 | 157 | array( |
| 95 | - 'general' => __( 'General', 'charitable' ), | |
| 96 | - 'gateways' => __( 'Payment Gateways', 'charitable' ), | |
| 97 | - 'emails' => __( 'Emails', 'charitable' ), | |
| 98 | - 'privacy' => __( 'Privacy', 'charitable' ), | |
| 99 | - 'advanced' => __( 'Advanced', 'charitable' ), | |
| 158 | + 'marketing__newsletters' => __( 'Newsletters', 'charitable' ) . $pro_badge, | |
| 159 | + 'marketing__conversion_tracking' => __( 'Conversion Tracking', 'charitable' ) . $pro_badge, | |
| 160 | + 'marketing__google_analytics' => __( 'Google Analytics', 'charitable' ) . $pro_badge, | |
| 100 | 161 | ) |
| 101 | 162 | ); |
| 163 | + } | |
| 102 | 164 | |
| 165 | + /** | |
| 166 | + * Redirect to the default Marketing sub-tab when no sub_tab is supplied. | |
| 167 | + * | |
| 168 | + * @since 1.8.11.3 | |
| 169 | + * | |
| 170 | + * @return void | |
| 171 | + */ | |
| 172 | + public function marketing_sub_tab_default() { | |
| 173 | + // Don't redirect during form submissions. | |
| 174 | + if ( ! empty( $_POST ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing | |
| 175 | + return; | |
| 176 | + } | |
| 177 | + | |
| 178 | + if ( ! charitable_is_settings_view( 'marketing' ) ) { | |
| 179 | + return; | |
| 180 | + } | |
| 181 | + | |
| 182 | + if ( isset( $_GET['sub_tab'] ) || isset( $_GET['group'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 183 | + return; | |
| 184 | + } | |
| 185 | + | |
| 186 | + wp_safe_redirect( | |
| 187 | + admin_url( 'admin.php?page=charitable-settings&tab=marketing&sub_tab=newsletters' ) | |
| 188 | + ); | |
| 189 | + exit; | |
| 103 | 190 | } |
| 104 | 191 | |
| 105 | 192 | /** |
| 106 | 193 | * Optionally add the extensions tab. |
| 107 | 194 | * |
| 108 | - * @since 1.3.0 | |
| 195 | + * @since 1.3.0 | |
| 196 | + * @version 1.8.5.1 Adjust index so it comes before the advanced tab. | |
| 109 | 197 | * |
| 110 | 198 | * @param string[] $tabs The existing set of tabs. |
| 111 | 199 | * @return string[] |
| 112 | 200 | */ |
| 113 | 201 | public function maybe_add_extensions_tab( $tabs ) { |
| 114 | - $actual_tab = isset( $_GET['tab'] ) ? $_GET['tab'] : 'general'; | |
| 202 | + $actual_tab = isset( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'general'; // phpcs:ignore | |
| 115 | 203 | |
| 116 | 204 | /* Set the tab to 'extensions' */ |
| 117 | 205 | $_GET['tab'] = 'extensions'; |
| 118 | 206 | |
| @@ -133,13 +221,20 @@ | ||
| 133 | 221 | $tabs, |
| 134 | 222 | 'extensions', |
| 135 | 223 | __( 'Extensions', 'charitable' ), |
| 136 | 224 | array( |
| 137 | - 'index' => 4, | |
| 225 | + 'index' => 7, | |
| 138 | 226 | ) |
| 139 | 227 | ); |
| 140 | 228 | } |
| 141 | 229 | |
| 230 | + // Ensure the advanced tab is always last by moving it to the end of the array. | |
| 231 | + if ( isset( $tabs['advanced'] ) ) { | |
| 232 | + $advanced_tab = $tabs['advanced']; | |
| 233 | + unset( $tabs['advanced'] ); | |
| 234 | + $tabs['advanced'] = $advanced_tab; | |
| 235 | + } | |
| 236 | + | |
| 142 | 237 | return $tabs; |
| 143 | 238 | } |
| 144 | 239 | |
| 145 | 240 | /** |
| @@ -179,10 +274,32 @@ | ||
| 179 | 274 | } |
| 180 | 275 | |
| 181 | 276 | register_setting( 'charitable_settings', 'charitable_settings', array( $this, 'sanitize_settings' ) ); |
| 182 | 277 | |
| 278 | + // Bridge the Newsletter Connect addon (which gates its filter on | |
| 279 | + // charitable_is_settings_view('extensions')) so its fields contribute | |
| 280 | + // when the user is on Marketing → Newsletters. We spoof $_GET['tab'] | |
| 281 | + // for the duration of get_fields() so the addon's gate passes; the | |
| 282 | + // extensions section is what the view's form group already targets | |
| 283 | + // on the Newsletters sub-tab. The Extensions top-level tab continues | |
| 284 | + // to work as before — this only adds an additional render path. | |
| 285 | + $charitable_bridge_newsletters = ( | |
| 286 | + isset( $_GET['tab'] ) && 'marketing' === $_GET['tab'] // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 287 | + && isset( $_GET['sub_tab'] ) && 'newsletters' === $_GET['sub_tab'] // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 288 | + && class_exists( 'Charitable_Newsletter_Connect' ) | |
| 289 | + ); | |
| 290 | + | |
| 291 | + if ( $charitable_bridge_newsletters ) { | |
| 292 | + $charitable_real_tab = $_GET['tab']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 293 | + $_GET['tab'] = 'extensions'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 294 | + } | |
| 295 | + | |
| 183 | 296 | $fields = $this->get_fields(); |
| 184 | 297 | |
| 298 | + if ( $charitable_bridge_newsletters ) { | |
| 299 | + $_GET['tab'] = $charitable_real_tab; // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 300 | + } | |
| 301 | + | |
| 185 | 302 | if ( empty( $fields ) ) { |
| 186 | 303 | return; |
| 187 | 304 | } |
| 188 | 305 | |
| @@ -214,9 +331,10 @@ | ||
| 214 | 331 | } |
| 215 | 332 | } |
| 216 | 333 | |
| 217 | 334 | /** |
| 218 | - * Sanitize submitted settings before saving to the database including "workaround". | |
| 335 | + * Sanitize submitted settings before saving to the database | |
| 336 | + * This includes: "workaround" for Stripe keys with 1.7.0.0, additional settings options after 1.7.0.6+ | |
| 219 | 337 | * |
| 220 | 338 | * @since 1.0.0 |
| 221 | 339 | * |
| 222 | 340 | * @param array $values The submitted values. |
| @@ -222,8 +340,9 @@ | ||
| 222 | 340 | * @param array $values The submitted values. |
| 223 | 341 | * @return string |
| 224 | 342 | */ |
| 225 | 343 | public function sanitize_settings( $values ) { |
| 344 | + | |
| 226 | 345 | $old_values = get_option( 'charitable_settings', array() ); |
| 227 | 346 | $new_values = array(); |
| 228 | 347 | |
| 229 | 348 | if ( ! is_array( $old_values ) ) { |
| @@ -240,27 +359,60 @@ | ||
| 240 | 359 | } |
| 241 | 360 | |
| 242 | 361 | $settings_keys = array_keys( $new_values ); |
| 243 | 362 | |
| 244 | - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { | |
| 245 | - error_log( 'santiize_settings' ); | |
| 246 | - error_log( 'values:' ); | |
| 247 | - error_log( print_r( $values, true ) ); | |
| 248 | - error_log( 'old_values:' ); | |
| 249 | - error_log( print_r( $old_values, true ) ); | |
| 250 | - error_log( 'new_values:' ); | |
| 251 | - error_log( print_r( $new_values, true ) ); | |
| 363 | + if ( charitable_is_debug() ) { | |
| 364 | + error_log( 'santiize_settings' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log | |
| 365 | + error_log( 'values:' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log | |
| 366 | + error_log( print_r( $values, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r | |
| 367 | + error_log( 'old_values:' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log | |
| 368 | + error_log( print_r( $old_values, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r | |
| 369 | + error_log( 'new_values:' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log | |
| 370 | + error_log( print_r( $new_values, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r | |
| 252 | 371 | } |
| 253 | 372 | |
| 254 | - // determine if Charitable gateway "test mode" is being changed, and if so add a notice to the user. | |
| 255 | - if ( array_key_exists('test_mode', $new_values ) && array_key_exists('test_mode', $old_values ) && $old_values['test_mode'] !== $new_values['test_mode'] ) { | |
| 373 | + // determine if Charitable gateway "test_mode" is being changed, and if so add a notice to the user. | |
| 374 | + if ( array_key_exists( 'test_mode', $new_values ) && array_key_exists( 'test_mode', $old_values ) && $old_values['test_mode'] !== $new_values['test_mode'] ) { | |
| 256 | 375 | $old_settings_keys = array_keys( $old_values ); |
| 257 | 376 | $dismissible = true; |
| 377 | + | |
| 378 | + // Check if Square has connection issues for the new mode | |
| 379 | + $square_has_issues = $this->check_square_connection_for_mode_change( $new_values['test_mode'] ); | |
| 380 | + | |
| 381 | + // Determine notice type and message | |
| 382 | + $notice_type = $square_has_issues ? 'error' : 'warning'; | |
| 383 | + $gateway_list = array(); | |
| 384 | + | |
| 258 | 385 | if ( in_array( 'gateways_stripe', $old_settings_keys ) ) { |
| 259 | - charitable_get_admin_notices()->add_notice( 'Some active payment gateways <strong>(including Stripe)</strong> might have reset their connections due to an update in the test mode. Please check your active payment gateways in ensure they are still connected.', 'warning', false, $dismissible ); | |
| 386 | + $gateway_list[] = 'Stripe'; | |
| 387 | + } | |
| 388 | + | |
| 389 | + if ( $square_has_issues ) { | |
| 390 | + $gateway_list[] = 'Square'; | |
| 391 | + } | |
| 392 | + | |
| 393 | + if ( ! empty( $gateway_list ) ) { | |
| 394 | + $gateway_text = implode( ' and ', $gateway_list ); | |
| 395 | + $message = sprintf( | |
| 396 | + /* translators: %s: comma-separated list of gateway names */ | |
| 397 | + __( 'Some active payment gateways <strong>(including %s)</strong> might have reset their connections due to an update in the test mode. Please check your active payment gateways to ensure they are still connected.', 'charitable' ), | |
| 398 | + $gateway_text | |
| 399 | + ); | |
| 260 | 400 | } else { |
| 261 | - charitable_get_admin_notices()->add_notice( 'Some active payment gateways might have reset their connections due to an update in the test mode. Please check your active payment gateways in ensure they are still connected.', 'warning', false, $dismissible ); | |
| 401 | + $message = __( 'Some active payment gateways might have reset their connections due to an update in the test mode. Please check your active payment gateways to ensure they are still connected.', 'charitable' ); | |
| 262 | 402 | } |
| 403 | + | |
| 404 | + // Add additional Square-specific message if Square has connection issues | |
| 405 | + if ( $square_has_issues ) { | |
| 406 | + $mode_label = $new_values['test_mode'] ? __( 'test', 'charitable' ) : __( 'live', 'charitable' ); | |
| 407 | + $message .= '<br><br><strong>' . sprintf( | |
| 408 | + /* translators: %s: mode (test or live) */ | |
| 409 | + __( 'Square payment gateway is enabled but not connected in %s mode. Please connect your Square account to continue processing payments.', 'charitable' ), | |
| 410 | + $mode_label | |
| 411 | + ) . '</strong>'; | |
| 412 | + } | |
| 413 | + | |
| 414 | + charitable_get_admin_notices()->add_notice( $message, $notice_type, false, $dismissible ); | |
| 263 | 415 | } |
| 264 | 416 | |
| 265 | 417 | if ( in_array( 'gateways_stripe', $settings_keys ) && charitable()->is_stripe_connect_addon() && false === charitable_using_stripe_connect() ) { |
| 266 | 418 | // non-existant array keys in the array for API keys might be a result of the "manual update key" feature which is based on ajax and might not load keys into form if the user doesn't click on the link in the settings to view/edit them. |
| @@ -275,18 +427,18 @@ | ||
| 275 | 427 | } |
| 276 | 428 | if ( ! array_key_exists( 'test_public_key', $values['gateways_stripe'] ) && isset( $old_values['gateways_stripe']['test_public_key'] ) && ( false !== $old_values['gateways_stripe']['test_public_key'] ) ) { |
| 277 | 429 | $values['gateways_stripe']['test_public_key'] = $old_values['gateways_stripe']['test_public_key']; |
| 278 | 430 | } |
| 279 | - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { | |
| 280 | - error_log( 'update:' ); | |
| 281 | - error_log( print_r( $values, true ) ); | |
| 431 | + if ( charitable_is_debug() ) { | |
| 432 | + error_log( 'update:' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log | |
| 433 | + error_log( print_r( $values, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r | |
| 282 | 434 | } |
| 283 | 435 | } |
| 284 | 436 | |
| 285 | - // determine if stripe is being returned as new values - if so, then perform the API key save workaround | |
| 437 | + // determine if stripe is being returned as new values - if so, then perform the API key save workaround. | |
| 286 | 438 | if ( in_array( 'gateways_stripe', $settings_keys ) && charitable()->is_stripe_connect_addon() && false === charitable_using_stripe_connect() ) { |
| 287 | - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { | |
| 288 | - error_log( 'there is a stripe connect addon but we are not using stripe connect' ); | |
| 439 | + if ( charitable_is_debug() ) { | |
| 440 | + error_log( 'there is a stripe connect addon but we are not using stripe connect' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log | |
| 289 | 441 | } |
| 290 | 442 | // the stripe connect addon is installed AND the AM Stripe Connect isn't being used... so it's possible the keys could be manual and the user could be updating them... therefore let's just make sure the new values match the values incoming. |
| 291 | 443 | $new_values['gateways_stripe']['live_secret_key'] = ( isset( $values['gateways_stripe']['live_secret_key'] ) && ( false !== $values['gateways_stripe']['live_secret_key'] ) ) ? $values['gateways_stripe']['live_secret_key'] : null; |
| 292 | 444 | $new_values['gateways_stripe']['live_public_key'] = ( isset( $values['gateways_stripe']['live_public_key'] ) && ( false !== $values['gateways_stripe']['live_public_key'] ) ) ? $values['gateways_stripe']['live_public_key'] : null; |
| @@ -291,12 +443,12 @@ | ||
| 291 | 443 | $new_values['gateways_stripe']['live_secret_key'] = ( isset( $values['gateways_stripe']['live_secret_key'] ) && ( false !== $values['gateways_stripe']['live_secret_key'] ) ) ? $values['gateways_stripe']['live_secret_key'] : null; |
| 292 | 444 | $new_values['gateways_stripe']['live_public_key'] = ( isset( $values['gateways_stripe']['live_public_key'] ) && ( false !== $values['gateways_stripe']['live_public_key'] ) ) ? $values['gateways_stripe']['live_public_key'] : null; |
| 293 | 445 | $new_values['gateways_stripe']['test_secret_key'] = ( isset( $values['gateways_stripe']['test_secret_key'] ) && ( false !== $values['gateways_stripe']['test_secret_key'] ) ) ? $values['gateways_stripe']['test_secret_key'] : null; |
| 294 | 446 | $new_values['gateways_stripe']['test_public_key'] = ( isset( $values['gateways_stripe']['test_public_key'] ) && ( false !== $values['gateways_stripe']['test_public_key'] ) ) ? $values['gateways_stripe']['test_public_key'] : null; |
| 295 | - } else if ( in_array( 'gateways_stripe', $settings_keys ) ) { | |
| 296 | - // otherwise we preserve the keys | |
| 297 | - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { | |
| 298 | - error_log( 'charitable debug, final with debug on:' ); | |
| 447 | + } elseif ( in_array( 'gateways_stripe', $settings_keys ) ) { | |
| 448 | + // otherwise we preserve the keys. | |
| 449 | + if ( charitable_is_debug() ) { | |
| 450 | + error_log( 'charitable debug, final with debug on:' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log | |
| 299 | 451 | $new_values['gateways_stripe']['live_secret_key'] = ( isset( $values['gateways_stripe']['live_secret_key'] ) && ( false !== $values['gateways_stripe']['live_secret_key'] ) ) ? $values['gateways_stripe']['live_secret_key'] : null; |
| 300 | 452 | $new_values['gateways_stripe']['live_public_key'] = ( isset( $values['gateways_stripe']['live_public_key'] ) && ( false !== $values['gateways_stripe']['live_public_key'] ) ) ? $values['gateways_stripe']['live_public_key'] : null; |
| 301 | 453 | $new_values['gateways_stripe']['test_secret_key'] = ( isset( $values['gateways_stripe']['test_secret_key'] ) && ( false !== $values['gateways_stripe']['test_secret_key'] ) ) ? $values['gateways_stripe']['test_secret_key'] : null; |
| 302 | 454 | $new_values['gateways_stripe']['test_public_key'] = ( isset( $values['gateways_stripe']['test_public_key'] ) && ( false !== $values['gateways_stripe']['test_public_key'] ) ) ? $values['gateways_stripe']['test_public_key'] : null; |
| @@ -309,21 +461,61 @@ | ||
| 309 | 461 | } |
| 310 | 462 | |
| 311 | 463 | // preserve any webhook keys, regardless if stripe connect addon is active or not. |
| 312 | 464 | if ( in_array( 'gateways_stripe', $settings_keys ) ) { |
| 313 | - if ( array_key_exists( 'test_webhook_id', $old_values['gateways_stripe'] ) && isset( $old_values['gateways_stripe']['test_webhook_id'] ) ) { | |
| 465 | + if ( ! empty( $old_values['gateways_stripe'] ) && array_key_exists( 'test_webhook_id', $old_values['gateways_stripe'] ) && isset( $old_values['gateways_stripe']['test_webhook_id'] ) ) { | |
| 314 | 466 | $new_values['gateways_stripe']['test_webhook_id'] = $old_values['gateways_stripe']['test_webhook_id']; |
| 315 | 467 | } |
| 316 | - if ( array_key_exists( 'live_webhook_id', $old_values['gateways_stripe'] ) && isset( $old_values['gateways_stripe']['live_webhook_id'] ) ) { | |
| 468 | + if ( ! empty( $old_values['gateways_stripe'] ) && array_key_exists( 'live_webhook_id', $old_values['gateways_stripe'] ) && isset( $old_values['gateways_stripe']['live_webhook_id'] ) ) { | |
| 317 | 469 | $new_values['gateways_stripe']['live_webhook_id'] = $old_values['gateways_stripe']['live_webhook_id']; |
| 318 | 470 | } |
| 319 | 471 | } |
| 320 | 472 | |
| 473 | + // account for incoming legacy licenses (1.7.0.4+) | |
| 474 | + // all we are doing is adding the licenses into the values so that the save_license hook can retreieve them and validate, etc. | |
| 475 | + if ( ! empty( $values['legacy_licenses'] ) && isset( $values['advanced']['section_hidden_licenses'] ) && 'licenses' === $values['advanced']['section_hidden_licenses'] ) { | |
| 476 | + if ( ! isset( $new_values['licenses']['legacy'] ) ) { | |
| 477 | + $new_values['licenses_legacy'] = (array) $values['legacy_licenses']; | |
| 478 | + } | |
| 479 | + } | |
| 480 | + | |
| 481 | + // ensure any hex color text files are valid hex fields. | |
| 482 | + if ( isset( $new_values['donation_form_default_highlight_colour'] ) ) { | |
| 483 | + $color_to_test = esc_html( $new_values['donation_form_default_highlight_colour'] ); | |
| 484 | + $color_valid = false; | |
| 485 | + // check for a hex color string | |
| 486 | + if ( preg_match( '/^#[a-f0-9]{6}$/i', $color_to_test ) ) { | |
| 487 | + // hex color is valid | |
| 488 | + $color_valid = true; | |
| 489 | + } | |
| 490 | + // Check for a hex color string without hash. | |
| 491 | + if ( preg_match( '/^[a-f0-9]{6}$/i', $color_to_test ) ) { | |
| 492 | + // hex color is valid | |
| 493 | + $color_valid = true; | |
| 494 | + $new_values['donation_form_default_highlight_colour'] = '#' . $color_to_test; | |
| 495 | + } | |
| 496 | + if ( false === $color_valid ) { | |
| 497 | + // not valid, make sure it is blank. | |
| 498 | + $new_values['donation_form_default_highlight_colour'] = false; | |
| 499 | + } | |
| 500 | + // clear the transient that stores the color styles. | |
| 501 | + delete_transient( 'charitable_custom_styles' ); | |
| 502 | + } | |
| 503 | + | |
| 321 | 504 | $values = wp_parse_args( $new_values, $old_values ); |
| 322 | 505 | |
| 506 | + // Sanitize decimal_count to prevent XSS attacks. | |
| 507 | + if ( isset( $values['decimal_count'] ) ) { | |
| 508 | + $values['decimal_count'] = absint( $values['decimal_count'] ); | |
| 509 | + // Ensure decimal_count is between 0 and 10. | |
| 510 | + $values['decimal_count'] = min( max( $values['decimal_count'], 0 ), 10 ); | |
| 511 | + } | |
| 512 | + | |
| 323 | 513 | if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { |
| 324 | - error_log( 'santiize_settings values updated' ); | |
| 325 | - error_log( print_r( $values, true ) ); | |
| 514 | + if ( charitable_is_debug() ) { | |
| 515 | + error_log( 'santiize_settings values updated' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log | |
| 516 | + error_log( print_r( $values, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r | |
| 517 | + } | |
| 326 | 518 | } |
| 327 | 519 | |
| 328 | 520 | /** |
| 329 | 521 | * Filter sanitized settings. |
| @@ -333,10 +525,24 @@ | ||
| 333 | 525 | * @param array $values All values, merged. |
| 334 | 526 | * @param array $new_values Newly submitted values. |
| 335 | 527 | * @param array $old_values Old settings. |
| 336 | 528 | */ |
| 529 | + | |
| 337 | 530 | $values = apply_filters( 'charitable_save_settings', $values, $new_values, $old_values ); |
| 338 | 531 | |
| 532 | + // save a temp transient for legacy licenses (1.7.0.8+) | |
| 533 | + // purpose is to provide better error reporting (transient should be deleted after settings page (advanced tab) is loaded). | |
| 534 | + // phpcs:disable WordPress.Security.NonceVerification.Missing | |
| 535 | + if ( isset( $_POST['charitable_settings']['legacy_licenses'] ) ) { | |
| 536 | + $referer = wp_get_referer(); | |
| 537 | + if ( false !== strpos( $referer, 'admin.php?page=charitable-settings&tab=advanced' ) ) { | |
| 538 | + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Array data, sanitized later | |
| 539 | + $legacy_licenses = wp_unslash( $_POST['charitable_settings']['legacy_licenses'] ); | |
| 540 | + set_transient( '_charitable_legacy_license_info', $legacy_licenses, MINUTE_IN_SECONDS ); | |
| 541 | + } | |
| 542 | + } | |
| 543 | + // phpcs:enable WordPress.Security.NonceVerification.Missing | |
| 544 | + | |
| 339 | 545 | $this->add_update_message( __( 'Settings saved', 'charitable' ), 'success' ); |
| 340 | 546 | |
| 341 | 547 | return $values; |
| 342 | 548 | } |
| @@ -407,9 +613,10 @@ | ||
| 407 | 613 | |
| 408 | 614 | /** |
| 409 | 615 | * Recursively add settings fields, given an array. |
| 410 | 616 | * |
| 411 | - * @since 1.0.0 | |
| 617 | + * @since 1.0.0 | |
| 618 | + * @version 1.8.7 | |
| 412 | 619 | * |
| 413 | 620 | * @param array $field The setting field. |
| 414 | 621 | * @param array $keys Array containing the section key and field key. |
| 415 | 622 | * @return void |
| @@ -428,9 +635,10 @@ | ||
| 428 | 635 | array_shift( $keys ); |
| 429 | 636 | } |
| 430 | 637 | |
| 431 | 638 | $field['key'] = $keys; |
| 432 | - $field['classes'] = $this->get_field_classes( $field ); | |
| 639 | + $field['classes'] = $this->get_field_classes( $field ); // deprecated? | |
| 640 | + $field['class'] = $this->get_field_classes( $field ); | |
| 433 | 641 | $callback = isset( $field['callback'] ) ? $field['callback'] : array( $this, 'render_field' ); |
| 434 | 642 | $label = $this->get_field_label( $field, end( $keys ) ); |
| 435 | 643 | |
| 436 | 644 | add_settings_field( |
| @@ -451,9 +659,9 @@ | ||
| 451 | 659 | * @param array $field The field definition. |
| 452 | 660 | * @param string $key The field key. |
| 453 | 661 | * @return string |
| 454 | 662 | */ |
| 455 | - private function get_field_label( $field, $key ) { | |
| 663 | + private function get_field_label( $field, $key ) { // phpcs:ignore | |
| 456 | 664 | $label = ''; |
| 457 | 665 | |
| 458 | 666 | if ( isset( $field['label_for'] ) ) { |
| 459 | 667 | $label = $field['label_for']; |
| @@ -554,9 +762,9 @@ | ||
| 554 | 762 | |
| 555 | 763 | switch ( $field_type ) { |
| 556 | 764 | |
| 557 | 765 | case 'checkbox': |
| 558 | - $value = intval( array_key_exists( $key, $submitted ) && 'on' == $submitted[ $key ] ); | |
| 766 | + $value = intval( array_key_exists( $key, $submitted ) && ( 'on' === $submitted[ $key ] || 1 === (int) $submitted[ $key ] ) ); | |
| 559 | 767 | break; |
| 560 | 768 | |
| 561 | 769 | case 'multi-checkbox': |
| 562 | 770 | $value = isset( $submitted[ $key ] ) ? $submitted[ $key ] : array(); |
| @@ -688,8 +896,504 @@ | ||
| 688 | 896 | 'Charitable_Admin_Notices::get_notices()' |
| 689 | 897 | ); |
| 690 | 898 | |
| 691 | 899 | return charitable_get_admin_notices()->get_notices(); |
| 900 | + } | |
| 901 | + | |
| 902 | + /** | |
| 903 | + * Display upgrade notice at the bottom on the plugin settings pages. | |
| 904 | + * | |
| 905 | + * @since 1.7.0.4 | |
| 906 | + * @version 1.8.8 | |
| 907 | + * | |
| 908 | + * @param string $view Current view inside the plugin settings page. | |
| 909 | + * @param string $css_class CSS class for the cta. | |
| 910 | + * @param bool $show_close_button Whether to show the close button. | |
| 911 | + */ | |
| 912 | + public function settings_cta( $view = false, $css_class = 'reports-lite-cta', $show_close_button = false ) { // phpcs:ignore | |
| 913 | + | |
| 914 | + $no_show_cta = array( | |
| 915 | + 'donors', | |
| 916 | + 'security', | |
| 917 | + 'marketing', | |
| 918 | + ); | |
| 919 | + | |
| 920 | + if ( in_array( $view, $no_show_cta ) ) { | |
| 921 | + return; | |
| 922 | + } | |
| 923 | + | |
| 924 | + if ( charitable_is_pro() ) { | |
| 925 | + // no need to display this cta since they have a valid license. | |
| 926 | + return; | |
| 927 | + } | |
| 928 | + | |
| 929 | + if ( get_option( 'charitable_lite_settings_upgrade', false ) || apply_filters( 'charitable_lite_settings_upgrade', false ) ) { | |
| 930 | + return; | |
| 931 | + } | |
| 932 | + ?> | |
| 933 | + <?php if ( $show_close_button ) : ?> | |
| 934 | + <div class="charitable-cta-dismiss-container"> | |
| 935 | + <button type="button" class="button-link charitable-banner-dismiss dismiss">x</button> | |
| 936 | + </div> | |
| 937 | + <?php endif; ?> | |
| 938 | + <?php charitable_render_global_upgrade_cta( $css_class ); ?> | |
| 939 | + <script type="text/javascript"> | |
| 940 | + jQuery( function ( $ ) { | |
| 941 | + $( document ).on( 'click', '.settings-lite-cta .dismiss', function ( event ) { | |
| 942 | + event.preventDefault(); | |
| 943 | + $.post( ajaxurl, { | |
| 944 | + action: 'charitable_lite_settings_upgrade', | |
| 945 | + charitable_action: 'remove_lite_cta' | |
| 946 | + } ); | |
| 947 | + $( '.settings-lite-cta' ).remove(); | |
| 948 | + } ); | |
| 949 | + } ); | |
| 950 | + </script> | |
| 951 | + <?php | |
| 952 | + } | |
| 953 | + | |
| 954 | + /** | |
| 955 | + * Show the settings CTA. | |
| 956 | + * | |
| 957 | + * @since 1.8.5.1 | |
| 958 | + * @version 1.8.9 | |
| 959 | + * | |
| 960 | + * @return void | |
| 961 | + */ | |
| 962 | + public function show_settings_cta() { | |
| 963 | + | |
| 964 | + $tab_values_to_check = array( | |
| 965 | + 'marketing', | |
| 966 | + 'donors', | |
| 967 | + 'security', | |
| 968 | + ); | |
| 969 | + | |
| 970 | + $tab_value = isset( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : ''; // phpcs:ignore | |
| 971 | + $sub_tab_value = isset( $_GET['sub_tab'] ) ? esc_attr( $_GET['sub_tab'] ) : ''; // phpcs:ignore | |
| 972 | + | |
| 973 | + if ( in_array( $tab_value, $tab_values_to_check ) ) { // phpcs:ignore | |
| 974 | + // UTM medium follows the sub_tab when present (e.g. marketing-conversion-tracking) | |
| 975 | + // so each upgrade button is attributable. | |
| 976 | + $upgrade_medium = ( 'marketing' === $tab_value && ! empty( $sub_tab_value ) ) | |
| 977 | + ? 'marketing-' . str_replace( '_', '-', $sub_tab_value ) | |
| 978 | + : $tab_value; | |
| 979 | + | |
| 980 | + ob_start(); | |
| 981 | + ?> | |
| 982 | + | |
| 983 | + <div class="charitable-education-page"> | |
| 984 | + | |
| 985 | + <?php | |
| 986 | + if ( 'marketing' === $tab_value ) { | |
| 987 | + // Default to the Newsletters CTA when no sub_tab is supplied | |
| 988 | + // (the marketing_sub_tab_default redirect should normally prevent this, | |
| 989 | + // but render safely if a redirect was skipped — e.g. during POST). | |
| 990 | + $marketing_sub_tab = '' !== $sub_tab_value ? $sub_tab_value : 'newsletters'; | |
| 991 | + | |
| 992 | + if ( 'conversion_tracking' === $marketing_sub_tab ) { | |
| 993 | + $this->get_settings_cta_education_content_conversion_tracking(); | |
| 994 | + } elseif ( 'google_analytics' === $marketing_sub_tab ) { | |
| 995 | + $this->get_settings_cta_education_content_google_analytics(); | |
| 996 | + } else { | |
| 997 | + $this->get_settings_cta_education_content_marketing_settings(); | |
| 998 | + } | |
| 999 | + } elseif ( 'donors' === $tab_value ) { | |
| 1000 | + $this->get_settings_cta_education_content_donor_settings(); | |
| 1001 | + } elseif ( 'security' === $tab_value && ! charitable_is_pro() ) { | |
| 1002 | + $this->get_settings_cta_education_content_advanced_security_settings(); | |
| 1003 | + } | |
| 1004 | + ?> | |
| 1005 | + <?php if ( charitable_is_pro() ) : ?> | |
| 1006 | + <div class="charitable-education-page-disabled-download"> | |
| 1007 | + <p> | |
| 1008 | + <?php | |
| 1009 | + printf( | |
| 1010 | + /* translators: %s: Documentation URL */ | |
| 1011 | + esc_html__( 'Please add your license and upgrade to Charitable Pro for more advanced security features. Please %s on how to download Charitable Pro.', 'charitable' ), | |
| 1012 | + '<a href="https://wpcharitable.com/docs/download-charitable-pro/" target="_blank">' . esc_html__( 'see our documentation', 'charitable' ) . '</a>' | |
| 1013 | + ); | |
| 1014 | + ?> | |
| 1015 | + </p> | |
| 1016 | + </div> | |
| 1017 | + <?php else : ?> | |
| 1018 | + <div class="charitable-education-page-button"> | |
| 1019 | + <a href="<?php echo esc_url( charitable_utm_link( 'https://wpcharitable.com/lite-upgrade/', $upgrade_medium, __( 'Upgrade to Charitable Pro', 'charitable' ) ) ); ?>" class="button button-primary" target="_blank"><?php esc_html_e( 'Upgrade to Charitable Pro', 'charitable' ); ?></a> | |
| 1020 | + </div> | |
| 1021 | + <?php endif; ?> | |
| 1022 | + </div> | |
| 1023 | + <?php | |
| 1024 | + echo ob_get_clean(); // phpcs:ignore | |
| 1025 | + } | |
| 1026 | + } | |
| 1027 | + | |
| 1028 | + /** | |
| 1029 | + * Get the settings CTA education content for the donor referrals sub tab. | |
| 1030 | + * | |
| 1031 | + * @since 1.8.5.1 | |
| 1032 | + * | |
| 1033 | + * @return void | |
| 1034 | + */ | |
| 1035 | + public function get_settings_cta_education_content_donor_settings() { | |
| 1036 | + ?> | |
| 1037 | + | |
| 1038 | + <div class="charitable-education-page-heading"> | |
| 1039 | + <h4><?php esc_html_e( 'New Donor Features', 'charitable' ); ?></h4> | |
| 1040 | + <p><?php esc_html_e( 'Give donors the power to manage their contributions to your organization with a new donor dashboard. Encourage donors to spread the word about your organization by offering rewards for successful referrals. And give donors the ability to post comments to campaigns when they donate.', 'charitable' ); ?></p> | |
| 1041 | + <p><?php esc_html_e( 'All of this is possible with the Charitable Pro plugin.', 'charitable' ); ?></p> | |
| 1042 | + </div> | |
| 1043 | + | |
| 1044 | + <div class="charitable-education-page-media"> | |
| 1045 | + <div class="charitable-education-page-images"> | |
| 1046 | + <figure> | |
| 1047 | + <div class="charitable-education-page-images-image"> | |
| 1048 | + <img src="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/donor-dashboard/education-1.png" alt="<?php esc_attr_e( 'Donor Dashboard', 'charitable' ); ?>"> | |
| 1049 | + <a href="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/donor-dashboard/education-1.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Donor Dashboard', 'charitable' ); ?>"></a> | |
| 1050 | + </div> | |
| 1051 | + <figcaption><?php esc_html_e( 'Donor Dashboard', 'charitable' ); ?></figcaption> | |
| 1052 | + </figure> | |
| 1053 | + <figure> | |
| 1054 | + <div class="charitable-education-page-images-image"> | |
| 1055 | + <img src="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/donor-referrals/education-2.png" alt="<?php esc_attr_e( 'Donor Referrals', 'charitable' ); ?>"> | |
| 1056 | + <a href="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/donor-referrals/education-2.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Donor Referrals', 'charitable' ); ?>"></a> | |
| 1057 | + </div> | |
| 1058 | + <figcaption><?php esc_html_e( 'Donor Referrals', 'charitable' ); ?></figcaption> | |
| 1059 | + </figure> | |
| 1060 | + <figure> | |
| 1061 | + <div class="charitable-education-page-images-image"> | |
| 1062 | + <img src="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/donor-comments/education-3.png" alt="<?php esc_attr_e( 'Donor Comments', 'charitable' ); ?>"> | |
| 1063 | + <a href="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/donor-comments/education-3.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Donor Comments', 'charitable' ); ?>"></a> | |
| 1064 | + </div> | |
| 1065 | + <figcaption><?php esc_html_e( 'Donor Comments', 'charitable' ); ?></figcaption> | |
| 1066 | + </figure> | |
| 1067 | + </div> | |
| 1068 | + </div> | |
| 1069 | + | |
| 1070 | + <div class="charitable-education-page-caps"> | |
| 1071 | + <p><?php esc_html_e( 'Give donors the power to manage their contributions to your organization.', 'charitable' ); ?></p> | |
| 1072 | + <ul> | |
| 1073 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Increased Donor Engagement', 'charitable' ); ?></li> | |
| 1074 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Customizable Dashboard', 'charitable' ); ?></li> | |
| 1075 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Donation History', 'charitable' ); ?></li> | |
| 1076 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'View Campaigns', 'charitable' ); ?></li> | |
| 1077 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'View Comments', 'charitable' ); ?></li> | |
| 1078 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Download Donation Receipts', 'charitable' ); ?></li> | |
| 1079 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Tracking Personalized Notifications', 'charitable' ); ?></li> | |
| 1080 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Donor Profile Management', 'charitable' ); ?></li> | |
| 1081 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'See Each Donor\'s Referrals', 'charitable' ); ?></li> | |
| 1082 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Track Referral Success Rates', 'charitable' ); ?></li> | |
| 1083 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Customizable Referral Rewards', 'charitable' ); ?></li> | |
| 1084 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Easy Promotion of Campaigns', 'charitable' ); ?></li> | |
| 1085 | + | |
| 1086 | + </ul> | |
| 1087 | + </div> | |
| 1088 | + <?php | |
| 1089 | + } | |
| 1090 | + | |
| 1091 | + /** | |
| 1092 | + * Get the settings CTA education content for the donor referrals sub tab. | |
| 1093 | + * | |
| 1094 | + * @since 1.8.5.1 | |
| 1095 | + * | |
| 1096 | + * @return void | |
| 1097 | + */ | |
| 1098 | + public function get_settings_cta_education_content_marketing_settings() { | |
| 1099 | + ?> | |
| 1100 | + | |
| 1101 | + <div class="charitable-education-page-heading"> | |
| 1102 | + <h4><?php esc_html_e( 'Marketing', 'charitable' ); ?></h4> | |
| 1103 | + <p><?php esc_html_e( 'Turn one-time donors into ongoing supporters with your newsletter list. This feature allows you to connect to your email marketing account and automatically add donors to your email newsletter list. You can integrate your campaigns seamlessly with MailChimp, Campaign Monitor, MailerLite, ActiveCampaign, Mailster and MailPoet, allowing you to enable one or more providers.', 'charitable' ); ?></p> | |
| 1104 | + </div> | |
| 1105 | + | |
| 1106 | + <div class="charitable-education-page-media"> | |
| 1107 | + <div class="charitable-education-page-images"> | |
| 1108 | + <figure> | |
| 1109 | + <div class="charitable-education-page-images-image"> | |
| 1110 | + <img src="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/marketing/education-1.png" alt="<?php esc_attr_e( 'Marketing', 'charitable' ); ?>"> | |
| 1111 | + <a href="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/marketing/education-1.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Marketing', 'charitable' ); ?>"></a> | |
| 1112 | + </div> | |
| 1113 | + <figcaption><?php esc_html_e( 'Choose a default list', 'charitable' ); ?></figcaption> | |
| 1114 | + </figure> | |
| 1115 | + <figure> | |
| 1116 | + <div class="charitable-education-page-images-image"> | |
| 1117 | + <img src="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/marketing/education-2.png" alt="<?php esc_attr_e( 'Marketing', 'charitable' ); ?>"> | |
| 1118 | + <a href="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/marketing/education-2.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Marketing', 'charitable' ); ?>"></a> | |
| 1119 | + </div> | |
| 1120 | + <figcaption><?php esc_html_e( 'Sync lists', 'charitable' ); ?></figcaption> | |
| 1121 | + </figure> | |
| 1122 | + <figure> | |
| 1123 | + <div class="charitable-education-page-images-image"> | |
| 1124 | + <img src="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/marketing/education-3.png" alt="<?php esc_attr_e( 'Marketing', 'charitable' ); ?>"> | |
| 1125 | + <a href="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/marketing/education-3.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Marketing', 'charitable' ); ?>"></a> | |
| 1126 | + </div> | |
| 1127 | + <figcaption><?php esc_html_e( 'Donation form options', 'charitable' ); ?></figcaption> | |
| 1128 | + </figure> | |
| 1129 | + </div> | |
| 1130 | + </div> | |
| 1131 | + | |
| 1132 | + <div class="charitable-education-page-caps"> | |
| 1133 | + <p><?php esc_html_e( 'Turn one-time donors into ongoing supporters.', 'charitable' ); ?></p> | |
| 1134 | + <ul> | |
| 1135 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Easy Integration', 'charitable' ); ?></li> | |
| 1136 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Built-in contact consent options', 'charitable' ); ?></li> | |
| 1137 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Automatically add donors to your email list', 'charitable' ); ?></li> | |
| 1138 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Organize donors with tags', 'charitable' ); ?></li> | |
| 1139 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Send email series to keep donors engaged', 'charitable' ); ?></li> | |
| 1140 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Enable multiple email services', 'charitable' ); ?></li> | |
| 1141 | + </ul> | |
| 1142 | + </div> | |
| 1143 | + <?php | |
| 1144 | + } | |
| 1145 | + | |
| 1146 | + /** | |
| 1147 | + * Get the settings CTA education content for the Marketing → Conversion Tracking sub-tab. | |
| 1148 | + * | |
| 1149 | + * @since 1.8.11.3 | |
| 1150 | + * | |
| 1151 | + * @return void | |
| 1152 | + */ | |
| 1153 | + public function get_settings_cta_education_content_conversion_tracking() { | |
| 1154 | + $assets_url = charitable()->get_path( 'assets', false ); | |
| 1155 | + ?> | |
| 1156 | + | |
| 1157 | + <div class="charitable-education-page-heading"> | |
| 1158 | + <h4><?php esc_html_e( 'Conversion Tracking', 'charitable' ); ?></h4> | |
| 1159 | + <p><?php esc_html_e( 'Send Charitable donation events into Meta Pixel, TikTok Pixel, and Google Tag Manager. Native, code-free conversion tracking that ties every completed donation to the ad campaigns and audiences that drove it.', 'charitable' ); ?></p> | |
| 1160 | + <p><?php esc_html_e( 'See which ads actually produce donations, optimize spend toward real revenue, and build remarketing audiences from your highest-value supporters.', 'charitable' ); ?></p> | |
| 1161 | + </div> | |
| 1162 | + | |
| 1163 | + <div class="charitable-education-page-media"> | |
| 1164 | + <div class="charitable-education-page-video"> | |
| 1165 | + <figure> | |
| 1166 | + <div class="charitable-education-page-video-embed"> | |
| 1167 | + <iframe src="https://www.youtube-nocookie.com/embed/sS-F6x6F-Fs?rel=0&modestbranding=1&iv_load_policy=3&loop=1&playlist=sS-F6x6F-Fs" title="<?php esc_attr_e( 'Introducing Conversion Tracking', 'charitable' ); ?>" allow="accelerometer; autoplay; clipboard-write; encrypted-media; picture-in-picture" allowfullscreen frameborder="0"></iframe> | |
| 1168 | + </div> | |
| 1169 | + <figcaption><a href="https://youtu.be/sS-F6x6F-Fs" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Watch: Introducing Conversion Tracking', 'charitable' ); ?></a></figcaption> | |
| 1170 | + </figure> | |
| 1171 | + </div> | |
| 1172 | + <div class="charitable-education-page-images"> | |
| 1173 | + <figure> | |
| 1174 | + <div class="charitable-education-page-images-image"> | |
| 1175 | + <img src="<?php echo esc_url( $assets_url ); ?>images/education/conversion-tracking/education-1.png" alt="<?php esc_attr_e( 'Conversion tracking settings', 'charitable' ); ?>"> | |
| 1176 | + <a href="<?php echo esc_url( $assets_url ); ?>images/education/conversion-tracking/education-1.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Pixel + GTM settings', 'charitable' ); ?>"></a> | |
| 1177 | + </div> | |
| 1178 | + <figcaption><?php esc_html_e( 'Pixel + GTM settings', 'charitable' ); ?></figcaption> | |
| 1179 | + </figure> | |
| 1180 | + <figure> | |
| 1181 | + <div class="charitable-education-page-images-image"> | |
| 1182 | + <img src="<?php echo esc_url( $assets_url ); ?>images/education/conversion-tracking/education-2.png" alt="<?php esc_attr_e( 'Per-donation tracking status', 'charitable' ); ?>"> | |
| 1183 | + <a href="<?php echo esc_url( $assets_url ); ?>images/education/conversion-tracking/education-2.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Per-donation tracking status', 'charitable' ); ?>"></a> | |
| 1184 | + </div> | |
| 1185 | + <figcaption><?php esc_html_e( 'Per-donation tracking status', 'charitable' ); ?></figcaption> | |
| 1186 | + </figure> | |
| 1187 | + <figure> | |
| 1188 | + <div class="charitable-education-page-images-image"> | |
| 1189 | + <img src="<?php echo esc_url( $assets_url ); ?>images/education/conversion-tracking/education-3.png" alt="<?php esc_attr_e( 'WP Consent API compliant', 'charitable' ); ?>"> | |
| 1190 | + <a href="<?php echo esc_url( $assets_url ); ?>images/education/conversion-tracking/education-3.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'WP Consent API compliant', 'charitable' ); ?>"></a> | |
| 1191 | + </div> | |
| 1192 | + <figcaption><?php esc_html_e( 'WP Consent API compliant', 'charitable' ); ?></figcaption> | |
| 1193 | + </figure> | |
| 1194 | + </div> | |
| 1195 | + </div> | |
| 1196 | + | |
| 1197 | + <div class="charitable-education-page-caps"> | |
| 1198 | + <p><?php esc_html_e( 'Track conversions with…', 'charitable' ); ?></p> | |
| 1199 | + <ul> | |
| 1200 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Meta Pixel (Facebook / Instagram)', 'charitable' ); ?></li> | |
| 1201 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'TikTok Pixel', 'charitable' ); ?></li> | |
| 1202 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Google Tag Manager (GTM)', 'charitable' ); ?></li> | |
| 1203 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Campaign page view tracking', 'charitable' ); ?></li> | |
| 1204 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Donation form open tracking', 'charitable' ); ?></li> | |
| 1205 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'WP Consent API (GDPR) integration', 'charitable' ); ?></li> | |
| 1206 | + </ul> | |
| 1207 | + </div> | |
| 1208 | + <?php | |
| 1209 | + } | |
| 1210 | + | |
| 1211 | + /** | |
| 1212 | + * Get the settings CTA education content for the Marketing → Google Analytics sub-tab. | |
| 1213 | + * | |
| 1214 | + * @since 1.8.11.3 | |
| 1215 | + * | |
| 1216 | + * @return void | |
| 1217 | + */ | |
| 1218 | + public function get_settings_cta_education_content_google_analytics() { | |
| 1219 | + $assets_url = charitable()->get_path( 'assets', false ); | |
| 1220 | + ?> | |
| 1221 | + | |
| 1222 | + <div class="charitable-education-page-heading"> | |
| 1223 | + <h4><?php esc_html_e( 'Google Analytics', 'charitable' ); ?></h4> | |
| 1224 | + <p><?php esc_html_e( 'Send Charitable donation events into Google Analytics 4. Native GA4 integration fires purchase, refund, sign-up, and login events both browser-side via gtag.js and server-side via the Measurement Protocol — so every donation, including off-site gateways and webhook-confirmed completions, makes it into GA4.', 'charitable' ); ?></p> | |
| 1225 | + <p><?php esc_html_e( 'See which campaigns and sources actually produce donations, stitch sessions across devices with hashed-email user_id, and stay EEA-compliant out of the box via Google Consent Mode v2 and the WP Consent API.', 'charitable' ); ?></p> | |
| 1226 | + </div> | |
| 1227 | + | |
| 1228 | + <div class="charitable-education-page-media"> | |
| 1229 | + <div class="charitable-education-page-images"> | |
| 1230 | + <figure> | |
| 1231 | + <div class="charitable-education-page-images-image"> | |
| 1232 | + <img src="<?php echo esc_url( $assets_url ); ?>images/education/google-analytics/education-1.png" alt="<?php esc_attr_e( 'Google Analytics settings', 'charitable' ); ?>"> | |
| 1233 | + <a href="<?php echo esc_url( $assets_url ); ?>images/education/google-analytics/education-1.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'GA4 settings + Test Connection', 'charitable' ); ?>"></a> | |
| 1234 | + </div> | |
| 1235 | + <figcaption><?php esc_html_e( 'GA4 settings + Test Connection', 'charitable' ); ?></figcaption> | |
| 1236 | + </figure> | |
| 1237 | + <figure> | |
| 1238 | + <div class="charitable-education-page-images-image"> | |
| 1239 | + <img src="<?php echo esc_url( $assets_url ); ?>images/education/google-analytics/education-2.png" alt="<?php esc_attr_e( 'Per-donation GA metabox', 'charitable' ); ?>"> | |
| 1240 | + <a href="<?php echo esc_url( $assets_url ); ?>images/education/google-analytics/education-2.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Per-donation tracking metabox', 'charitable' ); ?>"></a> | |
| 1241 | + </div> | |
| 1242 | + <figcaption><?php esc_html_e( 'Per-donation tracking metabox', 'charitable' ); ?></figcaption> | |
| 1243 | + </figure> | |
| 1244 | + <figure> | |
| 1245 | + <div class="charitable-education-page-images-image"> | |
| 1246 | + <img src="<?php echo esc_url( $assets_url ); ?>images/education/google-analytics/education-3.png" alt="<?php esc_attr_e( 'Test connection success', 'charitable' ); ?>"> | |
| 1247 | + <a href="<?php echo esc_url( $assets_url ); ?>images/education/google-analytics/education-3.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Validate your GA4 setup', 'charitable' ); ?>"></a> | |
| 1248 | + </div> | |
| 1249 | + <figcaption><?php esc_html_e( 'Validate your GA4 setup', 'charitable' ); ?></figcaption> | |
| 1250 | + </figure> | |
| 1251 | + </div> | |
| 1252 | + </div> | |
| 1253 | + | |
| 1254 | + <div class="charitable-education-page-caps"> | |
| 1255 | + <p><?php esc_html_e( 'Track donations in GA4 with…', 'charitable' ); ?></p> | |
| 1256 | + <ul> | |
| 1257 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'GA4 purchase events (browser + Measurement Protocol)', 'charitable' ); ?></li> | |
| 1258 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Server-side refund, sign_up, and login events', 'charitable' ); ?></li> | |
| 1259 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Full UTM capture (including utm_term and utm_id)', 'charitable' ); ?></li> | |
| 1260 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Hashed-email user_id for cross-device session stitching', 'charitable' ); ?></li> | |
| 1261 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Google Consent Mode v2 + WP Consent API integration', 'charitable' ); ?></li> | |
| 1262 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( '"Test Connection" button to validate your GA4 setup', 'charitable' ); ?></li> | |
| 1263 | + </ul> | |
| 1264 | + </div> | |
| 1265 | + <?php | |
| 1266 | + } | |
| 1267 | + | |
| 1268 | + /** | |
| 1269 | + * Get the settings CTA education content for the donor referrals sub tab. | |
| 1270 | + * | |
| 1271 | + * @since 1.8.5.1 | |
| 1272 | + * | |
| 1273 | + * @return void | |
| 1274 | + */ | |
| 1275 | + public function get_settings_cta_education_content_security_settings() { | |
| 1276 | + ?> | |
| 1277 | + | |
| 1278 | + <div class="charitable-education-page-heading"> | |
| 1279 | + <h4><?php esc_html_e( 'Security', 'charitable' ); ?></h4> | |
| 1280 | + <p><?php esc_html_e( 'It is important to protect against potential misuse while maintaining donor trust. CAPTCHA integration adds an essential layer of protection against automated attacks and spam donations. Every transaction is meticulously logged with IP address documentation and timestamp verification, providing a clear audit trail and helping prevent fraudulent activities.', 'charitable' ); ?></p> | |
| 1281 | + </div> | |
| 1282 | + | |
| 1283 | + <div class="charitable-education-page-media"> | |
| 1284 | + <div class="charitable-education-page-images"> | |
| 1285 | + <figure> | |
| 1286 | + <div class="charitable-education-page-images-image"> | |
| 1287 | + <img src="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/security/education-1.png" alt="<?php esc_attr_e( 'Security', 'charitable' ); ?>"> | |
| 1288 | + <a href="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/security/education-1.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Security', 'charitable' ); ?>"></a> | |
| 1289 | + </div> | |
| 1290 | + <figcaption><?php esc_html_e( 'Captchas', 'charitable' ); ?></figcaption> | |
| 1291 | + </figure> | |
| 1292 | + <figure> | |
| 1293 | + <div class="charitable-education-page-images-image"> | |
| 1294 | + <img src="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/security/education-3.png" alt="<?php esc_attr_e( 'Security', 'charitable' ); ?>"> | |
| 1295 | + <a href="<?php echo esc_url( charitable()->get_path( 'assets', false ) ); ?>images/education/security/education-3.png" class="hover" data-lity="" data-lity-desc="<?php esc_attr_e( 'Security', 'charitable' ); ?>"></a> | |
| 1296 | + </div> | |
| 1297 | + <figcaption><?php esc_html_e( 'Form options', 'charitable' ); ?></figcaption> | |
| 1298 | + </figure> | |
| 1299 | + </div> | |
| 1300 | + </div> | |
| 1301 | + | |
| 1302 | + <div class="charitable-education-page-caps"> | |
| 1303 | + <p><?php esc_html_e( 'Protect against potential misuse while maintaining donor trust.', 'charitable' ); ?></p> | |
| 1304 | + <ul> | |
| 1305 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Easy Activation', 'charitable' ); ?></li> | |
| 1306 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Record IP Addresses', 'charitable' ); ?></li> | |
| 1307 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Block Bad Bots', 'charitable' ); ?></li> | |
| 1308 | + </ul> | |
| 1309 | + </div> | |
| 1310 | + <?php | |
| 1311 | + } | |
| 1312 | + | |
| 1313 | + /** | |
| 1314 | + * Get the settings CTA education content for advanced security features. | |
| 1315 | + * | |
| 1316 | + * @since 1.8.9 | |
| 1317 | + * | |
| 1318 | + * @return void | |
| 1319 | + */ | |
| 1320 | + public function get_settings_cta_education_content_advanced_security_settings() { | |
| 1321 | + ?> | |
| 1322 | + | |
| 1323 | + <div class="charitable-education-page-heading"> | |
| 1324 | + <h4><?php esc_html_e( 'Advanced Security Features', 'charitable' ); ?></h4> | |
| 1325 | + <p><?php esc_html_e( 'Charitable Pro offers a fortified layer of safety designed for high-volume campaigns. Upgrade to unlock sophisticated spam filtering and enhanced payment protection, ensuring the highest level of trust and security for your donors.', 'charitable' ); ?></p> | |
| 1326 | + </div> | |
| 1327 | + <div class="charitable-education-page-caps"> | |
| 1328 | + <p><?php esc_html_e( 'Protect against potential misuse while maintaining donor trust.', 'charitable' ); ?></p> | |
| 1329 | + <ul> | |
| 1330 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'General Rate Limiting', 'charitable' ); ?></li> | |
| 1331 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Stripe Rate Limiting', 'charitable' ); ?></li> | |
| 1332 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'IP Blacklist/Whitelist', 'charitable' ); ?></li> | |
| 1333 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Email Pattern Blocking', 'charitable' ); ?></li> | |
| 1334 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Minimum Donation Features', 'charitable' ); ?></li> | |
| 1335 | + <li><i class="fa fa-solid fa-check"></i> <?php esc_html_e( 'Math Field Protection', 'charitable' ); ?></li> | |
| 1336 | + </ul> | |
| 1337 | + </div> | |
| 1338 | + <?php | |
| 1339 | + } | |
| 1340 | + | |
| 1341 | + /** | |
| 1342 | + * Dismiss upgrade notice at the bottom on the plugin settings pages. | |
| 1343 | + * | |
| 1344 | + * @since 1.7.0.4 | |
| 1345 | + * | |
| 1346 | + * @return void | |
| 1347 | + */ | |
| 1348 | + public function settings_cta_dismiss() { | |
| 1349 | + | |
| 1350 | + if ( ! charitable_current_user_can() ) { | |
| 1351 | + wp_send_json_error(); | |
| 1352 | + } | |
| 1353 | + | |
| 1354 | + update_option( 'charitable_lite_settings_upgrade', time() ); | |
| 1355 | + | |
| 1356 | + wp_send_json_success(); | |
| 1357 | + } | |
| 1358 | + | |
| 1359 | + /** | |
| 1360 | + * Check Square connection for the new mode. | |
| 1361 | + * | |
| 1362 | + * @since 1.8.5 | |
| 1363 | + * | |
| 1364 | + * @param string $new_mode The new test mode. | |
| 1365 | + * @return boolean True if Square has connection issues, false otherwise. | |
| 1366 | + */ | |
| 1367 | + private function check_square_connection_for_mode_change( $new_mode ) { | |
| 1368 | + // Check if Square gateway is active. | |
| 1369 | + $active_gateways = charitable_get_helper( 'gateways' )->get_active_gateways(); | |
| 1370 | + | |
| 1371 | + if ( ! is_array( $active_gateways ) || ! in_array( 'Charitable_Gateway_Square', $active_gateways ) ) { | |
| 1372 | + return false; | |
| 1373 | + } | |
| 1374 | + | |
| 1375 | + // Determine the mode string. | |
| 1376 | + $mode = $new_mode ? 'test' : 'live'; | |
| 1377 | + | |
| 1378 | + // Check if there's a Square connection for this mode. | |
| 1379 | + $connection = Charitable_Square_Connection::get( $mode ); | |
| 1380 | + | |
| 1381 | + // Check if connection exists and is properly configured. | |
| 1382 | + if ( ! $connection || ! $connection->is_configured() || ! $connection->is_valid() ) { | |
| 1383 | + | |
| 1384 | + // Set a warning flag that will be checked on the payment page. | |
| 1385 | + update_option( 'charitable_square_mode_connection_warning', array( | |
| 1386 | + 'mode' => $mode, | |
| 1387 | + 'timestamp' => time(), | |
| 1388 | + ) ); | |
| 1389 | + | |
| 1390 | + return true; // Square has connection issues. | |
| 1391 | + } else { | |
| 1392 | + // Clear the warning if connection exists. | |
| 1393 | + delete_option( 'charitable_square_mode_connection_warning' ); | |
| 1394 | + return false; // Square has no connection issues. | |
| 1395 | + } | |
| 692 | 1396 | } |
| 693 | 1397 | } |
| 694 | 1398 | |
| 695 | 1399 | endif; |