No Description

mailchimp.php 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
  2. /**
  3. * MailChimp Subscriber Popup Form shortcode
  4. *
  5. * Example:
  6. * [mailchimp_subscriber_popup baseUrl="mc.us11.list-manage.com" uuid="1ca7856462585a934b8674c71" lid="2d24f1898b"]
  7. *
  8. * Embed code example:
  9. * <script type="text/javascript" src="//downloads.mailchimp.com/js/signup-forms/popup/unique-methods/embed.js" data-dojo-config="usePlainJson: true, isDebug: false"></script><script type="text/javascript">window.dojoRequire(["mojo/signup-forms/Loader"], function(L) { L.start({"baseUrl":"mc.us11.list-manage.com","uuid":"1ca7856462585a934b8674c71","lid":"2d24f1898b","uniqueMethods":true}) })</script>
  10. */
  11. /**
  12. * Register [mailchimp_subscriber_popup] shortcode and add a filter to 'pre_kses' queue to reverse MailChimp embed to shortcode.
  13. *
  14. * @since 4.5.0
  15. */
  16. function jetpack_mailchimp_subscriber_popup() {
  17. add_shortcode(
  18. 'mailchimp_subscriber_popup',
  19. array(
  20. 'MailChimp_Subscriber_Popup',
  21. 'shortcode',
  22. )
  23. );
  24. add_filter(
  25. 'pre_kses',
  26. array(
  27. 'MailChimp_Subscriber_Popup',
  28. 'reversal',
  29. )
  30. );
  31. }
  32. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
  33. add_action( 'init', 'jetpack_mailchimp_subscriber_popup' );
  34. } else {
  35. jetpack_mailchimp_subscriber_popup();
  36. }
  37. /**
  38. * Class MailChimp_Subscriber_Popup
  39. *
  40. * @since 4.5.0
  41. */
  42. class MailChimp_Subscriber_Popup {
  43. /**
  44. * Regular expressions to reverse script tags to shortcodes.
  45. *
  46. * @var array
  47. */
  48. private static $reversal_regexes = array(
  49. /* raw examplejs */
  50. '/<script type="text\/javascript" src="(https?:)?\/\/downloads\.mailchimp\.com\/js\/signup-forms\/popup\/unique-methods\/embed\.js" data-dojo-config="([^"]*?)"><\/script><script type="text\/javascript">window.dojoRequire\(\["mojo\/signup-forms\/Loader"\]\, function\(L\) { L\.start\({([^}]*?)}\) }\)<\/script>/s', //phpcs:ignore
  51. /* visual editor */
  52. '/&lt;script type="text\/javascript" src="(https?:)?\/\/downloads\.mailchimp\.com\/js\/signup-forms\/popup\/unique-methods\/embed\.js" data-dojo-config="([^"]*?)"&gt;&lt;\/script&gt;&lt;script type="text\/javascript"&gt;window.dojoRequire\(\["mojo\/signup-forms\/Loader"]\, function\(L\) { L\.start\({([^}]*?)}\) }\)&lt;\/script&gt;/s',
  53. );
  54. /**
  55. * Allowed configuration attributes. Used in reversal when checking allowed attributes.
  56. *
  57. * @var array
  58. */
  59. private static $allowed_config = array(
  60. 'usePlainJson' => 'true',
  61. 'isDebug' => 'false',
  62. );
  63. /**
  64. * Allowed JS variables. Used in reversal to whitelist variables.
  65. *
  66. * @var array
  67. */
  68. private static $allowed_js_vars = array(
  69. 'baseUrl',
  70. 'uuid',
  71. 'lid',
  72. );
  73. /**
  74. * Runs the whole reversal.
  75. *
  76. * @since 4.5.0
  77. *
  78. * @param string $content Post Content.
  79. *
  80. * @return string Content with embeds replaced
  81. */
  82. public static function reversal( $content ) {
  83. // Bail without the js src.
  84. if ( ! is_string( $content ) || false === stripos( $content, 'downloads.mailchimp.com/js/signup-forms/popup/unique-methods/embed.js' ) ) {
  85. return $content;
  86. }
  87. // loop through our rules and find valid embeds.
  88. foreach ( self::$reversal_regexes as $regex ) {
  89. if ( ! preg_match_all( $regex, $content, $matches ) ) {
  90. continue;
  91. }
  92. foreach ( $matches[3] as $index => $js_vars ) {
  93. // the regex rule for a specific embed.
  94. $replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $matches[0][ $index ], '#' ) );
  95. $attrs = json_decode( '{' . $js_vars . '}' );
  96. if ( $matches[2][ $index ] ) {
  97. $config_attrs = json_decode( '{' . $matches[2][ $index ] . '}' );
  98. foreach ( $config_attrs as $key => $value ) {
  99. $attrs->$key = ( 1 === $value ) ? 'true' : 'false';
  100. }
  101. }
  102. $shortcode = self::build_shortcode_from_reversal_attrs( $attrs );
  103. $content = preg_replace( $replace_regex, "\n\n$shortcode\n\n", $content );
  104. /** This action is documented in modules/widgets/social-media-icons.php */
  105. do_action( 'jetpack_bump_stats_extras', 'html_to_shortcode', 'mailchimp_subscriber_popup' );
  106. }
  107. }
  108. return $content;
  109. }
  110. /**
  111. * Builds the actual shortcode based on passed in attributes.
  112. *
  113. * @since 4.5.0
  114. *
  115. * @param array $attrs A valid list of attributes (gets matched against self::$allowed_config and self::$allowed_js_vars).
  116. *
  117. * @return string
  118. */
  119. private static function build_shortcode_from_reversal_attrs( $attrs ) {
  120. $shortcode = '[mailchimp_subscriber_popup ';
  121. foreach ( $attrs as $key => $value ) {
  122. // skip unsupported keys.
  123. if (
  124. ! array_key_exists( $key, self::$allowed_config )
  125. && ! in_array( $key, self::$allowed_js_vars, true )
  126. ) {
  127. continue;
  128. }
  129. $value = esc_attr( $value );
  130. $shortcode .= "$key='$value' ";
  131. }
  132. return trim( $shortcode ) . ']';
  133. }
  134. /**
  135. * Parses the shortcode back out to embedded information.
  136. *
  137. * @since 4.5.0
  138. *
  139. * @param array $lcase_attrs Lowercase shortcode attributes.
  140. *
  141. * @return string
  142. */
  143. public static function shortcode( $lcase_attrs ) {
  144. static $displayed_once = false;
  145. // Limit to one form per page load.
  146. if ( $displayed_once ) {
  147. return '';
  148. }
  149. if ( empty( $lcase_attrs ) ) {
  150. return '<!-- Missing MailChimp baseUrl, uuid or lid -->';
  151. }
  152. $defaults = array_fill_keys( self::$allowed_js_vars, '' );
  153. $defaults = array_merge( $defaults, self::$allowed_config );
  154. // Convert $attrs back to proper casing since they come through in all lowercase.
  155. $attrs = array();
  156. foreach ( $defaults as $key => $value ) {
  157. if ( array_key_exists( strtolower( $key ), $lcase_attrs ) ) {
  158. $attrs[ $key ] = $lcase_attrs[ strtolower( $key ) ];
  159. }
  160. }
  161. $attrs = array_map( 'esc_js', array_filter( shortcode_atts( $defaults, $attrs ) ) );
  162. // Split config & js vars.
  163. $js_vars = array();
  164. $config_vars = array();
  165. foreach ( $attrs as $key => $value ) {
  166. if (
  167. 'baseUrl' === $key
  168. && (
  169. ! preg_match( '#mc\.us\d+\.list-manage\d?\.com#', $value, $matches )
  170. || $value !== $matches[0]
  171. )
  172. ) {
  173. return '<!-- Invalid MailChimp baseUrl -->';
  174. }
  175. if ( in_array( $key, self::$allowed_js_vars, true ) ) {
  176. $js_vars[ $key ] = $value;
  177. } else {
  178. $config_vars[] = "$key: $value";
  179. }
  180. }
  181. // If one of these parameters is missing we can't render the form so exist.
  182. if ( empty( $js_vars['baseUrl'] ) || empty( $js_vars['uuid'] ) || empty( $js_vars['lid'] ) ) {
  183. return '<!-- Missing MailChimp baseUrl, uuid or lid -->';
  184. }
  185. // Add a uniqueMethods parameter if it is missing from the data we got from the embed code.
  186. $js_vars['uniqueMethods'] = true;
  187. /** This action is already documented in modules/widgets/gravatar-profile.php */
  188. do_action( 'jetpack_stats_extra', 'mailchimp_subscriber_popup', 'view' );
  189. $displayed_once = true;
  190. return "\n\n" . '<script type="text/javascript" data-dojo-config="' . esc_attr( implode( ', ', $config_vars ) ) . '">jQuery.getScript( "//downloads.mailchimp.com/js/signup-forms/popup/unique-methods/embed.js", function( data, textStatus, jqxhr ) { window.dojoRequire(["mojo/signup-forms/Loader"], function(L) { L.start(' . wp_json_encode( $js_vars ) . ') });} );</script>' . "\n\n";
  191. }
  192. }