96e37147 by Jeff Balicki

plugins

Signed-off-by: Jeff <jeff@gotenzing.com>
1 parent 19caef7d
Showing 169 changed files with 4804 additions and 0 deletions
1 MC4WP: Mailchimp for WordPress
2 ======================
3 ![PHP status](https://github.com/ibericode/mailchimp-for-wordpress/workflows/PHP/badge.svg)
4 ![ESLint status](https://github.com/ibericode/mailchimp-for-wordpress/workflows/ESLint/badge.svg)
5 ![Active installs](https://img.shields.io/wordpress/plugin/installs/mailchimp-for-wp.svg)
6 ![Downloads](https://img.shields.io/wordpress/plugin/dt/mailchimp-for-wp.svg)
7 [![Rating](https://img.shields.io/wordpress/plugin/r/mailchimp-for-wp.svg)](https://wordpress.org/support/plugin/mailchimp-for-wp/reviews/)
8 [![License: GPLv3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
9
10 Here, you can browse the source code of the [MC4WP: Mailchimp for WordPress Plugin](https://wordpress.org/plugins/mailchimp-for-wp/), find and discuss open issues or contribute code to the plugin.
11
12 Requirements
13 --------------
14
15 - PHP version 7.2 or higher
16 - WordPress version 4.6 or higher
17
18
19 Installation
20 ------------
21
22 If you just want to install this plugin on your WordPress site, please download and install the latest version from WordPress.org: [Mailchimp for WordPress plugin on WordPress.org](https://wordpress.org/plugins/mailchimp-for-wp/).
23
24 To install the development version, take the following steps:
25
26 1. Clone the GitHub repository:
27 ```
28 git clone https://github.com/ibericode/mailchimp-for-wordpress.git mailchimp-for-wp
29 ```
30
31 1. Install Composer dependencies:
32 ```sh
33 composer install
34 ```
35
36 1. Install NPM dependencies:
37 ```
38 npm install
39 ```
40
41 1. Generate plugin asset files:
42 ```
43 npm run build
44 ```
45
46 1. Activate the plugin in your WordPress admin panel.
47
48 Bugs
49 ----
50 If you think you've found a bug, [please open an issue here](https://github.com/ibericode/mailchimp-for-wordpress/issues?state=open)!
51
52 Translations
53 -------------
54 You can help [help translate Mailchimp for WordPress](https://translate.wordpress.org/projects/wp-plugins/mailchimp-for-wp/stable/) on WordPress.org.
55
56 Support
57 -------
58 This is a developer's portal for the Mailchimp for WordPress plugin and should not be used for support.
59 Please visit the [Mailchimp for WordPress support forum on WordPress.org](https://wordpress.org/support/plugin/mailchimp-for-wp).
60
61 If you need priority support, [upgrade to Mailchimp for WordPress Premium](https://www.mc4wp.com/).
62
63 Developers
64 ----------
65
66 Looking for code snippets? Have a look at the [sample code snippets directory](https://github.com/ibericode/mailchimp-for-wordpress/tree/master/sample-code-snippets) for a collection of modification examples.
67
1 .mc4wp-checkbox-__INTEGRATION_SLUG__{clear:both;width:auto;display:block;position:static}.mc4wp-checkbox-__INTEGRATION_SLUG__ input{float:none;vertical-align:middle;-webkit-appearance:checkbox;width:auto;max-width:21px;margin:0 6px 0 0;padding:0;position:static;display:inline-block!important}.mc4wp-checkbox-__INTEGRATION_SLUG__ label{float:none;cursor:pointer;width:auto;margin:0 0 16px;display:block;position:static}
...\ No newline at end of file ...\ No newline at end of file
1 .mc4wp-form input[name^=_mc4wp_honey]{display:none!important}.mc4wp-form-basic{margin:1em 0}.mc4wp-form-basic label,.mc4wp-form-basic input{box-sizing:border-box;cursor:auto;vertical-align:baseline;width:auto;height:auto;line-height:normal;display:block}.mc4wp-form-basic label:after,.mc4wp-form-basic input:after{content:"";clear:both;display:table}.mc4wp-form-basic label{margin-bottom:6px;font-weight:700;display:block}.mc4wp-form-basic input[type=text],.mc4wp-form-basic input[type=email],.mc4wp-form-basic input[type=tel],.mc4wp-form-basic input[type=url],.mc4wp-form-basic input[type=date],.mc4wp-form-basic textarea,.mc4wp-form-basic select{width:100%;max-width:480px;min-height:32px}.mc4wp-form-basic input[type=number]{min-width:40px}.mc4wp-form-basic input[type=checkbox],.mc4wp-form-basic input[type=radio]{border:0;width:13px;height:13px;margin:0 6px 0 0;padding:0;display:inline-block;position:relative}.mc4wp-form-basic input[type=checkbox]{-webkit-appearance:checkbox;-moz-appearance:checkbox;appearance:checkbox}.mc4wp-form-basic input[type=radio]{-webkit-appearance:radio;-moz-appearance:radio;appearance:radio}.mc4wp-form-basic input[type=submit],.mc4wp-form-basic button,.mc4wp-form-basic input[type=button]{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;display:inline-block}.mc4wp-form-basic label>span,.mc4wp-form-basic li>label{font-weight:400}.mc4wp-alert{color:#c09853;clear:both}.mc4wp-success{color:#468847}.mc4wp-notice{color:#3a87ad}.mc4wp-error{color:#cd5c5c}.rtl .mc4wp-form-basic input[type=checkbox],.rtl .mc4wp-form-basic input[type=radio]{margin:0 0 0 6px}
...\ No newline at end of file ...\ No newline at end of file
1 .mc4wp-form input[name^=_mc4wp_honey]{display:none!important}.mc4wp-form-theme{margin:1em 0}.mc4wp-form-theme label,.mc4wp-form-theme input{box-sizing:border-box;cursor:auto;vertical-align:baseline;width:auto;height:auto;line-height:normal;display:block}.mc4wp-form-theme label:after,.mc4wp-form-theme input:after{content:"";clear:both;display:table}.mc4wp-form-theme label{margin-bottom:6px;font-weight:700;display:block}.mc4wp-form-theme input[type=text],.mc4wp-form-theme input[type=email],.mc4wp-form-theme input[type=tel],.mc4wp-form-theme input[type=url],.mc4wp-form-theme input[type=date],.mc4wp-form-theme textarea,.mc4wp-form-theme select{vertical-align:middle;text-shadow:none;background:#fff;border:1px solid #ccc;border-radius:2px;outline:0;width:100%;max-width:480px;height:auto;min-height:32px;padding:8px 16px;line-height:1.42857;color:#555!important}.mc4wp-form-theme textarea{height:auto}.mc4wp-form-theme input[readonly],.mc4wp-form-theme input[disabled]{background-color:#eee}.mc4wp-form-theme input[type=number]{min-width:40px}.mc4wp-form-theme input[type=checkbox],.mc4wp-form-theme input[type=radio]{border:0;width:13px;height:13px;margin:0 6px 0 0;padding:0;display:inline-block;position:relative}.mc4wp-form-theme input[type=checkbox]{-webkit-appearance:checkbox;-moz-appearance:checkbox;appearance:checkbox}.mc4wp-form-theme input[type=radio]{-webkit-appearance:radio;-moz-appearance:radio;appearance:radio}.mc4wp-form-theme button,.mc4wp-form-theme input[type=submit],.mc4wp-form-theme input[type=button]{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;text-align:center;white-space:nowrap;vertical-align:middle;user-select:none;text-shadow:none;filter:none;background:0 0;border:1px solid #0000;border-radius:2px;width:auto;height:auto;padding:8px 16px;font-weight:400;line-height:1.42857;display:inline-block}.mc4wp-form-theme button:hover,.mc4wp-form-theme input[type=submit]:hover,.mc4wp-form-theme input[type=button]:hover,.mc4wp-form-theme button:focus,.mc4wp-form-theme input[type=submit]:focus,.mc4wp-form-theme input[type=button]:focus{color:#333;background:0 0;outline:0;text-decoration:none}.mc4wp-form-theme label>span,.mc4wp-form-theme li>label{font-weight:400}.mc4wp-alert{color:#c09853;clear:both}.mc4wp-success{color:#468847}.mc4wp-notice{color:#3a87ad}.mc4wp-error{color:#cd5c5c}.rtl .mc4wp-form-theme input[type=checkbox],.rtl .mc4wp-form-theme input[type=radio]{margin:0 0 0 6px}.mc4wp-form-theme-dark button,.mc4wp-form-theme-dark input[type=submit],.mc4wp-form-theme-dark input[type=button]{border-color:#1e1e1e;color:#fff!important;background-color:#444!important}.mc4wp-form-theme-dark button:hover,.mc4wp-form-theme-dark input[type=submit]:hover,.mc4wp-form-theme-dark input[type=button]:hover,.mc4wp-form-theme-dark button:focus,.mc4wp-form-theme-dark input[type=submit]:focus,.mc4wp-form-theme-dark input[type=button]:focus{border-color:#000;color:#fff!important;background-color:#1e1e1e!important}.mc4wp-form-theme-dark input[type=text]:focus,.mc4wp-form-theme-dark input[type=email]:focus,.mc4wp-form-theme-dark input[type=tel]:focus,.mc4wp-form-theme-dark input[type=url]:focus,.mc4wp-form-theme-dark input[type=date]:focus,.mc4wp-form-theme-dark textarea:focus,.mc4wp-form-theme-dark select:focus{border-color:#6a6a6a}.mc4wp-form-theme-light button,.mc4wp-form-theme-light input[type=submit],.mc4wp-form-theme-light input[type=button]{border-color:#d9d9d9;color:#000!important;background-color:#fff!important}.mc4wp-form-theme-light button:hover,.mc4wp-form-theme-light input[type=submit]:hover,.mc4wp-form-theme-light input[type=button]:hover,.mc4wp-form-theme-light button:focus,.mc4wp-form-theme-light input[type=submit]:focus,.mc4wp-form-theme-light input[type=button]:focus{border-color:#b3b3b3;color:#000!important;background-color:#d9d9d9!important}.mc4wp-form-theme-light input[type=text]:focus,.mc4wp-form-theme-light input[type=email]:focus,.mc4wp-form-theme-light input[type=tel]:focus,.mc4wp-form-theme-light input[type=url]:focus,.mc4wp-form-theme-light input[type=date]:focus,.mc4wp-form-theme-light textarea:focus,.mc4wp-form-theme-light select:focus{border-color:#d9d9d9}.mc4wp-form-theme-red button,.mc4wp-form-theme-red input[type=submit],.mc4wp-form-theme-red input[type=button]{border-color:#b52b27;color:#fff!important;background-color:#d9534f!important}.mc4wp-form-theme-red button:hover,.mc4wp-form-theme-red input[type=submit]:hover,.mc4wp-form-theme-red input[type=button]:hover,.mc4wp-form-theme-red button:focus,.mc4wp-form-theme-red input[type=submit]:focus,.mc4wp-form-theme-red input[type=button]:focus{border-color:#761c19;color:#fff!important;background-color:#b52b27!important}.mc4wp-form-theme-red input[type=text]:focus,.mc4wp-form-theme-red input[type=email]:focus,.mc4wp-form-theme-red input[type=tel]:focus,.mc4wp-form-theme-red input[type=url]:focus,.mc4wp-form-theme-red input[type=date]:focus,.mc4wp-form-theme-red textarea:focus,.mc4wp-form-theme-red select:focus{border-color:#e7908e}.mc4wp-form-theme-blue button,.mc4wp-form-theme-blue input[type=submit],.mc4wp-form-theme-blue input[type=button]{border-color:#2a6496;color:#fff!important;background-color:#428bca!important}.mc4wp-form-theme-blue button:hover,.mc4wp-form-theme-blue input[type=submit]:hover,.mc4wp-form-theme-blue input[type=button]:hover,.mc4wp-form-theme-blue button:focus,.mc4wp-form-theme-blue input[type=submit]:focus,.mc4wp-form-theme-blue input[type=button]:focus{border-color:#193c5a;color:#fff!important;background-color:#2a6496!important}.mc4wp-form-theme-blue input[type=text]:focus,.mc4wp-form-theme-blue input[type=email]:focus,.mc4wp-form-theme-blue input[type=tel]:focus,.mc4wp-form-theme-blue input[type=url]:focus,.mc4wp-form-theme-blue input[type=date]:focus,.mc4wp-form-theme-blue textarea:focus,.mc4wp-form-theme-blue select:focus{border-color:#7eb0db}.mc4wp-form-theme-green button,.mc4wp-form-theme-green input[type=submit],.mc4wp-form-theme-green input[type=button]{border-color:#3d8b3d;color:#fff!important;background-color:#5cb85c!important}.mc4wp-form-theme-green button:hover,.mc4wp-form-theme-green input[type=submit]:hover,.mc4wp-form-theme-green input[type=button]:hover,.mc4wp-form-theme-green button:focus,.mc4wp-form-theme-green input[type=submit]:focus,.mc4wp-form-theme-green input[type=button]:focus{border-color:#255625;color:#fff!important;background-color:#3d8b3d!important}.mc4wp-form-theme-green input[type=text]:focus,.mc4wp-form-theme-green input[type=email]:focus,.mc4wp-form-theme-green input[type=tel]:focus,.mc4wp-form-theme-green input[type=url]:focus,.mc4wp-form-theme-green input[type=date]:focus,.mc4wp-form-theme-green textarea:focus,.mc4wp-form-theme-green select:focus{border-color:#91cf91}
...\ No newline at end of file ...\ No newline at end of file
1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <svg
3 xmlns:svg="http://www.w3.org/2000/svg"
4 xmlns="http://www.w3.org/2000/svg"
5 width="16"
6 height="16"
7 viewBox="0 0 16 16"
8 version="1.1">
9 <g
10 fill="#a0a5aa">
11 <path
12 opacity="1"
13 fill="#a0a5aa"
14 fill-opacity="1"
15 stroke="none"
16 d="M 8.0097656 0.052734375 A 8 8 0 0 0 0.009765625 8.0527344 A 8 8 0 0 0 8.0097656 16.052734 A 8 8 0 0 0 16.009766 8.0527344 A 8 8 0 0 0 8.0097656 0.052734375 z M 9.2597656 4.171875 C 9.3205456 4.171875 9.9296146 5.0233822 10.611328 6.0664062 C 11.293041 7.1094313 12.296018 8.5331666 12.841797 9.2285156 L 13.833984 10.492188 L 13.316406 11.041016 C 13.031321 11.342334 12.708299 11.587891 12.599609 11.587891 C 12.253798 11.587891 11.266634 10.490156 10.349609 9.0859375 C 9.8610009 8.3377415 9.4126385 7.7229 9.3515625 7.71875 C 9.2904825 7.71455 9.2402344 8.3477011 9.2402344 9.1269531 L 9.2402344 10.544922 L 8.5839844 10.982422 C 8.2233854 11.223015 7.8735746 11.418294 7.8066406 11.417969 C 7.7397106 11.417644 7.4861075 10.997223 7.2421875 10.482422 C 6.9982675 9.9676199 6.6560079 9.3946444 6.4824219 9.2089844 L 6.1679688 8.8710938 L 6.0664062 9.34375 C 5.7203313 10.974656 5.6693219 11.090791 5.0917969 11.505859 C 4.5805569 11.873288 4.2347982 12.017623 4.1914062 11.882812 C 4.1839062 11.859632 4.1482681 11.574497 4.1113281 11.25 C 3.9708341 10.015897 3.5347399 8.7602861 2.8105469 7.5019531 C 2.5672129 7.0791451 2.5711235 7.0651693 2.9765625 6.8320312 C 3.2046215 6.7008903 3.5466561 6.4845105 3.7363281 6.3515625 C 4.0587811 6.1255455 4.1076376 6.1466348 4.4941406 6.6679688 C 4.8138896 7.0992628 4.9275606 7.166285 4.9941406 6.96875 C 5.0960956 6.666263 6.181165 5.8574219 6.484375 5.8574219 C 6.600668 5.8574219 6.8857635 6.1981904 7.1171875 6.6152344 C 7.3486105 7.0322784 7.5790294 7.3728809 7.6308594 7.3730469 C 7.7759584 7.3735219 7.9383234 5.8938023 7.8339844 5.5195312 C 7.7605544 5.2561423 7.8865035 5.0831575 8.4453125 4.6796875 C 8.8327545 4.3999485 9.1989846 4.171875 9.2597656 4.171875 z "
17 id="path5822" />
18 </g>
19 </svg>
1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4 <svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12 width="64"
13 height="64"
14 viewBox="0 0 64 64"
15 version="1.1"
16 id="SVGRoot"
17 inkscape:version="0.92.4 5da689c313, 2019-01-14"
18 sodipodi:docname="mc4wp-logo-red-on-white.svg">
19 <g
20 inkscape:groupmode="layer"
21 id="layer2"
22 inkscape:label="Layer 2">
23 <circle
24 style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
25 id="path5822"
26 cx="32"
27 cy="32"
28 r="32" />
29 </g>
30 <g
31 inkscape:label="Layer 1"
32 inkscape:groupmode="layer"
33 id="layer1">
34 <path
35 style="fill:#cc4444;fill-opacity:1;stroke:none;"
36 d="m 16,47.324799 c -0.02985,-0.09271 -0.175159,-1.230558 -0.322927,-2.528543 -0.561978,-4.936413 -2.305204,-9.961206 -5.201976,-14.994537 -0.9733359,-1.691234 -0.9585997,-1.750867 0.663154,-2.683422 0.912236,-0.524562 2.279359,-1.38885 3.038049,-1.920641 1.289813,-0.904069 1.486868,-0.821985 3.032878,1.26335 1.278999,1.725178 1.731406,1.998919 1.997727,1.208779 0.407819,-1.209946 4.748289,-4.450438 5.96113,-4.450438 0.465172,0 1.603153,1.364871 2.528847,3.033047 0.925694,1.668177 1.852705,3.03359 2.060024,3.034253 0.580399,0.0019 1.2257,-5.915967 0.808345,-7.413054 -0.293707,-1.053553 0.21226,-1.748685 2.447515,-3.362568 1.549769,-1.118954 3.016679,-2.034461 3.2598,-2.034461 0.243121,0 2.673101,3.413534 5.399956,7.585632 2.726854,4.172097 6.744105,9.861321 8.927221,12.642719 l 3.969305,5.057088 -2.073345,2.191405 c -1.140339,1.205272 -2.429057,2.191404 -2.863817,2.191404 -1.383243,0 -5.331006,-4.389741 -8.999106,-10.006614 -1.954436,-2.992783 -3.753407,-5.455006 -3.997711,-5.471606 -0.244305,-0.0166 -0.44419,2.520101 -0.44419,5.637112 v 5.667295 l -2.62254,1.749768 c -1.442397,0.962371 -2.841596,1.748706 -3.109332,1.747409 -0.267735,-0.0013 -1.285075,-1.687162 -2.260756,-3.746367 -0.97568,-2.059206 -2.342064,-4.351629 -3.036409,-5.094272 l -1.262444,-1.350262 -0.401863,1.893807 c -1.3843,6.523625 -1.59298,6.985894 -3.90308,8.646166 C 17.549496,47.286963 16.173566,47.864041 16,47.324799 Z"
37 id="path4520"
38 inkscape:connector-curvature="0" />
39 </g>
40 </svg>
1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <svg
3 xmlns:dc="http://purl.org/dc/elements/1.1/"
4 xmlns:cc="http://creativecommons.org/ns#"
5 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
6 xmlns:svg="http://www.w3.org/2000/svg"
7 xmlns="http://www.w3.org/2000/svg"
8 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
9 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
10 width="64"
11 height="64"
12 viewBox="0 0 64 64"
13 version="1.1"
14 id="SVGRoot"
15 inkscape:version="0.92.4 5da689c313, 2019-01-14"
16 sodipodi:docname="mc4wp-logo-white-on-red.svg">
17 <g
18 inkscape:groupmode="layer"
19 id="layer2"
20 inkscape:label="Layer 2">
21 <circle
22 style="opacity:1;fill:#cc4444;fill-opacity:1;stroke:none;stroke-opacity:1"
23 id="path5822"
24 cx="32"
25 cy="32"
26 r="32" />
27 </g>
28 <g
29 inkscape:label="Layer 1"
30 inkscape:groupmode="layer"
31 id="layer1">
32 <path
33 style="fill:#ffffff;fill-opacity:1;stroke:none;"
34 d="m 16,47.324799 c -0.02985,-0.09271 -0.175159,-1.230558 -0.322927,-2.528543 -0.561978,-4.936413 -2.305204,-9.961206 -5.201976,-14.994537 -0.9733359,-1.691234 -0.9585997,-1.750867 0.663154,-2.683422 0.912236,-0.524562 2.279359,-1.38885 3.038049,-1.920641 1.289813,-0.904069 1.486868,-0.821985 3.032878,1.26335 1.278999,1.725178 1.731406,1.998919 1.997727,1.208779 0.407819,-1.209946 4.748289,-4.450438 5.96113,-4.450438 0.465172,0 1.603153,1.364871 2.528847,3.033047 0.925694,1.668177 1.852705,3.03359 2.060024,3.034253 0.580399,0.0019 1.2257,-5.915967 0.808345,-7.413054 -0.293707,-1.053553 0.21226,-1.748685 2.447515,-3.362568 1.549769,-1.118954 3.016679,-2.034461 3.2598,-2.034461 0.243121,0 2.673101,3.413534 5.399956,7.585632 2.726854,4.172097 6.744105,9.861321 8.927221,12.642719 l 3.969305,5.057088 -2.073345,2.191405 c -1.140339,1.205272 -2.429057,2.191404 -2.863817,2.191404 -1.383243,0 -5.331006,-4.389741 -8.999106,-10.006614 -1.954436,-2.992783 -3.753407,-5.455006 -3.997711,-5.471606 -0.244305,-0.0166 -0.44419,2.520101 -0.44419,5.637112 v 5.667295 l -2.62254,1.749768 c -1.442397,0.962371 -2.841596,1.748706 -3.109332,1.747409 -0.267735,-0.0013 -1.285075,-1.687162 -2.260756,-3.746367 -0.97568,-2.059206 -2.342064,-4.351629 -3.036409,-5.094272 l -1.262444,-1.350262 -0.401863,1.893807 c -1.3843,6.523625 -1.59298,6.985894 -3.90308,8.646166 C 17.549496,47.286963 16.173566,47.864041 16,47.324799 Z"
35 id="path4520"
36 inkscape:connector-curvature="0" />
37 </g>
38 </svg>
This diff could not be displayed because it is too large.
1 (()=>{const e=window.wp.i18n.__,{registerBlockType:t}=window.wp.blocks,{SelectControl:i}=window.wp.components,o=window.mc4wp_forms;t("mailchimp-for-wp/form",{title:e("Mailchimp for WordPress Form"),description:e("Block showing a Mailchimp for WordPress sign-up form"),category:"widgets",attributes:{id:{type:"int"}},icon:React.createElement("svg",{width:"16",height:"16",viewBox:"0 0 16 16",version:"1.1"},React.createElement("path",{opacity:"1",fill:"#a0a5aa",fillOpacity:"1",stroke:"none",d:"M 8.0097656 0.052734375 A 8 8 0 0 0 0.009765625 8.0527344 A 8 8 0 0 0 8.0097656 16.052734 A 8 8 0 0 0 16.009766 8.0527344 A 8 8 0 0 0 8.0097656 0.052734375 z M 9.2597656 4.171875 C 9.3205456 4.171875 9.9296146 5.0233822 10.611328 6.0664062 C 11.293041 7.1094313 12.296018 8.5331666 12.841797 9.2285156 L 13.833984 10.492188 L 13.316406 11.041016 C 13.031321 11.342334 12.708299 11.587891 12.599609 11.587891 C 12.253798 11.587891 11.266634 10.490156 10.349609 9.0859375 C 9.8610009 8.3377415 9.4126385 7.7229 9.3515625 7.71875 C 9.2904825 7.71455 9.2402344 8.3477011 9.2402344 9.1269531 L 9.2402344 10.544922 L 8.5839844 10.982422 C 8.2233854 11.223015 7.8735746 11.418294 7.8066406 11.417969 C 7.7397106 11.417644 7.4861075 10.997223 7.2421875 10.482422 C 6.9982675 9.9676199 6.6560079 9.3946444 6.4824219 9.2089844 L 6.1679688 8.8710938 L 6.0664062 9.34375 C 5.7203313 10.974656 5.6693219 11.090791 5.0917969 11.505859 C 4.5805569 11.873288 4.2347982 12.017623 4.1914062 11.882812 C 4.1839062 11.859632 4.1482681 11.574497 4.1113281 11.25 C 3.9708341 10.015897 3.5347399 8.7602861 2.8105469 7.5019531 C 2.5672129 7.0791451 2.5711235 7.0651693 2.9765625 6.8320312 C 3.2046215 6.7008903 3.5466561 6.4845105 3.7363281 6.3515625 C 4.0587811 6.1255455 4.1076376 6.1466348 4.4941406 6.6679688 C 4.8138896 7.0992628 4.9275606 7.166285 4.9941406 6.96875 C 5.0960956 6.666263 6.181165 5.8574219 6.484375 5.8574219 C 6.600668 5.8574219 6.8857635 6.1981904 7.1171875 6.6152344 C 7.3486105 7.0322784 7.5790294 7.3728809 7.6308594 7.3730469 C 7.7759584 7.3735219 7.9383234 5.8938023 7.8339844 5.5195312 C 7.7605544 5.2561423 7.8865035 5.0831575 8.4453125 4.6796875 C 8.8327545 4.3999485 9.1989846 4.171875 9.2597656 4.171875 z "})),supports:{html:!1},edit:function(t){const r=o.map((e=>({label:e.name,value:e.id})));return void 0===t.attributes.id&&o.length>0&&t.setAttributes({id:o[0].id}),React.createElement("div",{style:{backgroundColor:"#f8f9f9",padding:"14px"}},React.createElement(i,{label:e("Mailchimp for WordPress Sign-up Form"),value:t.attributes.id,options:r,onChange:e=>{t.setAttributes({id:e})}}))},save:function(e){return null}})})();
...\ No newline at end of file ...\ No newline at end of file
1 (()=>{var e={1419:e=>{e.exports=function(e){const t=window.pageXOffset||document.documentElement.scrollLeft,o=function(e){const t=document.body,o=document.documentElement,n=e.getBoundingClientRect(),r=o.clientHeight,i=Math.max(t.scrollHeight,t.offsetHeight,o.clientHeight,o.scrollHeight,o.offsetHeight),c=n.bottom-r/2-n.height/2,s=i-r;return Math.min(c+window.pageYOffset,s)}(e);window.scrollTo(t,o)}}},t={};function o(n){var r=t[n];if(void 0!==r)return r.exports;var i=t[n]={exports:{}};return e[n](i,i.exports,o),i.exports}o.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},o.d=(e,t)=>{for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{"use strict";var e=o(1419),t=o.n(e);const n=window.mc4wp_submitted_form,r=window.mc4wp.forms;if(n){const e=document.getElementById(n.element_id);!function(e,o,i,c){const s=Date.now(),d=document.body.clientHeight;i&&e.setData(c),window.scrollY<=10&&n.auto_scroll&&t()(e.element),window.addEventListener("load",(function(){r.trigger("submitted",[e]),i?r.trigger("error",[e,i]):(r.trigger("success",[e,c]),r.trigger(o,[e,c]),"updated_subscriber"===o&&r.trigger("subscribed",[e,c,!0]));const l=Date.now()-s;n.auto_scroll&&l>1e3&&l<2e3&&document.body.clientHeight!==d&&t()(e.element)}))}(r.getByElement(e),n.event,n.errors,n.data)}})()})();
...\ No newline at end of file ...\ No newline at end of file
1 (()=>{var e={9885:e=>{function t(){this.listeners={}}t.prototype.emit=function(e,t){this.listeners[e]=this.listeners[e]??[],this.listeners[e].forEach((e=>e.apply(null,t)))},t.prototype.on=function(e,t){this.listeners[e]=this.listeners[e]??[],this.listeners[e].push(t)},e.exports=t},5626:()=>{function e(e){const t=!!e.getAttribute("data-show-if"),n=t?e.getAttribute("data-show-if").split(":"):e.getAttribute("data-hide-if").split(":"),r=n[0],i=(n.length>1?n[1]:"*").split("|"),o=function(e,t){const n=[],r=e.querySelectorAll('input[name="'+t+'"],select[name="'+t+'"],textarea[name="'+t+'"]');for(let e=0;e<r.length;e++)("radio"!==r[e].type&&"checkbox"!==r[e].type||r[e].checked)&&n.push(r[e].value);return n}(function(e){let t=e;for(;t.parentElement;)if(t=t.parentElement,"FORM"===t.tagName)return t;return null}(e),r);let s=!1;for(let e=0;e<o.length&&!s;e++)s=i.indexOf(o[e])>-1||i.indexOf("*")>-1&&o[e].length>0;e.style.display=t?s?"":"none":s?"none":"";const a=e.querySelectorAll("input,select,textarea");for(let e=0;e<a.length;e++)(s||t)&&a[e].getAttribute("data-was-required")&&(a[e].required=!0,a[e].removeAttribute("data-was-required")),s&&t||!a[e].required||(a[e].setAttribute("data-was-required","true"),a[e].required=!1)}function t(){const t=document.querySelectorAll(".mc4wp-form [data-show-if],.mc4wp-form [data-hide-if]");for(let n=0;n<t.length;n++)e(t[n])}function n(t){if(!t.target||!t.target.form||t.target.form.className.indexOf("mc4wp-form")<0)return;const n=t.target.form.querySelectorAll("[data-show-if],[data-hide-if]");for(let t=0;t<n.length;t++)e(n[t])}document.addEventListener("keyup",n,!0),document.addEventListener("change",n,!0),document.addEventListener("mc4wp-refresh",t,!0),window.addEventListener("load",t),t()},6942:(e,t,n)=>{const r=n(2076),i=n(6564),o=function(e,t){this.id=e,this.element=t||document.createElement("form"),this.name=this.element.getAttribute("data-name")||"Form #"+this.id,this.errors=[],this.started=!1};o.prototype.setData=function(e){try{i(this.element,e)}catch(e){console.error(e)}},o.prototype.getData=function(){return r(this.element,{hash:!0,empty:!0})},o.prototype.getSerializedData=function(){return r(this.element,{hash:!1,empty:!0})},o.prototype.setResponse=function(e){this.element.querySelector(".mc4wp-response").innerHTML=e},o.prototype.reset=function(){this.setResponse(""),this.element.querySelector(".mc4wp-form-fields").style.display="",this.element.reset()},e.exports=o},9685:(e,t,n)=>{const r=n(6942),i=[],o=new(n(9885));function s(e,t){t=t||parseInt(e.getAttribute("data-id"))||0;const n=new r(t,e);return i.push(n),n}e.exports={get:function(e){e=parseInt(e);for(let t=0;t<i.length;t++)if(i[t].id===e)return i[t];return s(document.querySelector(".mc4wp-form-"+e),e)},getByElement:function(e){const t=e.form||e;for(let e=0;e<i.length;e++)if(i[e].element===t)return i[e];return s(t)},on:function(e,t){o.on(e,t)},trigger:function(e,t){"submit"===e||e.indexOf(".submit")>0?(o.emit(t[0].id+"."+e,t),o.emit(e,t)):window.setTimeout((function(){o.emit(t[0].id+"."+e,t),o.emit(e,t)}),10)}}},2076:e=>{var t=/^(?:submit|button|image|reset|file)$/i,n=/^(?:input|select|textarea|keygen)/i,r=/(\[[^\[\]]*\])/g;function i(e,t,n){if(0===t.length)return n;var r=t.shift(),o=r.match(/^\[(.+?)\]$/);if("[]"===r)return e=e||[],Array.isArray(e)?e.push(i(null,t,n)):(e._values=e._values||[],e._values.push(i(null,t,n))),e;if(o){var s=o[1],a=+s;isNaN(a)?(e=e||{})[s]=i(e[s],t,n):(e=e||[])[a]=i(e[a],t,n)}else e[r]=i(e[r],t,n);return e}function o(e,t,n){if(t.match(r))i(e,function(e){var t=[],n=new RegExp(r),i=/^([^\[\]]*)/.exec(e);for(i[1]&&t.push(i[1]);null!==(i=n.exec(e));)t.push(i[1]);return t}(t),n);else{var o=e[t];o?(Array.isArray(o)||(e[t]=[o]),e[t].push(n)):e[t]=n}return e}function s(e,t,n){return n=n.replace(/(\r)?\n/g,"\r\n"),n=(n=encodeURIComponent(n)).replace(/%20/g,"+"),e+(e?"&":"")+encodeURIComponent(t)+"="+n}e.exports=function(e,r){"object"!=typeof r?r={hash:!!r}:void 0===r.hash&&(r.hash=!0);for(var i=r.hash?{}:"",a=r.serializer||(r.hash?o:s),c=e&&e.elements?e.elements:[],l=Object.create(null),u=0;u<c.length;++u){var f=c[u];if((r.disabled||!f.disabled)&&f.name&&n.test(f.nodeName)&&!t.test(f.type)){var d=f.name,h=f.value;if("checkbox"!==f.type&&"radio"!==f.type||f.checked||(h=void 0),r.empty){if("checkbox"!==f.type||f.checked||(h=""),"radio"===f.type&&(l[f.name]||f.checked?f.checked&&(l[f.name]=!0):l[f.name]=!1),null==h&&"radio"==f.type)continue}else if(!h)continue;if("select-multiple"!==f.type)i=a(i,d,h);else{h=[];for(var p=f.options,m=!1,g=0;g<p.length;++g){var y=p[g],v=r.empty&&!y.value,w=y.value||v;y.selected&&w&&(m=!0,i=r.hash&&"[]"!==d.slice(d.length-2)?a(i,d+"[]",y.value):a(i,d,y.value))}!m&&r.empty&&(i=a(i,d,""))}}}if(r.empty)for(var d in l)l[d]||(i=a(i,d,""));return i}},6564:e=>{e.exports&&(e.exports=function e(t,n,r){for(const i in n){if(!n.hasOwnProperty(i))continue;const o=i;let s=n[i];if(void 0===s&&(s=""),null===s&&(s=""),void 0!==r&&(o=r+"["+i+"]"),s.constructor===Array)o+="[]";else if("object"==typeof s){e(t,s,o);continue}const a=t.elements.namedItem(o);if(!a)continue;const c=a.type||a[0].type;switch(c){default:a.value=s;break;case"radio":case"checkbox":{const e=s.constructor===Array?s:[s];for(let t=0;t<a.length;t++)a[t].checked=e.indexOf(a[t].value)>-1}break;case"select-multiple":{const e=s.constructor===Array?s:[s];for(let t=0;t<a.options.length;t++)a.options[t].selected=e.indexOf(a.options[t].value)>-1}break;case"select":case"select-one":a.value=s.toString()||s;break;case"date":a.value=new Date(s).toISOString().split("T")[0]}const l=new Event("change",{bubbles:!0});switch(c){default:a.dispatchEvent(l);break;case"radio":case"checkbox":for(let e=0;e<a.length;e++)a[e].checked&&a[e].dispatchEvent(l)}}})}},t={};function n(r){var i=t[r];if(void 0!==i)return i.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,n),o.exports}const r=window.mc4wp||{},i=n(9685);function o(e,t){document.addEventListener(e,(e=>{if(!e.target)return;const n=e.target;("string"==typeof n.className&&n.className.indexOf("mc4wp-form")>-1||"function"==typeof n.matches&&n.matches(".mc4wp-form *"))&&t.call(e,e)}),!0)}n(5626),o("submit",(function(e){if(e.defaultPrevented)return;const t=i.getByElement(e.target);i.trigger("submit",[t,e])})),o("focus",(function(e){const t=i.getByElement(e.target);t.started||(i.trigger("started",[t,e]),t.started=!0)})),o("change",(function(e){const t=i.getByElement(e.target);i.trigger("change",[t,e])})),r.listeners&&([].forEach.call(r.listeners,(function(e){i.on(e.event,e.callback)})),delete r.listeners),r.forms=i,window.mc4wp=r})();
...\ No newline at end of file ...\ No newline at end of file
1 (()=>{const e=window.mc4wp_vars.ajaxurl,t=window.mc4wp.settings,n=document.getElementById("notice-additional-fields");function i(){const t=[].filter.call(document.querySelectorAll(".mc4wp-list-input"),(e=>e.checked)).map((e=>e.value)).join(","),i=["EMAIL","FNAME","NAME","LNAME"];let l=!1;window.fetch(`${e}?action=mc4wp_get_list_details&ids=${t}`).then((e=>e.json())).then((e=>{e.forEach((e=>{e.merge_fields.forEach((e=>{e.required&&i.indexOf(e.tag)<0&&(l=!0)}))}))})).finally((()=>{n.style.display=l?"":"none"}))}n&&(i(),t.on("selectedLists.change",i))})();
...\ No newline at end of file ...\ No newline at end of file
1 <?php
2
3 require __DIR__ . '/includes/functions.php';
4 require __DIR__ . '/includes/deprecated-functions.php';
5 require __DIR__ . '/includes/forms/functions.php';
6 require __DIR__ . '/includes/forms/admin-functions.php';
7 require __DIR__ . '/includes/integrations/functions.php';
8
9 // require API class manually because our classloader is case-sensitive
10 require __DIR__ . '/includes/api/class-api-v3.php';
11
12 // load other classes dynamically
13 spl_autoload_register(function ($class) {
14 static $classmap = array(
15 'MC4WP_API_Connection_Exception' => __DIR__ . '/includes/api/class-connection-exception.php',
16 'MC4WP_API_Exception' => __DIR__ . '/includes/api/class-exception.php',
17 'MC4WP_API_Resource_Not_Found_Exception' => __DIR__ . '/includes/api/class-resource-not-found-exception.php',
18 'MC4WP_API_V3' => __DIR__ . '/includes/api/class-api-v3.php',
19 'MC4WP_API_V3_Client' => __DIR__ . '/includes/api/class-api-v3-client.php',
20 'MC4WP_Admin' => __DIR__ . '/includes/admin/class-admin.php',
21 'MC4WP_Admin_Ads' => __DIR__ . '/includes/admin/class-ads.php',
22 'MC4WP_Admin_Ajax' => __DIR__ . '/includes/admin/class-admin-ajax.php',
23 'MC4WP_Admin_Messages' => __DIR__ . '/includes/admin/class-admin-messages.php',
24 'MC4WP_Admin_Review_Notice' => __DIR__ . '/includes/admin/class-review-notice.php',
25 'MC4WP_Admin_Texts' => __DIR__ . '/includes/admin/class-admin-texts.php',
26 'MC4WP_Admin_Tools' => __DIR__ . '/includes/admin/class-admin-tools.php',
27 'MC4WP_AffiliateWP_Integration' => __DIR__ . '/integrations/affiliatewp/class-affiliatewp.php',
28 'MC4WP_BuddyPress_Integration' => __DIR__ . '/integrations/buddypress/class-buddypress.php',
29 'MC4WP_Comment_Form_Integration' => __DIR__ . '/integrations/wp-comment-form/class-comment-form.php',
30 'MC4WP_Contact_Form_7_Integration' => __DIR__ . '/integrations/contact-form-7/class-contact-form-7.php',
31 'MC4WP_Container' => __DIR__ . '/includes/class-container.php',
32 'MC4WP_Custom_Integration' => __DIR__ . '/integrations/custom/class-custom.php',
33 'MC4WP_Debug_Log' => __DIR__ . '/includes/class-debug-log.php',
34 'MC4WP_Debug_Log_Reader' => __DIR__ . '/includes/class-debug-log-reader.php',
35 'MC4WP_Dynamic_Content_Tags' => __DIR__ . '/includes/class-dynamic-content-tags.php',
36 'MC4WP_Easy_Digital_Downloads_Integration' => __DIR__ . '/integrations/easy-digital-downloads/class-easy-digital-downloads.php',
37 'MC4WP_Events_Manager_Integration' => __DIR__ . '/integrations/events-manager/class-events-manager.php',
38 'MC4WP_Field_Formatter' => __DIR__ . '/includes/class-field-formatter.php',
39 'MC4WP_Field_Guesser' => __DIR__ . '/includes/class-field-guesser.php',
40 'MC4WP_Form' => __DIR__ . '/includes/forms/class-form.php',
41 'MC4WP_Form_AMP' => __DIR__ . '/includes/forms/class-form-amp.php',
42 'MC4WP_Form_Asset_Manager' => __DIR__ . '/includes/forms/class-asset-manager.php',
43 'MC4WP_Form_Element' => __DIR__ . '/includes/forms/class-form-element.php',
44 'MC4WP_Form_Listener' => __DIR__ . '/includes/forms/class-form-listener.php',
45 'MC4WP_Form_Manager' => __DIR__ . '/includes/forms/class-form-manager.php',
46 'MC4WP_Form_Notice' => __DIR__ . '/includes/forms/class-form-message.php',
47 'MC4WP_Form_Output_Manager' => __DIR__ . '/includes/forms/class-output-manager.php',
48 'MC4WP_Form_Previewer' => __DIR__ . '/includes/forms/class-form-previewer.php',
49 'MC4WP_Form_Tags' => __DIR__ . '/includes/forms/class-form-tags.php',
50 'MC4WP_Form_Widget' => __DIR__ . '/includes/forms/class-widget.php',
51 'MC4WP_Forms_Admin' => __DIR__ . '/includes/forms/class-admin.php',
52 'MC4WP_Give_Integration' => __DIR__ . '/integrations/give/class-give.php',
53 'MC4WP_Gravity_Forms_Field' => __DIR__ . '/integrations/gravity-forms/class-field.php',
54 'MC4WP_Gravity_Forms_Integration' => __DIR__ . '/integrations/gravity-forms/class-gravity-forms.php',
55 'MC4WP_Integration' => __DIR__ . '/includes/integrations/class-integration.php',
56 'MC4WP_Integration_Admin' => __DIR__ . '/includes/integrations/class-admin.php',
57 'MC4WP_Integration_Fixture' => __DIR__ . '/includes/integrations/class-integration-fixture.php',
58 'MC4WP_Integration_Manager' => __DIR__ . '/includes/integrations/class-integration-manager.php',
59 'MC4WP_Integration_Tags' => __DIR__ . '/includes/integrations/class-integration-tags.php',
60 'MC4WP_List_Data_Mapper' => __DIR__ . '/includes/class-list-data-mapper.php',
61 'MC4WP_MailChimp' => __DIR__ . '/includes/class-mailchimp.php',
62 'MC4WP_MailChimp_Subscriber' => __DIR__ . '/includes/class-mailchimp-subscriber.php',
63 'MC4WP_MemberPress_Integration' => __DIR__ . '/integrations/memberpress/class-memberpress.php',
64 'MC4WP_Ninja_Forms_Action' => __DIR__ . '/integrations/ninja-forms/class-action.php',
65 'MC4WP_Ninja_Forms_Field' => __DIR__ . '/integrations/ninja-forms/class-field.php',
66 'MC4WP_Ninja_Forms_Integration' => __DIR__ . '/integrations/ninja-forms/class-ninja-forms.php',
67 'MC4WP_Ninja_Forms_V2_Integration' => __DIR__ . '/integrations/ninja-forms-2/class-ninja-forms.php',
68 'MC4WP_Plugin' => __DIR__ . '/includes/class-plugin.php',
69 'MC4WP_Queue' => __DIR__ . '/includes/class-queue.php',
70 'MC4WP_Queue_Job' => __DIR__ . '/includes/class-queue-job.php',
71 'MC4WP_Registration_Form_Integration' => __DIR__ . '/integrations/wp-registration-form/class-registration-form.php',
72 'MC4WP_Tools' => __DIR__ . '/includes/class-tools.php',
73 'MC4WP_Upgrade_Routines' => __DIR__ . '/includes/admin/class-upgrade-routines.php',
74 'MC4WP_User_Integration' => __DIR__ . '/includes/integrations/class-user-integration.php',
75 'MC4WP_WPForms_Field' => __DIR__ . '/integrations/wpforms/class-field.php',
76 'MC4WP_WPForms_Integration' => __DIR__ . '/integrations/wpforms/class-wpforms.php',
77 'MC4WP_WooCommerce_Integration' => __DIR__ . '/integrations/woocommerce/class-woocommerce.php',
78 );
79
80 if (isset($classmap[$class])) {
81 require $classmap[$class];
82 }
83 });
1 <?php
2
3 $email_label = esc_html__('Email address', 'mailchimp-for-wp');
4 $email_placeholder_attr = esc_attr__('Your email address', 'mailchimp-for-wp');
5 $signup_button_value = esc_attr__('Sign up', 'mailchimp-for-wp');
6
7 $content = "<p>\n\t<label for=\"email\">{$email_label}: \n";
8 $content .= "\t\t<input type=\"email\" id=\"email\" name=\"EMAIL\" placeholder=\"{$email_placeholder_attr}\" required>\n</label>\n</p>\n\n";
9 $content .= "<p>\n\t<input type=\"submit\" value=\"{$signup_button_value}\">\n</p>";
10
11 return $content;
1 <?php
2
3 return array(
4 'subscribed' => array(
5 'type' => 'success',
6 'text' => esc_html__('Thank you, your sign-up request was successful! Please check your email inbox to confirm.', 'mailchimp-for-wp'),
7 ),
8 'updated' => array(
9 'type' => 'success',
10 'text' => esc_html__('Thank you, your records have been updated!', 'mailchimp-for-wp'),
11 ),
12 'unsubscribed' => array(
13 'type' => 'success',
14 'text' => esc_html__('You were successfully unsubscribed.', 'mailchimp-for-wp'),
15 ),
16 'not_subscribed' => array(
17 'type' => 'notice',
18 'text' => esc_html__('Given email address is not subscribed.', 'mailchimp-for-wp'),
19 ),
20 'error' => array(
21 'type' => 'error',
22 'text' => esc_html__('Oops. Something went wrong. Please try again later.', 'mailchimp-for-wp'),
23 ),
24 'invalid_email' => array(
25 'type' => 'error',
26 'text' => esc_html__('Please provide a valid email address.', 'mailchimp-for-wp'),
27 ),
28 'already_subscribed' => array(
29 'type' => 'notice',
30 'text' => esc_html__('Given email address is already subscribed, thank you!', 'mailchimp-for-wp'),
31 ),
32 'required_field_missing' => array(
33 'type' => 'error',
34 'text' => esc_html__('Please fill in the required fields.', 'mailchimp-for-wp'),
35 ),
36 'no_lists_selected' => array(
37 'type' => 'error',
38 'text' => esc_html__('Please select at least one list.', 'mailchimp-for-wp'),
39 ),
40 );
1 <?php
2
3 return array(
4 'css' => 0,
5 'double_optin' => 1,
6 'hide_after_success' => 0,
7 'lists' => array(),
8 'redirect' => '',
9 'replace_interests' => 1,
10 'required_fields' => '',
11 'update_existing' => 0,
12 'subscriber_tags' => '',
13 );
1 <?php
2
3 return array(
4 'api_key' => '',
5 'allow_usage_tracking' => 0,
6 'debug_log_level' => 'warning',
7 );
1 <?php
2
3 class MC4WP_Admin_Ajax
4 {
5 /**
6 * @var MC4WP_Admin_Tools
7 */
8 protected $tools;
9
10 /**
11 * MC4WP_Admin_Ajax constructor.
12 *
13 * @param MC4WP_Admin_Tools $tools
14 */
15 public function __construct(MC4WP_Admin_Tools $tools)
16 {
17 $this->tools = $tools;
18 }
19
20 /**
21 * Hook AJAX actions
22 */
23 public function add_hooks()
24 {
25 add_action('wp_ajax_mc4wp_renew_mailchimp_lists', array( $this, 'refresh_mailchimp_lists' ));
26 add_action('wp_ajax_mc4wp_get_list_details', array( $this, 'get_list_details' ));
27 }
28
29 /**
30 * Empty lists cache & fetch lists again.
31 */
32 public function refresh_mailchimp_lists()
33 {
34 if (! $this->tools->is_user_authorized()) {
35 wp_send_json_error();
36 return;
37 }
38
39 check_ajax_referer('mc4wp-ajax');
40
41 $mailchimp = new MC4WP_MailChimp();
42 $success = $mailchimp->refresh_lists();
43 wp_send_json($success);
44 }
45
46 /**
47 * Retrieve details (merge fields and interest categories) for one or multiple lists in Mailchimp
48 * @throws MC4WP_API_Exception
49 */
50 public function get_list_details()
51 {
52 if (! $this->tools->is_user_authorized()) {
53 wp_send_json_error();
54 return;
55 }
56
57 $list_ids = (array) explode(',', $_GET['ids']);
58 $data = array();
59 $mailchimp = new MC4WP_MailChimp();
60 foreach ($list_ids as $list_id) {
61 $data[] = (object) array(
62 'id' => $list_id,
63 'merge_fields' => $mailchimp->get_list_merge_fields($list_id),
64 'interest_categories' => $mailchimp->get_list_interest_categories($list_id),
65 'marketing_permissions' => $mailchimp->get_list_marketing_permissions($list_id),
66 );
67 }
68
69 if (isset($_GET['format']) && $_GET['format'] === 'html') {
70 $merge_fields = $data[0]->merge_fields;
71 $interest_categories = $data[0]->interest_categories;
72 $marketing_permissions = $data[0]->marketing_permissions;
73 require MC4WP_PLUGIN_DIR . '/includes/views/parts/lists-overview-details.php';
74 } else {
75 wp_send_json($data);
76 }
77 exit;
78 }
79 }
1 <?php
2
3 /**
4 * Class MC4WP_Admin_Messages
5 *
6 * @ignore
7 * @since 3.0
8 */
9 class MC4WP_Admin_Messages
10 {
11 /**
12 * @var array
13 */
14 protected $bag;
15
16 /**
17 * @var bool
18 */
19 protected $dirty = false;
20
21 /**
22 * Add hooks
23 */
24 public function add_hooks()
25 {
26 add_action('admin_notices', array( $this, 'show' ));
27 register_shutdown_function(array( $this, 'save' ));
28 }
29
30 private function load()
31 {
32 if (is_null($this->bag)) {
33 $this->bag = get_option('mc4wp_flash_messages', array());
34 }
35 }
36
37 // empty flash bag
38 private function reset()
39 {
40 $this->bag = array();
41 $this->dirty = true;
42 }
43
44 /**
45 * Flash a message (shows on next pageload)
46 *
47 * @param $message
48 * @param string $type
49 */
50 public function flash($message, $type = 'success')
51 {
52 $this->load();
53 $this->bag[] = array(
54 'text' => $message,
55 'type' => $type,
56 );
57 $this->dirty = true;
58 }
59
60
61
62 /**
63 * Show queued flash messages
64 */
65 public function show()
66 {
67 $this->load();
68
69 foreach ($this->bag as $message) {
70 echo sprintf('<div class="notice notice-%s is-dismissible"><p>%s</p></div>', $message['type'], $message['text']);
71 }
72
73 $this->reset();
74 }
75
76 /**
77 * Save queued messages
78 *
79 * @hooked `shutdown`
80 */
81 public function save()
82 {
83 if ($this->dirty) {
84 update_option('mc4wp_flash_messages', $this->bag, false);
85 }
86 }
87 }
1 <?php
2
3 /**
4 * Class MC4WP_Admin_Texts
5 *
6 * @ignore
7 * @since 3.0
8 */
9 class MC4WP_Admin_Texts
10 {
11 /**
12 * @var string
13 */
14 protected $plugin_file;
15
16 /**
17 * @param string $plugin_file
18 */
19 public function __construct($plugin_file)
20 {
21 $this->plugin_file = $plugin_file;
22 }
23
24 /**
25 * Add hooks
26 */
27 public function add_hooks()
28 {
29 global $pagenow;
30
31 add_filter('admin_footer_text', array( $this, 'footer_text' ));
32
33 // Hooks for Plugins overview page
34 if ($pagenow === 'plugins.php') {
35 add_filter('plugin_action_links_' . $this->plugin_file, array( $this, 'add_plugin_settings_link' ), 10, 2);
36 add_filter('plugin_row_meta', array( $this, 'add_plugin_meta_links' ), 10, 2);
37 }
38 }
39
40 /**
41 * Ask for a plugin review in the WP Admin footer, if this is one of the plugin pages.
42 *
43 * @param string $text
44 *
45 * @return string
46 */
47 public function footer_text($text)
48 {
49 if (! empty($_GET['page']) && strpos($_GET['page'], 'mailchimp-for-wp') === 0) {
50 $text = sprintf('If you enjoy using <strong>Mailchimp for WordPress</strong>, please <a href="%s" target="_blank">leave us a ★★★★★ plugin review on WordPress.org</a>.', 'https://wordpress.org/support/plugin/mailchimp-for-wp/reviews/#new-post');
51 }
52
53 return $text;
54 }
55
56 /**
57 * Add the settings link to the Plugins overview
58 *
59 * @param array $links
60 * @param $file
61 *
62 * @return array
63 */
64 public function add_plugin_settings_link($links, $file)
65 {
66 if ($file !== $this->plugin_file) {
67 return $links;
68 }
69
70 $settings_link = sprintf('<a href="%s">%s</a>', admin_url('admin.php?page=mailchimp-for-wp'), esc_html__('Settings', 'mailchimp-for-wp'));
71 array_unshift($links, $settings_link);
72 return $links;
73 }
74
75 /**
76 * Adds meta links to the plugin in the WP Admin > Plugins screen
77 *
78 * @param array $links
79 * @param string $file
80 *
81 * @return array
82 */
83 public function add_plugin_meta_links($links, $file)
84 {
85 if ($file !== $this->plugin_file) {
86 return $links;
87 }
88
89 $links[] = '<a href="https://www.mc4wp.com/kb/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=plugins-page">' . esc_html__('Documentation', 'mailchimp-for-wp') . '</a>';
90
91 /**
92 * Filters meta links shown on the Plugins overview page
93 *
94 * This takes an array of strings
95 *
96 * @since 3.0
97 * @param array $links
98 * @ignore
99 */
100 $links = apply_filters('mc4wp_admin_plugin_meta_links', $links);
101
102 return $links;
103 }
104 }
1 <?php
2
3 class MC4WP_Admin_Tools
4 {
5 /**
6 * @return string
7 */
8 public function get_plugin_page()
9 {
10 if (empty($_GET['page'])) {
11 return '';
12 }
13
14 $prefix = 'mailchimp-for-wp';
15 $page = ltrim(substr($_GET['page'], strlen($prefix)), '-');
16 return $page;
17 }
18
19 /**
20 * @param string $page
21 *
22 * @return bool
23 */
24 public function on_plugin_page($page = null)
25 {
26 // any settings page
27 if (is_null($page)) {
28 return isset($_GET['page']) && strpos($_GET['page'], 'mailchimp-for-wp') === 0;
29 }
30
31 // specific page
32 return $this->get_plugin_page() === $page;
33 }
34
35 /**
36 * Does the logged-in user have the required capability?
37 *
38 * @return bool
39 */
40 public function is_user_authorized()
41 {
42 return current_user_can($this->get_required_capability());
43 }
44
45 /**
46 * Get required capability to access settings page and view dashboard widgets.
47 *
48 * @return string
49 */
50 public function get_required_capability()
51 {
52 $capability = 'manage_options';
53
54 /**
55 * Filters the required user capability to access the Mailchimp for WordPress' settings pages, view the dashboard widgets.
56 *
57 * Defaults to `manage_options`
58 *
59 * @since 3.0
60 * @param string $capability
61 * @see https://codex.wordpress.org/Roles_and_Capabilities
62 */
63 $capability = (string) apply_filters('mc4wp_admin_required_capability', $capability);
64
65 return $capability;
66 }
67 }
1 <?php
2
3 /**
4 * Class MC4WP_Admin_Ads
5 *
6 * @ignore
7 * @access private
8 */
9 class MC4WP_Admin_Ads
10 {
11 /**
12 * @return bool Adds hooks
13 */
14 public function add_hooks()
15 {
16
17 // don't hook if Premium is activated
18 if (defined('MC4WP_PREMIUM_VERSION')) {
19 return false;
20 }
21
22 add_filter('mc4wp_admin_plugin_meta_links', array( $this, 'plugin_meta_links' ));
23 add_action('mc4wp_admin_form_after_behaviour_settings_rows', array( $this, 'after_form_settings_rows' ));
24 add_action('mc4wp_admin_form_after_appearance_settings_rows', array( $this, 'after_form_appearance_settings_rows' ));
25 add_action('mc4wp_admin_sidebar', array( $this, 'admin_sidebar' ));
26 add_action('mc4wp_admin_footer', array( $this, 'admin_footer' ));
27 add_action('mc4wp_admin_other_settings', array( $this, 'ecommerce' ), 90);
28
29 add_filter('mc4wp_admin_menu_items', array( $this, 'add_menu_item' ));
30
31 add_action('mc4wp_admin_after_woocommerce_integration_settings', array( $this, 'ecommerce' ));
32 return true;
33 }
34
35 public function add_menu_item($items)
36 {
37 $items['extensions'] = array(
38 'title' => __('Add-ons', 'mailchimp-for-wp'),
39 'text' => __('Add-ons', 'mailchimp-for-wp'),
40 'slug' => 'extensions',
41 'callback' => array( $this, 'show_extensions_page' ),
42 'position' => 100,
43 );
44
45 return $items;
46 }
47
48 /**
49 * Add text row to "Form > Appearance" tab.
50 */
51 public function after_form_appearance_settings_rows()
52 {
53 echo '<tr>';
54 echo '<td colspan="2">';
55 echo '<p class="description">';
56 echo sprintf(__('Want to customize the style of your form? <a href="%s">Try our Styles Builder</a> & edit the look of your forms with just a few clicks.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=form-settings-link');
57 echo '</p>';
58 echo '</td>';
59 echo '</tr>';
60 }
61
62 /**
63 * Add text row to "Form > Settings" tab.
64 */
65 public function after_form_settings_rows()
66 {
67 echo '<tr>';
68 echo '<td colspan="2">';
69 echo '<p class="description">';
70
71 if (rand(1, 2) === 1) {
72 echo sprintf(__('Be notified whenever someone subscribes? <a href="%s">Mailchimp for WordPress Premium</a> allows you to set up email notifications for your forms.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=footer-link');
73 } else {
74 echo sprintf(__('Increased conversions? <a href="%s">Mailchimp for WordPress Premium</a> submits forms without reloading the entire page, resulting in a much better experience for your visitors.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=form-settings-link');
75 }
76
77 echo '</p>';
78 echo '</td>';
79 echo '</tr>';
80 }
81
82 /**
83 * @param array $links
84 *
85 * @return array
86 */
87 public function plugin_meta_links($links)
88 {
89 $links[] = '<a href="https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=plugins-upgrade-link">' . __('Upgrade to Premium', 'mailchimp-for-wp') . '</a>';
90 return $links;
91 }
92
93 /**
94 * Add several texts to admin footer.
95 */
96 public function admin_footer()
97 {
98 if (isset($_GET['view']) && $_GET['view'] === 'edit-form') {
99 // WPML & Polylang specific message
100 if (defined('ICL_LANGUAGE_CODE')) {
101 echo '<p class="description">' . sprintf(__('Do you want translated forms for all of your languages? <a href="%s">Try Mailchimp for WordPress Premium</a>, which does just that plus more.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=footer-link') . '</p>';
102 return;
103 }
104
105 // General "edit form" message
106 echo '<p class="description">' . sprintf(__('Do you want to create more than one form? Our Premium add-on does just that! <a href="%s">Have a look at all Premium benefits</a>.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=footer-link') . '</p>';
107 return;
108 }
109
110 // General message
111 echo '<p class="description">' . sprintf(__('Are you enjoying this plugin? The Premium add-on unlocks several powerful features. <a href="%s">Find out about all benefits now</a>.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=footer-link') . '</p>';
112 }
113
114 /**
115 * Add email opt-in form to sidebar
116 */
117 public function admin_sidebar()
118 {
119 echo '<style>.mc4wp-premium-box {
120 background: #fff8c5;
121 border: 1px solid #d4a72c66;
122 padding: 1em;
123 }</style>';
124 echo '<div class="mc4wp-box">';
125 echo '<div class="mc4wp-premium-box">';
126 echo '<h3>Mailchimp for WordPress Premium</h3>';
127 echo '<p>';
128 echo 'You are currently using the free version of Mailchimp for WordPress. ';
129 echo '</p>';
130 echo '<p>';
131 echo 'There is a Premium version of this plugin that adds several powerful features. Like multiple and improved sign-up forms, an easier way to visually enhance those forms, advanced e-commerce integration and keeping track of all sign-up attempts in your local WordPress database.';
132 echo '</p>';
133 echo '<p>You can have all those benefits for a small yearly fee. <a href="https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=upgrade-box">Take a look at Mailchimp for WordPress Premium here</a>.</p>';
134 echo '</div>';
135 echo '</div>';
136 }
137
138 /**
139 * Show notice about E-Commerce integration in Premium.
140 */
141 public function ecommerce()
142 {
143 // detect whether WooCommerce is installed & activated.
144 if (! class_exists('WooCommerce')) {
145 return;
146 }
147
148 echo '<div class="mc4wp-margin-m">';
149 echo '<h3>Advanced WooCommerce integration for Mailchimp</h3>';
150 echo '<p>';
151 echo __('Do you want to track all WooCommerce orders in Mailchimp so you can send emails based on the purchase activity of your subscribers?', 'mailchimp-for-wp');
152 echo '</p>';
153 echo '<p>';
154 echo sprintf(__('<a href="%1$s">Upgrade to Mailchimp for WordPress Premium</a> or <a href="%2$s">read more about Mailchimp\'s E-Commerce features</a>.', 'mailchimp-for-wp') . '</p>', 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=other-settings-link', 'https://www.mc4wp.com/kb/what-is-ecommerce360/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=other-settings-link');
155 echo '</p>';
156 echo '</div>';
157 }
158
159 public function show_extensions_page()
160 {
161 require MC4WP_PLUGIN_DIR . '/includes/views/extensions.php';
162 }
163 }
1 <?php
2
3 /**
4 * Class MC4WP_Admin_Review_Notice
5 *
6 * @ignore
7 */
8 class MC4WP_Admin_Review_Notice
9 {
10 /**
11 * @var MC4WP_Admin_Tools
12 */
13 protected $tools;
14
15 /**
16 * @var string
17 */
18 protected $meta_key_dismissed = '_mc4wp_review_notice_dismissed';
19
20 /**
21 * MC4WP_Admin_Review_Notice constructor.
22 *
23 * @param MC4WP_Admin_Tools $tools
24 */
25 public function __construct(MC4WP_Admin_Tools $tools)
26 {
27 $this->tools = $tools;
28 }
29
30 /**
31 * Add action & filter hooks.
32 */
33 public function add_hooks()
34 {
35 add_action('admin_notices', array( $this, 'show' ));
36 add_action('mc4wp_admin_dismiss_review_notice', array( $this, 'dismiss' ));
37 }
38
39 /**
40 * Set flag in user meta so notice won't be shown.
41 */
42 public function dismiss()
43 {
44 $user = wp_get_current_user();
45 update_user_meta($user->ID, $this->meta_key_dismissed, 1);
46 }
47
48 /**
49 * @return bool
50 */
51 public function show()
52 {
53 // only show on Mailchimp for WordPress' pages.
54 if (! $this->tools->on_plugin_page()) {
55 return false;
56 }
57
58 // only show if 2 weeks have passed since first use.
59 $two_weeks_in_seconds = ( 60 * 60 * 24 * 14 );
60 if ($this->time_since_first_use() <= $two_weeks_in_seconds) {
61 return false;
62 }
63
64 // only show if user did not dismiss before
65 $user = wp_get_current_user();
66 if (get_user_meta($user->ID, $this->meta_key_dismissed, true)) {
67 return false;
68 }
69
70 echo '<div class="notice notice-info mc4wp-is-dismissible" id="mc4wp-review-notice">';
71 echo '<p>';
72 echo esc_html__('You\'ve been using Mailchimp for WordPress for some time now; we hope you love it!', 'mailchimp-for-wp'), ' <br />';
73 echo sprintf(wp_kses(__('If you do, please <a href="%s">leave us a 5★ rating on WordPress.org</a>. It would be of great help to us.', 'mailchimp-for-wp'), array( 'a' => array( 'href' => array() ) )), 'https://wordpress.org/support/view/plugin-reviews/mailchimp-for-wp?rate=5#new-post');
74 echo '</p>';
75 echo '<form method="POST" id="mc4wp-dismiss-review-form"><button type="submit" class="notice-dismiss"><span class="screen-reader-text">', esc_html__('Dismiss this notice.', 'mailchimp-for-wp'), '</span></button><input type="hidden" name="_mc4wp_action" value="dismiss_review_notice" />', wp_nonce_field('_mc4wp_action', '_wpnonce', true, false), '</form>';
76 echo '</div>';
77 return true;
78 }
79
80 /**
81 * @return int
82 */
83 private function time_since_first_use()
84 {
85 $options = get_option('mc4wp', array());
86 if (! is_array($options)) {
87 $options = array();
88 }
89
90 // option was never added before, do it now.
91 if (empty($options['first_activated_on'])) {
92 $options['first_activated_on'] = time();
93 update_option('mc4wp', $options);
94 }
95
96 return time() - $options['first_activated_on'];
97 }
98 }
1 <?php
2
3 /**
4 * Class MC4WP_DB_Upgrader
5 *
6 * This class takes care of loading migration files from the specified migrations directory.
7 * Migration files should only use default WP functions and NOT use code which might not be there in the future.
8 *
9 * @ignore
10 */
11 class MC4WP_Upgrade_Routines
12 {
13 /**
14 * @var float
15 */
16 protected $version_from = 0;
17
18 /**
19 * @var float
20 */
21 protected $version_to = 0;
22
23 /**
24 * @var string
25 */
26 protected $migrations_dir = '';
27
28 /**
29 * @param float $from
30 * @param float $to
31 */
32 public function __construct($from, $to, $migrations_dir)
33 {
34 $this->version_from = $from;
35 $this->version_to = $to;
36 $this->migrations_dir = $migrations_dir;
37 }
38
39 /**
40 * Run the various upgrade routines, all the way up to the latest version
41 */
42 public function run()
43 {
44 $migrations = $this->find_migrations();
45
46 // run in sub-function for scope
47 array_map(array( $this, 'run_migration' ), $migrations);
48 }
49
50 /**
51 * @return array
52 */
53 public function find_migrations()
54 {
55 $files = glob(rtrim($this->migrations_dir, '/') . '/*.php');
56 $migrations = array();
57
58 // return empty array when glob returns non-array value.
59 if (! is_array($files)) {
60 return $migrations;
61 }
62
63 foreach ($files as $file) {
64 $migration = basename($file);
65 $parts = explode('-', $migration);
66 $version = $parts[0];
67
68 if (version_compare($this->version_from, $version, '<')) {
69 $migrations[] = $file;
70 }
71 }
72
73 return $migrations;
74 }
75
76 /**
77 * Include a migration file and runs it.
78 *
79 * @param string $file
80 */
81 protected function run_migration($file)
82 {
83 include $file;
84 }
85 }
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 // get options
6 $form_options = get_option('mc4wp_lite_form', array());
7
8 // bail if there are no previous options
9 if (empty($form_options)) {
10 return;
11 }
12
13 // bail if there are Pro forms already
14 $has_forms = get_posts(
15 array(
16 'post_type' => 'mc4wp-form',
17 'post_status' => 'publish',
18 'numberposts' => 1,
19 )
20 );
21
22 // There are forms already, don't continue.
23 if (! empty($has_forms)) {
24 // delete option as it apparently exists.
25 delete_option('mc4wp_lite_form');
26 return;
27 }
28
29 // create post type for form
30 $id = wp_insert_post(
31 array(
32 'post_type' => 'mc4wp-form',
33 'post_status' => 'publish',
34 'post_title' => __('Default sign-up form', 'mailchimp-for-wp'),
35 'post_content' => ( empty($form_options['markup']) ) ? '' : $form_options['markup'],
36 )
37 );
38
39 // set default_form_id
40 update_option('mc4wp_default_form_id', $id);
41
42 // set form settings
43 $setting_keys = array(
44 'css',
45 'custom_theme_color',
46 'double_optin',
47 'update_existing',
48 'replace_interests',
49 'send_welcome',
50 'redirect',
51 'hide_after_success',
52 );
53
54 $settings = array();
55
56 foreach ($setting_keys as $setting_key) {
57 // use isset to account for "0" settings
58 if (isset($form_options[ $setting_key ])) {
59 $settings[ $setting_key ] = $form_options[ $setting_key ];
60 }
61 }
62
63 // get only keys of lists setting
64 if (isset($form_options['lists'])) {
65 $settings['lists'] = array_keys($form_options['lists']);
66 }
67
68 update_post_meta($id, '_mc4wp_settings', $settings);
69
70 // set form message texts
71 $message_keys = array(
72 'text_subscribed',
73 'text_error',
74 'text_invalid_email',
75 'text_already_subscribed',
76 'text_required_field_missing',
77 'text_unsubscribed',
78 'text_not_subscribed',
79 );
80
81 foreach ($message_keys as $message_key) {
82 if (! empty($form_options[ $message_key ])) {
83 update_post_meta($id, $message_key, $form_options[ $message_key ]);
84 }
85 }
86
87 // delete old option
88 delete_option('mc4wp_lite_form');
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 $global_options = (array) get_option('mc4wp_form', array());
6
7 // find all form posts
8 $posts = get_posts(
9 array(
10 'post_type' => 'mc4wp-form',
11 'post_status' => 'publish',
12 'numberposts' => -1,
13 )
14 );
15
16 $css_map = array(
17 'default' => 'basic',
18 'custom' => 'styles-builder',
19 'light' => 'theme-light',
20 'dark' => 'theme-dark',
21 'red' => 'theme-red',
22 'green' => 'theme-green',
23 'blue' => 'theme-blue',
24 'custom-color' => 'theme-custom-color',
25 );
26
27 $stylesheets = array();
28
29 foreach ($posts as $post) {
30 // get form options from post meta directly
31 $options = (array) get_post_meta($post->ID, '_mc4wp_settings', true);
32
33 // store all global options in scoped form settings
34 // do this BEFORE changing css key, so we take that as well.
35 foreach ($global_options as $key => $value) {
36 if (strlen($value) > 0 && ( ! isset($options[ $key ]) || strlen($options[ $key ]) == 0 )) {
37 $options[ $key ] = $value;
38 }
39 }
40
41 // update "css" option value
42 if (isset($options['css']) && isset($css_map[ $options['css'] ])) {
43 $options['css'] = $css_map[ $options['css'] ];
44 }
45
46 // create stylesheets option
47 if (! empty($options['css'])) {
48 $stylesheet = $options['css'];
49 if (strpos($stylesheet, 'theme-') === 0) {
50 $stylesheet = 'themes';
51 }
52
53 if (! in_array($stylesheet, $stylesheets)) {
54 $stylesheets[] = $stylesheet;
55 }
56 }
57
58 update_post_meta($post->ID, '_mc4wp_settings', $options);
59 }
60
61 // update stylesheets option
62 update_option('mc4wp_form_stylesheets', $stylesheets);
63
64 // delete old options
65 delete_option('mc4wp_form');
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 // find all form posts
6 $posts = get_posts(
7 array(
8 'post_type' => 'mc4wp-form',
9 'post_status' => 'publish',
10 'numberposts' => -1,
11 )
12 );
13
14 // set form message texts
15 $message_keys = array(
16 'text_subscribed',
17 'text_error',
18 'text_invalid_email',
19 'text_already_subscribed',
20 'text_required_field_missing',
21 'text_unsubscribed',
22 'text_not_subscribed',
23 );
24
25 foreach ($posts as $post) {
26 $settings = get_post_meta($post->ID, '_mc4wp_settings', true);
27
28 foreach ($message_keys as $key) {
29 if (empty($settings[ $key ])) {
30 continue;
31 }
32
33 $message = $settings[ $key ];
34
35 // move message setting over to post meta
36 update_post_meta($post->ID, $key, $message);
37 unset($settings[ $key ]);
38 }
39
40 // update post meta with unset message keys
41 update_post_meta($post->ID, '_mc4wp_settings', $settings);
42 }
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 // transfer option
6 $options = (array) get_option('mc4wp_lite', array());
7
8 // merge options, with Pro options taking precedence
9 $pro_options = (array) get_option('mc4wp', array());
10 $options = array_merge($options, $pro_options);
11
12 // update options
13 update_option('mc4wp', $options);
14
15 // delete old option
16 delete_option('mc4wp_lite');
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 $old_options = get_option('mc4wp_lite_checkbox', array());
6 $pro_options = get_option('mc4wp_checkbox', array());
7 if (! empty($pro_options)) {
8 $old_options = array_merge($old_options, $pro_options);
9 }
10
11 // do we have to do something?
12 if (empty($old_options)) {
13 return;
14 }
15
16 // find activated integrations (show_at_xxx options)
17 $new_options = array();
18 $map = array(
19 'comment_form' => 'wp-comment-form',
20 'registration_form' => 'wp-registration-form',
21 'buddypress_form' => 'buddypress',
22 'bbpres_forms' => 'bbpress',
23 'woocommerce_checkout' => 'woocommerce',
24 'edd_checkout' => 'easy-digital-downloads',
25 );
26
27 $option_keys = array(
28 'label',
29 'precheck',
30 'css',
31 'lists',
32 'double_optin',
33 'update_existing',
34 'replace_interests',
35 'send_welcome',
36 );
37
38 foreach ($map as $old_integration_slug => $new_integration_slug) {
39 // check if integration is enabled using its old slug
40 $show_key = sprintf('show_at_%s', $old_integration_slug);
41 if (empty($old_options[ $show_key ])) {
42 continue;
43 }
44
45 $options = array(
46 'enabled' => 1,
47 );
48
49 foreach ($option_keys as $option_key) {
50 if (isset($old_options[ $option_key ])) {
51 $options[ $option_key ] = $old_options[ $option_key ];
52 }
53 }
54
55 // add to new options
56 $new_options[ $new_integration_slug ] = $options;
57 }
58
59 // save new settings
60 update_option('mc4wp_integrations', $new_options);
61
62 // delete old options
63 delete_option('mc4wp_lite_checkbox');
64 delete_option('mc4wp_checkbox');
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 // move stylebuilders file to bundle
6 $file = (string) get_option('mc4wp_custom_css_file', '');
7 if (empty($file)) {
8 return;
9 }
10
11 $uploads = wp_upload_dir();
12
13 // figure out absolute file path
14 $prefix = str_replace('http:', '', $uploads['baseurl']);
15 $relative_path = str_replace($prefix, '', $file);
16
17 // get part before ?
18 if (strpos($relative_path, '?') !== false) {
19 $parts = explode('?', $relative_path);
20 $relative_path = array_shift($parts);
21 }
22
23 // This is the absolute path to the file, he he..
24 $file = $uploads['basedir'] . $relative_path;
25
26 if (file_exists($file)) {
27 // create directory, if necessary
28 $dir = $uploads['basedir'] . '/mc4wp-stylesheets';
29 if (! file_exists($dir)) {
30 @mkdir($dir, 0755);
31 }
32
33 @chmod($dir, 0755);
34
35 // Move file to new location
36 $new_file = $dir . '/bundle.css';
37 $success = rename($file, $new_file);
38 }
39
40 // remove old option
41 delete_option('mc4wp_custom_css_file');
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 $section_widgets = get_option('sidebars_widgets', array());
6 $replaced = false;
7
8 foreach ($section_widgets as $section => $widgets) {
9 // WP has an "array_version" key that is not an array...
10 if (! is_array($widgets)) {
11 continue;
12 }
13
14 // loop through widget ID's
15 foreach ($widgets as $key => $widget_id) {
16 // does this widget ID start with "mc4wp_widget"?
17 if (strpos($widget_id, 'mc4wp_widget') === 0) {
18 // replace "mc4wp_widget" with "mc4wp_form_widget"
19 $new_widget_id = str_replace('mc4wp_widget', 'mc4wp_form_widget', $widget_id);
20 $section_widgets[ $section ][ $key ] = $new_widget_id;
21 $replaced = true;
22 }
23 }
24 }
25
26
27 // update option if we made changes
28 if ($replaced) {
29 update_option('sidebars_widgets', $section_widgets);
30 }
31
32 // update widget options
33 $options = get_option('widget_mc4wp_widget', false);
34 if ($options) {
35 update_option('widget_mc4wp_form_widget', $options);
36
37 // delete old option
38 delete_option('widget_mc4wp_widget');
39 }
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 $options = get_option('mc4wp_integrations', array());
6
7 if (! empty($options['woocommerce']) && ! empty($options['woocommerce']['position'])) {
8 $options['woocommerce']['position'] = sprintf('checkout_%s', $options['woocommerce']['position']);
9 }
10
11 update_option('mc4wp_integrations', $options);
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 /**
6 * @ignore
7 * @return object
8 */
9 function _mc4wp_400_find_grouping_for_interest_category($groupings, $interest_category)
10 {
11 foreach ($groupings as $grouping) {
12 // cast to stdClass because of missing class
13 $grouping = (object) (array) $grouping;
14
15 if ($grouping->name === $interest_category->title) {
16 return $grouping;
17 }
18 }
19
20 return null;
21 }
22
23 /**
24 * @ignore
25 * @return object
26 */
27 function _mc4wp_400_find_group_for_interest($groups, $interest)
28 {
29 foreach ($groups as $group_id => $group_name) {
30 if ($group_name === $interest->name) {
31 return (object) array(
32 'name' => $group_name,
33 'id' => $group_id,
34 );
35 }
36 }
37
38 return null;
39 }
40
41 // in case the migration is _very_ late to the party
42 if (! class_exists('MC4WP_API_V3')) {
43 return;
44 }
45
46 $options = get_option('mc4wp', array());
47 if (empty($options['api_key'])) {
48 return;
49 }
50
51 // get current state from transient
52 $lists = get_transient('mc4wp_mailchimp_lists_fallback');
53 if (empty($lists)) {
54 return;
55 }
56
57 @set_time_limit(600);
58 $api_v3 = new MC4WP_API_V3($options['api_key']);
59 $map = array();
60
61 foreach ($lists as $list) {
62 // cast to stdClass because of missing classes
63 $list = (object) (array) $list;
64
65 // no groupings? easy!
66 if (empty($list->groupings)) {
67 continue;
68 }
69
70 // fetch (new) interest categories for this list
71 try {
72 $interest_categories = $api_v3->get_list_interest_categories($list->id);
73 } catch (MC4WP_API_Exception $e) {
74 continue;
75 }
76
77
78 foreach ($interest_categories as $interest_category) {
79 // compare interest title with grouping name, if it matches, get new id.
80 $grouping = _mc4wp_400_find_grouping_for_interest_category($list->groupings, $interest_category);
81 if (! $grouping) {
82 continue;
83 }
84
85 $groups = array();
86
87 try {
88 $interests = $api_v3->get_list_interest_category_interests($list->id, $interest_category->id);
89 } catch (MC4WP_API_Exception $e) {
90 continue;
91 }
92
93 foreach ($interests as $interest) {
94 $group = _mc4wp_400_find_group_for_interest($grouping->groups, $interest);
95
96 if ($group) {
97 $groups[ $group->id ] = $interest->id;
98 $groups[ $group->name ] = $interest->id;
99 }
100 }
101
102 $map[ (string) $grouping->id ] = array(
103 'id' => $interest_category->id,
104 'groups' => $groups,
105 );
106 }
107 }
108
109
110 if (! empty($map)) {
111 update_option('mc4wp_groupings_map', $map);
112 }
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 /** @ignore */
6 function _mc4wp_400_replace_comma_with_pipe($matches)
7 {
8 $old = $matches[1];
9 $new = str_replace(',', '|', $old);
10 return str_replace($old, $new, $matches[0]);
11 }
12
13 // get all forms
14 $posts = get_posts(
15 array(
16 'post_type' => 'mc4wp-form',
17 'numberposts' => -1,
18 )
19 );
20
21 foreach ($posts as $post) {
22 // find hidden field values in form and pass through replace function
23 $old = $post->post_content;
24 $new = preg_replace_callback('/type="hidden" .* value="(.*)"/i', '_mc4wp_400_replace_comma_with_pipe', $old);
25
26 // update post if we replaced something
27 if ($new != $old) {
28 $post->post_content = $new;
29 wp_update_post($post);
30 }
31 }
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 // get old log filename
6 $upload_dir = wp_upload_dir(null, false);
7 $old_filename = trailingslashit($upload_dir['basedir']) . 'mc4wp-debug.log';
8 $new_filename = trailingslashit($upload_dir['basedir']) . 'mc4wp-debug-log.php';
9
10 // check if old default log file exists
11 if (! file_exists($old_filename)) {
12 return;
13 }
14
15 // rename to new file.
16 @rename($old_filename, $new_filename);
17
18 // if success, insert php exit tag as first line
19 if (file_exists($new_filename)) {
20 $handle = fopen($new_filename, 'r+');
21
22 if (is_resource($handle)) {
23 // make sure first line of log file is a PHP tag + exit statement (to prevent direct file access)
24 $line = fgets($handle);
25 $php_exit_string = '<?php exit; ?>';
26 if (strpos($line, $php_exit_string) !== 0) {
27 rewind($handle);
28 fwrite($handle, $php_exit_string . PHP_EOL . $line);
29 }
30
31 fclose($handle);
32 }
33 }
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 if (function_exists('mc4wp_refresh_mailchimp_lists')) {
6 mc4wp_refresh_mailchimp_lists();
7 }
8
9 delete_transient('mc4wp_mailchimp_lists_v3');
10 delete_option('mc4wp_mailchimp_lists_v3_fallback');
11
12 wp_schedule_event(strtotime('tomorrow 3 am'), 'daily', 'mc4wp_refresh_mailchimp_lists');
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 wp_clear_scheduled_hook('mc4wp_refresh_mailchimp_lists');
6
7 $time_string = sprintf('tomorrow %d:%d%d am', rand(1, 6), rand(0, 5), rand(0, 9));
8 wp_schedule_event(strtotime($time_string), 'daily', 'mc4wp_refresh_mailchimp_lists');
1 <?php
2
3 global $wpdb;
4 $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE 'mc4wp_mailchimp_list_%'");
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 // get old filename
6 $upload_dir = wp_upload_dir(null, false);
7 $old_filename = trailingslashit($upload_dir['basedir']) . 'mc4wp-debug-log.php';
8
9 // if old file exists, move it to new location
10 if (is_file($old_filename)) {
11 $new_filename = $upload_dir['basedir'] . '/mailchimp-for-wp/debug-log.php';
12 $dir = dirname($new_filename);
13 if (! is_dir($dir)) {
14 mkdir($dir, 0755, true);
15 }
16
17 rename($old_filename, $new_filename);
18 }
1 <?php
2
3 class MC4WP_API_V3_Client
4 {
5 /**
6 * @var string
7 */
8 private $api_key;
9
10 /**
11 * @var string
12 */
13 private $api_url = 'https://api.mailchimp.com/3.0/';
14
15 /**
16 * @var array
17 */
18 private $last_response;
19
20 /**
21 * @var array
22 */
23 private $last_request;
24
25 /**
26 * Constructor
27 *
28 * @param string $api_key
29 */
30 public function __construct($api_key)
31 {
32 $this->api_key = $api_key;
33
34 $dash_position = strpos($api_key, '-');
35 if ($dash_position !== false) {
36 $this->api_url = str_replace('//api.', '//' . substr($api_key, $dash_position + 1) . '.api.', $this->api_url);
37 }
38 }
39
40
41 /**
42 * @param string $resource
43 * @param array $args
44 *
45 * @return mixed
46 * @throws MC4WP_API_Exception
47 */
48 public function get($resource, array $args = array())
49 {
50 return $this->request('GET', $resource, $args);
51 }
52
53 /**
54 * @param string $resource
55 * @param array $data
56 *
57 * @return mixed
58 * @throws MC4WP_API_Exception
59 */
60 public function post($resource, array $data)
61 {
62 return $this->request('POST', $resource, $data);
63 }
64
65 /**
66 * @param string $resource
67 * @param array $data
68 * @return mixed
69 * @throws MC4WP_API_Exception
70 */
71 public function put($resource, array $data)
72 {
73 return $this->request('PUT', $resource, $data);
74 }
75
76 /**
77 * @param string $resource
78 * @param array $data
79 * @return mixed
80 * @throws MC4WP_API_Exception
81 */
82 public function patch($resource, array $data)
83 {
84 return $this->request('PATCH', $resource, $data);
85 }
86
87 /**
88 * @param string $resource
89 * @return mixed
90 * @throws MC4WP_API_Exception
91 */
92 public function delete($resource)
93 {
94 return $this->request('DELETE', $resource);
95 }
96
97 /**
98 * @param string $method
99 * @param string $resource
100 * @param array $data
101 *
102 * @return mixed
103 *
104 * @throws MC4WP_API_Exception
105 */
106 private function request($method, $resource, array $data = array())
107 {
108 $this->reset();
109
110 // don't bother if no API key was given.
111 if (empty($this->api_key)) {
112 throw new MC4WP_API_Exception('Missing API key', 001);
113 }
114
115 $method = strtoupper(trim($method));
116 $url = $this->api_url . ltrim($resource, '/');
117 $args = array(
118 'method' => $method,
119 'headers' => $this->get_headers(),
120 'timeout' => 20,
121 'sslverify' => apply_filters('mc4wp_use_sslverify', true),
122 );
123
124 if (! empty($data)) {
125 if (in_array($method, array( 'GET', 'DELETE' ), true)) {
126 $url = add_query_arg($data, $url);
127 } else {
128 $args['headers']['Content-Type'] = 'application/json';
129 $args['body'] = json_encode($data);
130 }
131 }
132
133 /**
134 * Filter the request arguments for all requests generated by this class
135 *
136 * @param array $args
137 */
138 $args = apply_filters('mc4wp_http_request_args', $args, $url);
139
140 // perform request
141 $response = wp_remote_request($url, $args);
142
143 // store request & response
144 $args['url'] = $url;
145 $this->last_request = $args;
146 $this->last_response = $response;
147
148 // parse response
149 $data = $this->parse_response($response);
150
151 return $data;
152 }
153
154 /**
155 * @return array
156 */
157 private function get_headers()
158 {
159 global $wp_version;
160
161 $headers = array(
162 'Authorization' => sprintf('Basic %s', base64_encode('mc4wp:' . $this->api_key)),
163 'User-Agent' => sprintf('mc4wp/%s; WordPress/%s; %s', MC4WP_VERSION, $wp_version, home_url()),
164 );
165
166 // Copy Accept-Language from browser headers
167 if (! empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
168 $headers['Accept-Language'] = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
169 }
170
171 return $headers;
172 }
173
174 /**
175 * @param array|WP_Error $response
176 *
177 * @return mixed
178 *
179 * @throws MC4WP_API_Connection_Exception|MC4WP_API_Resource_Not_Found_Exception|MC4WP_API_Exception
180 */
181 private function parse_response($response)
182 {
183 if ($response instanceof WP_Error) {
184 throw new MC4WP_API_Connection_Exception($response->get_error_message(), (int) $response->get_error_code(), $this->last_request);
185 }
186
187 // decode response body
188 $code = (int) wp_remote_retrieve_response_code($response);
189 $message = wp_remote_retrieve_response_message($response);
190 $body = wp_remote_retrieve_body($response);
191
192 // set body to "true" in case Mailchimp returned No Content
193 if ($code < 300 && empty($body)) {
194 $body = 'true';
195 }
196
197 $data = json_decode($body);
198 if ($code >= 400) {
199 // check for akamai errors
200 // {"type":"akamai_error_message","title":"akamai_503","status":503,"ref_no":"Reference Number: 00.950e16c3.1498559813.1450dbe2"}
201 if (is_object($data) && isset($data->type) && $data->type === 'akamai_error_message') {
202 throw new MC4WP_API_Connection_Exception($message, $code, $this->last_request, $this->last_response, $data);
203 }
204
205 if ($code === 404) {
206 throw new MC4WP_API_Resource_Not_Found_Exception($message, $code, $this->last_request, $this->last_response, $data);
207 }
208
209 // mailchimp returned an error..
210 throw new MC4WP_API_Exception($message, $code, $this->last_request, $this->last_response, $data);
211 }
212
213 // throw exception if unable to decode response
214 if ($data === null) {
215 throw new MC4WP_API_Exception($message, $code, $this->last_request, $this->last_response);
216 }
217
218 return $data;
219 }
220
221 /**
222 * Empties all data from previous response
223 */
224 private function reset()
225 {
226 $this->last_response = null;
227 $this->last_request = null;
228 }
229
230 /**
231 * @return string
232 */
233 public function get_last_response_body()
234 {
235 return wp_remote_retrieve_body($this->last_response);
236 }
237
238 /**
239 * @return array
240 */
241 public function get_last_response_headers()
242 {
243 return wp_remote_retrieve_headers($this->last_response);
244 }
245
246 /**
247 * @return array|WP_Error
248 */
249 public function get_last_response()
250 {
251 return $this->last_response;
252 }
253 }
1 <?php
2
3 class MC4WP_API_Connection_Exception extends MC4WP_API_Exception
4 {
5 }
1 <?php
2
3 /**
4 * Class MC4WP_API_Exception
5 *
6 * @property string $title
7 * @property string $detail
8 * @property array $errors
9 */
10 class MC4WP_API_Exception extends Exception
11 {
12 /**
13 * @var object
14 */
15 public $response = array();
16
17 /**
18 * @var object
19 */
20 public $request = array();
21
22 /**
23 * @var array
24 */
25 public $response_data = array();
26
27 /**
28 * MC4WP_API_Exception constructor.
29 *
30 * @param string $message
31 * @param int $code
32 * @param array $request
33 * @param array $response
34 * @param object $data
35 */
36 public function __construct($message, $code, $request = null, $response = null, $data = null)
37 {
38 parent::__construct($message, $code);
39
40 $this->request = $request;
41 $this->response = $response;
42
43 $this->response_data = $data;
44 }
45
46 /**
47 * Backwards compatibility for direct property access.
48 * @param string $property
49 * @return mixed
50 */
51 public function __get($property)
52 {
53 if (in_array($property, array( 'title', 'detail', 'errors' ), true)) {
54 if (! empty($this->response_data) && isset($this->response_data->{$property})) {
55 return $this->response_data->{$property};
56 }
57
58 return '';
59 }
60 }
61
62 /**
63 * @return string
64 */
65 public function __toString()
66 {
67 $string = $this->message . '.';
68
69 // add errors from response data returned by Mailchimp
70 if (! empty($this->response_data)) {
71 if (! empty($this->response_data->title) && $this->response_data->title !== $this->getMessage()) {
72 $string .= ' ' . $this->response_data->title . '.';
73 }
74
75 // add detail message
76 if (! empty($this->response_data->detail)) {
77 $string .= ' ' . $this->response_data->detail;
78 }
79
80 // add field specific errors
81 if (! empty($this->response_data->errors) && isset($this->response_data->errors[0]->field)) {
82 // strip off obsolete msg
83 $string = str_replace('For field-specific details, see the \'errors\' array.', '', $string);
84
85 // generate list of field errors
86 $field_errors = array();
87 foreach ($this->response_data->errors as $error) {
88 if (! empty($error->field)) {
89 $field_errors[] = sprintf('- %s : %s', $error->field, $error->message);
90 } else {
91 $field_errors[] = sprintf('- %s', $error->message);
92 }
93 }
94
95 $string .= " \n" . join("\n", $field_errors);
96 }
97 }
98
99 // Add request data
100 if (! empty($this->request) && is_array($this->request)) {
101 $string .= "\n\n" . sprintf("Request: \n%s %s\n", $this->request['method'], $this->request['url']);
102
103 // foreach ( $this->request['headers'] as $key => $value ) {
104 // $string .= sprintf( "%s: %s\n", $key, $value );
105 // }
106
107 if (! empty($this->request['body'])) {
108 $string .= "\n" . $this->request['body'];
109 }
110 }
111
112 // Add response data
113 if (! empty($this->response) && is_array($this->response)) {
114 $response_code = wp_remote_retrieve_response_code($this->response);
115 $response_message = wp_remote_retrieve_response_message($this->response);
116 $response_body = wp_remote_retrieve_body($this->response);
117 $string .= "\n\n" . sprintf("Response: \n%d %s\n%s", $response_code, $response_message, $response_body);
118 }
119
120 return $string;
121 }
122 }
1 <?php
2
3 class MC4WP_API_Resource_Not_Found_Exception extends MC4WP_API_Exception
4 {
5 // Thrown when a requested resource does not exist in Mailchimp
6 }
1 <?php
2
3 /**
4 * Class MC4WP_Service_Container
5 *
6 * @access private
7 * @ignore
8 */
9 class MC4WP_Container implements ArrayAccess
10 {
11 /**
12 * @var array
13 */
14 protected $services = array();
15
16 /**
17 * @var array
18 */
19 protected $resolved_services = array();
20
21 /**
22 * @param string $name
23 * @return boolean
24 */
25 public function has($name)
26 {
27 return isset($this->services[ $name ]);
28 }
29
30 /**
31 * @param string $name
32 *
33 * @return mixed
34 * @throws Exception
35 */
36 public function get($name)
37 {
38 if (! $this->has($name)) {
39 throw new Exception(sprintf('No service named %s was registered.', $name));
40 }
41
42 $service = $this->services[ $name ];
43
44 // is this a resolvable service?
45 if (is_callable($service)) {
46 // resolve service if it's not resolved yet
47 if (! isset($this->resolved_services[ $name ])) {
48 $this->resolved_services[ $name ] = call_user_func($service);
49 }
50
51 return $this->resolved_services[ $name ];
52 }
53
54 return $this->services[ $name ];
55 }
56
57 /**
58 * (PHP 5 &gt;= 5.0.0)<br/>
59 * Whether a offset exists
60 * @link http://php.net/manual/en/arrayaccess.offsetexists.php
61 *
62 * @param mixed $offset <p>
63 * An offset to check for.
64 * </p>
65 *
66 * @return boolean true on success or false on failure.
67 * </p>
68 * <p>
69 * The return value will be casted to boolean if non-boolean was returned.
70 */
71 #[\ReturnTypeWillChange]
72 public function offsetExists($offset)
73 {
74 return $this->has($offset);
75 }
76
77 /**
78 * (PHP 5 &gt;= 5.0.0)<br/>
79 * Offset to retrieve
80 * @link http://php.net/manual/en/arrayaccess.offsetget.php
81 *
82 * @param mixed $offset <p>
83 * The offset to retrieve.
84 * </p>
85 *
86 * @return mixed Can return all value types.
87 */
88 #[\ReturnTypeWillChange]
89 public function offsetGet($offset)
90 {
91 return $this->get($offset);
92 }
93
94 /**
95 * (PHP 5 &gt;= 5.0.0)<br/>
96 * Offset to set
97 * @link http://php.net/manual/en/arrayaccess.offsetset.php
98 *
99 * @param mixed $offset <p>
100 * The offset to assign the value to.
101 * </p>
102 * @param mixed $value <p>
103 * The value to set.
104 * </p>
105 *
106 * @return void
107 */
108 #[\ReturnTypeWillChange]
109 public function offsetSet($offset, $value)
110 {
111 $this->services[ $offset ] = $value;
112 }
113
114 /**
115 * (PHP 5 &gt;= 5.0.0)<br/>
116 * Offset to unset
117 * @link http://php.net/manual/en/arrayaccess.offsetunset.php
118 *
119 * @param mixed $offset <p>
120 * The offset to unset.
121 * </p>
122 *
123 * @return void
124 */
125 #[\ReturnTypeWillChange]
126 public function offsetUnset($offset)
127 {
128 unset($this->services[ $offset ]);
129 }
130 }
1 <?php
2
3 /**
4 * Class MC4WP_Debug_Log_Reader
5 */
6 class MC4WP_Debug_Log_Reader
7 {
8 /**
9 * @var resource|null
10 */
11 private $handle;
12
13 /**
14 * @var string
15 */
16 private static $regex = '/^(\[[\d \-\:]+\]) (\w+\:) (.*)$/S';
17
18 /**
19 * @var string
20 */
21 private static $html_template = '<span class="time">$1</span> <span class="level">$2</span> <span class="message">$3</span>';
22
23 /**
24 * @var string The log file location.
25 */
26 private $file;
27
28 /**
29 * MC4WP_Debug_Log_Reader constructor.
30 *
31 * @param $file
32 */
33 public function __construct($file)
34 {
35 $this->file = $file;
36 }
37
38 /**
39 * @return string
40 */
41 public function all()
42 {
43 return file_get_contents($this->file);
44 }
45
46 /**
47 * Sets file pointer to $n of lines from the end of file.
48 *
49 * @param int $n
50 */
51 private function seek_line_from_end($n)
52 {
53 $line_count = 0;
54
55 // get line count
56 while (! feof($this->handle)) {
57 fgets($this->handle);
58 ++$line_count;
59 }
60
61 // rewind to beginning
62 rewind($this->handle);
63
64 // calculate target
65 $target = $line_count - $n;
66 $target = $target > 1 ? $target : 1; // always skip first line because oh PHP header
67 $current = 0;
68
69 // keep reading until we're at target
70 while ($current < $target) {
71 fgets($this->handle);
72 ++$current;
73 }
74 }
75
76 /**
77 * @return string|null
78 */
79 public function read()
80 {
81
82 // open file if not yet opened
83 if (! is_resource($this->handle)) {
84 // doesn't exist?
85 if (! file_exists($this->file)) {
86 return null;
87 }
88
89 $this->handle = @fopen($this->file, 'r');
90
91 // unable to read?
92 if (! is_resource($this->handle)) {
93 return null;
94 }
95
96 // set pointer to 1000 files from EOF
97 $this->seek_line_from_end(1000);
98 }
99
100 // stop reading once we're at the end
101 if (feof($this->handle)) {
102 fclose($this->handle);
103 $this->handle = null;
104 return null;
105 }
106
107 // read line, up to 8kb
108 $text = fgets($this->handle);
109
110 // strip tags & trim
111 $text = strip_tags($text);
112 $text = trim($text);
113
114 return $text;
115 }
116
117 /**
118 * @return string
119 */
120 public function read_as_html()
121 {
122 $line = $this->read();
123
124 // null means end of file
125 if (is_null($line)) {
126 return null;
127 }
128
129 // empty string means empty line, but not yet eof
130 if (empty($line)) {
131 return '';
132 }
133
134 $line = preg_replace(self::$regex, self::$html_template, $line);
135 return $line;
136 }
137
138 /**
139 * Reads X number of lines.
140 *
141 * If $start is negative, reads from end of log file.
142 *
143 * @param int $start
144 * @param int $number
145 * @return string
146 */
147 public function lines($start, $number)
148 {
149 $handle = fopen($start, 'r');
150 $lines = '';
151
152 $current_line = 0;
153 while ($current_line < $number) {
154 $lines .= fgets($handle);
155 }
156
157 fclose($handle);
158 return $lines;
159 }
160 }
1 <?php
2
3 /**
4 * Class MC4WP_Debug_Log
5 *
6 * Simple logging class which writes to a file, loosely based on PSR-3.
7 */
8 class MC4WP_Debug_Log
9 {
10 /**
11 * Detailed debug information
12 */
13 const DEBUG = 100;
14
15 /**
16 * Interesting events
17 *
18 * Examples: Visitor subscribed
19 */
20 const INFO = 200;
21
22 /**
23 * Exceptional occurrences that are not errors
24 *
25 * Examples: User already subscribed
26 */
27 const WARNING = 300;
28
29 /**
30 * Runtime errors
31 */
32 const ERROR = 400;
33
34 /**
35 * Logging levels from syslog protocol defined in RFC 5424
36 *
37 * @var array $levels Logging levels
38 */
39 protected static $levels = array(
40 self::DEBUG => 'DEBUG',
41 self::INFO => 'INFO',
42 self::WARNING => 'WARNING',
43 self::ERROR => 'ERROR',
44 );
45
46 /**
47 * @var string The file to which messages should be written.
48 */
49 public $file;
50
51 /**
52 * @var int Only write messages with this level or higher
53 */
54 public $level;
55
56 /**
57 * @var resource
58 */
59 protected $stream;
60
61 /**
62 * MC4WP_Debug_Log constructor.
63 *
64 * @param string $file
65 * @param mixed $level;
66 */
67 public function __construct($file, $level = self::DEBUG)
68 {
69 $this->file = $file;
70 $this->level = self::to_level($level);
71 }
72
73 /**
74 * @param mixed $level
75 * @param string $message
76 * @return boolean
77 */
78 public function log($level, $message)
79 {
80 $level = self::to_level($level);
81
82 // only log if message level is higher than log level
83 if ($level < $this->level) {
84 return false;
85 }
86
87 // obfuscate email addresses in log message since log might be public.
88 $message = mc4wp_obfuscate_email_addresses((string) $message);
89
90 // first, get rid of everything between "invisible" tags
91 $message = preg_replace('/<(?:style|script|head)>.+?<\/(?:style|script|head)>/is', '', $message);
92
93 // then, strip tags (while retaining content of these tags)
94 $message = strip_tags($message);
95 $message = trim($message);
96
97 /**
98 * Modifies the message that is written to the debug log.
99 * Return an empty string to skip logging this message altogether.
100 *
101 * @param string $message
102 */
103 $message = apply_filters('mc4wp_debug_log_message', $message);
104 if (empty($message)) {
105 return false;
106 }
107
108 // generate line
109 $level_name = self::get_level_name($level);
110 $datetime = gmdate('Y-m-d H:i:s', time() + ( get_option('gmt_offset', 0) * HOUR_IN_SECONDS ));
111 $message = sprintf('[%s] %s: %s', $datetime, $level_name, $message) . PHP_EOL;
112
113 // did we open stream yet?
114 if (! is_resource($this->stream)) {
115 // attempt to open stream
116 $this->stream = @fopen($this->file, 'c+');
117 if (! is_resource($this->stream)) {
118 return false;
119 }
120
121 // make sure first line of log file is a PHP tag + exit statement (to prevent direct file access)
122 $line = fgets($this->stream);
123 $php_exit_string = '<?php exit; ?>';
124 if (strpos($line, $php_exit_string) !== 0) {
125 rewind($this->stream);
126 fwrite($this->stream, $php_exit_string . PHP_EOL . $line);
127 }
128
129 // place pointer at end of file
130 fseek($this->stream, 0, SEEK_END);
131 }
132
133 // lock file while we write, ignore errors (not much we can do)
134 flock($this->stream, LOCK_EX);
135
136 // write the message to the file
137 fwrite($this->stream, $message);
138
139 // unlock file again, but don't close it for remainder of this request
140 flock($this->stream, LOCK_UN);
141
142 return true;
143 }
144
145 /**
146 * @param string $message
147 * @return boolean
148 */
149 public function warning($message)
150 {
151 return $this->log(self::WARNING, $message);
152 }
153
154 /**
155 * @param string $message
156 * @return boolean
157 */
158 public function info($message)
159 {
160 return $this->log(self::INFO, $message);
161 }
162
163 /**
164 * @param string $message
165 * @return boolean
166 */
167 public function error($message)
168 {
169 return $this->log(self::ERROR, $message);
170 }
171
172 /**
173 * @param string $message
174 * @return boolean
175 */
176 public function debug($message)
177 {
178 return $this->log(self::DEBUG, $message);
179 }
180
181 /**
182 * Converts PSR-3 levels to local ones if necessary
183 *
184 * @param string|int Level number or name (PSR-3)
185 * @return int
186 */
187 public static function to_level($level)
188 {
189 if (is_string($level)) {
190 $level = strtoupper($level);
191 if (defined(__CLASS__ . '::' . $level)) {
192 return constant(__CLASS__ . '::' . $level);
193 }
194
195 throw new InvalidArgumentException('Level "' . $level . '" is not defined, use one of: ' . implode(', ', array_keys(self::$levels)));
196 }
197
198 return $level;
199 }
200
201 /**
202 * Gets the name of the logging level.
203 *
204 * @param int $level
205 * @return string
206 */
207 public static function get_level_name($level)
208 {
209 if (! isset(self::$levels[ $level ])) {
210 throw new InvalidArgumentException('Level "' . $level . '" is not defined, use one of: ' . implode(', ', array_keys(self::$levels)));
211 }
212
213 return self::$levels[ $level ];
214 }
215
216 /**
217 * Tests if the log file is writable
218 *
219 * @return bool
220 */
221 public function test()
222 {
223 $handle = @fopen($this->file, 'a');
224 $writable = false;
225
226 if (is_resource($handle)) {
227 $writable = true;
228 fclose($handle);
229 }
230
231 return $writable;
232 }
233 }
1 <?php
2
3 /**
4 * Class MC4WP_Dynamic_Content_Tags
5 *
6 * @access private
7 * @ignore
8 */
9 abstract class MC4WP_Dynamic_Content_Tags
10 {
11 /**
12 * @var string The escape function for replacement values.
13 */
14 protected $escape_function = null;
15
16 /**
17 * @var array Array of registered dynamic content tags
18 */
19 protected $tags = array();
20
21 /**
22 * Register template tags
23 */
24 protected function register()
25 {
26 // Global tags can go here
27 $this->tags['cookie'] = array(
28 'description' => sprintf(__('Data from a cookie.', 'mailchimp-for-wp')),
29 'callback' => array( $this, 'get_cookie' ),
30 'example' => "cookie name='my_cookie' default='Default Value'",
31 );
32
33 $this->tags['email'] = array(
34 'description' => __('The email address of the current visitor (if known).', 'mailchimp-for-wp'),
35 'callback' => array( $this, 'get_email' ),
36 );
37
38 $this->tags['current_url'] = array(
39 'description' => __('The URL of the page.', 'mailchimp-for-wp'),
40 'callback' => 'mc4wp_get_request_url',
41 );
42
43 $this->tags['current_path'] = array(
44 'description' => __('The path of the page.', 'mailchimp-for-wp'),
45 'callback' => 'mc4wp_get_request_path',
46 );
47
48 $this->tags['date'] = array(
49 'description' => sprintf(__('The current date. Example: %s.', 'mailchimp-for-wp'), '<strong>' . gmdate('Y/m/d', time() + ( get_option('gmt_offset') * HOUR_IN_SECONDS )) . '</strong>'),
50 'replacement' => gmdate('Y/m/d', time() + ( get_option('gmt_offset') * HOUR_IN_SECONDS )),
51 );
52
53 $this->tags['time'] = array(
54 'description' => sprintf(__('The current time. Example: %s.', 'mailchimp-for-wp'), '<strong>' . gmdate('H:i:s', time() + ( get_option('gmt_offset') * HOUR_IN_SECONDS )) . '</strong>'),
55 'replacement' => gmdate('H:i:s', time() + ( get_option('gmt_offset') * HOUR_IN_SECONDS )),
56 );
57
58 $this->tags['language'] = array(
59 'description' => sprintf(__('The site\'s language. Example: %s.', 'mailchimp-for-wp'), '<strong>' . get_locale() . '</strong>'),
60 'callback' => 'get_locale',
61 );
62
63 $this->tags['ip'] = array(
64 'description' => sprintf(__('The visitor\'s IP address. Example: %s.', 'mailchimp-for-wp'), '<strong>' . mc4wp_get_request_ip_address() . '</strong>'),
65 'callback' => 'mc4wp_get_request_ip_address',
66 );
67
68 $this->tags['user'] = array(
69 'description' => sprintf(__('The property of the currently logged-in user.', 'mailchimp-for-wp')),
70 'callback' => array( $this, 'get_user_property' ),
71 'example' => "user property='user_email'",
72 );
73
74 $this->tags['post'] = array(
75 'description' => sprintf(__('Property of the current page or post.', 'mailchimp-for-wp')),
76 'callback' => array( $this, 'get_post_property' ),
77 'example' => "post property='ID'",
78 );
79 }
80
81 /**
82 * @return array
83 */
84 public function all()
85 {
86 if ($this->tags === array()) {
87 $this->register();
88 }
89
90 return $this->tags;
91 }
92
93 /**
94 * @param array $matches
95 *
96 * @return string
97 */
98 protected function replace_tag(array $matches)
99 {
100 $tags = $this->all();
101 $tag = $matches[1];
102
103 if (isset($tags[ $tag ])) {
104 $config = $tags[ $tag ];
105 $replacement = '';
106
107 if (isset($config['replacement'])) {
108 $replacement = $config['replacement'];
109 } elseif (isset($config['callback'])) {
110 // parse attributes
111 $attributes = array();
112 if (isset($matches[2])) {
113 $attribute_string = $matches[2];
114 $attributes = shortcode_parse_atts($attribute_string);
115 }
116
117 // call function
118 $replacement = call_user_func($config['callback'], $attributes);
119 }
120
121 if (is_callable($this->escape_function)) {
122 $replacement = call_user_func($this->escape_function, $replacement);
123 }
124
125 return $replacement;
126 }
127
128 // default to not replacing it
129 return $matches[0];
130 }
131
132 /**
133 * @param string $string The string containing dynamic content tags.
134 * @param string $escape_function Escape mode for the replacement value. Leave empty for no escaping.
135 * @return string
136 */
137 protected function replace($string, $escape_function = '')
138 {
139 $this->escape_function = $escape_function;
140
141 // replace strings like this: {tagname attr="value"}
142 $string = preg_replace_callback('/\{(\w+)(\ +(?:(?!\{)[^}\n])+)*\}/', array( $this, 'replace_tag' ), $string);
143
144 // call again to take care of nested variables
145 $string = preg_replace_callback('/\{(\w+)(\ +(?:(?!\{)[^}\n])+)*\}/', array( $this, 'replace_tag' ), $string);
146 return $string;
147 }
148
149 /**
150 * @param string $string
151 *
152 * @return string
153 */
154 protected function replace_in_html($string)
155 {
156 return $this->replace($string, 'esc_html');
157 }
158
159 /**
160 * @param string $string
161 *
162 * @return string
163 */
164 protected function replace_in_attributes($string)
165 {
166 return $this->replace($string, 'esc_attr');
167 }
168
169 /**
170 * @param string $string
171 *
172 * @return string
173 */
174 protected function replace_in_url($string)
175 {
176 return $this->replace($string, 'urlencode');
177 }
178
179 /**
180 * Gets data variable from cookie.
181 *
182 * @param array $args
183 *
184 * @return string
185 */
186 protected function get_cookie($args = array())
187 {
188 if (empty($args['name'])) {
189 return '';
190 }
191
192 $name = $args['name'];
193 $default = isset($args['default']) ? $args['default'] : '';
194
195 if (isset($_COOKIE[ $name ])) {
196 return esc_html(stripslashes($_COOKIE[ $name ]));
197 }
198
199 return $default;
200 }
201
202 /*
203 * Get property of currently logged-in user
204 *
205 * @param array $args
206 *
207 * @return string
208 */
209 protected function get_user_property($args = array())
210 {
211 $property = empty($args['property']) ? 'user_email' : $args['property'];
212 $default = isset($args['default']) ? $args['default'] : '';
213 $user = wp_get_current_user();
214
215 if ($user instanceof WP_User && isset($user->{$property})) {
216 return esc_html($user->{$property});
217 }
218
219 return $default;
220 }
221
222 /*
223 * Get property of viewed post
224 *
225 * @param array $args
226 *
227 * @return string
228 */
229 protected function get_post_property($args = array())
230 {
231 global $post;
232 $property = empty($args['property']) ? 'ID' : $args['property'];
233 $default = isset($args['default']) ? $args['default'] : '';
234
235 if ($post instanceof WP_Post && isset($post->{$property})) {
236 return $post->{$property};
237 }
238
239 return $default;
240 }
241
242 /**
243 * @return string
244 */
245 protected function get_email()
246 {
247 if (! empty($_REQUEST['EMAIL'])) {
248 return strip_tags($_REQUEST['EMAIL']);
249 }
250
251 // then , try logged-in user
252 if (is_user_logged_in()) {
253 $user = wp_get_current_user();
254 return $user->user_email;
255 }
256
257 // TODO: Read from cookie? Or add $_COOKIE support to {data} tag?
258 return '';
259 }
260 }
1 <?php
2
3 /**
4 * Class MC4WP_Field_Formatter
5 *
6 * Formats values based on what the Mailchimp API expects or accepts for the given field types.
7 */
8 class MC4WP_Field_Formatter
9 {
10 /**
11 * @param mixed $value
12 * @param object $options
13 * @return array
14 */
15 public function address($value, $options = null)
16 {
17 // auto-format if this is a string
18 if (is_string($value)) {
19 // addr1, addr2, city, state, zip, country
20 $address_pieces = explode(',', $value);
21 $address_pieces = array_filter($address_pieces);
22 $address_pieces = array_values($address_pieces);
23
24 // try to fill it.... this is a long shot
25 $value = array(
26 'addr1' => $address_pieces[0],
27 'city' => isset($address_pieces[1]) ? $address_pieces[1] : '',
28 'state' => isset($address_pieces[2]) ? $address_pieces[2] : '',
29 'zip' => isset($address_pieces[3]) ? $address_pieces[3] : '',
30 );
31
32 if (! empty($address_pieces[4])) {
33 $value['country'] = $address_pieces[4];
34 }
35 } elseif (is_array($value)) {
36 // merge with array of empty defaults to allow skipping certain fields
37 $default = array_fill_keys(array( 'addr1', 'city', 'state', 'zip' ), '');
38 $value = array_merge($default, $value);
39 }
40
41 return $value;
42 }
43
44 /**
45 * @param mixed $value
46 * @param object $options
47 * @return string
48 */
49 public function birthday($value, $options = null)
50 {
51 $format = is_object($options) && isset($options->date_format) ? $options->date_format : 'MM/DD';
52
53 if (is_array($value)) {
54 // allow for "day" and "month" fields
55 if (isset($value['month']) && isset($value['day'])) {
56 $value = $value['month'] . '/' . $value['day'];
57 } else {
58 // if other array, just join together
59 $value = join('/', $value);
60 }
61 }
62
63 $value = trim($value);
64 if (empty($value)) {
65 return $value;
66 }
67
68 // always use slashes as delimiter, so next part works
69 $value = str_replace(array( '.', '-' ), '/', $value);
70
71 // if format = DD/MM OR if first part is definitely a day value (>12), then flip order
72 // this allows `strtotime` to understand `dd/mm` values
73 $values = explode('/', $value);
74 if ($format === 'DD/MM' || ( $values[0] > 12 && $values[0] <= 31 && isset($values[1]) && $values[1] <= 12 )) {
75 $values = array_reverse($values);
76 $value = join('/', $values);
77 }
78
79 // Mailchimp expects a MM/DD format, regardless of their display preference
80 $value = (string) gmdate('m/d', strtotime($value));
81 return $value;
82 }
83
84 /**
85 * @param mixed $value
86 * @param object $options
87 * @return string
88 */
89 public function date($value, $options = null)
90 {
91 if (is_array($value)) {
92 // allow for "year", "month" and "day" keys
93 if (isset($value['year']) && isset($value['month']) && isset($value['day'])) {
94 $value = $value['year'] . '/' . $value['month'] . '/' . $value['day'];
95 } else {
96 // if other array, just join together
97 $value = join('/', $value);
98 }
99 }
100
101 $value = trim($value);
102 if (empty($value)) {
103 return $value;
104 }
105
106 // Mailchimp expects a Y-m-d format no matter the display preference
107 return (string) gmdate('Y-m-d', strtotime($value));
108 }
109
110 /**
111 * @param string $value
112 * @param object $options
113 * @return string
114 */
115 public function language($value, $options = null)
116 {
117 $value = trim($value);
118
119 $exceptions = array(
120 'pt_PT',
121 'es_ES',
122 'fr_CA',
123 );
124
125 if (! in_array($value, $exceptions, true)) {
126 $value = substr($value, 0, 2);
127 }
128
129 return $value;
130 }
131
132 /**
133 * @param mixed $value
134 * @param object $options
135 * @return bool
136 */
137 public function boolean($value, $options = null)
138 {
139 $falsey = array( 'false', '0' );
140
141 if (in_array($value, $falsey, true)) {
142 return false;
143 }
144
145 // otherwise, just cast.
146 return (bool) $value;
147 }
148 }
1 <?php
2
3 /**
4 * Class MC4WP_Field_Guesser
5 *
6 * @access private
7 * @ignore
8 */
9 class MC4WP_Field_Guesser
10 {
11 /**
12 * @var array
13 */
14 protected $fields;
15
16 /**
17 * @param array $fields
18 */
19 public function __construct(array $fields)
20 {
21 $fields = array_change_key_case($fields, CASE_UPPER);
22 $this->fields = $fields;
23 }
24
25 /**
26 * Get all data which is namespaced with a given namespace
27 *
28 * @param string $namespace
29 *
30 * @return array
31 */
32 public function namespaced($namespace = 'mc4wp-')
33 {
34 $prefix = strtoupper($namespace);
35 $return = array();
36 $length = strlen($prefix);
37
38 foreach ($this->fields as $key => $value) {
39 if (strpos($key, $prefix) === 0) {
40 $new_key = substr($key, $length);
41 $return[ $new_key ] = $value;
42 }
43 }
44
45 return $return;
46 }
47
48 /**
49 * Guess values for the following fields
50 * - EMAIL
51 * - NAME
52 * - FNAME
53 * - LNAME
54 *
55 * @return array
56 */
57 public function guessed()
58 {
59 $guessed = array();
60
61 foreach ($this->fields as $field => $value) {
62 // transform value into array to support 1-level arrays
63 $sub_fields = is_array($value) ? $value : array( $value );
64
65 foreach ($sub_fields as $sub_field_value) {
66 // poor man's urldecode, to get Enfold theme's contact element to work.
67 $sub_field_value = str_replace('%40', '@', $sub_field_value);
68
69 // is this an email value? if so, assume it's the EMAIL field
70 if (empty($guessed['EMAIL']) && is_string($sub_field_value) && is_email($sub_field_value)) {
71 $guessed['EMAIL'] = $sub_field_value;
72 continue 2;
73 }
74
75 // remove special characters from field name
76 $simple_key = str_replace(array( '-', '_', ' ' ), '', $field);
77
78 if (empty($guessed['FNAME']) && $this->string_contains($simple_key, array( 'FIRSTNAME', 'FNAME', 'GIVENNAME', 'FORENAME' ))) {
79 // find first name field
80 $guessed['FNAME'] = $sub_field_value;
81 } elseif (empty($guessed['LNAME']) && $this->string_contains($simple_key, array( 'LASTNAME', 'LNAME', 'SURNAME', 'FAMILYNAME' ))) {
82 // find last name field
83 $guessed['LNAME'] = $sub_field_value;
84 } elseif (empty($guessed['NAME']) && $this->string_contains($simple_key, 'NAME')) {
85 // find name field
86 $guessed['NAME'] = $sub_field_value;
87 }
88 }
89 }
90
91 return $guessed;
92 }
93
94 /**
95 * @param $methods
96 *
97 * @return array
98 */
99 public function combine(array $methods)
100 {
101 $combined = array();
102
103 foreach ($methods as $method) {
104 if (method_exists($this, $method)) {
105 $combined = array_merge($combined, call_user_func(array( $this, $method )));
106 }
107 }
108
109 return $combined;
110 }
111
112 /**
113 * @param string $haystack
114 * @param string|array $needles
115 *
116 * @return bool
117 */
118 private function string_contains($haystack, $needles)
119 {
120 if (! is_array($needles)) {
121 $needles = array( $needles );
122 }
123
124 foreach ($needles as $needle) {
125 if (strpos($haystack, $needle) !== false) {
126 return true;
127 }
128 }
129
130 return false;
131 }
132 }
1 <?php
2
3 /**
4 * Class MC4WP_Field_Map
5 *
6 * @access private
7 * @since 4.0
8 * @ignore
9 */
10 class MC4WP_List_Data_Mapper
11 {
12 /**
13 * @var array
14 */
15 private $data = array();
16
17 /**
18 * @var array
19 */
20 private $list_ids = array();
21
22 /**
23 * @var MC4WP_Field_Formatter
24 */
25 private $formatter;
26
27 /**
28 * @var MC4WP_MailChimp
29 */
30 private $mailchimp;
31
32 /**
33 * @param array $data
34 * @param array $list_ids
35 */
36 public function __construct(array $data, array $list_ids)
37 {
38 $this->data = array_change_key_case($data, CASE_UPPER);
39 if (! isset($this->data['EMAIL'])) {
40 throw new InvalidArgumentException('Data needs at least an EMAIL key.');
41 }
42
43 $this->list_ids = $list_ids;
44 $this->formatter = new MC4WP_Field_Formatter();
45 $this->mailchimp = new MC4WP_MailChimp();
46 }
47
48 /**
49 * @return MC4WP_MailChimp_Subscriber[]
50 */
51 public function map()
52 {
53 $map = array();
54
55 foreach ($this->list_ids as $list_id) {
56 $map[ "$list_id" ] = $this->map_list($list_id);
57 }
58
59 return $map;
60 }
61
62 /**
63 * @param string $list_id
64 * @return MC4WP_MailChimp_Subscriber
65 * @throws Exception
66 */
67 protected function map_list($list_id)
68 {
69 $subscriber = new MC4WP_MailChimp_Subscriber();
70 $subscriber->email_address = $this->data['EMAIL'];
71
72 // find merge fields
73 $merge_fields = $this->mailchimp->get_list_merge_fields($list_id);
74 foreach ($merge_fields as $merge_field) {
75 // skip EMAIL field as that is handled separately (see above)
76 if ($merge_field->tag === 'EMAIL') {
77 continue;
78 }
79
80 // use empty() here to skip empty field values
81 if (empty($this->data[ $merge_field->tag ])) {
82 continue;
83 }
84
85 // format field value
86 $value = $this->data[ $merge_field->tag ];
87 $value = $this->format_merge_field_value($merge_field, $value);
88
89 // add to map
90 $subscriber->merge_fields[ $merge_field->tag ] = $value;
91 }
92
93 // find interest categories
94 if (! empty($this->data['INTERESTS'])) {
95 $interest_categories = $this->mailchimp->get_list_interest_categories($list_id);
96 foreach ($interest_categories as $interest_category) {
97 foreach ($interest_category->interests as $interest_id => $interest_name) {
98 // straight lookup by ID as key with value copy.
99 if (isset($this->data['INTERESTS'][ $interest_id ])) {
100 $subscriber->interests[ $interest_id ] = $this->formatter->boolean($this->data['INTERESTS'][ $interest_id ]);
101 }
102
103 // straight lookup by ID as top-level value
104 if (in_array($interest_id, $this->data['INTERESTS'], false)) {
105 $subscriber->interests[ $interest_id ] = true;
106 }
107
108 // look in array with category ID as key.
109 if (isset($this->data['INTERESTS'][ $interest_category->id ])) {
110 $value = $this->data['INTERESTS'][ $interest_category->id ];
111 $values = is_array($value) ? $value : array_map('trim', explode('|', $value));
112
113 // find by category ID + interest ID
114 if (in_array($interest_id, $values, false)) {
115 $subscriber->interests[ $interest_id ] = true;
116 }
117
118 // find by category ID + interest name
119 if (in_array($interest_name, $values, true)) {
120 $subscriber->interests[ $interest_id ] = true;
121 }
122 }
123 }
124 }
125 }
126
127 // add GDPR marketing permissions
128 if (! empty($this->data['MARKETING_PERMISSIONS'])) {
129 $values = $this->data['MARKETING_PERMISSIONS'];
130 $values = is_array($values) ? $values : explode(',', $values);
131 $values = array_map('trim', $values);
132 $marketing_permissions = $this->mailchimp->get_list_marketing_permissions($list_id);
133 foreach ($marketing_permissions as $mp) {
134 if (in_array($mp->marketing_permission_id, $values, true) || in_array($mp->text, $values, true)) {
135 $subscriber->marketing_permissions[] = (object) array(
136 'marketing_permission_id' => $mp->marketing_permission_id,
137 'enabled' => true,
138 );
139 }
140 }
141 }
142
143 // find language
144 /* @see http://kb.mailchimp.com/lists/managing-subscribers/view-and-edit-subscriber-languages?utm_source=mc-api&utm_medium=docs&utm_campaign=apidocs&_ga=1.211519638.2083589671.1469697070 */
145 if (! empty($this->data['MC_LANGUAGE'])) {
146 $subscriber->language = $this->formatter->language($this->data['MC_LANGUAGE']);
147 }
148
149 return $subscriber;
150 }
151
152
153 /**
154 * @param object $merge_field
155 * @param string $value
156 *
157 * @return mixed
158 */
159 private function format_merge_field_value($merge_field, $value)
160 {
161 $field_type = strtolower($merge_field->type);
162
163 if (method_exists($this->formatter, $field_type)) {
164 $value = call_user_func(array( $this->formatter, $field_type ), $value, $merge_field->options);
165 }
166
167 /**
168 * Filters the value of a field after it is formatted.
169 *
170 * Use this to format a field value according to the field type (in Mailchimp).
171 *
172 * @since 3.0
173 * @param string $value The value
174 * @param string $field_type The type of the field (in Mailchimp)
175 */
176 $value = apply_filters('mc4wp_format_field_value', $value, $field_type);
177
178 return $value;
179 }
180 }
1 <?php
2
3 class MC4WP_MailChimp_Subscriber
4 {
5 /**
6 * @var string Email address for this subscriber.
7 */
8 public $email_address = '';
9
10 /**
11 * @var array The key of this object’s properties is the ID of the interest in question.
12 */
13 public $interests = array();
14
15 /**
16 * @var array An individual merge var and value for a member.
17 */
18 public $merge_fields = array();
19
20 /**
21 * @var string Subscriber’s status.
22 */
23 public $status = 'pending';
24
25 /**
26 * @var string Type of email this member asked to get (‘html’ or ‘text’).
27 */
28 public $email_type = 'html';
29
30 /**
31 * @var string IP address the subscriber signed up from.
32 */
33 public $ip_signup;
34
35 /**
36 * @var string The subscriber's language
37 */
38 public $language;
39
40 /**
41 * @var boolean VIP status for subscriber.
42 */
43 public $vip;
44
45 /**
46 * @var array The tags applied to this member.
47 */
48 public $tags = array();
49
50 /**
51 * @var array The marketing permissions for the subscriber.
52 */
53 public $marketing_permissions = array();
54
55 /**
56 * Retrieves member data as an array, without null values.
57 *
58 * @return array
59 */
60 public function to_array()
61 {
62 $all = get_object_vars($this);
63 $array = array();
64
65 foreach ($all as $key => $value) {
66 // skip null values
67 if ($value === null) {
68 continue;
69 }
70
71 // skip empty marketing_permissions property
72 if ($key === 'marketing_permissions' && empty($value)) {
73 continue;
74 }
75
76 // otherwise, add to final array
77 $array[ $key ] = $value;
78 }
79
80 return $array;
81 }
82 }
1 <?php
2
3 /**
4 * Class MC4WP_Plugin
5 *
6 * Helper class for easy access to information like the plugin file or plugin directory.
7 * Used in MC4WP Premium.
8 *
9 * @access public
10 * @ignore
11 */
12 class MC4WP_Plugin
13 {
14 /**
15 * @var string The plugin version.
16 */
17 protected $version;
18
19 /**
20 * @var string The main plugin file.
21 */
22 protected $file;
23
24 /**
25 * @param string $file The plugin version.
26 * @param string $version The main plugin file.
27 */
28 public function __construct($file, $version)
29 {
30 $this->file = $file;
31 $this->version = $version;
32 }
33
34 /**
35 * Get the main plugin file.
36 *
37 * @return string
38 */
39 public function file()
40 {
41 return $this->file;
42 }
43
44 /**
45 * Get the plugin version.
46 *
47 * @return string
48 */
49 public function version()
50 {
51 return $this->version;
52 }
53
54 /**
55 * Gets the directory the plugin lives in.
56 *
57 * @param string $path
58 *
59 * @return string
60 */
61 public function dir($path = '')
62 {
63
64 // ensure path has leading slash
65 if ('' !== $path) {
66 $path = '/' . ltrim($path, '/');
67 }
68
69 return dirname($this->file) . $path;
70 }
71
72 /**
73 * Gets the URL to the plugin files.
74 *
75 * @param string $path
76 *
77 * @return string
78 */
79 public function url($path = '')
80 {
81 return plugins_url($path, $this->file);
82 }
83 }
1 <?php
2
3 /**
4 * Class MC4WP_Queue_Job
5 *
6 * @ignore
7 */
8 class MC4WP_Queue_Job
9 {
10 /**
11 * @var string
12 */
13 public $id;
14
15 /**
16 * @var mixed
17 */
18 public $data;
19
20 /**
21 * @var int
22 */
23 public $max_attempts = 1;
24
25 /**
26 * @var int
27 */
28 public $attempts = 0;
29
30 /**
31 * MC4WP_Queue_Job constructor.
32 *
33 * @param mixed $data
34 */
35 public function __construct($data)
36 {
37 $this->id = (string) microtime(true) . rand(1, 10000);
38 $this->data = $data;
39 }
40 }
1 <?php
2
3 /**
4 * Class MC4WP_Queue
5 *
6 * @ignore
7 */
8 class MC4WP_Queue
9 {
10 /**
11 * @var MC4WP_Queue_Job[]
12 */
13 protected $jobs;
14
15 /**
16 * @var string
17 */
18 protected $option_name;
19
20 /**
21 * @var bool
22 */
23 protected $dirty = false;
24
25 /**
26 * @var int
27 */
28 const MAX_JOB_COUNT = 1000;
29
30 /**
31 * MC4WP_Ecommerce_Queue constructor.
32 *
33 * @param string $option_name
34 */
35 public function __construct($option_name)
36 {
37 $this->option_name = $option_name;
38
39 register_shutdown_function(array( $this, 'save' ));
40 }
41
42 /**
43 * Load jobs from option
44 */
45 protected function load()
46 {
47 if (! is_null($this->jobs)) {
48 return;
49 }
50
51 $jobs = get_option($this->option_name, array());
52
53 if (! is_array($jobs)) {
54 $jobs = array();
55 } else {
56 $valid_jobs = array();
57
58 foreach ($jobs as $i => $obj) {
59 // filter invalid data from array
60 if (! is_object($obj) || empty($obj->data)) {
61 continue;
62 }
63
64 // make sure each job is instance of MC4WP_Queue_Job
65 if ($obj instanceof MC4WP_Queue_Job) {
66 $job = $obj;
67 } else {
68 $job = new MC4WP_Queue_Job($obj->data);
69 $job->id = $obj->id;
70 }
71
72 $valid_jobs[] = $job;
73 }
74
75 $jobs = $valid_jobs;
76 }
77
78 $this->jobs = $jobs;
79 }
80
81 /**
82 * Get all jobs in the queue
83 *
84 * @return MC4WP_Queue_Job[] Array of jobs
85 */
86 public function all()
87 {
88 $this->load();
89 return $this->jobs;
90 }
91
92 /**
93 * Add job to queue
94 *
95 * @param mixed $data
96 * @return boolean
97 */
98 public function put($data)
99 {
100 $this->load();
101
102 // check if we already have a job with same data
103 foreach ($this->jobs as $job) {
104 if ($job->data === $data) {
105 return false;
106 }
107 }
108
109 // if we have more than MAX_JOB_COUNT jobs, remove first job item.
110 // this protects against an ever-growing job list, but also potentially loses jobs if the queue is not processed soon enough.
111 if (count($this->jobs) > self::MAX_JOB_COUNT) {
112 array_shift($this->jobs);
113 }
114
115 // add job to end of jobs array
116 $job = new MC4WP_Queue_Job($data);
117 $this->jobs[] = $job;
118 $this->dirty = true;
119 return true;
120 }
121
122 /**
123 * Get all jobs in the queue
124 *
125 * @return MC4WP_Queue_Job|false
126 */
127 public function get()
128 {
129 $this->load();
130
131 // do we have jobs?
132 if (count($this->jobs) === 0) {
133 return false;
134 }
135
136 // return first element
137 return reset($this->jobs);
138 }
139
140 /**
141 * @param MC4WP_Queue_Job $job
142 */
143 public function delete(MC4WP_Queue_Job $job)
144 {
145 $this->load();
146
147 $index = array_search($job, $this->jobs, true);
148
149 // check for "false" here, as 0 is a valid index.
150 if ($index !== false) {
151 unset($this->jobs[ $index ]);
152 $this->jobs = array_values($this->jobs);
153 $this->dirty = true;
154 }
155 }
156
157 /**
158 * @param MC4WP_Queue_Job $job
159 */
160 public function reschedule(MC4WP_Queue_Job $job)
161 {
162 $this->load();
163
164 // delete job from start of queue
165 $this->delete($job);
166
167 // add job to end of queue
168 $this->jobs[] = $job;
169 $this->dirty = true;
170 }
171
172 /**
173 * Reset queue
174 */
175 public function reset()
176 {
177 $this->jobs = array();
178 $this->dirty = true;
179 }
180
181 /**
182 * Save the queue
183 */
184 public function save()
185 {
186 if (! $this->dirty || is_null($this->jobs)) {
187 return false;
188 }
189
190 $success = update_option($this->option_name, $this->jobs, false);
191
192 if ($success) {
193 $this->dirty = false;
194 }
195
196 return $success;
197 }
198 }
1 <?php
2
3 /**
4 * Class MC4WP_Tools
5 *
6 * @access private
7 * @ignore
8 */
9 class MC4WP_Tools
10 {
11 /**
12 * @return array
13 */
14 public static function get_countries()
15 {
16 return array(
17 'AF' => 'Afghanistan',
18 'AX' => 'Aland Islands',
19 'AL' => 'Albania',
20 'DZ' => 'Algeria',
21 'AS' => 'American Samoa',
22 'AD' => 'Andorra',
23 'AO' => 'Angola',
24 'AI' => 'Anguilla',
25 'AQ' => 'Antarctica',
26 'AG' => 'Antigua and Barbuda',
27 'AR' => 'Argentina',
28 'AM' => 'Armenia',
29 'AW' => 'Aruba',
30 'AU' => 'Australia',
31 'AT' => 'Austria',
32 'AZ' => 'Azerbaijan',
33 'BS' => 'Bahamas',
34 'BH' => 'Bahrain',
35 'BD' => 'Bangladesh',
36 'BB' => 'Barbados',
37 'BY' => 'Belarus',
38 'BE' => 'Belgium',
39 'BZ' => 'Belize',
40 'BJ' => 'Benin',
41 'BM' => 'Bermuda',
42 'BT' => 'Bhutan',
43 'BO' => 'Bolivia',
44 'BQ' => 'Bonaire, Saint Eustatius and Saba',
45 'BA' => 'Bosnia and Herzegovina',
46 'BW' => 'Botswana',
47 'BV' => 'Bouvet Island',
48 'BR' => 'Brazil',
49 'IO' => 'British Indian Ocean Territory',
50 'VG' => 'British Virgin Islands',
51 'BN' => 'Brunei',
52 'BG' => 'Bulgaria',
53 'BF' => 'Burkina Faso',
54 'BI' => 'Burundi',
55 'KH' => 'Cambodia',
56 'CM' => 'Cameroon',
57 'CA' => 'Canada',
58 'CV' => 'Cape Verde',
59 'KY' => 'Cayman Islands',
60 'CF' => 'Central African Republic',
61 'TD' => 'Chad',
62 'CL' => 'Chile',
63 'CN' => 'China',
64 'CX' => 'Christmas Island',
65 'CC' => 'Cocos Islands',
66 'CO' => 'Colombia',
67 'KM' => 'Comoros',
68 'CK' => 'Cook Islands',
69 'CR' => 'Costa Rica',
70 'HR' => 'Croatia',
71 'CU' => 'Cuba',
72 'CW' => 'Curacao',
73 'CY' => 'Cyprus',
74 'CZ' => 'Czech Republic',
75 'CD' => 'Democratic Republic of the Congo',
76 'DK' => 'Denmark',
77 'DJ' => 'Djibouti',
78 'DM' => 'Dominica',
79 'DO' => 'Dominican Republic',
80 'TL' => 'East Timor',
81 'EC' => 'Ecuador',
82 'EG' => 'Egypt',
83 'SV' => 'El Salvador',
84 'GQ' => 'Equatorial Guinea',
85 'ER' => 'Eritrea',
86 'EE' => 'Estonia',
87 'ET' => 'Ethiopia',
88 'FK' => 'Falkland Islands',
89 'FO' => 'Faroe Islands',
90 'FJ' => 'Fiji',
91 'FI' => 'Finland',
92 'FR' => 'France',
93 'GF' => 'French Guiana',
94 'PF' => 'French Polynesia',
95 'TF' => 'French Southern Territories',
96 'GA' => 'Gabon',
97 'GM' => 'Gambia',
98 'GE' => 'Georgia',
99 'DE' => 'Germany',
100 'GH' => 'Ghana',
101 'GI' => 'Gibraltar',
102 'GR' => 'Greece',
103 'GL' => 'Greenland',
104 'GD' => 'Grenada',
105 'GP' => 'Guadeloupe',
106 'GU' => 'Guam',
107 'GT' => 'Guatemala',
108 'GG' => 'Guernsey',
109 'GN' => 'Guinea',
110 'GW' => 'Guinea-Bissau',
111 'GY' => 'Guyana',
112 'HT' => 'Haiti',
113 'HM' => 'Heard Island and McDonald Islands',
114 'HN' => 'Honduras',
115 'HK' => 'Hong Kong',
116 'HU' => 'Hungary',
117 'IS' => 'Iceland',
118 'IN' => 'India',
119 'ID' => 'Indonesia',
120 'IR' => 'Iran',
121 'IQ' => 'Iraq',
122 'IE' => 'Ireland',
123 'IM' => 'Isle of Man',
124 'IL' => 'Israel',
125 'IT' => 'Italy',
126 'CI' => 'Ivory Coast',
127 'JM' => 'Jamaica',
128 'JP' => 'Japan',
129 'JE' => 'Jersey',
130 'JO' => 'Jordan',
131 'KZ' => 'Kazakhstan',
132 'KE' => 'Kenya',
133 'KI' => 'Kiribati',
134 'XK' => 'Kosovo',
135 'KW' => 'Kuwait',
136 'KG' => 'Kyrgyzstan',
137 'LA' => 'Laos',
138 'LV' => 'Latvia',
139 'LB' => 'Lebanon',
140 'LS' => 'Lesotho',
141 'LR' => 'Liberia',
142 'LY' => 'Libya',
143 'LI' => 'Liechtenstein',
144 'LT' => 'Lithuania',
145 'LU' => 'Luxembourg',
146 'MO' => 'Macao',
147 'MK' => 'Macedonia',
148 'MG' => 'Madagascar',
149 'MW' => 'Malawi',
150 'MY' => 'Malaysia',
151 'MV' => 'Maldives',
152 'ML' => 'Mali',
153 'MT' => 'Malta',
154 'MH' => 'Marshall Islands',
155 'MQ' => 'Martinique',
156 'MR' => 'Mauritania',
157 'MU' => 'Mauritius',
158 'YT' => 'Mayotte',
159 'MX' => 'Mexico',
160 'FM' => 'Micronesia',
161 'MD' => 'Moldova',
162 'MC' => 'Monaco',
163 'MN' => 'Mongolia',
164 'ME' => 'Montenegro',
165 'MS' => 'Montserrat',
166 'MA' => 'Morocco',
167 'MZ' => 'Mozambique',
168 'MM' => 'Myanmar',
169 'NA' => 'Namibia',
170 'NR' => 'Nauru',
171 'NP' => 'Nepal',
172 'NL' => 'Netherlands',
173 'NC' => 'New Caledonia',
174 'NZ' => 'New Zealand',
175 'NI' => 'Nicaragua',
176 'NE' => 'Niger',
177 'NG' => 'Nigeria',
178 'NU' => 'Niue',
179 'NF' => 'Norfolk Island',
180 'KP' => 'North Korea',
181 'MP' => 'Northern Mariana Islands',
182 'NO' => 'Norway',
183 'OM' => 'Oman',
184 'PK' => 'Pakistan',
185 'PW' => 'Palau',
186 'PS' => 'Palestinian Territory',
187 'PA' => 'Panama',
188 'PG' => 'Papua New Guinea',
189 'PY' => 'Paraguay',
190 'PE' => 'Peru',
191 'PH' => 'Philippines',
192 'PN' => 'Pitcairn',
193 'PL' => 'Poland',
194 'PT' => 'Portugal',
195 'PR' => 'Puerto Rico',
196 'QA' => 'Qatar',
197 'CG' => 'Republic of the Congo',
198 'RE' => 'Reunion',
199 'RO' => 'Romania',
200 'RU' => 'Russia',
201 'RW' => 'Rwanda',
202 'BL' => 'Saint Barthelemy',
203 'SH' => 'Saint Helena',
204 'KN' => 'Saint Kitts and Nevis',
205 'LC' => 'Saint Lucia',
206 'MF' => 'Saint Martin',
207 'PM' => 'Saint Pierre and Miquelon',
208 'VC' => 'Saint Vincent and the Grenadines',
209 'WS' => 'Samoa',
210 'SM' => 'San Marino',
211 'ST' => 'Sao Tome and Principe',
212 'SA' => 'Saudi Arabia',
213 'SN' => 'Senegal',
214 'RS' => 'Serbia',
215 'SC' => 'Seychelles',
216 'SL' => 'Sierra Leone',
217 'SG' => 'Singapore',
218 'SX' => 'Sint Maarten',
219 'SK' => 'Slovakia',
220 'SI' => 'Slovenia',
221 'SB' => 'Solomon Islands',
222 'SO' => 'Somalia',
223 'ZA' => 'South Africa',
224 'GS' => 'South Georgia and the South Sandwich Islands',
225 'KR' => 'South Korea',
226 'SS' => 'South Sudan',
227 'ES' => 'Spain',
228 'LK' => 'Sri Lanka',
229 'SD' => 'Sudan',
230 'SR' => 'Suriname',
231 'SJ' => 'Svalbard and Jan Mayen',
232 'SZ' => 'Swaziland',
233 'SE' => 'Sweden',
234 'CH' => 'Switzerland',
235 'SY' => 'Syria',
236 'TW' => 'Taiwan',
237 'TJ' => 'Tajikistan',
238 'TZ' => 'Tanzania',
239 'TH' => 'Thailand',
240 'TG' => 'Togo',
241 'TK' => 'Tokelau',
242 'TO' => 'Tonga',
243 'TT' => 'Trinidad and Tobago',
244 'TN' => 'Tunisia',
245 'TR' => 'Turkey',
246 'TM' => 'Turkmenistan',
247 'TC' => 'Turks and Caicos Islands',
248 'TV' => 'Tuvalu',
249 'VI' => 'U.S. Virgin Islands',
250 'UG' => 'Uganda',
251 'UA' => 'Ukraine',
252 'AE' => 'United Arab Emirates',
253 'GB' => 'United Kingdom',
254 'US' => 'United States',
255 'UM' => 'United States Minor Outlying Islands',
256 'UY' => 'Uruguay',
257 'UZ' => 'Uzbekistan',
258 'VU' => 'Vanuatu',
259 'VA' => 'Vatican',
260 'VE' => 'Venezuela',
261 'VN' => 'Vietnam',
262 'WF' => 'Wallis and Futuna',
263 'EH' => 'Western Sahara',
264 'YE' => 'Yemen',
265 'ZM' => 'Zambia',
266 'ZW' => 'Zimbabwe',
267 );
268 }
269 }
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 add_action('mc4wp_refresh_mailchimp_lists', 'mc4wp_refresh_mailchimp_lists');
1 <?php
2
3 defined('ABSPATH') or exit;
4
5 add_filter('mc4wp_form_data', 'mc4wp_add_name_data', 60);
6 add_filter('mc4wp_integration_data', 'mc4wp_add_name_data', 60);
7
8 add_filter('mctb_data', '_mc4wp_update_groupings_data', PHP_INT_MAX);
9 add_filter('mc4wp_form_data', '_mc4wp_update_groupings_data', PHP_INT_MAX);
10 add_filter('mc4wp_integration_data', '_mc4wp_update_groupings_data', PHP_INT_MAX);
11 add_filter('mailchimp_sync_user_data', '_mc4wp_update_groupings_data', PHP_INT_MAX);
12 add_filter('mc4wp_use_sslverify', '_mc4wp_use_sslverify', 1);
13
14 mc4wp_apply_deprecated_filters('mc4wp_merge_vars', 'mc4wp_form_data');
15 mc4wp_apply_deprecated_filters('mc4wp_form_merge_vars', 'mc4wp_form_data');
16 mc4wp_apply_deprecated_filters('mc4wp_integration_merge_vars', 'mc4wp_integration_data');
1 <?php
2
3 /**
4 * Gets the absolute url to edit a form
5 *
6 * @param int $form_id ID of the form
7 * @param string $tab Tab identifier to open
8 *
9 * @return string
10 */
11 function mc4wp_get_edit_form_url($form_id, $tab = '')
12 {
13 $url = admin_url(sprintf('admin.php?page=mailchimp-for-wp-forms&view=edit-form&form_id=%d', $form_id));
14
15 if (! empty($tab)) {
16 $url .= sprintf('&tab=%s', $tab);
17 }
18
19 return $url;
20 }
21
22 /**
23 * Get absolute URL to create a new form
24 *
25 * @return string
26 */
27 function mc4wp_get_add_form_url()
28 {
29 $url = admin_url('admin.php?page=mailchimp-for-wp-forms&view=add-form');
30 return $url;
31 }
1 <?php
2
3 /**
4 * This class takes care of all form assets related functionality
5 *
6 * @access private
7 * @ignore
8 */
9 class MC4WP_Form_Asset_Manager
10 {
11 /**
12 * @var bool Flag to determine whether scripts should be enqueued.
13 */
14 private $load_scripts = false;
15
16 /**
17 * Add hooks
18 */
19 public function add_hooks()
20 {
21 add_action('init', array( $this, 'register_scripts' ));
22 add_action('wp_enqueue_scripts', array( $this, 'load_stylesheets' ));
23 add_action('wp_footer', array( $this, 'load_scripts' ));
24 add_action('mc4wp_output_form', array( $this, 'before_output_form' ));
25 add_action('script_loader_tag', array( $this, 'add_defer_attribute' ), 10, 2);
26 }
27
28 /**
29 * Register scripts to be enqueued later.
30 */
31 public function register_scripts()
32 {
33 wp_register_script('mc4wp-forms-api', mc4wp_plugin_url('assets/js/forms.js'), array(), MC4WP_VERSION, true);
34 }
35
36 /**
37 * @param string $stylesheet
38 *
39 * @return bool
40 */
41 public function is_registered_stylesheet($stylesheet)
42 {
43 $stylesheets = $this->get_registered_stylesheets();
44 return in_array($stylesheet, $stylesheets, true);
45 }
46
47 /**
48 * @return array
49 */
50 public function get_registered_stylesheets()
51 {
52 return array(
53 'basic',
54 'themes',
55 );
56 }
57
58 /**
59 * @param string $stylesheet
60 *
61 * @return string
62 */
63 public function get_stylesheet_url($stylesheet)
64 {
65 return mc4wp_plugin_url('assets/css/form-' . $stylesheet . '.css');
66 }
67
68 /**
69 * Get array of stylesheet handles which should be enqueued.
70 *
71 * @return array
72 */
73 public function get_active_stylesheets()
74 {
75 $stylesheets = (array) get_option('mc4wp_form_stylesheets', array());
76
77 /**
78 * Filters the stylesheets to be loaded
79 *
80 * Should be an array of stylesheet handles previously registered using `wp_register_style`.
81 * Each value is prefixed with `mc4wp-form-` to get the handle.
82 *
83 * Return an empty array if you want to disable the loading of all stylesheets.
84 *
85 * @since 3.0
86 * @param array $stylesheets Array of valid stylesheet handles
87 */
88 $stylesheets = (array) apply_filters('mc4wp_form_stylesheets', $stylesheets);
89 return $stylesheets;
90 }
91
92 /**
93 * Load the various stylesheets
94 */
95 public function load_stylesheets()
96 {
97 $stylesheets = $this->get_active_stylesheets();
98
99 foreach ($stylesheets as $stylesheet) {
100 if (! $this->is_registered_stylesheet($stylesheet)) {
101 continue;
102 }
103
104 $handle = 'mc4wp-form-' . $stylesheet;
105 $url = $this->get_stylesheet_url($stylesheet);
106 wp_enqueue_style($handle, $url, array(), MC4WP_VERSION);
107 add_editor_style($url);
108 }
109
110 /**
111 * @ignore
112 */
113 do_action('mc4wp_load_form_stylesheets', $stylesheets);
114 }
115
116 /**
117 * Get data object for client-side use for after a form is submitted over HTTP POST (not AJAX).
118 *
119 * @return array
120 */
121 public function get_submitted_form_data()
122 {
123 $submitted_form = mc4wp_get_submitted_form();
124 if (! $submitted_form instanceof MC4WP_Form) {
125 return null;
126 }
127
128 $data = array(
129 'id' => $submitted_form->ID,
130 'event' => $submitted_form->last_event,
131 'data' => $submitted_form->get_data(),
132 'element_id' => $submitted_form->config['element_id'],
133 'auto_scroll' => true,
134 );
135
136 if ($submitted_form->has_errors()) {
137 $data['errors'] = $submitted_form->errors;
138 }
139
140 /**
141 * Filters the `auto_scroll` setting for when a form is submitted.
142 * Set to false to disable scrolling to form.
143 *
144 * @param boolean $auto_scroll
145 * @since 3.0
146 */
147 $data['auto_scroll'] = apply_filters('mc4wp_form_auto_scroll', $data['auto_scroll']);
148
149 return $data;
150 }
151
152 /**
153 * Load JavaScript files
154 */
155 public function before_output_form()
156 {
157 $load_scripts = apply_filters('mc4wp_load_form_scripts', true);
158 if (! $load_scripts) {
159 return;
160 }
161
162 $this->print_dummy_javascript();
163 $this->load_scripts = true;
164 }
165
166 /**
167 * Prints dummy JavaScript which allows people to call `mc4wp.forms.on()` before the JS is loaded.
168 */
169 public function print_dummy_javascript()
170 {
171 echo '<script>';
172 include __DIR__ . '/views/js/dummy-api.js';
173 echo '</script>';
174 }
175
176 /**
177 * Outputs the inline JavaScript that is used to enhance forms
178 */
179 public function load_scripts()
180 {
181 $load_scripts = apply_filters('mc4wp_load_form_scripts', $this->load_scripts);
182 if (! $load_scripts) {
183 return;
184 }
185
186 // load general client-side form API
187 wp_enqueue_script('mc4wp-forms-api');
188
189 // maybe load JS file for when a form was submitted over HTTP POST
190 $submitted_form_data = $this->get_submitted_form_data();
191 if ($submitted_form_data !== null) {
192 wp_enqueue_script('mc4wp-forms-submitted', mc4wp_plugin_url('assets/js/forms-submitted.js'), array( 'mc4wp-forms-api' ), MC4WP_VERSION, true);
193 wp_localize_script('mc4wp-forms-submitted', 'mc4wp_submitted_form', $submitted_form_data);
194 }
195
196 // print inline scripts
197 echo '<script>';
198 echo '(function() {';
199 include __DIR__ . '/views/js/url-fields.js';
200 echo '})();';
201 echo '</script>';
202
203 /** @ignore */
204 do_action('mc4wp_load_form_scripts');
205 }
206
207 /**
208 * Adds `defer` attribute to all form-related `<script>` elements so they do not block page rendering.
209 *
210 * @param string $tag
211 * @param string $handle
212 * @return string
213 */
214 public function add_defer_attribute($tag, $handle)
215 {
216 if (! in_array($handle, array( 'mc4wp-forms-api', 'mc4wp-forms-submitted' ), true) || stripos($tag, ' defer') !== false) {
217 return $tag;
218 }
219
220 return str_replace(' src=', ' defer src=', $tag);
221 }
222 }
1 <?php
2
3 /**
4 * Class MC4WP_Form_AMP
5 */
6 class MC4WP_Form_AMP
7 {
8 /**
9 * Hook!
10 */
11 public function add_hooks()
12 {
13 add_filter('mc4wp_form_content', array( $this, 'add_response_templates' ), 10, 2);
14 add_filter('mc4wp_form_element_attributes', array( $this, 'add_amp_request' ));
15 add_filter('mc4wp_load_form_scripts', array( $this, 'suppress_scripts' ));
16 }
17
18 /**
19 * Add AMP templates for submit/success/error.
20 *
21 * @param string $content The form content.
22 * @param MC4WP_Form $form The form object.
23 * @return string Modified $content.
24 */
25 public function add_response_templates($content, $form)
26 {
27 if (! function_exists('amp_is_request') || ! amp_is_request()) {
28 return $content;
29 }
30
31 ob_start();
32 ?>
33 <div submitting>
34 <template type="amp-mustache">
35 <?php echo esc_html__('Submitting...', 'mailchimp-for-wp'); ?>
36 </template>
37 </div>
38 <div submit-success>
39 <template type="amp-mustache">
40 <?php
41 echo wp_kses(
42 $form->get_message('subscribed'),
43 array(
44 'a' => array(),
45 'strong' => array(),
46 'em' => array(),
47 )
48 );
49 ?>
50 </template>
51 </div>
52 <div submit-error>
53 <template type="amp-mustache">
54 {{message}}
55 </template>
56 </div>
57 <?php
58 $content .= ob_get_clean();
59
60 return $content;
61 }
62
63 /**
64 * Add 'action-xhr' to AMP forms.
65 *
66 * @param array $attributes Key-Value pairs of attributes output on form.
67 * @return array Modified $attributes.
68 */
69 public function add_amp_request($attributes)
70 {
71 if (function_exists('amp_is_request') && amp_is_request()) {
72 $attributes['action-xhr'] = get_rest_url(null, 'mc4wp/v1/form');
73 }
74
75 return $attributes;
76 }
77
78 /**
79 * Suppress form scripts on AMP pages.
80 *
81 * @param bool $load_scripts Whether scripts should be loaded.
82 * @return bool Modified $load_scripts.
83 */
84 public function suppress_scripts($load_scripts)
85 {
86 if (function_exists('amp_is_request') && amp_is_request()) {
87 return false;
88 }
89
90 return $load_scripts;
91 }
92 }
1 <?php
2
3 /**
4 * This class takes care of all form related functionality
5 *
6 * Do not interact with this class directly, use `mc4wp_form` functions tagged with @access public instead.
7 *
8 * @class MC4WP_Form_Manager
9 * @ignore
10 * @access private
11 */
12 class MC4WP_Form_Manager
13 {
14 /**
15 * @var MC4WP_Form_Output_Manager
16 */
17 protected $output_manager;
18
19 /**
20 * @var MC4WP_Form_Listener
21 */
22 protected $listener;
23
24 /**
25 * @var MC4WP_Form_Tags
26 */
27 protected $tags;
28
29 /**
30 * @var MC4WP_Form_Previewer
31 */
32 protected $previewer;
33
34 /**
35 * @var MC4WP_Form_Asset_Manager
36 */
37 protected $assets;
38
39 /**
40 * @var MC4WP_Form_AMP
41 */
42 protected $amp_compatibility;
43
44 /**
45 * Constructor
46 */
47 public function __construct()
48 {
49 $this->output_manager = new MC4WP_Form_Output_Manager();
50 $this->tags = new MC4WP_Form_Tags();
51 $this->listener = new MC4WP_Form_Listener();
52 $this->previewer = new MC4WP_Form_Previewer();
53 $this->assets = new MC4WP_Form_Asset_Manager();
54 $this->amp_compatibility = new MC4WP_Form_AMP();
55 }
56
57 /**
58 * Hook!
59 */
60 public function add_hooks()
61 {
62 add_action('init', array( $this, 'initialize' ));
63 add_action('widgets_init', array( $this, 'register_widget' ));
64 add_action('rest_api_init', array( $this, 'register_endpoint' ));
65
66 $this->listener->add_hooks();
67 $this->output_manager->add_hooks();
68 $this->assets->add_hooks();
69 $this->tags->add_hooks();
70 $this->previewer->add_hooks();
71 $this->amp_compatibility->add_hooks();
72 }
73
74 /**
75 * Initialize
76 */
77 public function initialize()
78 {
79 $this->register_post_type();
80 $this->register_block_type();
81 }
82
83 private function register_block_type()
84 {
85 // Bail if register_block_type does not exist (available since WP 5.0)
86 if (! function_exists('register_block_type')) {
87 return;
88 }
89
90 register_block_type(
91 'mailchimp-for-wp/form',
92 array(
93 'render_callback' => array( $this->output_manager, 'shortcode' ),
94 )
95 );
96 }
97
98 /**
99 * Register post type "mc4wp-form"
100 */
101 private function register_post_type()
102 {
103 // register post type
104 register_post_type(
105 'mc4wp-form',
106 array(
107 'labels' => array(
108 'name' => 'Mailchimp Sign-up Forms',
109 'singular_name' => 'Sign-up Form',
110 ),
111 'public' => false,
112 )
113 );
114 }
115
116 /**
117 * Register our Form widget
118 */
119 public function register_widget()
120 {
121 register_widget('MC4WP_Form_Widget');
122 }
123
124 /**
125 * Register an API endpoint for handling a form.
126 */
127 public function register_endpoint()
128 {
129 register_rest_route(
130 'mc4wp/v1',
131 '/form',
132 array(
133 'methods' => 'POST',
134 'permission_callback' => '__return_true',
135 'callback' => array( $this, 'handle_endpoint' ),
136 )
137 );
138 }
139
140 /**
141 * Process requests to the form endpoint.
142 *
143 * A listener checks every request for a form submit, so we just need to fetch the listener and get its status.
144 */
145 public function handle_endpoint()
146 {
147 $form = mc4wp_get_submitted_form();
148 if (! $form instanceof MC4WP_Form) {
149 return new WP_Error(
150 'not_found',
151 esc_html__('Resource does not exist.', 'mailchimp-for-wp'),
152 array(
153 'status' => 404,
154 )
155 );
156 }
157
158 if ($form->has_errors()) {
159 $message_key = $form->errors[0];
160 $message = $form->get_message($message_key);
161 return new WP_Error(
162 $message_key,
163 $message,
164 array(
165 'status' => 400,
166 )
167 );
168 }
169
170 return new WP_REST_Response(true, 200);
171 }
172
173 /**
174 * @param $form_id
175 * @param array $config
176 * @param bool $echo
177 *
178 * @return string
179 */
180 public function output_form($form_id, $config = array(), $echo = true)
181 {
182 return $this->output_manager->output_form($form_id, $config, $echo);
183 }
184
185 /**
186 * Gets the currently submitted form
187 *
188 * @return MC4WP_Form|null
189 */
190 public function get_submitted_form()
191 {
192 if ($this->listener->submitted_form instanceof MC4WP_Form) {
193 return $this->listener->submitted_form;
194 }
195
196 return null;
197 }
198
199 /**
200 * Return all tags
201 *
202 * @return array
203 */
204 public function get_tags()
205 {
206 return $this->tags->all();
207 }
208 }
1 <?php
2
3 /**
4 * Class MC4WP_Form_Notice
5 *
6 * @ignore
7 * @access private
8 */
9 class MC4WP_Form_Notice
10 {
11 /**
12 * @var string
13 */
14 public $type = 'error';
15
16 /**
17 * @var string
18 */
19 public $text;
20
21 /**
22 * @param string $text
23 * @param string $type
24 */
25 public function __construct($text, $type = 'error')
26 {
27 $this->text = $text;
28
29 if (! empty($type)) {
30 $this->type = $type;
31 }
32 }
33
34 /**
35 * @return string
36 */
37 public function __toString()
38 {
39 return $this->text;
40 }
41 }
1 <?php
2
3 class MC4WP_Form_Previewer
4 {
5 public function add_hooks()
6 {
7 add_action('parse_request', array( $this, 'listen' ));
8 }
9
10 public function listen()
11 {
12 if (empty($_GET['mc4wp_preview_form'])) {
13 return;
14 }
15
16 if (! current_user_can('edit_posts')) {
17 return;
18 }
19
20 show_admin_bar(false);
21 add_filter('pre_handle_404', '__return_true');
22 remove_all_actions('template_redirect');
23 add_action('template_redirect', array( $this, 'load_preview' ));
24 }
25
26 public function load_preview()
27 {
28 // clear output, some plugin or hooked code might have thrown errors by now.
29 if (ob_get_level() > 0) {
30 ob_end_clean();
31 }
32
33 $form_id = (int) $_GET['mc4wp_preview_form'];
34 status_header(200);
35
36 require __DIR__ . '/views/preview.php';
37 exit;
38 }
39 }
1 <?php
2
3 /**
4 * Class MC4WP_Form_Tags
5 *
6 * @access private
7 * @ignore
8 */
9 class MC4WP_Form_Tags extends MC4WP_Dynamic_Content_Tags
10 {
11 /**
12 * @var MC4WP_Form
13 */
14 protected $form;
15
16 /**
17 * @var MC4WP_Form_Element
18 */
19 protected $form_element;
20
21 public function add_hooks()
22 {
23 add_filter('mc4wp_form_response_html', array( $this, 'replace_in_form_response' ), 10, 2);
24 add_filter('mc4wp_form_content', array( $this, 'replace_in_form_content' ), 10, 3);
25 add_filter('mc4wp_form_redirect_url', array( $this, 'replace_in_form_redirect_url' ), 10, 2);
26 }
27
28 /**
29 * Register template tags
30 */
31 public function register()
32 {
33 parent::register();
34
35 $this->tags['response'] = array(
36 'description' => __('Replaced with the form response (error or success messages).', 'mailchimp-for-wp'),
37 'callback' => array( $this, 'get_form_response' ),
38 );
39
40 $this->tags['data'] = array(
41 'description' => sprintf(__('Data from the URL or a submitted form.', 'mailchimp-for-wp')),
42 'callback' => array( $this, 'get_data' ),
43 'example' => "data key='UTM_SOURCE' default='Default Source'",
44 );
45
46 $this->tags['subscriber_count'] = array(
47 'description' => __('Replaced with the number of subscribers on the selected list(s)', 'mailchimp-for-wp'),
48 'callback' => array( $this, 'get_subscriber_count' ),
49 );
50 }
51
52
53 public function replace_in_form_content($string, MC4WP_Form $form, MC4WP_Form_Element $element = null)
54 {
55 $this->form = $form;
56 $this->form_element = $element;
57
58 $string = $this->replace($string);
59 return $string;
60 }
61
62 public function replace_in_form_response($string, MC4WP_Form $form)
63 {
64 $this->form = $form;
65
66 $string = $this->replace($string);
67 return $string;
68 }
69
70 public function replace_in_form_redirect_url($string, MC4WP_Form $form)
71 {
72 $this->form = $form;
73 $string = $this->replace_in_url($string);
74 return $string;
75 }
76
77 /**
78 * Returns the number of subscribers on the selected lists (for the form context)
79 *
80 * @return int
81 */
82 public function get_subscriber_count()
83 {
84 $mailchimp = new MC4WP_MailChimp();
85 $count = $mailchimp->get_subscriber_count($this->form->get_lists());
86 return number_format($count);
87 }
88
89 /**
90 * Returns the form response
91 *
92 * @return string
93 */
94 public function get_form_response()
95 {
96 if ($this->form_element instanceof MC4WP_Form_Element) {
97 return $this->form_element->get_response_html();
98 }
99
100 return '';
101 }
102
103 /**
104 * Gets data value from GET or POST variables.
105 *
106 * @param array $args
107 * @return string
108 */
109 public function get_data(array $args = array())
110 {
111 if (empty($args['key'])) {
112 return '';
113 }
114
115 $default = isset($args['default']) ? $args['default'] : '';
116 $key = $args['key'];
117
118 $data = array_merge($_GET, $_POST);
119 $value = isset($data[ $key ]) ? $data[ $key ] : $default;
120
121 // turn array into readable value
122 if (is_array($value)) {
123 $value = array_filter($value);
124 $value = join(', ', $value);
125 }
126
127 return esc_html($value);
128 }
129 }
1 <?php
2
3 /**
4 * Class MC4WP_Form_Output_Manager
5 *
6 * @ignore
7 * @access private
8 */
9 class MC4WP_Form_Output_Manager
10 {
11 /**
12 * @var int The # of forms outputted
13 */
14 public $count = 0;
15
16 /**
17 * @const string
18 */
19 const SHORTCODE = 'mc4wp_form';
20
21 /**
22 * Add hooks
23 */
24 public function add_hooks()
25 {
26 // enable shortcodes in form content
27 add_filter('mc4wp_form_content', 'do_shortcode');
28 add_action('init', array( $this, 'register_shortcode' ));
29 }
30
31 /**
32 * Registers the [mc4wp_form] shortcode
33 */
34 public function register_shortcode()
35 {
36 add_shortcode(self::SHORTCODE, array( $this, 'shortcode' ));
37 }
38
39 /**
40 * @param array $attributes
41 * @param string $content
42 * @return string
43 */
44 public function shortcode($attributes = array(), $content = '')
45 {
46 $default_attributes = array(
47 'id' => '',
48 'lists' => '',
49 'email_type' => '',
50 'element_id' => '',
51 'element_class' => '',
52 );
53
54 $attributes = shortcode_atts(
55 $default_attributes,
56 $attributes,
57 self::SHORTCODE
58 );
59
60 $config = array(
61 'element_id' => $attributes['element_id'],
62 'lists' => $attributes['lists'],
63 'email_type' => $attributes['email_type'],
64 'element_class' => $attributes['element_class'],
65 );
66
67 return $this->output_form($attributes['id'], $config, false);
68 }
69
70 /**
71 * @param int $id
72 * @param array $config
73 * @param bool $echo
74 *
75 * @return string
76 */
77 public function output_form($id = 0, $config = array(), $echo = true)
78 {
79 try {
80 $form = mc4wp_get_form($id);
81 } catch (Exception $e) {
82 if (current_user_can('manage_options')) {
83 return sprintf('<strong>Mailchimp for WordPress error:</strong> %s', $e->getMessage());
84 }
85
86 return '';
87 }
88
89 ++$this->count;
90
91 // set a default element_id if none is given
92 if (empty($config['element_id'])) {
93 $config['element_id'] = 'mc4wp-form-' . $this->count;
94 }
95
96 $form_html = $form->get_html($config['element_id'], $config);
97
98 try {
99 // start new output buffer
100 ob_start();
101
102 /**
103 * Runs just before a form element is outputted.
104 *
105 * @since 3.0
106 *
107 * @param MC4WP_Form $form
108 */
109 do_action('mc4wp_output_form', $form);
110
111 // output the form (in output buffer)
112 echo $form_html;
113
114 // grab all contents in current output buffer & then clean + end it.
115 $html = ob_get_clean();
116 } catch (Error $e) {
117 $html = $form_html;
118 }
119
120 // echo content if necessary
121 if ($echo) {
122 echo $html;
123 }
124
125 return $html;
126 }
127 }
This diff could not be displayed because it is too large.