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