Changeset 3460927
- Timestamp:
- 02/13/2026 04:57:35 PM (4 days ago)
- Location:
- charitable/trunk
- Files:
-
- 12 edited
-
CHANGELOG.md (modified) (1 diff)
-
assets/js/campaign-builder/admin-builder.js (modified) (1 diff)
-
assets/js/campaign-builder/utils.js (modified) (2 diffs)
-
charitable.php (modified) (2 diffs)
-
i18n/languages/charitable.pot (modified) (15 diffs)
-
includes/abstracts/abstract-class-charitable-email.php (modified) (5 diffs)
-
includes/admin/tools/class-charitable-tools-email-diagnostics.php (modified) (3 diffs)
-
includes/emails/class-charitable-email-offline-donation-receipt.php (modified) (1 diff)
-
includes/gateways/class-charitable-gateway-stripe-am.php (modified) (3 diffs)
-
includes/shortcodes/class-charitable-email-shortcode.php (modified) (4 diffs)
-
includes/stripe/gateway/class-charitable-stripe-webhook-processor.php (modified) (2 diffs)
-
readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
charitable/trunk/CHANGELOG.md
r3455474 r3460927 1 # 1.8.9.5 2 * FIX: Added additional checks to resolved issue with Stripe webhook that was causing a fatal error a certain scenario. 3 * FIX: Allow more international characters into campaign title fields in campaign visual builder. 4 * IMPROVED: Email shortcode processing with recursion prevention for better reliability. 5 * IMPROVED: Added additional enhanced email error logging and diagnostics. 6 1 7 # 1.8.9.4 2 8 * FIX: Resolved seemingly missing social media icons in some campaign builder template previews in certain scenarios. -
charitable/trunk/assets/js/campaign-builder/admin-builder.js
r3453160 r3460927 2104 2104 2105 2105 // Clean the string. 2106 title = title.replace(/[^ a-z0-9 _.,!"'/$]/gi, '');2106 title = title.replace(/[^\w\s\u00C0-\u024F\u1E00-\u1EFF\u2C60-\u2C7F\uA720-\uA7FF _.,!"()'\/$[\]:@#%-]/gi, ''); 2107 2107 2108 2108 // Should we allow a blank title even temp? -
charitable/trunk/assets/js/campaign-builder/utils.js
r2987535 r3460927 24 24 santitizeTitle: function ( stringValue ) { 25 25 26 return stringValue.replace(/[^ a-z0-9 _.,!"()'/$[]:]/gi, '');26 return stringValue.replace(/[^\w\s\u00C0-\u024F\u1E00-\u1EFF\u2C60-\u2C7F\uA720-\uA7FF _.,!"()'\/$[\]:@#%-]/gi, ''); 27 27 28 28 }, … … 40 40 santitizeTextInput: function ( stringValue ) { 41 41 42 return stringValue.replace(/[^ a-z0-9 _.,!"()'/$[]:-]/gi, '');42 return stringValue.replace(/[^\w\s\u00C0-\u024F\u1E00-\u1EFF\u2C60-\u2C7F\uA720-\uA7FF _.,!"()'\/$[\]:@#%-]/gi, ''); 43 43 44 44 }, -
charitable/trunk/charitable.php
r3455474 r3460927 4 4 * Plugin URI: https://www.wpcharitable.com 5 5 * Description: The best WordPress donation plugin. Fundraising with recurring donations, and powerful features to help you raise more money online. 6 * Version: 1.8.9. 46 * Version: 1.8.9.5 7 7 * Author: Charitable Donations & Fundraising Team 8 8 * Author URI: https://wpcharitable.com 9 9 * Requires at least: 5.0 10 * Stable tag: 1.8.9. 410 * Stable tag: 1.8.9.5 11 11 * License: GPLv2 or later 12 12 * License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html … … 40 40 41 41 /* Plugin version. */ 42 const VERSION = '1.8.9. 4';42 const VERSION = '1.8.9.5'; 43 43 44 44 /* Version of database schema. */ -
charitable/trunk/i18n/languages/charitable.pot
r3453160 r3460927 3 3 msgid "" 4 4 msgstr "" 5 "Project-Id-Version: Charitable 1.8.9. 2\n"5 "Project-Id-Version: Charitable 1.8.9.5\n" 6 6 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/charitable\n" 7 7 "Last-Translator: Charitable Team\n" … … 10 10 "Content-Type: text/plain; charset=UTF-8\n" 11 11 "Content-Transfer-Encoding: 8bit\n" 12 "POT-Creation-Date: 2026-02- 02T22:56:07+00:00\n"12 "POT-Creation-Date: 2026-02-13T00:21:50+00:00\n" 13 13 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 14 "X-Generator: WP-CLI 2.10.0\n" … … 5355 5355 5356 5356 #: includes/admin/campaign-builder/campaign-congrats-wizard/popup.php:38 5357 #: includes/admin/onboarding/class-charitable-setup.php:187 45357 #: includes/admin/onboarding/class-charitable-setup.php:1879 5358 5358 msgid "Congratulations!" 5359 5359 msgstr "" … … 10830 10830 msgstr "" 10831 10831 10832 #: includes/admin/onboarding/class-charitable-setup.php:46 110833 #: includes/admin/onboarding/class-charitable-setup.php:46 210832 #: includes/admin/onboarding/class-charitable-setup.php:466 10833 #: includes/admin/onboarding/class-charitable-setup.php:467 10834 10834 msgid "Setup Charitable" 10835 10835 msgstr "" 10836 10836 10837 #: includes/admin/onboarding/class-charitable-setup.php:186 410837 #: includes/admin/onboarding/class-charitable-setup.php:1869 10838 10838 msgid "Starting..." 10839 10839 msgstr "" 10840 10840 10841 #: includes/admin/onboarding/class-charitable-setup.php:18 6510841 #: includes/admin/onboarding/class-charitable-setup.php:1870 10842 10842 msgid "Setting Up General Settings..." 10843 10843 msgstr "" 10844 10844 10845 #: includes/admin/onboarding/class-charitable-setup.php:18 6610845 #: includes/admin/onboarding/class-charitable-setup.php:1871 10846 10846 msgid "Updating Plugins..." 10847 10847 msgstr "" 10848 10848 10849 #: includes/admin/onboarding/class-charitable-setup.php:18 6710849 #: includes/admin/onboarding/class-charitable-setup.php:1872 10850 10850 msgid "Installing Plugins..." 10851 10851 msgstr "" 10852 10852 10853 #: includes/admin/onboarding/class-charitable-setup.php:18 6810853 #: includes/admin/onboarding/class-charitable-setup.php:1873 10854 10854 msgid "Activating Plugins..." 10855 10855 msgstr "" 10856 10856 10857 #: includes/admin/onboarding/class-charitable-setup.php:18 6910858 #: includes/admin/onboarding/class-charitable-setup.php:187 010857 #: includes/admin/onboarding/class-charitable-setup.php:1874 10858 #: includes/admin/onboarding/class-charitable-setup.php:1875 10859 10859 msgid "Setting Up Features..." 10860 10860 msgstr "" 10861 10861 10862 #: includes/admin/onboarding/class-charitable-setup.php:187 110862 #: includes/admin/onboarding/class-charitable-setup.php:1876 10863 10863 msgid "Setting Up Your First Campaign..." 10864 10864 msgstr "" 10865 10865 10866 #: includes/admin/onboarding/class-charitable-setup.php:187 210866 #: includes/admin/onboarding/class-charitable-setup.php:1877 10867 10867 msgid "Setting Up Payment Methods..." 10868 10868 msgstr "" 10869 10869 10870 #: includes/admin/onboarding/class-charitable-setup.php:187 310870 #: includes/admin/onboarding/class-charitable-setup.php:1878 10871 10871 msgid "Almost done!" 10872 10872 msgstr "" 10873 10873 10874 #: includes/admin/onboarding/class-charitable-setup.php:18 7810874 #: includes/admin/onboarding/class-charitable-setup.php:1883 10875 10875 msgid "Updating country, currency, and related settings for you." 10876 10876 msgstr "" 10877 10877 10878 #: includes/admin/onboarding/class-charitable-setup.php:18 7910878 #: includes/admin/onboarding/class-charitable-setup.php:1884 10879 10879 msgid "Checking plugins..." 10880 10880 msgstr "" 10881 10881 10882 #: includes/admin/onboarding/class-charitable-setup.php:188 210883 #: includes/admin/onboarding/class-charitable-setup.php:188 310882 #: includes/admin/onboarding/class-charitable-setup.php:1887 10883 #: includes/admin/onboarding/class-charitable-setup.php:1888 10884 10884 msgid "Checking license and site information..." 10885 10885 msgstr "" 10886 10886 10887 #: includes/admin/onboarding/class-charitable-setup.php:188 410887 #: includes/admin/onboarding/class-charitable-setup.php:1889 10888 10888 msgid "Creating draft..." 10889 10889 msgstr "" 10890 10890 10891 #: includes/admin/onboarding/class-charitable-setup.php:18 8510891 #: includes/admin/onboarding/class-charitable-setup.php:1890 10892 10892 msgid "Checking payment methods..." 10893 10893 msgstr "" 10894 10894 10895 #: includes/admin/onboarding/class-charitable-setup.php:18 8610895 #: includes/admin/onboarding/class-charitable-setup.php:1891 10896 10896 msgid "Finishing things..." 10897 10897 msgstr "" 10898 10898 10899 #: includes/admin/onboarding/class-charitable-setup.php:18 8710899 #: includes/admin/onboarding/class-charitable-setup.php:1892 10900 10900 msgid "Stripe offers a seamless and secure payment experience for both you and your donors." 10901 10901 msgstr "" 10902 10902 10903 #: includes/admin/onboarding/class-charitable-setup.php:18 8810903 #: includes/admin/onboarding/class-charitable-setup.php:1893 10904 10904 msgid "Your Charitable install has been setup and is ready for you." 10905 10905 msgstr "" 10906 10906 10907 10907 #. translators: %1$s: List of requested features 10908 #: includes/admin/onboarding/class-charitable-setup.php:190 210908 #: includes/admin/onboarding/class-charitable-setup.php:1907 10909 10909 msgid "In order to install and activate some of the features you requested %1$s you need to activate your PRO license after setup is complete." 10910 10910 msgstr "" 10911 10911 10912 #: includes/admin/onboarding/class-charitable-setup.php:190 310912 #: includes/admin/onboarding/class-charitable-setup.php:1908 10913 10913 msgid "Activating license and installing addons..." 10914 10914 msgstr "" 10915 10915 10916 #: includes/admin/onboarding/class-charitable-setup.php:19 0810916 #: includes/admin/onboarding/class-charitable-setup.php:1913 10917 10917 msgid "Skip setting up Stripe" 10918 10918 msgstr "" … … 17015 17015 17016 17016 #: includes/gateways/class-charitable-gateway-square.php:2402 17017 #: includes/gateways/class-charitable-gateway-stripe-am.php:11 2017017 #: includes/gateways/class-charitable-gateway-stripe-am.php:1163 17018 17018 msgid "Unknown error." 17019 17019 msgstr "" … … 17237 17237 17238 17238 #: includes/gateways/class-charitable-gateway-stripe-am.php:841 17239 #: includes/gateways/class-charitable-gateway-stripe-am.php:15 3217239 #: includes/gateways/class-charitable-gateway-stripe-am.php:1579 17240 17240 msgid "Missing keys for Stripe payment gateway. Unable to proceed with payment." 17241 17241 msgstr "" … … 17255 17255 msgstr "" 17256 17256 17257 #: includes/gateways/class-charitable-gateway-stripe-am.php:1114 17257 #: includes/gateways/class-charitable-gateway-stripe-am.php:1102 17258 msgid "Cancellation failed: No gateway subscription ID found." 17259 msgstr "" 17260 17261 #: includes/gateways/class-charitable-gateway-stripe-am.php:1122 17262 msgid "Cancellation failed: No Stripe API key configured." 17263 msgstr "" 17264 17265 #: includes/gateways/class-charitable-gateway-stripe-am.php:1149 17266 msgid "Retrieved subscription from Stripe - Current status: %s" 17267 msgstr "" 17268 17269 #: includes/gateways/class-charitable-gateway-stripe-am.php:1157 17258 17270 msgid "Subscription cancelled in Stripe." 17259 17271 msgstr "" 17260 17272 17261 17273 #. translators: %s: error message 17262 #: includes/gateways/class-charitable-gateway-stripe-am.php:11 2517274 #: includes/gateways/class-charitable-gateway-stripe-am.php:1168 17263 17275 msgid "Stripe cancellation failed: %s" 17264 17276 msgstr "" 17265 17277 17266 #: includes/gateways/class-charitable-gateway-stripe-am.php:1 26817267 #: includes/gateways/class-charitable-gateway-stripe-am.php:1 36917278 #: includes/gateways/class-charitable-gateway-stripe-am.php:1315 17279 #: includes/gateways/class-charitable-gateway-stripe-am.php:1416 17268 17280 #: includes/stripe/abstracts/class-charitable-stripe-gateway-processor.php:484 17269 17281 #: includes/stripe/abstracts/class-charitable-stripe-gateway-processor.php:1354 … … 17276 17288 msgstr "" 17277 17289 17278 #: includes/gateways/class-charitable-gateway-stripe-am.php:13 5117290 #: includes/gateways/class-charitable-gateway-stripe-am.php:1398 17279 17291 msgid "Donor for" 17280 17292 msgstr "" 17281 17293 17282 #: includes/gateways/class-charitable-gateway-stripe-am.php:14 1217294 #: includes/gateways/class-charitable-gateway-stripe-am.php:1459 17283 17295 msgid "Missing credit card details. Unable to proceed with payment." 17284 17296 msgstr "" … … 17517 17529 msgstr "" 17518 17530 17519 #: includes/shortcodes/class-charitable-email-shortcode.php:1 0717531 #: includes/shortcodes/class-charitable-email-shortcode.php:126 17520 17532 msgid "[charitable_email] cannot be called until a class instance has been created." 17533 msgstr "" 17534 17535 #: includes/shortcodes/class-charitable-email-shortcode.php:241 17536 msgid "Payment instructions will be provided separately." 17537 msgstr "" 17538 17539 #: includes/shortcodes/class-charitable-email-shortcode.php:242 17540 msgid "Donation summary unavailable." 17541 msgstr "" 17542 17543 #: includes/shortcodes/class-charitable-email-shortcode.php:243 17544 msgid "Donor information unavailable." 17545 msgstr "" 17546 17547 #: includes/shortcodes/class-charitable-email-shortcode.php:244 17548 msgid "Email unavailable." 17549 msgstr "" 17550 17551 #: includes/shortcodes/class-charitable-email-shortcode.php:246 17552 msgid "Campaign information unavailable." 17553 msgstr "" 17554 17555 #: includes/shortcodes/class-charitable-email-shortcode.php:250 17556 msgid "Content temporarily unavailable." 17521 17557 msgstr "" 17522 17558 … … 17820 17856 17821 17857 #: includes/square/gateway/class-charitable-square-webhook-processor.php:176 17822 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:14 017858 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:141 17823 17859 msgid "Webhook processed." 17824 17860 msgstr "" 17825 17861 17826 17862 #: includes/square/gateway/class-charitable-square-webhook-processor.php:185 17827 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:15117828 17863 msgid "Error while retrieving event." 17829 17864 msgstr "" … … 17885 17920 #: includes/square/gateway/class-charitable-square-webhook-processor.php:1015 17886 17921 #: includes/square/gateway/class-charitable-square-webhook-processor.php:1028 17887 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:4 0017922 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:411 17888 17923 msgid "Donation Webhook: Refund processed" 17889 17924 msgstr "" … … 17895 17930 #: includes/square/gateway/class-charitable-square-webhook-processor.php:1041 17896 17931 #: includes/square/gateway/class-charitable-square-webhook-processor.php:1103 17897 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:4 7017898 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:7 5817899 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:7 8717900 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:8 2117901 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php: 88817902 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php: 91817932 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:481 17933 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:769 17934 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:798 17935 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:832 17936 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:912 17937 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:1001 17903 17938 msgid "Subscription Webhook: Unable to process without Charitable Recurring extension." 17904 17939 msgstr "" 17905 17940 17906 17941 #: includes/square/gateway/class-charitable-square-webhook-processor.php:1064 17907 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:7 6517908 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:8 0017909 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:8 2817910 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php: 89517911 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php: 92517942 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:776 17943 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:811 17944 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:839 17945 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:937 17946 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:1025 17912 17947 msgid "Subscription Webhook: Missing subscription" 17913 17948 msgstr "" … … 17915 17950 #: includes/square/gateway/class-charitable-square-webhook-processor.php:1088 17916 17951 #: includes/square/gateway/class-charitable-square-webhook-processor.php:1222 17917 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:9 0517952 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:975 17918 17953 msgid "Subscription Webhook: Recurring donation updated" 17919 17954 msgstr "" … … 17929 17964 #. translators: %d: threshold 17930 17965 #: includes/square/gateway/class-charitable-square-webhook-processor.php:1310 17931 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:1 01417966 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:1165 17932 17967 msgid "The payment intent has been cancelled after %d failed payment attempts." 17933 17968 msgstr "" … … 18107 18142 msgstr "" 18108 18143 18109 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:13 518144 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:136 18110 18145 msgid "Test webhook successfully received." 18111 18146 msgstr "" 18112 18147 18113 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:371 18114 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:420 18115 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:558 18148 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:162 18149 msgid "Error while processing webhook." 18150 msgstr "" 18151 18152 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:382 18153 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:431 18154 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:569 18116 18155 msgid "Donation Webhook: Missing donation ID" 18117 18156 msgstr "" 18118 18157 18119 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:3 8318158 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:394 18120 18159 msgid "Donation Webhook: Refund donation ID not valid" 18121 18160 msgstr "" 18122 18161 18123 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php: 39518162 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:406 18124 18163 msgid "Donation Webhook: Charge ID does not match donation reference on this site" 18125 18164 msgstr "" 18126 18165 18127 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php: 39818166 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:409 18128 18167 msgid "Donation refunded from the Stripe dashboard." 18129 18168 msgstr "" 18130 18169 18131 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:4 2618132 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:5 7018133 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:6 6218170 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:437 18171 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:581 18172 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:673 18134 18173 msgid "Donation Webhook: Donation ID not valid" 18135 18174 msgstr "" 18136 18175 18137 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:4 3818138 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:5 8018176 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:449 18177 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:591 18139 18178 msgid "Donation Webhook: Payment Intent does not match donation reference on this site" 18140 18179 msgstr "" 18141 18180 18142 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:4 5718181 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:468 18143 18182 msgid "Donation Webhook: Donation marked as Failed" 18144 18183 msgstr "" 18145 18184 18146 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:4 8218185 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:493 18147 18186 msgid "Donation Webhook: Unable to retrieve invoice for failed payment intent." 18148 18187 msgstr "" 18149 18188 18150 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:4 8818189 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:499 18151 18190 msgid "Donation Webhook: No matching subscription found for invoice with failed payment intent." 18152 18191 msgstr "" 18153 18192 18154 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:5 0118193 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:512 18155 18194 msgid "Donation Webhook: Recurring donation for payment intent marked as cancelled." 18156 18195 msgstr "" 18157 18196 18158 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:5 0418197 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:515 18159 18198 msgid "Donation Webhook: Recurring donation for payment intent marked as pending cancellation." 18160 18199 msgstr "" 18161 18200 18162 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:5 3018201 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:541 18163 18202 msgid "Donation Webhook: Recurring donation and initial payment for payment intent marked as failed" 18164 18203 msgstr "" 18165 18204 18166 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:6 2818205 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:639 18167 18206 msgid "Donation Webhook: Donation marked as Paid" 18168 18207 msgstr "" 18169 18208 18170 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:6 5718209 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:668 18171 18210 msgid "Donation Webhook: Session id does not match donation reference on this site" 18172 18211 msgstr "" 18173 18212 18174 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:6 7218213 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:683 18175 18214 msgid "Donation Webhook: Missing payment intent" 18176 18215 msgstr "" 18177 18216 18178 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php: 68918217 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:700 18179 18218 msgid "Session Webhook: Donation updated with Payment Intent data" 18180 18219 msgstr "" 18181 18220 18182 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:7 0618221 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:717 18183 18222 msgid "Session Webhook: Missing subscription" 18184 18223 msgstr "" 18185 18224 18186 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:7 1518225 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:726 18187 18226 msgid "Session Webhook: Invalid subscription" 18188 18227 msgstr "" 18189 18228 18190 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:7 4018229 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:751 18191 18230 msgid "Unable to set cancel time for subscription." 18192 18231 msgstr "" 18193 18232 18194 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:7 4518233 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:756 18195 18234 msgid "Session Webhook: Donation and subscription updated with session data" 18196 18235 msgstr "" 18197 18236 18198 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:7 7418237 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:785 18199 18238 msgid "Subscription Webhook: Invoice created" 18200 18239 msgstr "" 18201 18240 18202 18241 #. translators: %s is the invoice status. 18203 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php: 79418242 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:805 18204 18243 msgid "Subscription Webhook: Not processing invoice with a status of %s." 18205 18244 msgstr "" 18206 18245 18207 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:8 0818246 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:819 18208 18247 msgid "Subscription Webhook: Invoice payment failed" 18209 18248 msgstr "" 18210 18249 18211 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:8 4018250 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:851 18212 18251 msgid "Subscription Webhook: Renewal has already been added" 18213 18252 msgstr "" 18214 18253 18215 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:8 7218254 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:883 18216 18255 msgid "Unable to save donation ID to Stripe charge metadata." 18217 18256 msgstr "" 18218 18257 18219 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:8 7518258 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:886 18220 18259 msgid "Subscription Webhook: Payment complete" 18221 18260 msgstr "" 18222 18261 18223 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php: 93218262 #: includes/stripe/gateway/class-charitable-stripe-webhook-processor.php:1049 18224 18263 msgid "Subscription Webhook: Recurring donation cancelled" 18225 18264 msgstr "" -
charitable/trunk/includes/abstracts/abstract-class-charitable-email.php
r3453160 r3460927 962 962 * 963 963 * @since 1.8.9.2 964 * @since 1.8.9.5 Enhanced with detailed diagnostic context for recipient extraction failures. 964 965 * 965 966 * @return string|false Email recipient or false on error. … … 969 970 $recipient = $this->get_recipient(); 970 971 971 if ( empty( $recipient ) || ! is_email( $recipient ) ) { 972 $this->log_email_error( 'invalid_recipient', 'Recipient email is empty or invalid: ' . $recipient ); 972 if ( empty( $recipient ) || ! $this->is_valid_recipient( $recipient ) ) { 973 // Phase 1: Enhanced diagnostics - minimal overhead, only on errors 974 $diagnostic_context = array( 975 'recipient_value' => $recipient, 976 'recipient_type' => gettype( $recipient ), 977 'recipient_length' => strlen( (string) $recipient ) 978 ); 979 980 // Add donation context if available (safe checks) 981 if ( is_object( $this->donation ) && method_exists( $this->donation, 'get_donor_id' ) ) { 982 $donor_id = $this->donation->get_donor_id(); 983 $diagnostic_context['donation_id'] = method_exists( $this->donation, 'get_donation_id' ) ? $this->donation->get_donation_id() : 'unknown'; 984 $diagnostic_context['donor_id'] = $donor_id; 985 $diagnostic_context['donor_id_type'] = gettype( $donor_id ); 986 987 // Check campaign donations count (common failure point) 988 if ( method_exists( $this->donation, 'get_campaign_donations' ) ) { 989 $campaign_donations = $this->donation->get_campaign_donations(); 990 $diagnostic_context['campaign_donations_count'] = is_array( $campaign_donations ) ? count( $campaign_donations ) : 'not_array'; 991 } 992 993 // Check donor object validity if donor_id exists 994 if ( ! empty( $donor_id ) && $donor_id !== false && method_exists( $this->donation, 'get_donor' ) ) { 995 $donor = $this->donation->get_donor(); 996 $diagnostic_context['donor_object_type'] = gettype( $donor ); 997 $diagnostic_context['donor_object_class'] = is_object( $donor ) ? get_class( $donor ) : 'not_object'; 998 } 999 } else { 1000 $diagnostic_context['donation_object_type'] = gettype( $this->donation ); 1001 } 1002 1003 $this->log_email_error( 'invalid_recipient', 1004 'Recipient email is empty or invalid - Enhanced diagnosis: ' . wp_json_encode( $diagnostic_context ) ); 973 1005 return false; 974 1006 } … … 1020 1052 * 1021 1053 * @since 1.8.9.2 1054 * @since 1.8.9.5 Enhanced with detailed diagnostic context for email build failures. 1022 1055 * 1023 1056 * @return string|false Email body or false on error. … … 1046 1079 restore_error_handler(); 1047 1080 } 1048 $this->log_email_error( 'email_build_failed', $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine() ); 1081 1082 // Phase 1: Enhanced email build diagnostics 1083 $build_context = array( 1084 'email_class' => get_class( $this ), 1085 'email_id' => method_exists( $this, 'get_email_id' ) ? $this->get_email_id() : 'unknown', 1086 'error_message' => $e->getMessage(), 1087 'error_file' => basename( $e->getFile() ), 1088 'error_line' => $e->getLine(), 1089 'ob_level' => ob_get_level() 1090 ); 1091 1092 // Add donation context for template building 1093 if ( is_object( $this->donation ) ) { 1094 $build_context['has_donation_data'] = true; 1095 $build_context['donation_id'] = method_exists( $this->donation, 'get_donation_id' ) ? $this->donation->get_donation_id() : 'unknown'; 1096 } else { 1097 $build_context['has_donation_data'] = false; 1098 } 1099 1100 // Check template availability 1101 $template_dir = CHARITABLE_DIRECTORY_PATH . 'templates/emails/'; 1102 $build_context['templates_exist'] = array( 1103 'header' => file_exists( $template_dir . 'header.php' ), 1104 'body' => file_exists( $template_dir . 'body.php' ), 1105 'footer' => file_exists( $template_dir . 'footer.php' ) 1106 ); 1107 1108 $this->log_email_error( 'email_build_failed', 1109 'Email template build failed - Enhanced diagnosis: ' . wp_json_encode( $build_context ) ); 1049 1110 return false; 1050 1111 } … … 1125 1186 return charitable_log_form_error( 'email_failure', $error_details, $context ); 1126 1187 } 1188 1189 /** 1190 * Check if recipient string is valid (handles single emails and comma-separated lists). 1191 * 1192 * @since 1.8.9.5 1193 * 1194 * @param string $recipient The recipient string to validate. 1195 * @return boolean True if valid, false otherwise. 1196 */ 1197 private function is_valid_recipient( $recipient ) { 1198 if ( empty( $recipient ) ) { 1199 return false; 1200 } 1201 1202 // If it's a single email, use is_email() 1203 if ( strpos( $recipient, ',' ) === false ) { 1204 return is_email( trim( $recipient ) ); 1205 } 1206 1207 // Handle comma-separated emails 1208 $emails = explode( ',', $recipient ); 1209 foreach ( $emails as $email ) { 1210 $email = trim( $email ); 1211 if ( empty( $email ) || ! is_email( $email ) ) { 1212 return false; 1213 } 1214 } 1215 1216 return true; 1217 } 1127 1218 } 1128 1219 -
charitable/trunk/includes/admin/tools/class-charitable-tools-email-diagnostics.php
r3453160 r3460927 365 365 } 366 366 367 // Phase 1 Integration: Test recipient extraction with real donation data 368 $email_test['recipient_extraction'] = $this->test_recipient_extraction_for_email( $email_instance, $email_id ); 369 367 370 $successful_accesses++; 368 371 } catch ( Exception $e ) { … … 393 396 $result['average_time'] = round( $total_time / count( $this->priority_emails ), 1 ); 394 397 398 // Phase 1 Integration: Count recipient extraction failures 399 $recipient_failures = 0; 400 foreach ( $result['email_tests'] as $email_test ) { 401 if ( isset( $email_test['recipient_extraction']['tested'] ) && 402 $email_test['recipient_extraction']['tested'] && 403 ! $email_test['recipient_extraction']['success'] ) { 404 $recipient_failures++; 405 } 406 } 407 $result['details']['recipient_extraction_failures'] = $recipient_failures; 408 395 409 // Determine status and score 396 410 if ( $successful_accesses === count( $this->priority_emails ) ) { 397 411 $result['status'] = 'success'; 398 412 $result['score'] = 20; 413 414 // Reduce score for recipient extraction failures 415 if ( $recipient_failures > 0 ) { 416 $result['score'] -= ( $recipient_failures * 3 ); // -3 points per failure 417 $result['status'] = 'partial'; 418 $result['details']['recipient_warning'] = "Recipient extraction failing for {$recipient_failures} email(s)"; 419 } 399 420 } elseif ( $successful_accesses > 0 ) { 400 421 $result['status'] = 'partial'; 401 422 $result['score'] = round( ( $successful_accesses / count( $this->priority_emails ) ) * 20 ); 423 424 // Additional penalty for recipient failures 425 if ( $recipient_failures > 0 ) { 426 $result['score'] -= ( $recipient_failures * 2 ); 427 } 402 428 } 403 429 … … 920 946 * 921 947 * @since 1.8.9.2 948 * @since 1.8.9.5 Enhanced to connect with Phase 1 error logging improvements. 922 949 * 923 950 * @return int Number of recent email errors. 924 951 */ 925 952 private function count_recent_email_errors() { 926 // This would typically check error logs or database for email failures 927 // For now, return 0 as we don't have a built-in error tracking system 928 // This could be enhanced to check wp_mail failures or charitable-specific logs 929 return 0; 953 $error_count = 0; 954 955 try { 956 // Connect to Phase 1 enhanced error logging via activities table 957 if ( function_exists( 'charitable_get_table' ) ) { 958 $activities_table = charitable_get_table( 'charitable_activities' ); 959 if ( $activities_table ) { 960 global $wpdb; 961 $table_name = $activities_table->get_table_name(); 962 $seven_days_ago = date( 'Y-m-d H:i:s', strtotime( '-7 days' ) ); 963 964 // Count email failures from the last 7 days 965 $error_count = (int) $wpdb->get_var( $wpdb->prepare( 966 "SELECT COUNT(*) FROM {$table_name} 967 WHERE type = 'form_error' 968 AND error_type = 'email_failure' 969 AND timestamp >= %s", 970 $seven_days_ago 971 ) ); 972 } 973 } 974 } catch ( Exception $e ) { 975 // Fail silently for diagnostics - don't break the diagnostic system 976 error_log( 'Charitable Email Diagnostics: Error counting recent email errors - ' . $e->getMessage() ); 977 } 978 979 return $error_count; 980 } 981 982 /** 983 * Test recipient extraction for a specific email with real donation data. 984 * 985 * @since 1.8.9.5 Phase 1 Integration 986 * 987 * @param object $email_instance Email instance to test. 988 * @param string $email_id Email ID being tested. 989 * @return array Test results. 990 */ 991 private function test_recipient_extraction_for_email( $email_instance, $email_id ) { 992 $extraction_test = array( 993 'tested' => false, 994 'success' => false, 995 'recipient_valid' => false, 996 'recipient_value' => '', 997 'donation_context' => 'none', 998 'error' => null 999 ); 1000 1001 try { 1002 // Skip recipient extraction test for emails that don't need donations 1003 $non_donation_emails = array( 'password_reset', 'email_verification' ); 1004 if ( in_array( $email_id, $non_donation_emails ) ) { 1005 $extraction_test['tested'] = true; 1006 $extraction_test['success'] = true; 1007 $extraction_test['recipient_value'] = 'N/A - No donation required'; 1008 return $extraction_test; 1009 } 1010 1011 // Find a recent completed donation for testing 1012 $recent_donations = get_posts( array( 1013 'post_type' => 'donation', 1014 'post_status' => 'charitable-completed', 1015 'posts_per_page' => 1, 1016 'orderby' => 'date', 1017 'order' => 'DESC' 1018 ) ); 1019 1020 if ( empty( $recent_donations ) ) { 1021 $extraction_test['donation_context'] = 'no_donations'; 1022 $extraction_test['error'] = 'No completed donations available for testing'; 1023 return $extraction_test; 1024 } 1025 1026 $donation = charitable_get_donation( $recent_donations[0]->ID ); 1027 if ( ! $donation ) { 1028 $extraction_test['donation_context'] = 'invalid_donation'; 1029 $extraction_test['error'] = 'Could not load donation object'; 1030 return $extraction_test; 1031 } 1032 1033 $extraction_test['donation_context'] = 'donation_' . $donation->get_donation_id(); 1034 $extraction_test['tested'] = true; 1035 1036 // Create new email instance with donation context 1037 $email_class = get_class( $email_instance ); 1038 $test_email = new $email_class( array( 'donation' => $donation ) ); 1039 1040 // Test recipient extraction 1041 if ( method_exists( $test_email, 'get_recipient' ) ) { 1042 $recipient = $test_email->get_recipient(); 1043 $extraction_test['recipient_value'] = $recipient; 1044 $extraction_test['recipient_valid'] = is_email( $recipient ); 1045 $extraction_test['success'] = ! empty( $recipient ) && is_email( $recipient ); 1046 } else { 1047 $extraction_test['error'] = 'get_recipient method not available'; 1048 } 1049 1050 } catch ( Exception $e ) { 1051 $extraction_test['error'] = $e->getMessage(); 1052 $extraction_test['exception_file'] = basename( $e->getFile() ); 1053 $extraction_test['exception_line'] = $e->getLine(); 1054 } 1055 1056 return $extraction_test; 930 1057 } 931 1058 -
charitable/trunk/includes/emails/class-charitable-email-offline-donation-receipt.php
r3328339 r3460927 135 135 } 136 136 137 return true;137 return $sent; 138 138 } 139 139 -
charitable/trunk/includes/gateways/class-charitable-gateway-stripe-am.php
r3453160 r3460927 1090 1090 */ 1091 1091 public static function cancel_subscription( $cancelled, Charitable_Recurring_Donation $donation ) { 1092 // Enhanced logging for cancellation debugging 1093 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { 1094 error_log( sprintf( 1095 'CHARITABLE_STRIPE_CANCEL_DEBUG: Starting cancellation for donation #%d', 1096 $donation->get_donation_id() 1097 ) ); 1098 } 1099 1092 1100 $subscription_id = $donation->get_gateway_subscription_id(); 1093 1101 1094 1102 if ( ! $subscription_id ) { 1103 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { 1104 error_log( 'CHARITABLE_STRIPE_CANCEL_DEBUG: No subscription ID found - cancellation aborted' ); 1105 } 1106 $donation->log()->add( __( 'Cancellation failed: No gateway subscription ID found.', 'charitable' ) ); 1095 1107 return false; 1108 } 1109 1110 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { 1111 error_log( sprintf( 1112 'CHARITABLE_STRIPE_CANCEL_DEBUG: Attempting to cancel subscription %s', 1113 $subscription_id 1114 ) ); 1096 1115 } 1097 1116 … … 1103 1122 1104 1123 if ( ! $api_key ) { 1124 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { 1125 error_log( sprintf( 1126 'CHARITABLE_STRIPE_CANCEL_DEBUG: No API key found for mode %s - cancellation aborted', 1127 $donation->get_test_mode( false ) ? 'test' : 'live' 1128 ) ); 1129 } 1130 $donation->log()->add( __( 'Cancellation failed: No Stripe API key configured.', 'charitable' ) ); 1105 1131 return false; 1106 1132 } 1107 1133 1134 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { 1135 error_log( sprintf( 1136 'CHARITABLE_STRIPE_CANCEL_DEBUG: Using %s mode, account: %s', 1137 $donation->get_test_mode( false ) ? 'test' : 'live', 1138 $account ? $account : 'none' 1139 ) ); 1140 } 1141 1108 1142 $gateway->setup_api( $api_key ); 1109 1143 1110 1144 try { 1145 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { 1146 error_log( sprintf( 1147 'CHARITABLE_STRIPE_CANCEL_DEBUG: Retrieving subscription %s from Stripe', 1148 $subscription_id 1149 ) ); 1150 } 1151 1111 1152 $subscription = \Stripe\Subscription::retrieve( $subscription_id, $options ); 1153 1154 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { 1155 error_log( sprintf( 1156 'CHARITABLE_STRIPE_CANCEL_DEBUG: Retrieved subscription status: %s', 1157 $subscription->status 1158 ) ); 1159 } 1160 1161 // Log current subscription state before cancellation 1162 $donation->log()->add( sprintf( 1163 __( 'Retrieved subscription from Stripe - Current status: %s', 'charitable' ), 1164 $subscription->status 1165 ) ); 1166 1112 1167 $subscription->cancel( null, $options ); 1168 1169 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { 1170 error_log( 'CHARITABLE_STRIPE_CANCEL_DEBUG: Stripe cancellation API call completed successfully' ); 1171 } 1113 1172 1114 1173 $donation->log()->add( __( 'Subscription cancelled in Stripe.', 'charitable' ) ); … … 1131 1190 1132 1191 } finally { 1192 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) { 1193 error_log( sprintf( 1194 'CHARITABLE_STRIPE_CANCEL_DEBUG: Cancellation result: %s', 1195 $cancelled ? 'SUCCESS' : 'FAILED' 1196 ) ); 1197 } 1133 1198 return $cancelled; 1134 1199 } -
charitable/trunk/includes/shortcodes/class-charitable-email-shortcode.php
r2987535 r3460927 9 9 * @since 1.5.0 10 10 * @version 1.5.0 11 * @version 1.8.9.5 Added recursion prevention for email shortcodes. 11 12 */ 12 13 … … 42 43 */ 43 44 private $fields; 45 46 /** 47 * Processing stack to track active shortcodes and prevent recursion. 48 * 49 * @since 1.8.9.5 50 * 51 * @var array 52 */ 53 private static $processing_stack = array(); 54 55 /** 56 * Processing depth counter for recursion detection. 57 * 58 * @since 1.8.9.5 59 * 60 * @var int 61 */ 62 private static $processing_depth = 0; 44 63 45 64 /** … … 122 141 } 123 142 124 return self::$instance->get( $args['show'], $args ); 143 // Recursion prevention - Added in 1.8.9.5 144 $recursion_result = self::check_recursion( $args['show'], $args ); 145 if ( false !== $recursion_result ) { 146 return $recursion_result; 147 } 148 149 // Add to processing stack 150 self::push_processing_stack( $args['show'] ); 151 152 // Process the shortcode 153 $result = self::$instance->get( $args['show'], $args ); 154 155 // Remove from processing stack 156 self::pop_processing_stack( $args['show'] ); 157 158 return $result; 125 159 } 126 160 … … 138 172 return $value; 139 173 } 174 175 /** 176 * Check for recursion and return fallback content if detected. 177 * 178 * @since 1.8.9.5 179 * 180 * @param string $show The field to show. 181 * @param array $args Mixed arguments. 182 * @return string|false False if no recursion, fallback content if recursion detected. 183 */ 184 private static function check_recursion( $show, $args ) { 185 // Check depth limit 186 $max_depth = apply_filters( 'charitable_email_recursion_depth_limit', 3 ); 187 if ( self::$processing_depth >= $max_depth ) { 188 self::log_recursion_attempt( 'depth', $show, self::$processing_depth, $max_depth ); 189 return self::get_context_specific_fallback( $show, 'depth_limit' ); 190 } 191 192 // Check for direct recursion (same field already being processed) 193 $stack_key = $show; 194 if ( in_array( $stack_key, self::$processing_stack, true ) ) { 195 self::log_recursion_attempt( 'circular', $show, count( self::$processing_stack ), $max_depth ); 196 return self::get_context_specific_fallback( $show, 'circular_reference' ); 197 } 198 199 return false; // No recursion detected 200 } 201 202 /** 203 * Add a field to the processing stack. 204 * 205 * @since 1.8.9.5 206 * 207 * @param string $show The field being processed. 208 */ 209 private static function push_processing_stack( $show ) { 210 self::$processing_stack[] = $show; 211 self::$processing_depth++; 212 } 213 214 /** 215 * Remove a field from the processing stack. 216 * 217 * @since 1.8.9.5 218 * 219 * @param string $show The field being processed. 220 */ 221 private static function pop_processing_stack( $show ) { 222 $index = array_search( $show, self::$processing_stack, true ); 223 if ( false !== $index ) { 224 unset( self::$processing_stack[ $index ] ); 225 self::$processing_stack = array_values( self::$processing_stack ); // Re-index array 226 } 227 self::$processing_depth = max( 0, self::$processing_depth - 1 ); 228 } 229 230 /** 231 * Get context-specific fallback content when recursion is detected. 232 * 233 * @since 1.8.9.5 234 * 235 * @param string $show The field that caused recursion. 236 * @param string $reason The reason for fallback (depth_limit, circular_reference). 237 * @return string Fallback content. 238 */ 239 private static function get_context_specific_fallback( $show, $reason ) { 240 $fallbacks = array( 241 'offline_instructions' => __( 'Payment instructions will be provided separately.', 'charitable' ), 242 'donation_summary' => __( 'Donation summary unavailable.', 'charitable' ), 243 'donor' => __( 'Donor information unavailable.', 'charitable' ), 244 'donor_email' => __( 'Email unavailable.', 'charitable' ), 245 'site_name' => get_bloginfo( 'name' ), 246 'campaign_title' => __( 'Campaign information unavailable.', 'charitable' ), 247 ); 248 249 // Get specific fallback or generic one 250 $fallback = isset( $fallbacks[ $show ] ) ? $fallbacks[ $show ] : __( 'Content temporarily unavailable.', 'charitable' ); 251 252 /** 253 * Filter the fallback content for recursive email shortcodes. 254 * 255 * @since 1.8.9.5 256 * 257 * @param string $fallback The default fallback content. 258 * @param string $show The field that caused recursion. 259 * @param string $reason The reason for fallback. 260 */ 261 return apply_filters( 'charitable_email_shortcode_recursion_fallback', $fallback, $show, $reason ); 262 } 263 264 /** 265 * Log recursion attempts for debugging. 266 * 267 * @since 1.8.9.5 268 * 269 * @param string $type Type of recursion (circular, depth). 270 * @param string $show The field that caused recursion. 271 * @param int $current Current depth/stack size. 272 * @param int $limit The configured limit. 273 */ 274 private static function log_recursion_attempt( $type, $show, $current, $limit ) { 275 // Only log if both CHARITABLE_DEBUG and CHARITABLE_DEBUG_EMAILS are enabled 276 if ( ! charitable_is_debug() || ! defined( 'CHARITABLE_DEBUG_EMAILS' ) || ! CHARITABLE_DEBUG_EMAILS ) { 277 return; 278 } 279 280 $message = sprintf( 281 '[CHARITABLE_EMAIL_DEBUG] Recursion prevented: %s recursion detected for shortcode [charitable_email show="%s"]. Current: %d, Limit: %d, Stack: [%s]', 282 $type, 283 $show, 284 $current, 285 $limit, 286 implode( ', ', self::$processing_stack ) 287 ); 288 289 error_log( $message ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 290 } 140 291 } 141 292 -
charitable/trunk/includes/stripe/gateway/class-charitable-stripe-webhook-processor.php
r3453160 r3460927 122 122 * 123 123 * @since 1.3.0 124 * @since 1.8.9.5 Fixed fatal error when ErrorException is thrown by using type-safe exception handling. 124 125 * 125 126 * @return void … … 141 142 142 143 } catch ( Exception $e ) { 143 $body = $e->getJsonBody(); 144 // phpcs:disable 145 if ( charitable_is_debug() ) { 146 error_log( $body['error']['message'] ); 147 } 148 // phpcs:enable 144 // Handle Stripe API exceptions that have getJsonBody method 145 if ( method_exists( $e, 'getJsonBody' ) ) { 146 $body = $e->getJsonBody(); 147 // phpcs:disable 148 if ( charitable_is_debug() ) { 149 error_log( 'Stripe API Error: ' . $body['error']['message'] ); 150 } 151 // phpcs:enable 152 } else { 153 // Handle generic PHP exceptions (ErrorException, etc.) 154 // phpcs:disable 155 if ( charitable_is_debug() ) { 156 error_log( 'Webhook Processing Error: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine() ); 157 } 158 // phpcs:enable 159 } 160 149 161 status_header( 500 ); 150 151 die( __( 'Error while retrieving event.', 'charitable' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 162 die( __( 'Error while processing webhook.', 'charitable' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 152 163 }//end try 153 164 } -
charitable/trunk/readme.txt
r3455615 r3460927 5 5 Tested up to: 6.9.1 6 6 Requires PHP: 7.2 7 Stable tag: 1.8.9. 47 Stable tag: 1.8.9.5 8 8 License: GPLv2 or later 9 9 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 269 269 == Changelog == 270 270 271 = Donation Form & Fundraising Campaigns v1.8.9.5 = 272 * FIX: Added additional checks to resolved issue with Stripe webhook that was causing a fatal error a certain scenario. 273 * FIX: Allow more international characters into campaign title fields in campaign visual builder. 274 * IMPROVED: Email shortcode processing with recursion prevention for better reliability. 275 * IMPROVED: Added additional enhanced email error logging and diagnostics. 276 271 277 = Donation Form & Fundraising Campaigns v1.8.9.4 = 272 278 * FIX: Resolved seemingly missing social media icons in some campaign builder template previews in certain scenarios.
Note: See TracChangeset
for help on using the changeset viewer.