├── .gitignore ├── Gruntfile.js ├── README.md ├── assets ├── css │ ├── admin │ │ ├── wtsfc-admin.css │ │ └── wtsfc-admin.min.css │ └── frontend │ │ ├── wtsfc-frontend.css │ │ └── wtsfc-frontend.min.css ├── images │ ├── loading.svg │ └── select-arrow.jpg └── js │ ├── admin │ ├── wtsfc-admin.js │ └── wtsfc-admin.min.js │ └── frontend │ ├── wtsfc-frontend.js │ └── wtsfc-frontend.min.js ├── changelog.txt ├── includes ├── class-wtsfc-ajax.php ├── class-wtsfc-api.php ├── class-wtsfc-mailchimp-api.php ├── class-wtsfc-settings.php ├── class-wtsfc-shortcode.php ├── class-wtsfc-webhooks.php ├── index.php └── views │ └── html-subscribe-form.php ├── package.json └── subscribe-for-content.php /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function( grunt ) { 2 | 'use strict'; 3 | 4 | grunt.initConfig({ 5 | 6 | // Setting folder templates 7 | dirs: { 8 | css: 'assets/css', 9 | fonts: 'assets/fonts', 10 | images: 'assets/images', 11 | js: 'assets/js' 12 | }, 13 | 14 | // Minify .js files. 15 | uglify: { 16 | options: { 17 | preserveComments: 'some' 18 | }, 19 | admin: { 20 | files: [{ 21 | expand: true, 22 | cwd: '<%= dirs.js %>/admin/', 23 | src: [ 24 | '*.js', 25 | '!*.min.js' 26 | ], 27 | dest: '<%= dirs.js %>/admin/', 28 | ext: '.min.js' 29 | }] 30 | }, 31 | frontend: { 32 | files: [{ 33 | expand: true, 34 | cwd: '<%= dirs.js %>/frontend/', 35 | src: [ 36 | '*.js', 37 | '!*.min.js' 38 | ], 39 | dest: '<%= dirs.js %>/frontend/', 40 | ext: '.min.js' 41 | }] 42 | } 43 | }, 44 | 45 | // Minify all .css files. 46 | cssmin: { 47 | admin: { 48 | expand: true, 49 | cwd: '<%= dirs.css %>/admin/', 50 | src: [ 51 | '*.css', 52 | '!*.min.css' 53 | ], 54 | dest: '<%= dirs.css %>/admin/', 55 | ext: '.min.css' 56 | }, 57 | frontend: { 58 | expand: true, 59 | cwd: '<%= dirs.css %>/frontend/', 60 | src: [ 61 | '*.css', 62 | '!*.min.css' 63 | ], 64 | dest: '<%= dirs.css %>/frontend/', 65 | ext: '.min.css' 66 | } 67 | }, 68 | 69 | sass: { 70 | admin: { 71 | expand: true, 72 | cwd: '<%= dirs.css %>/admin/', 73 | src: [ 74 | '*.scss' 75 | ], 76 | dest: '<%= dirs.css %>/admin/', 77 | ext: '.css', 78 | options: { 79 | sourcemap: 'none' 80 | } 81 | }, 82 | frontend: { 83 | expand: true, 84 | cwd: '<%= dirs.css %>/frontend/', 85 | src: [ 86 | '*.scss' 87 | ], 88 | dest: '<%= dirs.css %>/frontend/', 89 | ext: '.css', 90 | options: { 91 | sourcemap: 'none' 92 | } 93 | } 94 | }, 95 | 96 | // Watch changes for assets 97 | watch: { 98 | sass: { 99 | files: [ 100 | '<%= dirs.css %>/admin/*.scss', 101 | '<%= dirs.css %>/frontend/*.scss' 102 | ], 103 | tasks: ['sass'] 104 | }, 105 | js: { 106 | files: [ 107 | '<%= dirs.js %>/admin/*js', 108 | '<%= dirs.js %>/frontend/*js', 109 | '!<%= dirs.js %>/admin/*.min.js', 110 | '!<%= dirs.js %>/frontend/*.min.js' 111 | ], 112 | tasks: ['uglify'] 113 | } 114 | }, 115 | 116 | makepot: { 117 | dist: { 118 | options: { 119 | type: 'wp-plugin', 120 | potHeaders: { 121 | 'report-msgid-bugs-to': 'http://support.woothemes.com/hc/', 122 | 'language-team': 'LANGUAGE ' 123 | } 124 | } 125 | } 126 | }, 127 | 128 | checktextdomain: { 129 | options:{ 130 | text_domain: 'subscribe-for-content', 131 | keywords: [ 132 | '__:1,2d', 133 | '_e:1,2d', 134 | '_x:1,2c,3d', 135 | 'esc_html__:1,2d', 136 | 'esc_html_e:1,2d', 137 | 'esc_html_x:1,2c,3d', 138 | 'esc_attr__:1,2d', 139 | 'esc_attr_e:1,2d', 140 | 'esc_attr_x:1,2c,3d', 141 | '_ex:1,2c,3d', 142 | '_n:1,2,4d', 143 | '_nx:1,2,4c,5d', 144 | '_n_noop:1,2,3d', 145 | '_nx_noop:1,2,3c,4d' 146 | ] 147 | }, 148 | files: { 149 | src: [ 150 | '**/*.php', // Include all files 151 | '!node_modules/**' // Exclude node_modules/ 152 | ], 153 | expand: true 154 | } 155 | }, 156 | 157 | notify_hooks: { 158 | options: { 159 | enabled: true, 160 | max_jshint_notifications: 5, // maximum number of notifications from jshint output 161 | title: "Subscribe For Content", // defaults to the name in package.json, or will use project directory's name 162 | success: true, // whether successful grunt executions should be notified automatically 163 | duration: 3 // the duration of notification in seconds, for `notify-send only 164 | } 165 | } 166 | }); 167 | 168 | // Load NPM tasks to be used here 169 | grunt.loadNpmTasks( 'grunt-contrib-uglify' ); 170 | grunt.loadNpmTasks( 'grunt-contrib-cssmin' ); 171 | grunt.loadNpmTasks( 'grunt-contrib-watch' ); 172 | grunt.loadNpmTasks( 'grunt-contrib-sass' ); 173 | grunt.loadNpmTasks( 'grunt-wp-i18n' ); 174 | grunt.loadNpmTasks( 'grunt-checktextdomain' ); 175 | grunt.loadNpmTasks( 'grunt-notify' ); 176 | 177 | // Register tasks 178 | grunt.registerTask( 'default', [ 179 | 'cssmin', 180 | 'uglify', 181 | 'sass', 182 | ]); 183 | 184 | // Run notify 185 | grunt.task.run('notify_hooks'); 186 | }; 187 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Subscribe for Content 2 | A WordPress plugin that allows you to hide content until a user subscribes to a [MailChimp](https://mailchimp.com/) mailing list. :no_entry_sign: :open_mouth: :email: :sweat_smile: :monkey_face: :book: :heart_eyes: 3 | 4 | It allows per-list subscribing. So after subscribing to a single **list**, the user will see all content throughout your site that is hidden with the same list, but will have to subscribe again if it's another list. It also supports **interest groups**. 5 | 6 | How it remembers if someone has subscribed is by setting a cookie in the user's browser. The cookie key is dependent on the list ID and the cookie value is a random key that matches a locally stored key/email record. If a user is logged in it will also check their account's email. 7 | 8 | The cookie starts with `wtsfc_` - you may need to set up a cacheing exclusion with your host. By default it uses [cookie.js](https://github.com/js-cookie/js-cookie) and javascript to set the cookie, but you may want to use plain PHP to do it. If so, simply use the `wtsfc_setcookie_js` filter like so: 9 | 10 | ``` 11 | add_filter( 'wtsfc_setcookie_js', '__return_false' ); 12 | ``` 13 | 14 | Bots will still see the content that you're hiding, checking the `HTTP_USER_AGENT` against several common ones used by bots. If you want to override this and hide the content from bots, you can use the `wtsfc_show_bots` filter like so: 15 | 16 | ``` 17 | add_filter( 'wtsfc_show_bots', '__return_false' ); 18 | ``` 19 | 20 | The plugin automatically creates a webhook in MailChimp for the chosen list, which notifies your site when an email is unsubscribed. If that email is listed in the locally saved subscribed emails, it's removed and in turn that user won't have access to the content again (until they resubscribe). 21 | 22 | ## Usage 23 | 24 | Install it on your WordPress install, following the general install instructions, and then activate it. 25 | 26 | First thing you should do is **re-save your permalinks under Settings > Permalinks**. 27 | 28 | Under **Settings > Subscribe for Content**, you can enter your MailChimp API Key. Click **Get Lists** and it will grab your MailChimp lists. 29 | 30 | Set a list and then optionally set an **Interest Group** too. 31 | 32 | If you'd like you can set some defaults for the copy used in the form too. 33 | 34 | You can now start using it to hide content! 35 | 36 | Through the normal WordPress post editor, you can just wrap whatever you want to hide within the `[wtsfc]` shortcode, like so: 37 | 38 | ``` 39 | [wtsfc]You can't see this until you subscribe![/wtsfc] 40 | ``` 41 | 42 | There are a number of shortcode attributes you can use to customise the form: 43 | 44 | ``` 45 | list - list id 46 | group - group id 47 | interest - interest name (group should be set too) 48 | heading - the main heading 49 | subheading - the paragraph / subheading below the main heading 50 | button - button copy 51 | ``` 52 | 53 | By setting the interest name as well as the group, you can have the form automatically add them to a certain interest group with a preset interest, like so: 54 | 55 | ``` 56 | [wtsfc group="15753" interest="Developer"]You're now subscribed as a developer to our interest group![/wtsfc] 57 | ``` 58 | 59 | You can use the shortcode in your PHP code by using the [`do_shortcode`](https://developer.wordpress.org/reference/functions/do_shortcode/) function. 60 | 61 | ## Contributing 62 | 63 | The plugin uses [Grunt](http://gruntjs.com/) to handle basic tasks like minification. Be sure to install that locally first (you'll want to have [npm](https://www.npmjs.com/) too): 64 | 65 | ``` 66 | sudo npm install 67 | ``` 68 | 69 | And then just: 70 | 71 | ``` 72 | grunt watch 73 | ``` 74 | 75 | When you do make a contribution, please be sure to open an issue first. Then create a branch in your fork like `patch-101` (where 101 is the issue number) and make a PR from that branch. 76 | 77 | ## License 78 | 79 | [GNU GPLv3](http://www.gnu.org/licenses/gpl-3.0.en.html) - You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build & install instructions. 80 | 81 | ## By 82 | 83 | Built for [WooThemes.com](https://woothemes.com) by the team at [WooThemes](https://woothemes.com) + [Automattic](https://automattic.com). -------------------------------------------------------------------------------- /assets/css/admin/wtsfc-admin.css: -------------------------------------------------------------------------------- 1 | .wtsfc-settings .loading-icon { 2 | padding-left: 5px; 3 | width: 25px; 4 | } 5 | .wtsfc-settings em.description { 6 | display: block; 7 | margin-top: 5px; 8 | } 9 | .wtsfc-settings em.interests-description { 10 | margin-top: 15px; 11 | } -------------------------------------------------------------------------------- /assets/css/admin/wtsfc-admin.min.css: -------------------------------------------------------------------------------- 1 | .wtsfc-settings .loading-icon{padding-left:5px;width:25px}.wtsfc-settings em.description{display:block;margin-top:5px}.wtsfc-settings em.interests-description{margin-top:15px} -------------------------------------------------------------------------------- /assets/css/frontend/wtsfc-frontend.css: -------------------------------------------------------------------------------- 1 | #wtsfc.subscribe-for-content-box { 2 | border: 7px solid #42a2ce; 3 | margin-bottom: 20px; 4 | padding: 35px 50px; 5 | position: relative; 6 | text-align: center; 7 | } 8 | #wtsfc.subscribe-for-content-box.subscribed-success { 9 | border-color: #71b02f; 10 | padding-bottom: 20px; 11 | } 12 | #wtsfc.subscribe-for-content-box.subscribed-success p { 13 | margin-bottom: 1em; 14 | } 15 | #wtsfc.subscribe-for-content-box.loading h3, 16 | #wtsfc.subscribe-for-content-box.loading p, 17 | #wtsfc.subscribe-for-content-box.loading form { 18 | opacity: 0.25; 19 | } 20 | #wtsfc.subscribe-for-content-box.loading .loading-img { 21 | display: block !important; 22 | left: calc(50% - 25px); 23 | position: absolute; 24 | top: 40%; 25 | width: 50px; 26 | } 27 | #wtsfc.subscribe-for-content-box p { 28 | font-size: 17px; 29 | } 30 | #wtsfc.subscribe-for-content-box .error { 31 | color: #bd123b; 32 | font-size: 14px; 33 | font-weight: bold; 34 | margin-top: 20px; 35 | } 36 | #wtsfc.subscribe-for-content-box form .email-input { 37 | margin: -1px 12px 0 0; 38 | padding: 12px 2px 11px 18px; 39 | vertical-align: top; 40 | } 41 | #wtsfc.subscribe-for-content-box form .email-input::-webkit-input-placeholder { color:#aaa; } 42 | #wtsfc.subscribe-for-content-box form .email-input::-moz-placeholder { color:#aaa; } /* firefox 19+ */ 43 | #wtsfc.subscribe-for-content-box form .email-input:-ms-input-placeholder { color:#aaa; } /* ie */ 44 | #wtsfc.subscribe-for-content-box form select { 45 | -webkit-appearance: none; 46 | -moz-appearance: none; 47 | appearance: none; 48 | background: url('../../images/select-arrow.jpg')95% 1.2em no-repeat #fff; 49 | background-size: .6em; 50 | border: 1px solid #e6e6e6; 51 | height: 2.65em; 52 | margin: -1px 10px 0 0; 53 | padding-left: 10px; 54 | vertical-align: top; 55 | width: 11em; 56 | } 57 | #wtsfc.subscribe-for-content-box form .button { 58 | display: inline-block; 59 | margin: 0 0 1em 0; 60 | padding: 1em 1.563em 0.9em; 61 | line-height: 1; 62 | background: #71b02f; 63 | color: #fff!important; 64 | cursor: pointer; 65 | border: none; 66 | text-shadow: none; 67 | font-size: .9em; 68 | font-family: "proxima-nova", sans-serif; 69 | font-weight: 600; 70 | text-align: center; 71 | text-decoration: none !important; 72 | text-transform: uppercase; 73 | outline: none!important; 74 | -webkit-box-sizing: border-box; 75 | -moz-box-sizing: border-box; 76 | box-sizing: border-box; 77 | -webkit-border-radius: 100px; 78 | border-radius: 100px; 79 | -moz-background-clip: padding; 80 | -webkit-background-clip: padding-box; 81 | background-clip: padding-box; 82 | } -------------------------------------------------------------------------------- /assets/css/frontend/wtsfc-frontend.min.css: -------------------------------------------------------------------------------- 1 | #wtsfc.subscribe-for-content-box{border:7px solid #42a2ce;margin-bottom:20px;padding:35px 50px;position:relative;text-align:center}#wtsfc.subscribe-for-content-box.subscribed-success{border-color:#71b02f;padding-bottom:20px}#wtsfc.subscribe-for-content-box.subscribed-success p{margin-bottom:1em}#wtsfc.subscribe-for-content-box.loading form,#wtsfc.subscribe-for-content-box.loading h3,#wtsfc.subscribe-for-content-box.loading p{opacity:.25}#wtsfc.subscribe-for-content-box.loading .loading-img{display:block!important;left:calc(50% - 25px);position:absolute;top:40%;width:50px}#wtsfc.subscribe-for-content-box p{font-size:17px}#wtsfc.subscribe-for-content-box .error{color:#bd123b;font-size:14px;font-weight:700;margin-top:20px}#wtsfc.subscribe-for-content-box form .email-input{margin:-1px 12px 0 0;padding:12px 2px 11px 18px;vertical-align:top}#wtsfc.subscribe-for-content-box form .email-input::-webkit-input-placeholder{color:#aaa}#wtsfc.subscribe-for-content-box form .email-input::-moz-placeholder{color:#aaa}#wtsfc.subscribe-for-content-box form .email-input:-ms-input-placeholder{color:#aaa}#wtsfc.subscribe-for-content-box form select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:url(../../images/select-arrow.jpg)95% 1.2em no-repeat #fff;background-size:.6em;border:1px solid #e6e6e6;height:2.65em;margin:-1px 10px 0 0;padding-left:10px;vertical-align:top;width:11em}#wtsfc.subscribe-for-content-box form .button{display:inline-block;margin:0 0 1em;padding:1em 1.563em .9em;line-height:1;background:#71b02f;color:#fff!important;cursor:pointer;border:none;text-shadow:none;font-size:.9em;font-family:proxima-nova,sans-serif;font-weight:600;text-align:center;text-decoration:none!important;text-transform:uppercase;outline:0!important;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-border-radius:100px;border-radius:100px;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box} -------------------------------------------------------------------------------- /assets/images/loading.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /assets/images/select-arrow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woocommerce/subscribe-for-content/ccb1405fc462aba1bcf618281413760faefffc8e/assets/images/select-arrow.jpg -------------------------------------------------------------------------------- /assets/js/admin/wtsfc-admin.js: -------------------------------------------------------------------------------- 1 | (function ( $ ) { 2 | 'use strict'; 3 | 4 | $(document).ready(function() { 5 | 6 | /** 7 | * After API key has been added, we can get lists for it. 8 | */ 9 | $('.wtsfc-settings .mailchimp-api-key').on('keyup', function () { 10 | var $disabled = ( $(this).val() == '' ) ? true : false; 11 | $('.wtsfc-settings .mailchimp-get-lists-button').prop('disabled', $disabled); 12 | }); 13 | 14 | /** 15 | * Get Lists button. 16 | */ 17 | $('.wtsfc-settings .mailchimp-get-lists-button').on('click', function (e) { 18 | e.preventDefault(); 19 | 20 | var $this = $(this); 21 | var $api_key = $('.wtsfc-settings .mailchimp-api-key').val(); 22 | 23 | $this.prop('disabled', true).attr('value', 'Getting Lists').after(''); 24 | 25 | /** 26 | * Data to post. 27 | */ 28 | var post_data = { 29 | action: 'wtsfc_get_mailchimp_lists', 30 | security: wtsfc_params.security, 31 | api_key: $api_key 32 | }; 33 | 34 | /** 35 | * Here we make the actual Ajax request. 36 | */ 37 | $.ajax({ 38 | type: 'POST', 39 | url: wtsfc_params.ajax_url, 40 | cache: false, 41 | dataType: 'json', 42 | data: post_data, 43 | success: function (data) { 44 | 45 | // remove loading icon 46 | $this.next().remove(); 47 | 48 | /** 49 | * Check we have a response before continuing. 50 | */ 51 | if (null !== data) { 52 | var data = $.parseJSON(data); 53 | /** 54 | * If we have one that's successful, let you know. 55 | * If not, show an error with the reason why. 56 | */ 57 | if (true == data.success) { 58 | console.log(data); 59 | 60 | // add lists select 61 | $this.after(''); 62 | $.each(data.lists.data, function (key, value) { 63 | $('select#mailchimp_list').append( 64 | '' 65 | ); 66 | }); 67 | 68 | // remove this 69 | $this.remove(); 70 | //$this.after('Done indexing!'); 71 | } else { 72 | if (true == data.error) { 73 | $this.after('
' + data.reason + '
'); 74 | $this.prop('disabled', false); 75 | } 76 | } 77 | } 78 | } 79 | }); 80 | }); 81 | 82 | /** 83 | * Show list ID below after select list. 84 | * @todo also show interest groups. 85 | */ 86 | $('.wtsfc-settings #mailchimp_list').on('change', function(e) { 87 | e.preventDefault(); 88 | $(this).siblings('.list-id').remove(); // remove previous list id descriptions first 89 | $(this).after('This list\'s ID is ' + $(this).val() + '.'); 90 | }); 91 | 92 | /** 93 | * Show interest group interests. 94 | */ 95 | $('.wtsfc-settings #mailchimp_group').on('change', function(e) { 96 | e.preventDefault(); 97 | var $selected = $(this).find('option:selected').val(); 98 | $('.wtsfc-settings ul.interests').css('display', 'none'); 99 | if ( $selected !== 'none' ) { 100 | $('.wtsfc-settings .interests-description').css('display', 'block'); 101 | $('.wtsfc-settings ul.interests-' + $selected).css('display', 'block'); 102 | } else { 103 | $('.wtsfc-settings .interests-description').css('display', 'none'); 104 | } 105 | }); 106 | 107 | }); 108 | 109 | }( jQuery )); -------------------------------------------------------------------------------- /assets/js/admin/wtsfc-admin.min.js: -------------------------------------------------------------------------------- 1 | !function(a){"use strict";a(document).ready(function(){a(".wtsfc-settings .mailchimp-api-key").on("keyup",function(){var b=""==a(this).val()?!0:!1;a(".wtsfc-settings .mailchimp-get-lists-button").prop("disabled",b)}),a(".wtsfc-settings .mailchimp-get-lists-button").on("click",function(b){b.preventDefault();var c=a(this),d=a(".wtsfc-settings .mailchimp-api-key").val();c.prop("disabled",!0).attr("value","Getting Lists").after('');var e={action:"wtsfc_get_mailchimp_lists",security:wtsfc_params.security,api_key:d};a.ajax({type:"POST",url:wtsfc_params.ajax_url,cache:!1,dataType:"json",data:e,success:function(b){if(c.next().remove(),null!==b){var b=a.parseJSON(b);1==b.success?(console.log(b),c.after(''),a.each(b.lists.data,function(b,c){a("select#mailchimp_list").append('")}),c.remove()):1==b.error&&(c.after('
'+b.reason+"
"),c.prop("disabled",!1))}}})}),a(".wtsfc-settings #mailchimp_list").on("change",function(b){b.preventDefault(),a(this).siblings(".list-id").remove(),a(this).after('This list\'s ID is '+a(this).val()+".")}),a(".wtsfc-settings #mailchimp_group").on("change",function(b){b.preventDefault();var c=a(this).find("option:selected").val();a(".wtsfc-settings ul.interests").css("display","none"),"none"!==c?(a(".wtsfc-settings .interests-description").css("display","block"),a(".wtsfc-settings ul.interests-"+c).css("display","block")):a(".wtsfc-settings .interests-description").css("display","none")})})}(jQuery); -------------------------------------------------------------------------------- /assets/js/frontend/wtsfc-frontend.js: -------------------------------------------------------------------------------- 1 | (function ( $ ) { 2 | 'use strict'; 3 | 4 | // Cookie.js - Copyright (c) 2012 Florian H., https://github.com/js-coder https://github.com/js-coder/cookie.js 5 | !function(e,t){var n=function(){return n.get.apply(n,arguments)},r=n.utils={isArray:Array.isArray||function(e){return Object.prototype.toString.call(e)==="[object Array]"},isPlainObject:function(e){return!!e&&Object.prototype.toString.call(e)==="[object Object]"},toArray:function(e){return Array.prototype.slice.call(e)},getKeys:Object.keys||function(e){var t=[],n="";for(n in e)e.hasOwnProperty(n)&&t.push(n);return t},escape:function(e){return String(e).replace(/[,;"\\=\s%]/g,function(e){return encodeURIComponent(e)})},retrieve:function(e,t){return e==null?t:e}};n.defaults={},n.expiresMultiplier=86400,n.set=function(n,i,s){if(r.isPlainObject(n))for(var o in n)n.hasOwnProperty(o)&&this.set(o,n[o],i);else{s=r.isPlainObject(s)?s:{expires:s};var u=s.expires!==t?s.expires:this.defaults.expires||"",a=typeof u;a==="string"&&u!==""?u=new Date(u):a==="number"&&(u=new Date(+(new Date)+1e3*this.expiresMultiplier*u)),u!==""&&"toGMTString"in u&&(u=";expires="+u.toGMTString());var f=s.path||this.defaults.path;f=f?";path="+f:"";var l=s.domain||this.defaults.domain;l=l?";domain="+l:"";var c=s.secure||this.defaults.secure?";secure":"";e.cookie=r.escape(n)+"="+r.escape(i)+u+f+l+c}return this},n.remove=function(e){e=r.isArray(e)?e:r.toArray(arguments);for(var t=0,n=e.length;t' + wtsfc_frontend_params.message_thankyou + '' + 97 | '

' + wtsfc_frontend_params.message_loading + '

' + 98 | '' 99 | ); 100 | 101 | /** 102 | * Data to post. 103 | */ 104 | var post_data = { 105 | action: 'wtsfc_get_full_content', 106 | security: wtsfc_frontend_params.security, 107 | current_post: $current_post 108 | }; 109 | 110 | /** 111 | * Here we make the actual Ajax request. 112 | */ 113 | $.ajax({ 114 | type: 'POST', 115 | url: wtsfc_frontend_params.ajax_url, 116 | cache: false, 117 | dataType: 'json', 118 | data: post_data, 119 | success: function (data) { 120 | /** 121 | * Check we have a response before continuing. 122 | */ 123 | if (null !== data) { 124 | var data = $.parseJSON(data); 125 | /** 126 | * If we have one that's successful, let you know. 127 | * If not, show an error with the reason why. 128 | */ 129 | if (true == data.success) { 130 | var $content = $(data.the_content).filter('.wtsfc-hidden-content').html(); 131 | $box.replaceWith('
' + $content + '
'); 132 | } else { 133 | if (true == data.error) { 134 | $this.after('
' + data.reason + '
'); 135 | } 136 | } 137 | } 138 | } 139 | }); 140 | 141 | } else { 142 | if (true == data.error) { 143 | $this.after('
' + data.reason + '
'); 144 | } 145 | } 146 | } 147 | } 148 | }); 149 | 150 | }); 151 | 152 | }); 153 | 154 | }( jQuery )); -------------------------------------------------------------------------------- /assets/js/frontend/wtsfc-frontend.min.js: -------------------------------------------------------------------------------- 1 | !function(a){"use strict";!function(a,b){var c=function(){return c.get.apply(c,arguments)},d=c.utils={isArray:Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)},isPlainObject:function(a){return!!a&&"[object Object]"===Object.prototype.toString.call(a)},toArray:function(a){return Array.prototype.slice.call(a)},getKeys:Object.keys||function(a){var b=[],c="";for(c in a)a.hasOwnProperty(c)&&b.push(c);return b},escape:function(a){return String(a).replace(/[,;"\\=\s%]/g,function(a){return encodeURIComponent(a)})},retrieve:function(a,b){return null==a?b:a}};c.defaults={},c.expiresMultiplier=86400,c.set=function(c,e,f){if(d.isPlainObject(c))for(var g in c)c.hasOwnProperty(g)&&this.set(g,c[g],e);else{f=d.isPlainObject(f)?f:{expires:f};var h=f.expires!==b?f.expires:this.defaults.expires||"",i=typeof h;"string"===i&&""!==h?h=new Date(h):"number"===i&&(h=new Date(+new Date+1e3*this.expiresMultiplier*h)),""!==h&&"toGMTString"in h&&(h=";expires="+h.toGMTString());var j=f.path||this.defaults.path;j=j?";path="+j:"";var k=f.domain||this.defaults.domain;k=k?";domain="+k:"";var l=f.secure||this.defaults.secure?";secure":"";a.cookie=d.escape(c)+"="+d.escape(e)+h+j+k+l}return this},c.remove=function(a){a=d.isArray(a)?a:d.toArray(arguments);for(var b=0,c=a.length;c>b;b++)this.set(a[b],"",-1);return this},c.empty=function(){return this.remove(d.getKeys(this.all()))},c.get=function(a,c){c=c||b;var e=this.all();if(d.isArray(a)){for(var f={},g=0,h=a.length;h>g;g++){var i=a[g];f[i]=d.retrieve(e[i],c)}return f}return d.retrieve(e[a],c)},c.all=function(){if(""===a.cookie)return{};for(var b=a.cookie.split("; "),c={},d=0,e=b.length;e>d;d++){var f=b[d].split("=");c[decodeURIComponent(f[0])]=decodeURIComponent(f[1])}return c},c.enabled=function(){if(navigator.cookieEnabled)return!0;var a="_"===c.set("_","_").get("_");return c.remove("_"),a},"function"==typeof define&&define.amd?define(function(){return c}):"undefined"!=typeof exports?exports.cookie=c:window.cookie=c}(document),a(document).ready(function(){var b=a("#wtsfc.subscribe-for-content-box form#subscribe");b.find("select.group-interest").on("change",function(c){c.preventDefault(),b.find(".interests").val(a(this).find("option:selected").text())}),b.on("submit",function(c){c.preventDefault();var d=a(this),e=b.find(".email-input").val(),f=b.find(".list-id").val(),g=b.find(".group-id").val(),h=b.find(".interests").val(),i=b.find(".current-post").val();d.siblings(".error").remove(),d.parent().addClass("loading"),d.find(".submit-subscribe").prop("disabled",!0);var j={action:"wtsfc_subscribe_list",security:wtsfc_frontend_params.security,email:e,list:f,group:g,interests:h,current_post:i};a.ajax({type:"POST",url:wtsfc_frontend_params.ajax_url,cache:!1,dataType:"json",data:j,success:function(b){if(d.parent().removeClass("loading"),d.find(".submit-subscribe").prop("disabled",!1),null!==b){var b=a.parseJSON(b);if(1==b.success){null!==b.cookie&&cookie.set(b.cookie.key,b.cookie.value,{expires:365,path:b.cookie.path,secure:!1});var c=d.closest("#wtsfc");c.addClass("subscribed-success").html("

"+wtsfc_frontend_params.message_thankyou+"

"+wtsfc_frontend_params.message_loading+'

');var e={action:"wtsfc_get_full_content",security:wtsfc_frontend_params.security,current_post:i};a.ajax({type:"POST",url:wtsfc_frontend_params.ajax_url,cache:!1,dataType:"json",data:e,success:function(b){if(null!==b){var b=a.parseJSON(b);if(1==b.success){var e=a(b.the_content).filter(".wtsfc-hidden-content").html();c.replaceWith('
'+e+"
")}else 1==b.error&&d.after('
'+b.reason+"
")}}})}else 1==b.error&&d.after('
'+b.reason+"
")}}})})})}(jQuery); -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | *** Subscribe For Content Changelog *** 2 | 3 | 2015.10.06 - version 1.0.1 4 | * Wrap ajax-requested content in hidden class. 5 | 6 | 2015.09.02 - version 1.0.0 7 | * First Release. 8 | -------------------------------------------------------------------------------- /includes/class-wtsfc-ajax.php: -------------------------------------------------------------------------------- 1 | true, 44 | 'reason' => __( 'No API Key sent!', 'subscribe-for-content' ), 45 | ) ) ); 46 | } 47 | 48 | /** 49 | * What is the API key we're dealing with? 50 | */ 51 | $api_key = sanitize_text_field( $_POST['api_key'] ); 52 | 53 | /** 54 | * Get lists. 55 | */ 56 | $api = new WT_Subscribe_For_Content_MailChimp_API( $api_key ); 57 | $lists = $api->get_lists(); 58 | 59 | /** 60 | * Have lists? 61 | */ 62 | if ( ! $lists ) { 63 | wp_send_json( json_encode( array( 64 | 'error' => true, 65 | 'reason' => __( 'No lists found for this API Key! Try another one or add a list first.', 'subscribe-for-content' ), 66 | ) ) ); 67 | } 68 | 69 | /** 70 | * Build response. 71 | */ 72 | $response = array( 73 | 'success' => true, 74 | 'lists' => $lists, 75 | ); 76 | 77 | /** 78 | * Return response. 79 | */ 80 | wp_send_json( json_encode( $response ) ); 81 | 82 | } 83 | 84 | /** 85 | * Subscribes an email to the list. 86 | */ 87 | public function subscribe_list() { 88 | /** 89 | * Should we be here? 90 | */ 91 | check_ajax_referer( 'wtsfc_nonce', 'security' ); 92 | 93 | /** 94 | * Have Email & Current Post? 95 | */ 96 | if ( ! isset( $_POST['email'] ) || ! isset( $_POST['current_post'] ) ) { 97 | wp_send_json( json_encode( array( 98 | 'error' => true, 99 | 'reason' => __( 'No email / post provided!', 'subscribe-for-content' ), 100 | ) ) ); 101 | } 102 | 103 | /** 104 | * What is the email we're dealing with? 105 | */ 106 | $email = sanitize_email( $_POST['email'] ); 107 | 108 | /** 109 | * Figure out the list ID to subscribe to. 110 | */ 111 | $list_id = sanitize_text_field( $_POST['list'] ); 112 | 113 | /** 114 | * Are we dealing with interests/groups? 115 | * @note for now, only single group, but multiple possible. 116 | * @ps I know the use of group + interest terms is confusing ;) 117 | */ 118 | $groups = array(); 119 | if ( isset( $_POST['group'] ) && isset( $_POST['interests'] ) ) { 120 | $groups = array( 121 | 'id' => sanitize_text_field( $_POST['group'] ), 122 | 'groups' => array( sanitize_text_field( $_POST['interests'] ) ), 123 | ); 124 | } 125 | 126 | /** 127 | * Subscribe email to list. 128 | */ 129 | $options = get_option( 'wtsfc_settings' ); 130 | $api = new WT_Subscribe_For_Content_MailChimp_API( $options['wtsfc_mailchimp_api_key'] ); 131 | $subscribe = $api->subscribe_to_list_by_email( $list_id, $email, $groups ); 132 | 133 | /** 134 | * Could subscribe? 135 | */ 136 | if ( ! $subscribe ) { 137 | wp_send_json( json_encode( array( 138 | 'error' => true, 139 | 'reason' => __( 'Something went wrong and we could not subscribe you! Please try again.', 'subscribe-for-content' ), 140 | ) ) ); 141 | } 142 | 143 | /** 144 | * The 42-character key for the email is a random key we save in a cookie 145 | * and as the key for the subscribed email record saved. 146 | */ 147 | $random_key = substr( str_shuffle( MD5( microtime() ) ), 0, 42 ); 148 | 149 | /** 150 | * Set cookie for the user with their email. 151 | */ 152 | $cookiepath = defined( 'COOKIEPATH' ) ? COOKIEPATH : '/'; 153 | $cookie = NULL; 154 | if ( apply_filters( 'wtsfc_setcookie_js', true ) ) { 155 | $cookie = array( 156 | 'key' => 'wtsfc_' . $list_id . '_email', 157 | 'value' => $random_key, 158 | 'path' => $cookiepath, 159 | ); 160 | } else { 161 | setcookie( 'wtsfc_' . $list_id . '_email', $random_key, time() + ( 1 * YEAR_IN_SECONDS ), $cookiepath ); 162 | } 163 | 164 | /** 165 | * Add to option for this list where emails are saved: 166 | */ 167 | $subscribed_emails = get_option( 'wtsfc_' . $list_id . '_subscribed_emails' ); 168 | if ( $subscribed_emails == false || empty( $subscribed_emails ) ) { 169 | /** 170 | * First email saved, create a fresh array to store it. 171 | */ 172 | $subscribed_emails = array( $random_key => $email ); 173 | } else { 174 | /** 175 | * If by some miracle, literally *miracle*, the key already 176 | * exists, create a new one for this email before saving. 177 | */ 178 | if ( isset( $subscribed_emails[$random_key] ) ) { 179 | $random_key = substr( str_shuffle( MD5( microtime() ) ), 0, 42 ); 180 | } 181 | /** 182 | * Append to existing array. 183 | */ 184 | $subscribed_emails[$random_key] = $email; 185 | } 186 | update_option( 'wtsfc_' . $list_id . '_subscribed_emails', $subscribed_emails ); 187 | 188 | /** 189 | * Build successful response. 190 | */ 191 | $response = array( 192 | 'success' => true, 193 | 'message' => __( 'We successfully subscribed you!', 'subscribe-for-content' ), 194 | 'cookie' => $cookie, 195 | ); 196 | 197 | /** 198 | * Return response. 199 | */ 200 | wp_send_json( json_encode( $response ) ); 201 | 202 | } 203 | 204 | /** 205 | * Get full content for a post to output after subscribing. 206 | */ 207 | public function get_content() { 208 | /** 209 | * Should we be here? 210 | */ 211 | check_ajax_referer( 'wtsfc_nonce', 'security' ); 212 | 213 | /** 214 | * Have Email & Current Post? 215 | */ 216 | if ( ! isset( $_POST['current_post'] ) ) { 217 | wp_send_json( json_encode( array( 218 | 'error' => true, 219 | 'reason' => __( 'No post provided!', 'subscribe-for-content' ), 220 | ) ) ); 221 | } 222 | 223 | /** 224 | * What is the post id we're dealing with? 225 | */ 226 | $post_id = intval( $_POST['current_post'] ); 227 | 228 | /** 229 | * Current post they're looking at. 230 | * We need to get the_content for it. 231 | */ 232 | $post = get_post( $post_id ); 233 | $the_content = apply_filters( 'the_content', $post->post_content ); 234 | 235 | /** 236 | * Build successful response. 237 | */ 238 | $response = array( 239 | 'success' => true, 240 | 'the_content' => $the_content, 241 | ); 242 | 243 | /** 244 | * Return response. 245 | */ 246 | wp_send_json( json_encode( $response ) ); 247 | 248 | } 249 | 250 | } 251 | 252 | new WT_Subscribe_For_Content_Ajax; 253 | 254 | endif; -------------------------------------------------------------------------------- /includes/class-wtsfc-api.php: -------------------------------------------------------------------------------- 1 | query_vars['wtsfc-api'] = $_GET['wtsfc-api']; 64 | } 65 | 66 | // wtsfc-api endpoint requests 67 | if ( ! empty( $wp->query_vars['wtsfc-api'] ) ) { 68 | 69 | // Buffer, we won't want any output here 70 | ob_start(); 71 | 72 | // Get API trigger 73 | $api = strtolower( esc_attr( $wp->query_vars['wtsfc-api'] ) ); 74 | 75 | // Trigger actions 76 | do_action( 'wtsfc_api_' . $api ); 77 | 78 | // Done, clear buffer and exit 79 | ob_end_clean(); 80 | die('1'); 81 | } 82 | } 83 | 84 | } 85 | 86 | endif; 87 | 88 | new WTSFC_API(); -------------------------------------------------------------------------------- /includes/class-wtsfc-mailchimp-api.php: -------------------------------------------------------------------------------- 1 | .api.mailchimp.com/2.0"; 22 | 23 | /** 24 | * MailChimp API Key 25 | * @var string 26 | */ 27 | private $api_key; 28 | 29 | /** 30 | * Constructor 31 | * 32 | * @param string $api_key 33 | */ 34 | public function __construct( $api_key ) { 35 | $this->api_key = $api_key; 36 | list( , $datacentre ) = explode( '-', $this->api_key ); 37 | $this->api_url = str_replace( '', $datacentre, $this->api_url ); 38 | } 39 | 40 | /** 41 | * Make a call to the API 42 | * 43 | * @param string $endpoint 44 | * @param array $body 45 | * @param string $method 46 | * 47 | * @return Object 48 | */ 49 | private function perform_request( $endpoint, $body = array(), $method = 'POST' ) { 50 | 51 | // Set API key if not set 52 | if ( ! isset( $body['apikey'] ) ) { 53 | $body['apikey'] = $this->api_key; 54 | } 55 | 56 | $args = apply_filters( 'wtsfc_mailchimp_request_args', array( 57 | 'method' => $method, 58 | 'timeout' => apply_filters( 'wtsfc_mailchimp_api_timeout', 45 ), // default to 45 seconds 59 | 'redirection' => 0, 60 | 'httpversion' => '1.0', 61 | 'sslverify' => false, 62 | 'blocking' => true, 63 | 'headers' => array( 64 | 'accept' => 'application/json', 65 | 'content-type' => 'application/json', 66 | ), 67 | 'body' => json_encode( $body ), 68 | 'cookies' => array(), 69 | 'user-agent' => "PHP " . PHP_VERSION . '/' . get_bloginfo('name'), 70 | ) ); 71 | 72 | $response = wp_remote_request( $this->api_url . $endpoint, $args ); 73 | 74 | if ( is_wp_error( $response ) ) { 75 | throw new Exception( 'Error performing remote MailChimp request.' ); 76 | } 77 | 78 | return $response; 79 | } // End perform_request() 80 | 81 | /** 82 | * Get a list of email lists 83 | * @return bool|array 84 | */ 85 | public function get_lists() { 86 | $response = $this->perform_request( '/lists/list.json' ); 87 | 88 | $response = wp_remote_retrieve_body( $response ); 89 | if ( is_wp_error( $response ) ) { 90 | return false; 91 | } 92 | 93 | $response = json_decode( $response, true ); 94 | 95 | if ( isset( $response['status'] ) && 'error' == $response['status'] ) { 96 | return false; 97 | } 98 | 99 | return $response; 100 | } // End get_lists() 101 | 102 | /** 103 | * Get a list of email list interest groups 104 | * @return bool|array 105 | */ 106 | public function get_interest_groups( $list_id ) { 107 | $data = array( 108 | 'id' => $list_id, 109 | ); 110 | $response = $this->perform_request( '/lists/interest-groupings.json', $data ); 111 | 112 | $response = wp_remote_retrieve_body( $response ); 113 | if ( is_wp_error( $response ) ) { 114 | return false; 115 | } 116 | 117 | $response = json_decode( $response, true ); 118 | 119 | if ( isset( $response['status'] ) && 'error' == $response['status'] ) { 120 | return false; 121 | } 122 | 123 | return $response; 124 | } // End get_interest_groups() 125 | 126 | /** 127 | * Subscribe to list by email address only 128 | * @param string $list_id [description] 129 | * @param string $email [description] 130 | * @param array $groupings [description] 131 | * @return boolean [description] 132 | */ 133 | public function subscribe_to_list_by_email( $list_id, $email, $groupings = array() ) { 134 | $data = array( 135 | 'id' => $list_id, 136 | 'email' => array( 'email' => $email ), 137 | 'double_optin' => apply_filters( 'wtsfc_subscribe_double_optin', false ), 138 | 'update_existing' => apply_filters( 'wtsfc_subscribe_update_existing', true ), 139 | ); 140 | 141 | if ( ! empty( $groupings ) ) { 142 | $data['merge_vars']['groupings'] = array( $groupings ); 143 | } 144 | 145 | $response = $this->perform_request( '/lists/subscribe.json', $data ); 146 | 147 | $response = wp_remote_retrieve_body( $response ); 148 | if ( is_wp_error( $response ) ) { 149 | return false; 150 | } 151 | 152 | $response = json_decode( $response, true ); 153 | 154 | if ( isset( $response['status'] ) && 'error' == $response['status'] ) { 155 | return false; 156 | } 157 | 158 | return true; 159 | } // End subscribe_to_list_by_email() 160 | 161 | /** 162 | * Creates the needed webhooks in MailChimp. 163 | * By default, this is only unsubscribes. 164 | * 165 | * @param $list_id 166 | * @param $url 167 | * @param array $actions 168 | * 169 | * @return bool 170 | */ 171 | public function create_webhook( $list_id, $url, $actions = array() ) { 172 | $data = array( 173 | 'id' => $list_id, 174 | 'url' => $url, 175 | ); 176 | 177 | if ( ! empty( $actions ) ) { 178 | $data['actions'] = $actions; 179 | } 180 | 181 | $response = $this->perform_request( '/lists/webhook-add.json', $data ); 182 | 183 | $response = wp_remote_retrieve_body( $response ); 184 | 185 | if ( is_wp_error( $response ) ) { 186 | return false; 187 | } 188 | 189 | $response = json_decode( $response, true ); 190 | 191 | if ( isset( $response['status'] ) && 'error' == $response['status'] ) { 192 | return false; 193 | } 194 | 195 | return true; 196 | } 197 | 198 | } 199 | 200 | endif; -------------------------------------------------------------------------------- /includes/class-wtsfc-settings.php: -------------------------------------------------------------------------------- 1 | site_url = trailingslashit( site_url() ); 27 | 28 | } 29 | 30 | public function admin_scripts( $hook_suffix ) { 31 | 32 | $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; 33 | wp_register_style( 'wtsfc-admin-styles', plugins_url( 'assets/css/admin/wtsfc-admin.css', plugin_dir_path( __FILE__ ) ), array(), WT_Subscribe_For_Content::VERSION ); 34 | wp_register_script( 'wtsfc-admin-scripts', plugins_url( 'assets/js/admin/wtsfc-admin' . $suffix . '.js', plugin_dir_path( __FILE__ ) ), array( 'jquery' ), WT_Subscribe_For_Content::VERSION, true ); 35 | wp_localize_script( 36 | 'wtsfc-admin-scripts', 37 | 'wtsfc_params', 38 | array( 39 | 'ajax_url' => admin_url( 'admin-ajax.php' ), 40 | 'security' => wp_create_nonce( 'wtsfc_nonce' ), 41 | 'loading_img' => plugins_url( 'assets/images/loading.svg', plugin_dir_path( __FILE__ ) ), 42 | ) 43 | ); 44 | 45 | if ( $hook_suffix == 'settings_page_subscribe-for-content' ) { 46 | wp_enqueue_style( 'wtsfc-admin-styles' ); 47 | wp_enqueue_script( 'wtsfc-admin-scripts' ); 48 | } 49 | 50 | } 51 | 52 | /** 53 | * If the MailChimp API key & list ID is set, but 54 | * the webhooks have not been created yet, 55 | * create them and update the option. 56 | */ 57 | public function maybe_create_webhooks() { 58 | $options = get_option( 'wtsfc_settings' ); 59 | 60 | /** 61 | * This is a unique option for the currently selected list ID, 62 | * that lets us know if the webhook has been set yet. 63 | * The option stores a secret random key that is 64 | * used to validate MailChimp requests too. 65 | */ 66 | 67 | if ( isset( $options['wtsfc_mailchimp_api_key'] ) && $options['wtsfc_mailchimp_api_key'] && isset( $options['wtsfc_mailchimp_list'] ) && $options['wtsfc_mailchimp_list'] && current_user_can( 'manage_options' ) ) { 68 | 69 | $webhook_option_name = 'wtsfc_mailchimp_' . $options['wtsfc_mailchimp_list'] . '_webhooks_set'; 70 | $force = ( isset( $_GET['wtsfc_force_webhook_creation'] ) && $_GET['wtsfc_force_webhook_creation'] == 'true' ) ? true : false; 71 | 72 | if ( ! get_option( $webhook_option_name ) || $force ) { 73 | 74 | $api = new WT_Subscribe_For_Content_MailChimp_API( $options['wtsfc_mailchimp_api_key'] ); 75 | 76 | /** 77 | * Build the URL to create a webhook for receiving only unsubscribe notifications. 78 | */ 79 | $random_key = substr( str_shuffle( MD5( microtime() ) ), 0, 30 ); 80 | $url = $this->site_url . 'wtsfc-api/mailchimp-unsubscribe?mckey=' . $random_key; 81 | $actions = array( 82 | 'subscribe' => false, 83 | 'unsubscribe' => true, 84 | 'profile' => false, 85 | 'cleaned' => false, 86 | 'upemail' => false, 87 | 'campaign' => false, 88 | ); 89 | $create_webhook = $api->create_webhook( $options['wtsfc_mailchimp_list'], $url, $actions ); 90 | 91 | /** 92 | * Successful webhook creation? Set random key as the option. 93 | */ 94 | if ( $create_webhook ) { 95 | update_option( $webhook_option_name, $random_key ); 96 | } 97 | 98 | } 99 | 100 | } 101 | } 102 | 103 | public function admin_menu() { 104 | add_options_page( __( 'Subscribe For Content', 'subscribe-for-content' ), __( 'Subscribe For Content', 'subscribe-for-content' ), 'manage_options', 'subscribe-for-content', array( $this, 'page' ) ); 105 | } 106 | 107 | public function settings_init() { 108 | register_setting( 'sfc_settings', 'wtsfc_settings' ); 109 | 110 | add_settings_section( 111 | 'wtsfc_mailchimp_auth', 112 | __( 'MailChimp Settings', 'subscribe-for-content' ), 113 | array( $this, 'auth_description_render' ), 114 | 'sfc_settings' 115 | ); 116 | 117 | add_settings_field( 118 | 'wtsfc_mailchimp_api_key', 119 | __( 'API Key', 'subscribe-for-content' ), 120 | array( $this, 'mailchimp_api_key_render' ), 121 | 'sfc_settings', 122 | 'wtsfc_mailchimp_auth' 123 | ); 124 | 125 | add_settings_field( 126 | 'wtsfc_mailchimp_list', 127 | __( 'List (default)', 'subscribe-for-content' ), 128 | array( $this, 'mailchimp_list_render' ), 129 | 'sfc_settings', 130 | 'wtsfc_mailchimp_auth' 131 | ); 132 | 133 | add_settings_field( 134 | 'wtsfc_mailchimp_interest_groups', 135 | __( 'Interest Group (default)', 'subscribe-for-content' ), 136 | array( $this, 'mailchimp_interest_groups_render' ), 137 | 'sfc_settings', 138 | 'wtsfc_mailchimp_auth' 139 | ); 140 | 141 | /** 142 | * If the API key and list settings have been set, 143 | * show the settings to modify box copy. 144 | */ 145 | $options = get_option( 'wtsfc_settings' ); 146 | 147 | if ( isset( $options['wtsfc_mailchimp_api_key'] ) && $options['wtsfc_mailchimp_api_key'] && isset( $options['wtsfc_mailchimp_list'] ) ) { 148 | 149 | add_settings_section( 150 | 'wtsfc_copy', 151 | __( 'Subscribe Box Copy', 'subscribe-for-content' ), 152 | array( $this, 'copy_description_render' ), 153 | 'sfc_settings' 154 | ); 155 | 156 | add_settings_field( 157 | 'wtsfc_copy_heading', 158 | __( 'Heading', 'subscribe-for-content' ), 159 | array( $this, 'copy_heading_render' ), 160 | 'sfc_settings', 161 | 'wtsfc_copy' 162 | ); 163 | 164 | add_settings_field( 165 | 'wtsfc_copy_subheading', 166 | __( 'Sub-heading', 'subscribe-for-content' ), 167 | array( $this, 'copy_subheading_render' ), 168 | 'sfc_settings', 169 | 'wtsfc_copy' 170 | ); 171 | 172 | add_settings_field( 173 | 'wtsfc_copy_button', 174 | __( 'Subscribe button', 'subscribe-for-content' ), 175 | array( $this, 'copy_button_render' ), 176 | 'sfc_settings', 177 | 'wtsfc_copy' 178 | ); 179 | 180 | } 181 | 182 | /** 183 | * Blank API key? Clear settings. 184 | * @todo once setting for saved subscribers is split up for lists, clear webhook event settings too (per list). 185 | */ 186 | if ( isset( $options['wtsfc_mailchimp_api_key'] ) && ! $options['wtsfc_mailchimp_api_key'] ) { 187 | delete_option( 'wtsfc_settings' ); 188 | } 189 | 190 | } 191 | 192 | public function auth_description_render() { 193 | _e( 'MailChimp settings for integration with Subscribe For Content.', 'subscribe-for-content' ); 194 | } 195 | 196 | public function mailchimp_api_key_render() { 197 | $options = get_option( 'wtsfc_settings' ); ?> 198 | '> 199 | 200 | MailChimp Account' ); ?> 201 | 202 | '; 210 | } else { 211 | if ( $lists = $this->get_mailchimp_lists( $options['wtsfc_mailchimp_api_key'] ) ) { 212 | ?> 213 | 219 | 220 | . 221 | get_mailchimp_interest_groups( $options['wtsfc_mailchimp_api_key'], $options['wtsfc_mailchimp_list']) ) { 233 | ?> 234 | 241 | 242 | 245 | > 246 | 247 |
    248 | 249 |
  • :
  • 250 | 251 |
252 | 265 | ' placeholder=""> 266 | 271 | ' placeholder=""> 272 | 277 | ' placeholder=""> 278 | get_lists(); 299 | set_transient( 'wtsfc_' . substr( $api_key, 0, 5 ) . '_mailchimp_lists', $lists, 1 * DAY_IN_SECONDS ); 300 | } 301 | 302 | /** 303 | * No lists, return false. 304 | */ 305 | if ( $lists['total'] == 0 ) { 306 | return false; 307 | } 308 | 309 | /** 310 | * Have lists - return lists. 311 | */ 312 | return $lists['data']; 313 | } 314 | 315 | /** 316 | * Get MailChimp list group interests based on list ID. 317 | * 318 | * @param bool|false $api_key 319 | * @param $list_id 320 | * 321 | * @return bool 322 | */ 323 | public function get_mailchimp_interest_groups( $api_key, $list_id ) { 324 | if ( ! $api_key || ! $list_id ) { 325 | return false; 326 | } 327 | 328 | /** 329 | * Get interest groups. 330 | */ 331 | $api = new WT_Subscribe_For_Content_MailChimp_API( $api_key ); 332 | if ( false === ( $interest_groups = get_transient( 'wtsfc_' . $list_id . '_mailchimp_interest_groups' ) ) ) { 333 | $interest_groups = $api->get_interest_groups( $list_id ); 334 | set_transient( 'wtsfc_' . $list_id . '_mailchimp_interest_groups', $interest_groups, 1 * DAY_IN_SECONDS ); 335 | } 336 | 337 | 338 | /** 339 | * No interest groups, return false. 340 | */ 341 | if ( count( $interest_groups ) < 1 ) { 342 | return false; 343 | } 344 | 345 | /** 346 | * All good, return interest groups. 347 | */ 348 | return $interest_groups; 349 | } 350 | 351 | public function page() { 352 | $options = get_option( 'wtsfc_settings' ); 353 | ?> 354 |
355 | 356 |

357 | 358 | 363 | 364 |
365 | All Emails'; 368 | $lists = $this->get_mailchimp_lists( $options['wtsfc_mailchimp_api_key'] ); 369 | foreach( $lists as $list ) { 370 | echo '

' . $list['name'] . '

'; 371 | echo '
';
372 | 					print_r( get_option( 'wtsfc_' . $list['id'] . '_subscribed_emails' ) );
373 | 				echo '
'; 374 | } 375 | } 376 | } 377 | } 378 | 379 | new WT_Subscribe_For_Content_Settings; 380 | 381 | endif; -------------------------------------------------------------------------------- /includes/class-wtsfc-shortcode.php: -------------------------------------------------------------------------------- 1 | admin_url( 'admin-ajax.php', is_ssl() ? 'https' : 'http' ), 39 | 'security' => wp_create_nonce( 'wtsfc_nonce' ), 40 | 'loading_img' => plugins_url( 'assets/images/loading.svg', plugin_dir_path( __FILE__ ) ), 41 | 'message_thankyou' => __( 'Thank you for subscribing!', 'subscribe-for-content' ), 42 | 'message_loading' => __( 'Loading content for you now...', 'subscribe-for-content' ), 43 | ) ) ); 44 | 45 | // enqueue 46 | wp_enqueue_script( 'wtsfc-frontend-scripts' ); 47 | wp_enqueue_style( 'wtsfc-frontend-styles' ); 48 | 49 | } 50 | 51 | /** 52 | * The [wtsfc] shortcode's output. 53 | * 54 | * @param $atts 55 | * @param null $content 56 | * 57 | * @return string 58 | */ 59 | public function shortcode_output( $atts, $content = null ) { 60 | 61 | /** 62 | * Get the saved settings for defaults. 63 | */ 64 | $options = get_option( 'wtsfc_settings' ); 65 | 66 | /** 67 | * If API key and default list not set, just stop now and show normal content. 68 | */ 69 | if ( ! isset( $options['wtsfc_mailchimp_api_key'] ) || ! $options['wtsfc_mailchimp_api_key'] || ! isset( $options['wtsfc_mailchimp_list'] ) || ! $options['wtsfc_mailchimp_list'] ) { 70 | return apply_filters( 'the_content', $content ); 71 | } 72 | 73 | /** 74 | * Shortcode attributes. 75 | */ 76 | $a = shortcode_atts( array( 77 | 'list' => $options['wtsfc_mailchimp_list'], 78 | 'group' => isset( $options['wtsfc_mailchimp_interest_group'] ) && $options['wtsfc_mailchimp_interest_group'] !== 'none' ? $options['wtsfc_mailchimp_interest_group'] : false, 79 | 'interest' => false, 80 | 'heading' => isset( $options['wtsfc_copy_heading'] ) && $options['wtsfc_copy_heading'] ? sanitize_text_field( $options['wtsfc_copy_heading'] ) : __( 'Unlock some awesome content!', 'subscribe-for-content' ), 81 | 'subheading' => isset( $options['wtsfc_copy_subheading'] ) && $options['wtsfc_copy_subheading'] ? sanitize_text_field( $options['wtsfc_copy_subheading'] ) : '', 82 | 'button' => isset( $options['wtsfc_copy_button'] ) && $options['wtsfc_copy_button'] ? sanitize_text_field( $options['wtsfc_copy_button'] ) : __( 'Subscribe', 'subscribe-for-content' ), 83 | ), $atts ); 84 | 85 | /** 86 | * Get subscribed emails. 87 | */ 88 | $subscribed_emails = get_option( 'wtsfc_' . $a['list'] . '_subscribed_emails' ); 89 | 90 | /** 91 | * Figure out if they are already subscribed by cookie. 92 | */ 93 | $user_email_key = isset( $_COOKIE['wtsfc_' . $a['list'] . '_email'] ) ? $_COOKIE['wtsfc_' . $a['list'] . '_email'] : false; 94 | if ( $user_email_key ) { 95 | if ( isset( $subscribed_emails[$user_email_key] ) ) { 96 | return '
' . apply_filters( 'the_content', $content ) . '
'; 97 | } 98 | } 99 | 100 | /** 101 | * Figure out if they are already subscribed with their logged in account email. 102 | */ 103 | if ( is_user_logged_in() ) { 104 | global $current_user; 105 | get_currentuserinfo(); 106 | $current_user_email = sanitize_email( $current_user->user_email ); 107 | if ( ( $key = array_search( $current_user_email, $subscribed_emails ) ) !== false ) { 108 | return '
' . apply_filters( 'the_content', $content ) . '
'; 109 | } 110 | } 111 | 112 | /** 113 | * Check if it's a search engine / bot indexing the site. If so, we want to show them the content. 114 | * You can hide the content from bots by adding a filter like so to your functions.php: 115 | * add_filter( 'wtsfc_show_bots', '__return_false' ); 116 | */ 117 | if ( apply_filters( 'wtsfc_show_bots', true ) && isset( $_SERVER['HTTP_USER_AGENT'] ) && preg_match('/bot|crawl|slurp|spider/i', $_SERVER['HTTP_USER_AGENT'] ) ) { 118 | return apply_filters( 'the_content', $content ); 119 | } 120 | 121 | /** 122 | * Otherwise, show subscribe form. 123 | */ 124 | $loading_image = plugins_url( 'assets/images/loading.svg', plugin_dir_path( __FILE__ ) ); 125 | ob_start(); 126 | include_once( 'views/html-subscribe-form.php' ); 127 | return ob_get_clean(); 128 | } 129 | 130 | } 131 | 132 | new WT_Subscribe_For_Content_Shortcode; 133 | 134 | endif; -------------------------------------------------------------------------------- /includes/class-wtsfc-webhooks.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 |

5 |
6 | 7 | 18 | '; 20 | foreach ( $interests as $interest ) { 21 | echo ''; 22 | } 23 | echo ''; 24 | } ?> 25 | 26 | '; 29 | echo ''; 30 | } ?> 31 | 32 | 33 |
34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "subscribe-for-content", 3 | "description": "Hide parts of posts for non-subscribed users.", 4 | "version": "1.0.1", 5 | "title": "Subscribe For Content", 6 | "main": "Gruntfile.js", 7 | "devDependencies": { 8 | "grunt": "^0.4.5", 9 | "grunt-checktextdomain": "^0.1.1", 10 | "grunt-contrib-cssmin": "^0.9.0", 11 | "grunt-contrib-sass": "^0.9.2", 12 | "grunt-contrib-uglify": "^0.4.0", 13 | "grunt-contrib-watch": "^0.6.0", 14 | "grunt-notify": "^0.4.1", 15 | "grunt-wp-i18n": "^0.4.6", 16 | "install": "^0.1.8", 17 | "npm": "^2.7.1" 18 | }, 19 | "engines": { 20 | "node": ">=0.8.0", 21 | "npm": ">=1.1.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /subscribe-for-content.php: -------------------------------------------------------------------------------- 1 | ' . __( 'Settings', 'subscribe-for-content' ) . ''; 81 | $links[] = '' . __( 'Documentation', 'subscribe-for-content' ) . ''; 82 | return $links; 83 | } 84 | 85 | /** 86 | * Load the plugin text domain for translation. 87 | * 88 | * @return void 89 | */ 90 | public function load_plugin_textdomain() { 91 | $locale = apply_filters( 'plugin_locale', get_locale(), 'subscribe-for-content' ); 92 | 93 | load_textdomain( 'subscribe-for-content', trailingslashit( WP_LANG_DIR ) . 'subscribe-for-content/subscribe-for-content-' . $locale . '.mo' ); 94 | load_plugin_textdomain( 'subscribe-for-content', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' ); 95 | } 96 | 97 | } 98 | 99 | add_action( 'plugins_loaded', array( 'WT_Subscribe_For_Content', 'get_instance' ), 0 ); 100 | 101 | endif; --------------------------------------------------------------------------------