Нет описания

donations.php 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <?php
  2. /**
  3. * Donations Block.
  4. *
  5. * @since 8.x
  6. *
  7. * @package automattic/jetpack
  8. */
  9. namespace Automattic\Jetpack\Extensions\Donations;
  10. use Automattic\Jetpack\Blocks;
  11. use Jetpack_Gutenberg;
  12. const FEATURE_NAME = 'donations';
  13. const BLOCK_NAME = 'jetpack/' . FEATURE_NAME;
  14. /**
  15. * Registers the block for use in Gutenberg
  16. * This is done via an action so that we can disable
  17. * registration if we need to.
  18. */
  19. function register_block() {
  20. Blocks::jetpack_register_block(
  21. BLOCK_NAME,
  22. array(
  23. 'render_callback' => __NAMESPACE__ . '\render_block',
  24. 'plan_check' => true,
  25. 'attributes' => array(
  26. 'currency' => array(
  27. 'type' => 'string',
  28. 'default' => 'USD',
  29. ),
  30. 'oneTimeDonation' => array(
  31. 'type' => 'object',
  32. 'default' => array(
  33. 'show' => true,
  34. 'planId' => null,
  35. 'amounts' => array( 5, 15, 100 ),
  36. 'heading' => __( 'Make a one-time donation', 'jetpack' ),
  37. 'extraText' => __( 'Your contribution is appreciated.', 'jetpack' ),
  38. 'buttonText' => __( 'Donate', 'jetpack' ),
  39. ),
  40. ),
  41. 'monthlyDonation' => array(
  42. 'type' => 'object',
  43. 'default' => array(
  44. 'show' => true,
  45. 'planId' => null,
  46. 'amounts' => array( 5, 15, 100 ),
  47. 'heading' => __( 'Make a monthly donation', 'jetpack' ),
  48. 'extraText' => __( 'Your contribution is appreciated.', 'jetpack' ),
  49. 'buttonText' => __( 'Donate monthly', 'jetpack' ),
  50. ),
  51. ),
  52. 'annualDonation' => array(
  53. 'type' => 'object',
  54. 'default' => array(
  55. 'show' => true,
  56. 'planId' => null,
  57. 'amounts' => array( 5, 15, 100 ),
  58. 'heading' => __( 'Make a yearly donation', 'jetpack' ),
  59. 'extraText' => __( 'Your contribution is appreciated.', 'jetpack' ),
  60. 'buttonText' => __( 'Donate yearly', 'jetpack' ),
  61. ),
  62. ),
  63. 'showCustomAmount' => array(
  64. 'type' => 'boolean',
  65. 'default' => true,
  66. ),
  67. 'chooseAmountText' => array(
  68. 'type' => 'string',
  69. 'default' => __( 'Choose an amount', 'jetpack' ),
  70. ),
  71. 'customAmountText' => array(
  72. 'type' => 'string',
  73. 'default' => __( 'Or enter a custom amount', 'jetpack' ),
  74. ),
  75. 'fallbackLinkUrl' => array(
  76. 'type' => 'string',
  77. ),
  78. ),
  79. )
  80. );
  81. }
  82. add_action( 'init', __NAMESPACE__ . '\register_block' );
  83. /**
  84. * Donations block dynamic rendering.
  85. *
  86. * @param array $attr Array containing the Donations block attributes.
  87. * @param string $content String containing the Donations block content.
  88. *
  89. * @return string
  90. */
  91. function render_block( $attr, $content ) {
  92. // Keep content as-is if rendered in other contexts than frontend (i.e. feed, emails, API, etc.).
  93. if ( ! jetpack_is_frontend() ) {
  94. return $content;
  95. }
  96. Jetpack_Gutenberg::load_assets_as_required( FEATURE_NAME, array( 'thickbox' ) );
  97. add_thickbox();
  98. require_once JETPACK__PLUGIN_DIR . 'modules/memberships/class-jetpack-memberships.php';
  99. jetpack_require_lib( 'class-jetpack-currencies' );
  100. $donations = array(
  101. 'one-time' => array_merge(
  102. array(
  103. 'title' => __( 'One-Time', 'jetpack' ),
  104. 'class' => 'donations__one-time-item',
  105. ),
  106. $attr['oneTimeDonation']
  107. ),
  108. );
  109. if ( $attr['monthlyDonation']['show'] ) {
  110. $donations['1 month'] = array_merge(
  111. array(
  112. 'title' => __( 'Monthly', 'jetpack' ),
  113. 'class' => 'donations__monthly-item',
  114. ),
  115. $attr['monthlyDonation']
  116. );
  117. }
  118. if ( $attr['annualDonation']['show'] ) {
  119. $donations['1 year'] = array_merge(
  120. array(
  121. 'title' => __( 'Yearly', 'jetpack' ),
  122. 'class' => 'donations__annual-item',
  123. ),
  124. $attr['annualDonation']
  125. );
  126. }
  127. $currency = $attr['currency'];
  128. $nav = '';
  129. $headings = '';
  130. $amounts = '';
  131. $extra_text = '';
  132. $buttons = '';
  133. foreach ( $donations as $interval => $donation ) {
  134. $plan_id = (int) $donation['planId'];
  135. $plan = get_post( $plan_id );
  136. if ( ! $plan || is_wp_error( $plan ) ) {
  137. continue;
  138. }
  139. if ( count( $donations ) > 1 ) {
  140. if ( ! $nav ) {
  141. $nav .= '<div class="donations__nav">';
  142. }
  143. $nav .= sprintf(
  144. '<div role="button" tabindex="0" class="donations__nav-item" data-interval="%1$s">%2$s</div>',
  145. esc_attr( $interval ),
  146. esc_html( $donation['title'] )
  147. );
  148. }
  149. $headings .= sprintf(
  150. '<h4 class="%1$s">%2$s</h4>',
  151. esc_attr( $donation['class'] ),
  152. wp_kses_post( $donation['heading'] )
  153. );
  154. $amounts .= sprintf(
  155. '<div class="donations__amounts %s">',
  156. esc_attr( $donation['class'] )
  157. );
  158. foreach ( $donation['amounts'] as $amount ) {
  159. $amounts .= sprintf(
  160. '<div class="donations__amount" data-amount="%1$s">%2$s</div>',
  161. esc_attr( $amount ),
  162. esc_html( \Jetpack_Currencies::format_price( $amount, $currency ) )
  163. );
  164. }
  165. $amounts .= '</div>';
  166. $extra_text .= sprintf(
  167. '<p class="%1$s">%2$s</p>',
  168. esc_attr( $donation['class'] ),
  169. wp_kses_post( $donation['extraText'] )
  170. );
  171. $buttons .= sprintf(
  172. '<a class="wp-block-button__link donations__donate-button %1$s" href="%2$s">%3$s</a>',
  173. esc_attr( $donation['class'] ),
  174. esc_url( \Jetpack_Memberships::get_instance()->get_subscription_url( $plan_id ) ),
  175. wp_kses_post( $donation['buttonText'] )
  176. );
  177. }
  178. if ( $nav ) {
  179. $nav .= '</div>';
  180. }
  181. $custom_amount = '';
  182. if ( $attr['showCustomAmount'] ) {
  183. $custom_amount .= sprintf(
  184. '<p>%s</p>',
  185. wp_kses_post( $attr['customAmountText'] )
  186. );
  187. $default_custom_amount = \Jetpack_Memberships::SUPPORTED_CURRENCIES[ $currency ] * 100;
  188. $custom_amount .= sprintf(
  189. '<div class="donations__amount donations__custom-amount">
  190. %1$s
  191. <div class="donations__amount-value" data-currency="%2$s" data-empty-text="%3$s"></div>
  192. </div>',
  193. esc_html( \Jetpack_Currencies::CURRENCIES[ $attr['currency'] ]['symbol'] ),
  194. esc_attr( $attr['currency'] ),
  195. esc_attr( \Jetpack_Currencies::format_price( $default_custom_amount, $currency, false ) )
  196. );
  197. }
  198. return sprintf(
  199. '
  200. <div class="%1$s">
  201. <div class="donations__container">
  202. %2$s
  203. <div class="donations__content">
  204. <div class="donations__tab">
  205. %3$s
  206. <p>%4$s</p>
  207. %5$s
  208. %6$s
  209. <hr class="donations__separator">
  210. %7$s
  211. %8$s
  212. </div>
  213. </div>
  214. </div>
  215. ',
  216. esc_attr( Blocks::classes( FEATURE_NAME, $attr ) ),
  217. $nav,
  218. $headings,
  219. $attr['chooseAmountText'],
  220. $amounts,
  221. $custom_amount,
  222. $extra_text,
  223. $buttons
  224. );
  225. }
  226. /**
  227. * Determine if AMP should be disabled on posts having Donations blocks.
  228. *
  229. * @param bool $skip Skipped.
  230. * @param int $post_id Post ID.
  231. * @param WP_Post $post Post.
  232. *
  233. * @return bool Whether to skip the post from AMP.
  234. */
  235. function amp_skip_post( $skip, $post_id, $post ) {
  236. // When AMP is on standard mode, there are no non-AMP posts to link to where the donation can be completed, so let's
  237. // prevent the post from being available in AMP.
  238. if ( function_exists( 'amp_is_canonical' ) && \amp_is_canonical() && has_block( BLOCK_NAME, $post->post_content ) ) {
  239. return true;
  240. }
  241. return $skip;
  242. }
  243. add_filter( 'amp_skip_post', __NAMESPACE__ . '\amp_skip_post', 10, 3 );