PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 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 All 508 releases
← All changes | modules/shortcodes/mailchimp.php +229 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,229 @@
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 +if ( ! defined( 'ABSPATH' ) ) {
13 + exit( 0 );
14 +}
15 +
16 +// phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
17 +
18 +/**
19 + * Register [mailchimp_subscriber_popup] shortcode and add a filter to 'pre_kses' queue to reverse MailChimp embed to shortcode.
20 + *
21 + * @since 4.5.0
22 + */
23 +function jetpack_mailchimp_subscriber_popup() {
24 + add_shortcode(
25 + 'mailchimp_subscriber_popup',
26 + array(
27 + 'MailChimp_Subscriber_Popup',
28 + 'shortcode',
29 + )
30 + );
31 +
32 + if ( jetpack_shortcodes_should_hook_pre_kses() ) {
33 + add_filter(
34 + 'pre_kses',
35 + array(
36 + 'MailChimp_Subscriber_Popup',
37 + 'reversal',
38 + )
39 + );
40 + }
41 +}
42 +
43 +if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
44 + add_action( 'init', 'jetpack_mailchimp_subscriber_popup' );
45 +} else {
46 + jetpack_mailchimp_subscriber_popup();
47 +}
48 +
49 +/**
50 + * Class MailChimp_Subscriber_Popup
51 + *
52 + * @since 4.5.0
53 + */
54 +class MailChimp_Subscriber_Popup {
55 +
56 + /**
57 + * Regular expressions to reverse script tags to shortcodes.
58 + *
59 + * @var array
60 + */
61 + private static $reversal_regexes = array(
62 + /* raw examplejs */
63 + '/<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
64 + /* visual editor */
65 + '/&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',
66 + );
67 +
68 + /**
69 + * Allowed configuration attributes. Used in reversal when checking allowed attributes.
70 + *
71 + * @var array
72 + */
73 + private static $allowed_config = array(
74 + 'usePlainJson' => 'true',
75 + 'isDebug' => 'false',
76 + );
77 +
78 + /**
79 + * Allowed JS variables. Used in reversal to whitelist variables.
80 + *
81 + * @var array
82 + */
83 + private static $allowed_js_vars = array(
84 + 'baseUrl',
85 + 'uuid',
86 + 'lid',
87 + );
88 +
89 + /**
90 + * Runs the whole reversal.
91 + *
92 + * @since 4.5.0
93 + *
94 + * @param string $content Post Content.
95 + *
96 + * @return string Content with embeds replaced
97 + */
98 + public static function reversal( $content ) {
99 + // Bail without the js src.
100 + if ( ! is_string( $content ) || false === stripos( $content, 'downloads.mailchimp.com/js/signup-forms/popup/unique-methods/embed.js' ) ) {
101 + return $content;
102 + }
103 +
104 + // loop through our rules and find valid embeds.
105 + foreach ( self::$reversal_regexes as $regex ) {
106 +
107 + if ( ! preg_match_all( $regex, $content, $matches ) ) {
108 + continue;
109 + }
110 +
111 + foreach ( $matches[3] as $index => $js_vars ) {
112 + // the regex rule for a specific embed.
113 + $replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $matches[0][ $index ], '#' ) );
114 +
115 + $attrs = json_decode( '{' . $js_vars . '}' );
116 + // If JSON is garbage, skip.
117 + if ( ! $attrs ) {
118 + continue;
119 + }
120 +
121 + $shortcode = self::build_shortcode_from_reversal_attrs( $attrs );
122 +
123 + $content = preg_replace( $replace_regex, "\n\n$shortcode\n\n", $content );
124 +
125 + /** This action is documented in modules/widgets/social-media-icons.php */
126 + do_action( 'jetpack_bump_stats_extras', 'html_to_shortcode', 'mailchimp_subscriber_popup' );
127 + }
128 + }
129 +
130 + return $content;
131 + }
132 +
133 + /**
134 + * Builds the actual shortcode based on passed in attributes.
135 + *
136 + * @since 4.5.0
137 + *
138 + * @param array $attrs A valid list of attributes (gets matched against self::$allowed_config and self::$allowed_js_vars).
139 + *
140 + * @return string
141 + */
142 + private static function build_shortcode_from_reversal_attrs( $attrs ) {
143 + $shortcode = '[mailchimp_subscriber_popup ';
144 +
145 + foreach ( $attrs as $key => $value ) {
146 + // skip unsupported keys.
147 + if (
148 + ! array_key_exists( $key, self::$allowed_config )
149 + && ! in_array( $key, self::$allowed_js_vars, true )
150 + ) {
151 + continue;
152 + }
153 +
154 + $value = esc_attr( $value );
155 + $shortcode .= "$key='$value' ";
156 + }
157 + return trim( $shortcode ) . ']';
158 + }
159 +
160 + /**
161 + * Parses the shortcode back out to embedded information.
162 + *
163 + * @since 4.5.0
164 + *
165 + * @param array $lcase_attrs Lowercase shortcode attributes.
166 + *
167 + * @return string
168 + */
169 + public static function shortcode( $lcase_attrs ) {
170 + static $displayed_once = false;
171 +
172 + // Limit to one form per page load.
173 + if ( $displayed_once ) {
174 + return '';
175 + }
176 +
177 + if ( empty( $lcase_attrs ) ) {
178 + return '<!-- Missing MailChimp baseUrl, uuid or lid -->';
179 + }
180 +
181 + $defaults = array_fill_keys( self::$allowed_js_vars, '' );
182 + $defaults = array_merge( $defaults, self::$allowed_config );
183 +
184 + // Convert $attrs back to proper casing since they come through in all lowercase.
185 + $attrs = array();
186 + foreach ( $defaults as $key => $value ) {
187 + if ( array_key_exists( strtolower( $key ), $lcase_attrs ) ) {
188 + $attrs[ $key ] = $lcase_attrs[ strtolower( $key ) ];
189 + }
190 + }
191 + $attrs = array_map( 'esc_js', array_filter( shortcode_atts( $defaults, $attrs ) ) );
192 +
193 + // Split config & js vars.
194 + $js_vars = array();
195 + $config_vars = array();
196 + foreach ( $attrs as $key => $value ) {
197 + if (
198 + 'baseUrl' === $key
199 + && (
200 + ! preg_match( '#mc\.us\d+\.list-manage\d?\.com#', $value, $matches )
201 + || $value !== $matches[0]
202 + )
203 + ) {
204 + return '<!-- Invalid MailChimp baseUrl -->';
205 + }
206 +
207 + if ( in_array( $key, self::$allowed_js_vars, true ) ) {
208 + $js_vars[ $key ] = $value;
209 + } else {
210 + $config_vars[] = "$key: $value";
211 + }
212 + }
213 +
214 + // If one of these parameters is missing we can't render the form so exist.
215 + if ( empty( $js_vars['baseUrl'] ) || empty( $js_vars['uuid'] ) || empty( $js_vars['lid'] ) ) {
216 + return '<!-- Missing MailChimp baseUrl, uuid or lid -->';
217 + }
218 +
219 + // Add a uniqueMethods parameter if it is missing from the data we got from the embed code.
220 + $js_vars['uniqueMethods'] = true;
221 +
222 + /** This action is already documented in modules/widgets/gravatar-profile.php */
223 + do_action( 'jetpack_stats_extra', 'mailchimp_subscriber_popup', 'view' );
224 +
225 + $displayed_once = true;
226 +
227 + 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, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ') });} );</script>' . "\n\n";
228 + }
229 +}