PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 15.7.2
Jetpack – WP Security, Backup, Speed, & Growth v15.7.2
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / extensions / blocks / donations / donations.php
jetpack / extensions / blocks / donations Last commit date
donations.php 7 months ago
donations.php
298 lines
1 <?php
2 /**
3 * Donations Block.
4 *
5 * @since 8.x
6 *
7 * @package automattic/jetpack
8 */
9
10 namespace Automattic\Jetpack\Extensions\Donations;
11
12 use Automattic\Jetpack\Blocks;
13 use Automattic\Jetpack\Status\Request;
14 use Jetpack_Gutenberg;
15 use WP_Post;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit( 0 );
19 }
20
21 /**
22 * Registers the block for use in Gutenberg
23 * This is done via an action so that we can disable
24 * registration if we need to.
25 */
26 function register_block() {
27
28 require_once JETPACK__PLUGIN_DIR . '/modules/memberships/class-jetpack-memberships.php';
29 if ( \Jetpack_Memberships::should_enable_monetize_blocks_in_editor() ) {
30 Blocks::jetpack_register_block(
31 __DIR__,
32 array(
33 'render_callback' => __NAMESPACE__ . '\render_block',
34 'plan_check' => true,
35 )
36 );
37 }
38 // Add a meta field to the user to track if the donation warning has been dismissed.
39 \register_meta(
40 'user',
41 'jetpack_donation_warning_dismissed',
42 array(
43 'type' => 'boolean',
44 'single' => true,
45 'show_in_rest' => true,
46 'default' => false,
47 )
48 );
49 }
50 add_action( 'init', __NAMESPACE__ . '\register_block' );
51
52 /**
53 * Donations block dynamic rendering.
54 *
55 * @param array $attr Array containing the Donations block attributes.
56 * @param string $content String containing the Donations block content.
57 *
58 * @return string
59 */
60 function render_block( $attr, $content ) {
61 // Keep content as-is if rendered in other contexts than frontend (i.e. feed, emails, API, etc.).
62 if ( ! Request::is_frontend() ) {
63 $parsed = parse_blocks( $content );
64 if ( ! empty( $parsed[0] ) ) {
65 // Inject the link of the current post from the server side as the fallback link to make sure the donations block
66 // points to the correct post when it's inserted from the synced pattern (aka “My Pattern”).
67 $post_link = get_permalink();
68 $parsed[0]['attrs']['fallbackLinkUrl'] = $post_link;
69 $content = \render_block( $parsed[0] );
70 if ( preg_match( '/<a\s+class="jetpack-donations-fallback-link"\s+href="([^"]*)"/', $content, $matches ) ) {
71 $content = str_replace( $matches[1], $post_link, $content );
72 }
73 }
74
75 return $content;
76 }
77
78 require_once JETPACK__PLUGIN_DIR . 'modules/memberships/class-jetpack-memberships.php';
79
80 // If stripe isn't connected don't show anything to potential donors - they can't actually make a donation.
81 if ( ! \Jetpack_Memberships::has_connected_account() ) {
82 return '';
83 }
84
85 Jetpack_Gutenberg::load_assets_as_required( __DIR__ );
86
87 require_once JETPACK__PLUGIN_DIR . '/_inc/lib/class-jetpack-currencies.php';
88
89 $default_texts = get_default_texts();
90
91 $donations = array(
92 'one-time' => array_merge(
93 array(
94 'planId' => null,
95 'title' => __( 'One-Time', 'jetpack' ),
96 'class' => 'donations__one-time-item',
97 'heading' => $default_texts['oneTimeDonation']['heading'],
98 'buttonText' => $default_texts['oneTimeDonation']['buttonText'],
99 ),
100 $attr['oneTimeDonation']
101 ),
102 );
103 if ( $attr['monthlyDonation']['show'] ) {
104 $donations['1 month'] = array_merge(
105 array(
106 'planId' => null,
107 'title' => __( 'Monthly', 'jetpack' ),
108 'class' => 'donations__monthly-item',
109 'heading' => $default_texts['monthlyDonation']['heading'],
110 'buttonText' => $default_texts['monthlyDonation']['buttonText'],
111 ),
112 $attr['monthlyDonation']
113 );
114 }
115 if ( $attr['annualDonation']['show'] ) {
116 $donations['1 year'] = array_merge(
117 array(
118 'planId' => null,
119 'title' => __( 'Yearly', 'jetpack' ),
120 'class' => 'donations__annual-item',
121 'heading' => $default_texts['annualDonation']['heading'],
122 'buttonText' => $default_texts['annualDonation']['buttonText'],
123 ),
124 $attr['annualDonation']
125 );
126 }
127
128 $choose_amount_text = isset( $attr['chooseAmountText'] ) && ! empty( $attr['chooseAmountText'] ) ? $attr['chooseAmountText'] : $default_texts['chooseAmountText'];
129 $custom_amount_text = isset( $attr['customAmountText'] ) && ! empty( $attr['customAmountText'] ) ? $attr['customAmountText'] : $default_texts['customAmountText'];
130 $currency = $attr['currency'];
131 $nav = '';
132 $headings = '';
133 $amounts = '';
134 $extra_text = '';
135 $buttons = '';
136 foreach ( $donations as $interval => $donation ) {
137 $plan_id = (int) $donation['planId'];
138 $plan = get_post( $plan_id );
139 if ( ! $plan || is_wp_error( $plan ) ) {
140 continue;
141 }
142
143 if ( count( $donations ) > 1 ) {
144 if ( ! $nav ) {
145 $nav .= '<div class="donations__nav">';
146 }
147 $nav .= sprintf(
148 '<div role="button" tabindex="0" class="donations__nav-item" data-interval="%1$s">%2$s</div>',
149 esc_attr( $interval ),
150 esc_html( $donation['title'] )
151 );
152 }
153 $headings .= sprintf(
154 '<h4 class="%1$s">%2$s</h4>',
155 esc_attr( $donation['class'] ),
156 wp_kses_post( $donation['heading'] )
157 );
158 $amounts .= sprintf(
159 '<div class="donations__amounts %s">',
160 esc_attr( $donation['class'] )
161 );
162 foreach ( $donation['amounts'] as $amount ) {
163 $amounts .= sprintf(
164 '<div class="donations__amount" data-amount="%1$s">%2$s</div>',
165 esc_attr( $amount ),
166 esc_html( \Jetpack_Currencies::format_price( $amount, $currency ) )
167 );
168 }
169 $amounts .= '</div>';
170 $extra_text .= sprintf(
171 '<p class="%1$s">%2$s</p>',
172 esc_attr( $donation['class'] ),
173 wp_kses_post( $donation['extraText'] ?? $default_texts['extraText'] )
174 );
175 $buttons .= sprintf(
176 '<a class="wp-block-button__link donations__donate-button %1$s" href="%2$s">%3$s</a>',
177 esc_attr( $donation['class'] ),
178 esc_url( \Jetpack_Memberships::get_instance()->get_subscription_url( $plan_id ) ),
179 wp_kses_post( $donation['buttonText'] )
180 );
181 }
182 if ( $nav ) {
183 $nav .= '</div>';
184 }
185
186 $custom_amount = '';
187 if ( $attr['showCustomAmount'] ) {
188 $custom_amount .= sprintf(
189 '<p>%s</p>',
190 wp_kses_post( $custom_amount_text )
191 );
192 $default_custom_amount = ( \Jetpack_Memberships::SUPPORTED_CURRENCIES[ $currency ] ?? 1 ) * 100;
193 $custom_amount .= sprintf(
194 '<div class="donations__amount donations__custom-amount">
195 %1$s
196 <div class="donations__amount-value" data-currency="%2$s" data-empty-text="%3$s"></div>
197 </div>',
198 esc_html( \Jetpack_Currencies::CURRENCIES[ $currency ]['symbol'] ?? '¤' ),
199 esc_attr( $currency ),
200 esc_attr( \Jetpack_Currencies::format_price( $default_custom_amount, $currency, false ) )
201 );
202 }
203
204 return sprintf(
205 '
206 <div class="%1$s">
207 <div class="donations__container">
208 %2$s
209 <div class="donations__content">
210 <div class="donations__tab">
211 %3$s
212 <p>%4$s</p>
213 %5$s
214 %6$s
215 <hr class="donations__separator">
216 %7$s
217 %8$s
218 </div>
219 </div>
220 </div>
221 </div>
222 ',
223 esc_attr( Blocks::classes( Blocks::get_block_feature( __DIR__ ), $attr ) ),
224 $nav,
225 $headings,
226 $choose_amount_text,
227 $amounts,
228 $custom_amount,
229 $extra_text,
230 $buttons
231 );
232 }
233
234 /**
235 * Get the default texts for the block.
236 *
237 * @return array
238 */
239 function get_default_texts() {
240 return array(
241 'chooseAmountText' => __( 'Choose an amount', 'jetpack' ),
242 'customAmountText' => __( 'Or enter a custom amount', 'jetpack' ),
243 'extraText' => __( 'Your contribution is appreciated.', 'jetpack' ),
244 'oneTimeDonation' => array(
245 'heading' => __( 'Make a one-time donation', 'jetpack' ),
246 'buttonText' => __( 'Donate', 'jetpack' ),
247 ),
248 'monthlyDonation' => array(
249 'heading' => __( 'Make a monthly donation', 'jetpack' ),
250 'buttonText' => __( 'Donate monthly', 'jetpack' ),
251 ),
252 'annualDonation' => array(
253 'heading' => __( 'Make a yearly donation', 'jetpack' ),
254 'buttonText' => __( 'Donate yearly', 'jetpack' ),
255 ),
256 );
257 }
258
259 /**
260 * Make default texts available to the editor.
261 */
262 function load_editor_scripts() {
263 // Only relevant to the editor right now.
264 if ( ! is_admin() ) {
265 return;
266 }
267
268 $data = array(
269 'defaultTexts' => get_default_texts(),
270 );
271
272 wp_add_inline_script(
273 'jetpack-blocks-editor',
274 'var Jetpack_DonationsBlock = ' . wp_json_encode( $data, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ';',
275 'before'
276 );
277 }
278 add_action( 'enqueue_block_assets', __NAMESPACE__ . '\load_editor_scripts', 11 );
279
280 /**
281 * Determine if AMP should be disabled on posts having Donations blocks.
282 *
283 * @param bool $skip Skipped.
284 * @param int $post_id Post ID.
285 * @param WP_Post $post Post.
286 *
287 * @return bool Whether to skip the post from AMP.
288 */
289 function amp_skip_post( $skip, $post_id, $post ) {
290 // When AMP is on standard mode, there are no non-AMP posts to link to where the donation can be completed, so let's
291 // prevent the post from being available in AMP.
292 if ( function_exists( 'amp_is_canonical' ) && \amp_is_canonical() && has_block( Blocks::get_block_name( __DIR__ ), $post->post_content ) ) {
293 return true;
294 }
295 return $skip;
296 }
297 add_filter( 'amp_skip_post', __NAMESPACE__ . '\amp_skip_post', 10, 3 );
298