Better Notifications for WordPress - Version 1.8.8

Version Description

  • 4th February 2022 =
  • Improved: Select2 library is now included with the plugin instead of being loaded from CDN.
  • Fixed: Various changes relating to plugin structure, data sanitisation, and validation.
Download this release

Release Info

Developer voltronik
Plugin Icon 128x128 Better Notifications for WordPress
Version 1.8.8
Comparing to
See all releases

Code changes from version 1.8.7 to 1.8.8

README.txt CHANGED
@@ -5,7 +5,7 @@ Tags: notification, email, alert, message, notify, send, HTML, customize, bulk,
5
  Requires at least: 4.8
6
  Tested up to: 5.9
7
  Requires PHP: 7.0
8
- Stable tag: 1.8.7
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
  Update URI: https://wordpress.org/plugins/bnfw/
@@ -242,6 +242,10 @@ Yes, of course! The plugin is completely translation-friendly and if you send me
242
 
243
  == Changelog ==
244
 
 
 
 
 
245
  = 1.8.7 - 27th January 2022 =
246
  * IMPORTANT! It is recommended that you update this plugin to the latest version.
247
  * Fixed: A security issue affecting select2 fields when searching for a user or user role.
5
  Requires at least: 4.8
6
  Tested up to: 5.9
7
  Requires PHP: 7.0
8
+ Stable tag: 1.8.8
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
  Update URI: https://wordpress.org/plugins/bnfw/
242
 
243
  == Changelog ==
244
 
245
+ = 1.8.8 - 4th February 2022 =
246
+ * Improved: Select2 library is now included with the plugin instead of being loaded from CDN.
247
+ * Fixed: Various changes relating to plugin structure, data sanitisation, and validation.
248
+
249
  = 1.8.7 - 27th January 2022 =
250
  * IMPORTANT! It is recommended that you update this plugin to the latest version.
251
  * Fixed: A security issue affecting select2 fields when searching for a user or user role.
assets/css/select2.min.css ADDED
@@ -0,0 +1 @@
 
1
+ .select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;height:1px !important;margin:-1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__placeholder{color:#999;margin-top:5px;float:left}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb}
assets/js/select2.full.min.js ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){var b=function(){if(a&&a.fn&&a.fn.select2&&a.fn.select2.amd)var b=a.fn.select2.amd;var b;return function(){if(!b||!b.requirejs){b?c=b:b={};var a,c,d;!function(b){function e(a,b){return u.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=s.map,p=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(a=a.split("/"),g=a.length-1,s.nodeIdCompat&&w.test(a[g])&&(a[g]=a[g].replace(w,"")),a=n.slice(0,n.length-1).concat(a),k=0;k<a.length;k+=1)if(m=a[k],"."===m)a.splice(k,1),k-=1;else if(".."===m){if(1===k&&(".."===a[2]||".."===a[0]))break;k>0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if((n||p)&&o){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),n)for(l=n.length;l>0;l-=1)if(e=o[n.slice(0,l).join("/")],e&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&p&&p[d]&&(i=p[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(a,c){return function(){var d=v.call(arguments,0);return"string"!=typeof d[0]&&1===d.length&&d.push(null),n.apply(b,d.concat([a,c]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){q[a]=b}}function j(a){if(e(r,a)){var c=r[a];delete r[a],t[a]=!0,m.apply(b,c)}if(!e(q,a)&&!e(t,a))throw new Error("No "+a);return q[a]}function k(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function l(a){return function(){return s&&s.config&&s.config[a]||{}}}var m,n,o,p,q={},r={},s={},t={},u=Object.prototype.hasOwnProperty,v=[].slice,w=/\.js$/;o=function(a,b){var c,d=k(a),e=d[0];return a=d[1],e&&(e=f(e,b),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(b)):f(a,b):(a=f(a,b),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},p={require:function(a){return g(a)},exports:function(a){var b=q[a];return"undefined"!=typeof b?b:q[a]={}},module:function(a){return{id:a,uri:"",exports:q[a],config:l(a)}}},m=function(a,c,d,f){var h,k,l,m,n,s,u=[],v=typeof d;if(f=f||a,"undefined"===v||"function"===v){for(c=!c.length&&d.length?["require","exports","module"]:c,n=0;n<c.length;n+=1)if(m=o(c[n],f),k=m.f,"require"===k)u[n]=p.require(a);else if("exports"===k)u[n]=p.exports(a),s=!0;else if("module"===k)h=u[n]=p.module(a);else if(e(q,k)||e(r,k)||e(t,k))u[n]=j(k);else{if(!m.p)throw new Error(a+" missing "+k);m.p.load(m.n,g(f,!0),i(k),{}),u[n]=q[k]}l=d?d.apply(q[a],u):void 0,a&&(h&&h.exports!==b&&h.exports!==q[a]?q[a]=h.exports:l===b&&s||(q[a]=l))}else a&&(q[a]=d)},a=c=n=function(a,c,d,e,f){if("string"==typeof a)return p[a]?p[a](c):j(o(a,c).f);if(!a.splice){if(s=a,s.deps&&n(s.deps,s.callback),!c)return;c.splice?(a=c,c=d,d=null):a=b}return c=c||function(){},"function"==typeof d&&(d=e,e=f),e?m(b,a,c,d):setTimeout(function(){m(b,a,c,d)},4),n},n.config=function(a){return n(a)},a._defined=q,d=function(a,b,c){if("string"!=typeof a)throw new Error("See almond README: incorrect module build, no module name");b.splice||(c=b,b=[]),e(q,a)||e(r,a)||(r[a]=[a,b,c])},d.amd={jQuery:!0}}(),b.requirejs=a,b.require=c,b.define=d}}(),b.define("almond",function(){}),b.define("jquery",[],function(){var b=a||$;return null==b&&console&&console.error&&console.error("Select2: An instance of jQuery or a jQuery-compatible library was not found. Make sure that you are including jQuery before Select2 on your web page."),b}),b.define("select2/utils",["jquery"],function(a){function b(a){var b=a.prototype,c=[];for(var d in b){var e=b[d];"function"==typeof e&&"constructor"!==d&&c.push(d)}return c}var c={};c.Extend=function(a,b){function c(){this.constructor=a}var d={}.hasOwnProperty;for(var e in b)d.call(b,e)&&(a[e]=b[e]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},c.Decorate=function(a,c){function d(){var b=Array.prototype.unshift,d=c.prototype.constructor.length,e=a.prototype.constructor;d>0&&(b.call(arguments,a.prototype.constructor),e=c.prototype.constructor),e.apply(this,arguments)}function e(){this.constructor=d}var f=b(c),g=b(a);c.displayName=a.displayName,d.prototype=new e;for(var h=0;h<g.length;h++){var i=g[h];d.prototype[i]=a.prototype[i]}for(var j=(function(a){var b=function(){};a in d.prototype&&(b=d.prototype[a]);var e=c.prototype[a];return function(){var a=Array.prototype.unshift;return a.call(arguments,b),e.apply(this,arguments)}}),k=0;k<f.length;k++){var l=f[k];d.prototype[l]=j(l)}return d};var d=function(){this.listeners={}};return d.prototype.on=function(a,b){this.listeners=this.listeners||{},a in this.listeners?this.listeners[a].push(b):this.listeners[a]=[b]},d.prototype.trigger=function(a){var b=Array.prototype.slice,c=b.call(arguments,1);this.listeners=this.listeners||{},null==c&&(c=[]),0===c.length&&c.push({}),c[0]._type=a,a in this.listeners&&this.invoke(this.listeners[a],b.call(arguments,1)),"*"in this.listeners&&this.invoke(this.listeners["*"],arguments)},d.prototype.invoke=function(a,b){for(var c=0,d=a.length;d>c;c++)a[c].apply(this,b)},c.Observable=d,c.generateChars=function(a){for(var b="",c=0;a>c;c++){var d=Math.floor(36*Math.random());b+=d.toString(36)}return b},c.bind=function(a,b){return function(){a.apply(b,arguments)}},c._convertData=function(a){for(var b in a){var c=b.split("-"),d=a;if(1!==c.length){for(var e=0;e<c.length;e++){var f=c[e];f=f.substring(0,1).toLowerCase()+f.substring(1),f in d||(d[f]={}),e==c.length-1&&(d[f]=a[b]),d=d[f]}delete a[b]}}return a},c.hasScroll=function(b,c){var d=a(c),e=c.style.overflowX,f=c.style.overflowY;return e!==f||"hidden"!==f&&"visible"!==f?"scroll"===e||"scroll"===f?!0:d.innerHeight()<c.scrollHeight||d.innerWidth()<c.scrollWidth:!1},c.escapeMarkup=function(a){var b={"\\":"&#92;","&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#47;"};return"string"!=typeof a?a:String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})},c.appendMany=function(b,c){if("1.7"===a.fn.jquery.substr(0,3)){var d=a();a.map(c,function(a){d=d.add(a)}),c=d}b.append(c)},c}),b.define("select2/results",["jquery","./utils"],function(a,b){function c(a,b,d){this.$element=a,this.data=d,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<ul class="select2-results__options" role="tree"></ul>');return this.options.get("multiple")&&b.attr("aria-multiselectable","true"),this.$results=b,b},c.prototype.clear=function(){this.$results.empty()},c.prototype.displayMessage=function(b){var c=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var d=a('<li role="treeitem" aria-live="assertive" class="select2-results__option"></li>'),e=this.options.get("translations").get(b.message);d.append(c(e(b.args))),d[0].className+=" select2-results__message",this.$results.append(d)},c.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},c.prototype.append=function(a){this.hideLoading();var b=[];if(null==a.results||0===a.results.length)return void(0===this.$results.children().length&&this.trigger("results:message",{message:"noResults"}));a.results=this.sort(a.results);for(var c=0;c<a.results.length;c++){var d=a.results[c],e=this.option(d);b.push(e)}this.$results.append(b)},c.prototype.position=function(a,b){var c=b.find(".select2-results");c.append(a)},c.prototype.sort=function(a){var b=this.options.get("sorter");return b(a)},c.prototype.highlightFirstItem=function(){var a=this.$results.find(".select2-results__option[aria-selected]"),b=a.filter("[aria-selected=true]");b.length>0?b.first().trigger("mouseenter"):a.first().trigger("mouseenter"),this.ensureHighlightVisible()},c.prototype.setClasses=function(){var b=this;this.data.current(function(c){var d=a.map(c,function(a){return a.id.toString()}),e=b.$results.find(".select2-results__option[aria-selected]");e.each(function(){var b=a(this),c=a.data(this,"data"),e=""+c.id;null!=c.element&&c.element.selected||null==c.element&&a.inArray(e,d)>-1?b.attr("aria-selected","true"):b.attr("aria-selected","false")})})},c.prototype.showLoading=function(a){this.hideLoading();var b=this.options.get("translations").get("searching"),c={disabled:!0,loading:!0,text:b(a)},d=this.option(c);d.className+=" loading-results",this.$results.prepend(d)},c.prototype.hideLoading=function(){this.$results.find(".loading-results").remove()},c.prototype.option=function(b){var c=document.createElement("li");c.className="select2-results__option";var d={role:"treeitem","aria-selected":"false"};b.disabled&&(delete d["aria-selected"],d["aria-disabled"]="true"),null==b.id&&delete d["aria-selected"],null!=b._resultId&&(c.id=b._resultId),b.title&&(c.title=b.title),b.children&&(d.role="group",d["aria-label"]=b.text,delete d["aria-selected"]);for(var e in d){var f=d[e];c.setAttribute(e,f)}if(b.children){var g=a(c),h=document.createElement("strong");h.className="select2-results__group";a(h);this.template(b,h);for(var i=[],j=0;j<b.children.length;j++){var k=b.children[j],l=this.option(k);i.push(l)}var m=a("<ul></ul>",{"class":"select2-results__options select2-results__options--nested"});m.append(i),g.append(h),g.append(m)}else this.template(b,c);return a.data(c,"data",b),c},c.prototype.bind=function(b,c){var d=this,e=b.id+"-results";this.$results.attr("id",e),b.on("results:all",function(a){d.clear(),d.append(a.data),b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("results:append",function(a){d.append(a.data),b.isOpen()&&d.setClasses()}),b.on("query",function(a){d.hideMessages(),d.showLoading(a)}),b.on("select",function(){b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("unselect",function(){b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("open",function(){d.$results.attr("aria-expanded","true"),d.$results.attr("aria-hidden","false"),d.setClasses(),d.ensureHighlightVisible()}),b.on("close",function(){d.$results.attr("aria-expanded","false"),d.$results.attr("aria-hidden","true"),d.$results.removeAttr("aria-activedescendant")}),b.on("results:toggle",function(){var a=d.getHighlightedResults();0!==a.length&&a.trigger("mouseup")}),b.on("results:select",function(){var a=d.getHighlightedResults();if(0!==a.length){var b=a.data("data");"true"==a.attr("aria-selected")?d.trigger("close",{}):d.trigger("select",{data:b})}}),b.on("results:previous",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a);if(0!==c){var e=c-1;0===a.length&&(e=0);var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top,h=f.offset().top,i=d.$results.scrollTop()+(h-g);0===e?d.$results.scrollTop(0):0>h-g&&d.$results.scrollTop(i)}}),b.on("results:next",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a),e=c+1;if(!(e>=b.length)){var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top+d.$results.outerHeight(!1),h=f.offset().top+f.outerHeight(!1),i=d.$results.scrollTop()+h-g;0===e?d.$results.scrollTop(0):h>g&&d.$results.scrollTop(i)}}),b.on("results:focus",function(a){a.element.addClass("select2-results__option--highlighted")}),b.on("results:message",function(a){d.displayMessage(a)}),a.fn.mousewheel&&this.$results.on("mousewheel",function(a){var b=d.$results.scrollTop(),c=d.$results.get(0).scrollHeight-b+a.deltaY,e=a.deltaY>0&&b-a.deltaY<=0,f=a.deltaY<0&&c<=d.$results.height();e?(d.$results.scrollTop(0),a.preventDefault(),a.stopPropagation()):f&&(d.$results.scrollTop(d.$results.get(0).scrollHeight-d.$results.height()),a.preventDefault(),a.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(b){var c=a(this),e=c.data("data");return"true"===c.attr("aria-selected")?void(d.options.get("multiple")?d.trigger("unselect",{originalEvent:b,data:e}):d.trigger("close",{})):void d.trigger("select",{originalEvent:b,data:e})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(b){var c=a(this).data("data");d.getHighlightedResults().removeClass("select2-results__option--highlighted"),d.trigger("results:focus",{data:c,element:a(this)})})},c.prototype.getHighlightedResults=function(){var a=this.$results.find(".select2-results__option--highlighted");return a},c.prototype.destroy=function(){this.$results.remove()},c.prototype.ensureHighlightVisible=function(){var a=this.getHighlightedResults();if(0!==a.length){var b=this.$results.find("[aria-selected]"),c=b.index(a),d=this.$results.offset().top,e=a.offset().top,f=this.$results.scrollTop()+(e-d),g=e-d;f-=2*a.outerHeight(!1),2>=c?this.$results.scrollTop(0):(g>this.$results.outerHeight()||0>g)&&this.$results.scrollTop(f)}},c.prototype.template=function(b,c){var d=this.options.get("templateResult"),e=this.options.get("escapeMarkup"),f=d(b,c);null==f?c.style.display="none":"string"==typeof f?c.innerHTML=e(f):a(c).append(f)},c}),b.define("select2/keys",[],function(){var a={BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46};return a}),b.define("select2/selection/base",["jquery","../utils","../keys"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,b.Observable),d.prototype.render=function(){var b=a('<span class="select2-selection" role="combobox" aria-haspopup="true" aria-expanded="false"></span>');return this._tabindex=0,null!=this.$element.data("old-tabindex")?this._tabindex=this.$element.data("old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),b.attr("title",this.$element.attr("title")),b.attr("tabindex",this._tabindex),this.$selection=b,b},d.prototype.bind=function(a,b){var d=this,e=(a.id+"-container",a.id+"-results");this.container=a,this.$selection.on("focus",function(a){d.trigger("focus",a)}),this.$selection.on("blur",function(a){d._handleBlur(a)}),this.$selection.on("keydown",function(a){d.trigger("keypress",a),a.which===c.SPACE&&a.preventDefault()}),a.on("results:focus",function(a){d.$selection.attr("aria-activedescendant",a.data._resultId)}),a.on("selection:update",function(a){d.update(a.data)}),a.on("open",function(){d.$selection.attr("aria-expanded","true"),d.$selection.attr("aria-owns",e),d._attachCloseHandler(a)}),a.on("close",function(){d.$selection.attr("aria-expanded","false"),d.$selection.removeAttr("aria-activedescendant"),d.$selection.removeAttr("aria-owns"),d.$selection.focus(),d._detachCloseHandler(a)}),a.on("enable",function(){d.$selection.attr("tabindex",d._tabindex)}),a.on("disable",function(){d.$selection.attr("tabindex","-1")})},d.prototype._handleBlur=function(b){var c=this;window.setTimeout(function(){document.activeElement==c.$selection[0]||a.contains(c.$selection[0],document.activeElement)||c.trigger("blur",b)},1)},d.prototype._attachCloseHandler=function(b){a(document.body).on("mousedown.select2."+b.id,function(b){var c=a(b.target),d=c.closest(".select2"),e=a(".select2.select2-container--open");e.each(function(){var b=a(this);if(this!=d[0]){var c=b.data("element");c.select2("close")}})})},d.prototype._detachCloseHandler=function(b){a(document.body).off("mousedown.select2."+b.id)},d.prototype.position=function(a,b){var c=b.find(".selection");c.append(a)},d.prototype.destroy=function(){this._detachCloseHandler(this.container)},d.prototype.update=function(a){throw new Error("The `update` method must be defined in child classes.")},d}),b.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(a,b,c,d){function e(){e.__super__.constructor.apply(this,arguments)}return c.Extend(e,b),e.prototype.render=function(){var a=e.__super__.render.call(this);return a.addClass("select2-selection--single"),a.html('<span class="select2-selection__rendered"></span><span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span>'),a},e.prototype.bind=function(a,b){var c=this;e.__super__.bind.apply(this,arguments);var d=a.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",d),this.$selection.attr("aria-labelledby",d),this.$selection.on("mousedown",function(a){1===a.which&&c.trigger("toggle",{originalEvent:a})}),this.$selection.on("focus",function(a){}),this.$selection.on("blur",function(a){}),a.on("focus",function(b){a.isOpen()||c.$selection.focus()}),a.on("selection:update",function(a){c.update(a.data)})},e.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},e.prototype.display=function(a,b){var c=this.options.get("templateSelection"),d=this.options.get("escapeMarkup");return d(c(a,b))},e.prototype.selectionContainer=function(){return a("<span></span>")},e.prototype.update=function(a){if(0===a.length)return void this.clear();var b=a[0],c=this.$selection.find(".select2-selection__rendered"),d=this.display(b,c);c.empty().append(d),c.prop("title",b.title||b.text)},e}),b.define("select2/selection/multiple",["jquery","./base","../utils"],function(a,b,c){function d(a,b){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--multiple"),a.html('<ul class="select2-selection__rendered"></ul>'),a},d.prototype.bind=function(b,c){var e=this;d.__super__.bind.apply(this,arguments),this.$selection.on("click",function(a){e.trigger("toggle",{originalEvent:a})}),this.$selection.on("click",".select2-selection__choice__remove",function(b){if(!e.options.get("disabled")){var c=a(this),d=c.parent(),f=d.data("data");e.trigger("unselect",{originalEvent:b,data:f})}})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a,b){var c=this.options.get("templateSelection"),d=this.options.get("escapeMarkup");return d(c(a,b))},d.prototype.selectionContainer=function(){var b=a('<li class="select2-selection__choice"><span class="select2-selection__choice__remove" role="presentation">&times;</span></li>');return b},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d<a.length;d++){var e=a[d],f=this.selectionContainer(),g=this.display(e,f);f.append(g),f.prop("title",e.title||e.text),f.data("data",e),b.push(f)}var h=this.$selection.find(".select2-selection__rendered");c.appendMany(h,b)}},d}),b.define("select2/selection/placeholder",["../utils"],function(a){function b(a,b,c){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c)}return b.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},b.prototype.createPlaceholder=function(a,b){var c=this.selectionContainer();return c.html(this.display(b)),c.addClass("select2-selection__placeholder").removeClass("select2-selection__choice"),c},b.prototype.update=function(a,b){var c=1==b.length&&b[0].id!=this.placeholder.id,d=b.length>1;if(d||c)return a.call(this,b);this.clear();var e=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(e)},b}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e<d.length;e++){var f={data:d[e]};if(this.trigger("unselect",f),f.prevented)return}this.$element.val(this.placeholder.id).trigger("change"),this.trigger("toggle",{})}}},c.prototype._handleKeyboardClear=function(a,c,d){d.isOpen()||(c.which==b.DELETE||c.which==b.BACKSPACE)&&this._handleClear(c)},c.prototype.update=function(b,c){if(b.call(this,c),!(this.$selection.find(".select2-selection__placeholder").length>0||0===c.length)){var d=a('<span class="select2-selection__clear">&times;</span>');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('<li class="select2-search select2-search--inline"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" aria-autocomplete="list" /></li>');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return this._transferTabIndex(),d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.trigger("focus")}),b.on("close",function(){e.$search.val(""),e.$search.removeAttr("aria-activedescendant"),e.$search.trigger("focus")}),b.on("enable",function(){e.$search.prop("disabled",!1),e._transferTabIndex()}),b.on("disable",function(){e.$search.prop("disabled",!0)}),b.on("focus",function(a){e.$search.trigger("focus")}),b.on("results:focus",function(a){e.$search.attr("aria-activedescendant",a.id)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e._handleBlur(a)}),this.$selection.on("keydown",".select2-search--inline",function(a){a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented();var b=a.which;if(b===c.BACKSPACE&&""===e.$search.val()){var d=e.$searchContainer.prev(".select2-selection__choice");if(d.length>0){var f=d.data("data");e.searchRemoveChoice(f),a.preventDefault()}}});var f=document.documentMode,g=f&&11>=f;this.$selection.on("input.searchcheck",".select2-search--inline",function(a){return g?void e.$selection.off("input.search input.searchcheck"):void e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(a){if(g&&"input"===a.type)return void e.$selection.off("input.search input.searchcheck");var b=a.which;b!=c.SHIFT&&b!=c.CTRL&&b!=c.ALT&&b!=c.TAB&&e.handleSearch(a)})},d.prototype._transferTabIndex=function(a){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){var c=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch(),c&&this.$search.focus()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.$search.val(b.text),this.handleSearch()},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{var b=this.$search.val().length+1;a=.75*b+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){var a={"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"};return a}),b.define("select2/data/base",["../utils"],function(a){function b(a,c){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(a){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(a,b){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(a,b){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),d+=null!=c.id?"-"+c.id.toString():"-"+a.generateChars(4)},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change");
2
+ if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f<a.length;f++){var g=a[f].id;-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")});else{var d=a.id;this.$element.val(d),this.$element.trigger("change")}},d.prototype.unselect=function(a){var b=this;if(this.$element.prop("multiple"))return a.selected=!1,c(a.element).is("option")?(a.element.selected=!1,void this.$element.trigger("change")):void this.current(function(d){for(var e=[],f=0;f<d.length;f++){var g=d[f].id;g!==a.id&&-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")})},d.prototype.bind=function(a,b){var c=this;this.container=a,a.on("select",function(a){c.select(a.data)}),a.on("unselect",function(a){c.unselect(a.data)})},d.prototype.destroy=function(){this.$element.find("*").each(function(){c.removeData(this,"data")})},d.prototype.query=function(a,b){var d=[],e=this,f=this.$element.children();f.each(function(){var b=c(this);if(b.is("option")||b.is("optgroup")){var f=e.item(b),g=e.matches(a,f);null!==g&&d.push(g)}}),b({results:d})},d.prototype.addOptions=function(a){b.appendMany(this.$element,a)},d.prototype.option=function(a){var b;a.children?(b=document.createElement("optgroup"),b.label=a.text):(b=document.createElement("option"),void 0!==b.textContent?b.textContent=a.text:b.innerText=a.text),a.id&&(b.value=a.id),a.disabled&&(b.disabled=!0),a.selected&&(b.selected=!0),a.title&&(b.title=a.title);var d=c(b),e=this._normalizeItem(a);return e.element=b,c.data(b,"data",e),d},d.prototype.item=function(a){var b={};if(b=c.data(a[0],"data"),null!=b)return b;if(a.is("option"))b={id:a.val(),text:a.text(),disabled:a.prop("disabled"),selected:a.prop("selected"),title:a.prop("title")};else if(a.is("optgroup")){b={text:a.prop("label"),children:[],title:a.prop("title")};for(var d=a.children("option"),e=[],f=0;f<d.length;f++){var g=c(d[f]),h=this.item(g);e.push(h)}b.children=e}return b=this._normalizeItem(b),b.element=a[0],c.data(a[0],"data",b),b},d.prototype._normalizeItem=function(a){c.isPlainObject(a)||(a={id:a,text:a}),a=c.extend({},{text:""},a);var b={selected:!1,disabled:!1};return null!=a.id&&(a.id=a.id.toString()),null!=a.text&&(a.text=a.text.toString()),null==a._resultId&&a.id&&null!=this.container&&(a._resultId=this.generateResultId(this.container,a)),c.extend({},b,a)},d.prototype.matches=function(a,b){var c=this.options.get("matcher");return c(a,b)},d}),b.define("select2/data/array",["./select","../utils","jquery"],function(a,b,c){function d(a,b){var c=b.get("data")||[];d.__super__.constructor.call(this,a,b),this.addOptions(this.convertToOptions(c))}return b.Extend(d,a),d.prototype.select=function(a){var b=this.$element.find("option").filter(function(b,c){return c.value==a.id.toString()});0===b.length&&(b=this.option(a),this.addOptions(b)),d.__super__.select.call(this,a)},d.prototype.convertToOptions=function(a){function d(a){return function(){return c(this).val()==a.id}}for(var e=this,f=this.$element.find("option"),g=f.map(function(){return e.item(c(this)).id}).get(),h=[],i=0;i<a.length;i++){var j=this._normalizeItem(a[i]);if(c.inArray(j.id,g)>=0){var k=f.filter(d(j)),l=this.item(k),m=c.extend(!0,{},j,l),n=this.option(m);k.replaceWith(n)}else{var o=this.option(j);if(j.children){var p=this.convertToOptions(j.children);b.appendMany(o,p)}h.push(o)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(a,b){this.ajaxOptions=this._applyDefaults(b.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),d.__super__.constructor.call(this,a,b)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return c.extend({},a,{q:a.term})},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){d.status&&"0"===d.status||e.trigger("results:message",{message:"errorLoading"})});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url.call(this.$element,a)),"function"==typeof f.data&&(f.data=f.data.call(this.$element,a)),this.ajaxOptions.delay&&null!=a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");void 0!==f&&(this.createTag=f);var g=d.get("insertTag");if(void 0!==g&&(this.insertTag=g),b.call(this,c,d),a.isArray(e))for(var h=0;h<e.length;h++){var i=e[h],j=this._normalizeItem(i),k=this.option(j);this.$element.append(k)}}return b.prototype.query=function(a,b,c){function d(a,f){for(var g=a.results,h=0;h<g.length;h++){var i=g[h],j=null!=i.children&&!d({results:i.children},!0),k=i.text===b.term;if(k||j)return f?!1:(a.data=g,void c(a))}if(f)return!0;var l=e.createTag(b);if(null!=l){var m=e.option(l);m.attr("data-select2-tag",!0),e.addOptions([m]),e.insertTag(g,l)}a.results=g,c(a)}var e=this;return this._removeOldTags(),null==b.term||null!=b.page?void a.call(this,b,c):void a.call(this,b,d)},b.prototype.createTag=function(b,c){var d=a.trim(c.term);return""===d?null:{id:d,text:d}},b.prototype.insertTag=function(a,b,c){b.unshift(c)},b.prototype._removeOldTags=function(b){var c=(this._lastTag,this.$element.find("option[data-select2-tag]"));c.each(function(){this.selected||a(this).remove()})},b}),b.define("select2/data/tokenizer",["jquery"],function(a){function b(a,b,c){var d=c.get("tokenizer");void 0!==d&&(this.tokenizer=d),a.call(this,b,c)}return b.prototype.bind=function(a,b,c){a.call(this,b,c),this.$search=b.dropdown.$search||b.selection.$search||c.find(".select2-search__field")},b.prototype.query=function(b,c,d){function e(b){var c=g._normalizeItem(b),d=g.$element.find("option").filter(function(){return a(this).val()===c.id});if(!d.length){var e=g.option(c);e.attr("data-select2-tag",!0),g._removeOldTags(),g.addOptions([e])}f(c)}function f(a){g.trigger("select",{data:a})}var g=this;c.term=c.term||"";var h=this.tokenizer(c,this.options,e);h.term!==c.term&&(this.$search.length&&(this.$search.val(h.term),this.$search.focus()),c.term=h.term),b.call(this,c,d)},b.prototype.tokenizer=function(b,c,d,e){for(var f=d.get("tokenSeparators")||[],g=c.term,h=0,i=this.createTag||function(a){return{id:a.term,text:a.term}};h<g.length;){var j=g[h];if(-1!==a.inArray(j,f)){var k=g.substr(0,h),l=a.extend({},c,{term:k}),m=i(l);null!=m?(e(m),g=g.substr(h+1)||"",h=0):h++}else h++}return{term:g}},b}),b.define("select2/data/minimumInputLength",[],function(){function a(a,b,c){this.minimumInputLength=c.get("minimumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",b.term.length<this.minimumInputLength?void this.trigger("results:message",{message:"inputTooShort",args:{minimum:this.minimumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumInputLength",[],function(){function a(a,b,c){this.maximumInputLength=c.get("maximumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",this.maximumInputLength>0&&b.term.length>this.maximumInputLength?void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;return d.maximumSelectionLength>0&&f>=d.maximumSelectionLength?void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}}):void a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<span class="select2-dropdown"><span class="select2-results"></span></span>');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.bind=function(){},c.prototype.position=function(a,b){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a,b){function c(){}return c.prototype.render=function(b){var c=b.call(this),d=a('<span class="select2-search select2-search--dropdown"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" /></span>');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},c.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(b){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("focus",function(){c.isOpen()&&e.$search.focus()}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){var b=e.showSearch(a);b?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},c.prototype.handleSearch=function(a){if(!this._keyUpPrevented){var b=this.$search.val();this.trigger("query",{term:b})}this._keyUpPrevented=!1},c.prototype.showSearch=function(a,b){return!0},c}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){var c=e.$results.offset().top+e.$results.outerHeight(!1),d=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1);c+50>=d&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('<li class="select2-results__option select2-results__option--load-more"role="treeitem" aria-disabled="true"></li>'),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(b,c,d){this.$dropdownParent=d.get("dropdownParent")||a(document.body),b.call(this,c,d)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.destroy=function(a){a.call(this),this.$dropdownContainer.remove()},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a("<span></span>"),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(a){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c,d){var e=this,f="scroll.select2."+d.id,g="resize.select2."+d.id,h="orientationchange.select2."+d.id,i=this.$container.parents().filter(b.hasScroll);i.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),i.on(f,function(b){var c=a(this).data("select2-scroll-position");a(this).scrollTop(c.y)}),a(window).on(f+" "+g+" "+h,function(a){e._positionDropdown(),e._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c,d){var e="scroll.select2."+d.id,f="resize.select2."+d.id,g="orientationchange.select2."+d.id,h=this.$container.parents().filter(b.hasScroll);h.off(e),a(window).off(e+" "+f+" "+g)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=this.$container.offset();f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.top<f.top-h.height,k=i.bottom>f.bottom+h.height,l={left:f.left,top:g.bottom},m=this.$dropdownParent;"static"===m.css("position")&&(m=m.offsetParent());var n=m.offset();l.top-=n.top,l.left-=n.left,c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-n.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.position="relative",a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(a){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d<b.length;d++){var e=b[d];e.children?c+=a(e.children):c++}return c}function b(a,b,c,d){this.minimumResultsForSearch=c.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),a.call(this,b,c,d)}return b.prototype.showSearch=function(b,c){return a(c.data.results)<this.minimumResultsForSearch?!1:b.call(this,c)},b}),b.define("select2/dropdown/selectOnClose",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("close",function(a){d._handleSelectOnClose(a)})},a.prototype._handleSelectOnClose=function(a,b){if(b&&null!=b.originalSelect2Event){var c=b.originalSelect2Event;if("select"===c._type||"unselect"===c._type)return}var d=this.getHighlightedResults();if(!(d.length<1)){var e=d.data("data");null!=e.element&&e.element.selected||null==e.element&&e.selected||this.trigger("select",{data:e})}},a}),b.define("select2/dropdown/closeOnSelect",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("select",function(a){d._selectTriggered(a)}),b.on("unselect",function(a){d._selectTriggered(a)})},a.prototype._selectTriggered=function(a,b){var c=b.originalEvent;c&&c.ctrlKey||this.trigger("close",{originalEvent:c,originalSelect2Event:b})},a}),b.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(a){var b=a.input.length-a.maximum,c="Please delete "+b+" character";return 1!=b&&(c+="s"),c},inputTooShort:function(a){var b=a.minimum-a.input.length,c="Please enter "+b+" or more characters";return c},loadingMore:function(){return"Loading more results…"},maximumSelected:function(a){var b="You can only select "+a.maximum+" item";return 1!=a.maximum&&(b+="s"),b},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),b.define("select2/defaults",["jquery","require","./results","./selection/single","./selection/multiple","./selection/placeholder","./selection/allowClear","./selection/search","./selection/eventRelay","./utils","./translation","./diacritics","./data/select","./data/array","./data/ajax","./data/tags","./data/tokenizer","./data/minimumInputLength","./data/maximumInputLength","./data/maximumSelectionLength","./dropdown","./dropdown/search","./dropdown/hidePlaceholder","./dropdown/infiniteScroll","./dropdown/attachBody","./dropdown/minimumResultsForSearch","./dropdown/selectOnClose","./dropdown/closeOnSelect","./i18n/en"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C){function D(){this.reset()}D.prototype.apply=function(l){if(l=a.extend(!0,{},this.defaults,l),null==l.dataAdapter){if(null!=l.ajax?l.dataAdapter=o:null!=l.data?l.dataAdapter=n:l.dataAdapter=m,l.minimumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),(null!=l.tokenSeparators||null!=l.tokenizer)&&(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.multiple?l.selectionAdapter=e:l.selectionAdapter=d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L<K.length;L++){var M=K[L],N={};try{N=k.loadPath(M)}catch(O){try{M=this.defaults.amdLanguageBase+M,N=k.loadPath(M)}catch(P){l.debug&&window.console&&console.warn&&console.warn('Select2: The language file for "'+M+'" could not be automatically loaded. A fallback will be used instead.');continue}}J.extend(N)}l.translations=J}else{var Q=k.loadPath(this.defaults.amdLanguageBase+"en"),R=new k(l.language);R.extend(Q),l.translations=R}return l},D.prototype.reset=function(){function b(a){function b(a){return l[a]||a}return a.replace(/[^\u0000-\u007E]/g,b)}function c(d,e){if(""===a.trim(d.term))return e;if(e.children&&e.children.length>0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){var h=e.children[g],i=c(d,h);null==i&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var j=b(e.text).toUpperCase(),k=b(d.term).toUpperCase();return j.indexOf(k)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)};var E=new D;return E}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(a.prop("dir")?this.options.dir=a.prop("dir"):a.closest("[dir]").prop("dir")?this.options.dir=a.closest("[dir]").prop("dir"):this.options.dir="ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b=b.replace(/(:|\.|\[|\]|,)/g,""),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return 0>=e?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;i>h;h+=1){var j=g[h].replace(/\s/g,""),k=j.match(c);if(null!==k&&k.length>=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this.$element.on("focus.select2",function(a){b.trigger("focus",a)}),this._syncA=c.bind(this._syncAttributes,this),this._syncS=c.bind(this._syncSubtree,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._syncA);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._syncA),a.each(c,b._syncS)}),this._observer.observe(this.$element[0],{attributes:!0,childList:!0,subtree:!1})):this.$element[0].addEventListener&&(this.$element[0].addEventListener("DOMAttrModified",b._syncA,!1),this.$element[0].addEventListener("DOMNodeInserted",b._syncS,!1),this.$element[0].addEventListener("DOMNodeRemoved",b._syncS,!1))},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle","focus"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("focus",function(a){b.focus(a)}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open",{}),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ESC||c===d.TAB||c===d.UP&&b.altKey?(a.close(),b.preventDefault()):c===d.ENTER?(a.trigger("results:select",{}),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle",{}),b.preventDefault()):c===d.UP?(a.trigger("results:previous",{}),b.preventDefault()):c===d.DOWN&&(a.trigger("results:next",{}),b.preventDefault()):(c===d.ENTER||c===d.SPACE||c===d.DOWN&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable",{})):this.trigger("enable",{})},e.prototype._syncSubtree=function(a,b){var c=!1,d=this;if(!a||!a.target||"OPTION"===a.target.nodeName||"OPTGROUP"===a.target.nodeName){if(b)if(b.addedNodes&&b.addedNodes.length>0)for(var e=0;e<b.addedNodes.length;e++){var f=b.addedNodes[e];f.selected&&(c=!0)}else b.removedNodes&&b.removedNodes.length>0&&(c=!0);else c=!0;c&&this.dataAdapter.current(function(a){d.trigger("selection:update",{data:a})})}},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(void 0===b&&(b={}),a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||this.trigger("query",{})},e.prototype.close=function(){this.isOpen()&&this.trigger("close",{})},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.hasFocus=function(){return this.$container.hasClass("select2-container--focus")},e.prototype.focus=function(a){this.hasFocus()||(this.$container.addClass("select2-container--focus"),this.trigger("focus",{}))},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),(null==a||0===a.length)&&(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._syncA),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&(this.$element[0].removeEventListener("DOMAttrModified",this._syncA,!1),this.$element[0].removeEventListener("DOMNodeInserted",this._syncS,!1),this.$element[0].removeEventListener("DOMNodeRemoved",this._syncS,!1)),this._syncA=null,this._syncS=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null;
3
+ },e.prototype.render=function(){var b=a('<span class="select2 select2-container"><span class="selection"></span><span class="dropdown-wrapper" aria-hidden="true"></span></span>');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("select2/compat/utils",["jquery"],function(a){function b(b,c,d){var e,f,g=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0===this.indexOf("select2-")&&g.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0!==this.indexOf("select2-")&&(f=d(this),null!=f&&g.push(f))})),b.attr("class",g.join(" "))}return{syncCssClasses:b}}),b.define("select2/compat/containerCss",["jquery","./utils"],function(a,b){function c(a){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("containerCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptContainerCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all:","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("containerCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/dropdownCss",["jquery","./utils"],function(a,b){function c(a){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("dropdownCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptDropdownCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all:","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("dropdownCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/initSelection",["jquery"],function(a){function b(a,b,c){c.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `initSelection` option has been deprecated in favor of a custom data adapter that overrides the `current` method. This method is now called multiple times instead of a single time when the instance is initialized. Support will be removed for the `initSelection` option in future versions of Select2"),this.initSelection=c.get("initSelection"),this._isInitialized=!1,a.call(this,b,c)}return b.prototype.current=function(b,c){var d=this;return this._isInitialized?void b.call(this,c):void this.initSelection.call(null,this.$element,function(b){d._isInitialized=!0,a.isArray(b)||(b=[b]),c(b)})},b}),b.define("select2/compat/inputData",["jquery"],function(a){function b(a,b,c){this._currentData=[],this._valueSeparator=c.get("valueSeparator")||",","hidden"===b.prop("type")&&c.get("debug")&&console&&console.warn&&console.warn("Select2: Using a hidden input with Select2 is no longer supported and may stop working in the future. It is recommended to use a `<select>` element instead."),a.call(this,b,c)}return b.prototype.current=function(b,c){function d(b,c){var e=[];return b.selected||-1!==a.inArray(b.id,c)?(b.selected=!0,e.push(b)):b.selected=!1,b.children&&e.push.apply(e,d(b.children,c)),e}for(var e=[],f=0;f<this._currentData.length;f++){var g=this._currentData[f];e.push.apply(e,d(g,this.$element.val().split(this._valueSeparator)))}c(e)},b.prototype.select=function(b,c){if(this.options.get("multiple")){var d=this.$element.val();d+=this._valueSeparator+c.id,this.$element.val(d),this.$element.trigger("change")}else this.current(function(b){a.map(b,function(a){a.selected=!1})}),this.$element.val(c.id),this.$element.trigger("change")},b.prototype.unselect=function(a,b){var c=this;b.selected=!1,this.current(function(a){for(var d=[],e=0;e<a.length;e++){var f=a[e];b.id!=f.id&&d.push(f.id)}c.$element.val(d.join(c._valueSeparator)),c.$element.trigger("change")})},b.prototype.query=function(a,b,c){for(var d=[],e=0;e<this._currentData.length;e++){var f=this._currentData[e],g=this.matches(b,f);null!==g&&d.push(g)}c({results:d})},b.prototype.addOptions=function(b,c){var d=a.map(c,function(b){return a.data(b[0],"data")});this._currentData.push.apply(this._currentData,d)},b}),b.define("select2/compat/matcher",["jquery"],function(a){function b(b){function c(c,d){var e=a.extend(!0,{},d);if(null==c.term||""===a.trim(c.term))return e;if(d.children){for(var f=d.children.length-1;f>=0;f--){var g=d.children[f],h=b(c.term,g.text,g);h||e.children.splice(f,1)}if(e.children.length>0)return e}return b(c.term,d.text,d)?e:null}return c}return b}),b.define("select2/compat/query",[],function(){function a(a,b,c){c.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `query` option has been deprecated in favor of a custom data adapter that overrides the `query` method. Support will be removed for the `query` option in future versions of Select2."),a.call(this,b,c)}return a.prototype.query=function(a,b,c){b.callback=c;var d=this.options.get("query");d.call(null,b)},a}),b.define("select2/dropdown/attachContainer",[],function(){function a(a,b,c){a.call(this,b,c)}return a.prototype.position=function(a,b,c){var d=c.find(".dropdown-wrapper");d.append(b),b.addClass("select2-dropdown--below"),c.addClass("select2-container--below")},a}),b.define("select2/dropdown/stopPropagation",[],function(){function a(){}return a.prototype.bind=function(a,b,c){a.call(this,b,c);var d=["blur","change","click","dblclick","focus","focusin","focusout","input","keydown","keyup","keypress","mousedown","mouseenter","mouseleave","mousemove","mouseover","mouseup","search","touchend","touchstart"];this.$dropdown.on(d.join(" "),function(a){a.stopPropagation()})},a}),b.define("select2/selection/stopPropagation",[],function(){function a(){}return a.prototype.bind=function(a,b,c){a.call(this,b,c);var d=["blur","change","click","dblclick","focus","focusin","focusout","input","keydown","keyup","keypress","mousedown","mouseenter","mouseleave","mousemove","mouseover","mouseup","search","touchend","touchstart"];this.$selection.on(d.join(" "),function(a){a.stopPropagation()})},a}),function(c){"function"==typeof b.define&&b.define.amd?b.define("jquery-mousewheel",["jquery"],c):"object"==typeof exports?module.exports=c:c(a)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})}),b.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults"],function(a,b,c,d){if(null==a.fn.select2){var e=["open","close","destroy"];a.fn.select2=function(b){if(b=b||{},"object"==typeof b)return this.each(function(){var d=a.extend(!0,{},b);new c(a(this),d)}),this;if("string"==typeof b){var d,f=Array.prototype.slice.call(arguments,1);return this.each(function(){var c=a(this).data("select2");null==c&&window.console&&console.error&&console.error("The select2('"+b+"') method was called on an element that is not using Select2."),d=c[b].apply(c,f)}),a.inArray(b,e)>-1?this:d}throw new Error("Invalid arguments for Select2: "+b)}}return null==a.fn.select2.defaults&&(a.fn.select2.defaults=d),c}),{define:b.define,require:b.require}}(),c=b.require("jquery.select2");return a.fn.select2.amd=b,c});
bnfw.php CHANGED
@@ -1,1519 +1,1523 @@
1
- <?php
2
-
3
- /**
4
- * Plugin Name: Better Notifications for WP
5
- * Plugin URI: https://wordpress.org/plugins/bnfw/
6
- * Description: Supercharge your WordPress notifications using a WYSIWYG editor and shortcodes. Default and new notifications available. Add more power with Add-ons.
7
- * Version: 1.8.7
8
- * Requires at least: 4.8
9
- * Requires PHP: 7.0
10
- * Author: Made with Fuel
11
- * Author URI: https://madewithfuel.com/
12
- * License: GPLv2 or later
13
- * License URI: http://www.gnu.org/licenses/gpl-2.0.html
14
- * Text Domain: bnfw
15
- * Domain Path: /languages
16
- */
17
-
18
- /**
19
- * Copyright © 2022 Made with Fuel Ltd. (hello@betternotificationsforwp.com)
20
- * This program is free software; you can redistribute it and/or modify
21
- * it under the terms of the GNU General Public License, version 2, as
22
- * published by the Free Software Foundation.
23
- * This program is distributed in the hope that it will be useful,
24
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
- * GNU General Public License for more details.
27
- * You should have received a copy of the GNU General Public License
28
- * along with this program; if not, write to the Free Software
29
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30
- */
31
- class BNFW {
32
-
33
- /**
34
- * Constructor.
35
- *
36
- * @since 1.0
37
- */
38
- function __construct() {
39
- $this->load_textdomain();
40
- $this->includes();
41
- $this->hooks();
42
-
43
- /**
44
- * BNFW Notification.
45
- *
46
- * @var \BNFW_Notification
47
- */
48
- $this->notifier = new BNFW_Notification;
49
-
50
- /**
51
- * BNFW Engine.
52
- *
53
- * @var \BNFW_Engine
54
- */
55
- $this->engine = new BNFW_Engine;
56
- }
57
-
58
- /**
59
- * Factory method to return the instance of the class.
60
- *
61
- * Makes sure that only one instance is created.
62
- *
63
- * @return \BNFW Instance of the class.
64
- */
65
- public static function factory() {
66
- static $instance = false;
67
- if ( ! $instance ) {
68
- $instance = new self();
69
- }
70
- return $instance;
71
- }
72
-
73
- /**
74
- * Loads the plugin language files
75
- *
76
- * @since 1.0
77
- */
78
- public function load_textdomain() {
79
- // Load localization domain
80
- $this->translations = dirname( plugin_basename( __FILE__ ) ) . '/languages/';
81
- load_plugin_textdomain( 'bnfw', false, $this->translations );
82
- }
83
-
84
- /**
85
- * Include required files.
86
- *
87
- * @since 1.0
88
- */
89
- public function includes() {
90
-
91
- // Load license related classes
92
- if ( ! class_exists( 'EDD_SL_Plugin_Updater' ) ) {
93
- require_once 'includes/libraries/EDD_SL_Plugin_Updater.php';
94
- }
95
-
96
- include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
97
-
98
- require_once 'vendor/persist-admin-notices-dismissal/persist-admin-notices-dismissal.php';
99
-
100
- require_once 'includes/license/class-bnfw-license.php';
101
- require_once 'includes/license/class-bnfw-license-setting.php';
102
-
103
- // Load Engine
104
- require_once 'includes/engine/class-bnfw-engine.php';
105
- require_once 'includes/overrides.php';
106
-
107
- // Load notification post type and notification helpers
108
- require_once 'includes/admin/class-bnfw-notification.php';
109
- require_once 'includes/notification/post-notification.php';
110
-
111
- // Helpers
112
- require_once 'includes/helpers/helpers.php';
113
- require_once 'includes/helpers/ajax-helpers.php';
114
-
115
- // Load Admin Pages
116
- if ( is_admin() ) {
117
- require_once 'includes/admin/bnfw-settings.php';
118
- }
119
- }
120
-
121
- /**
122
- * Register Hooks.
123
- *
124
- * @since 1.0
125
- */
126
- public function hooks() {
127
- global $wp_version;
128
-
129
- register_activation_hook( __FILE__, array( $this, 'activate' ) );
130
-
131
- add_action( 'admin_init', array( 'PAnD', 'init' ) );
132
- add_action( 'admin_init', array( $this, 'add_capability_to_admin' ) );
133
-
134
- add_action( 'draft_to_private', array( $this, 'private_post' ) );
135
- add_action( 'future_to_private', array( $this, 'private_post' ) );
136
- add_action( 'pending_to_private', array( $this, 'private_post' ) );
137
- add_action( 'publish_to_private', array( $this, 'private_post' ) );
138
-
139
- add_action( 'wp_insert_post', array( $this, 'insert_post' ), 10, 3 );
140
-
141
- add_action( 'publish_to_trash', array( $this, 'trash_post' ) );
142
-
143
- add_action( 'auto-draft_to_publish', array( $this, 'publish_post' ) );
144
- add_action( 'draft_to_publish', array( $this, 'publish_post' ) );
145
- add_action( 'future_to_publish', array( $this, 'publish_post' ) );
146
- add_action( 'pending_to_publish', array( $this, 'publish_post' ) );
147
- add_action( 'private_to_publish', array( $this, 'publish_post' ) );
148
- // add_action( 'acf/submit_form' , array( $this, 'acf_submit_form' ), 10, 2 );
149
-
150
- add_action( 'publish_to_publish', array( $this, 'update_post' ) );
151
- add_action( 'private_to_private', array( $this, 'update_post' ) );
152
-
153
- add_action( 'add_attachment', array( $this, 'new_publish_media_notification' ), 10, 1 );
154
- add_action( 'edit_attachment', array( $this, 'media_attachment_data_update_notification' ), 10 );
155
-
156
- add_action( 'transition_post_status', array( $this, 'on_post_transition' ), 10, 3 );
157
-
158
- add_action( 'init', array( $this, 'custom_post_type_hooks' ), 100 );
159
- add_action( 'create_term', array( $this, 'create_term' ), 10, 3 );
160
-
161
- add_action( 'transition_comment_status', array( $this, 'on_comment_status_change' ), 10, 3 );
162
- add_action( 'comment_post', array( $this, 'comment_post' ) );
163
- add_action( 'trackback_post', array( $this, 'trackback_post' ) );
164
- add_action( 'pingback_post', array( $this, 'pingback_post' ) );
165
-
166
- add_action( 'user_register', array( $this, 'user_register' ) );
167
-
168
- add_action( 'user_register', array( $this, 'welcome_email' ) );
169
-
170
- if ( is_plugin_active( 'members/members.php' ) ) {
171
-
172
- add_action('add_user_role', array($this,'user_role_added_from_member_plugin'), 10, 2);
173
- add_action('remove_user_role', array($this,'user_role_removed_from_member_plugin'), 10, 2);
174
- add_action('set_user_role', array( $this, 'user_role_changed' ), 10, 3 );
175
-
176
- add_action( 'profile_update', array( $this, 'user_role_added' ), 10, 2 );
177
- } else {
178
- add_action( 'set_user_role', array( $this, 'user_role_changed' ), 10, 3 );
179
- }
180
-
181
-
182
-
183
- add_action( 'wp_login', array( $this, 'user_login' ), 10, 2 );
184
-
185
- if ( version_compare( $wp_version, '4.4', '>=' ) ) {
186
- add_filter( 'retrieve_password_title', array( $this, 'change_password_email_title' ), 10, 3 );
187
- } else {
188
- add_filter( 'retrieve_password_title', array( $this, 'change_password_email_title' ) );
189
- }
190
- add_action( 'lostpassword_post', array( $this, 'on_lost_password' ) );
191
- add_filter( 'retrieve_password_message', array( $this, 'change_password_email_message' ), 10, 4 );
192
-
193
- add_action( 'after_password_reset', array( $this, 'on_password_reset' ) );
194
-
195
- add_filter( 'send_password_change_email', array( $this, 'should_password_changed_email_be_sent' ), 10, 3 );
196
- add_filter( 'password_change_email', array( $this, 'on_password_changed' ), 10, 2 );
197
-
198
- add_filter( 'send_email_change_email', array( $this, 'should_email_changed_email_be_sent' ), 10, 3 );
199
- add_filter( 'email_change_email', array( $this, 'on_email_changed' ), 10, 3 );
200
- add_filter( 'new_user_email_content', array( $this, 'on_email_changing' ), 10, 2 );
201
-
202
- add_filter( 'auto_core_update_email', array( $this, 'on_core_updated' ), 10, 4 );
203
-
204
- add_filter( 'user_request_action_email_content', array( $this, 'handle_user_request_email_content' ), 10, 2 );
205
- add_filter( 'user_request_action_email_subject', array( $this, 'handle_user_request_email_subject' ), 10, 3 );
206
-
207
- add_filter( 'user_confirmed_action_email_content', array( $this, 'handle_user_confirmed_action_email_content' ), 10, 2 );
208
-
209
- add_filter( 'wp_privacy_personal_data_email_content', array( $this, 'handle_data_export_email_content' ), 10, 3 );
210
-
211
- add_filter( 'user_erasure_complete_email_subject', array( $this, 'handle_erasure_complete_email_subject' ), 10, 3 );
212
- add_filter( 'user_confirmed_action_email_content', array( $this, 'handle_erasure_complete_email_content' ), 10, 2 );
213
-
214
- add_filter( 'plugin_action_links', array( $this, 'plugin_action_links' ), 10, 4 );
215
- add_action( 'shutdown', array( $this, 'on_shutdown' ) );
216
- }
217
-
218
- /**
219
- * Add 'bnfw' capability to admin.
220
- */
221
- public function add_capability_to_admin() {
222
- $admins = get_role( 'administrator' );
223
-
224
- if ( is_null( $admins ) ) {
225
- return;
226
- }
227
-
228
- if ( ! $admins->has_cap( 'bnfw' ) ) {
229
- $admins->add_cap( 'bnfw' );
230
- }
231
- }
232
-
233
- /**
234
- * On post transition.
235
- *
236
- * @param string $new_status New post status.
237
- * @param string $old_status Old post status.
238
- * @param \WP_Post $post Post object.
239
- */
240
- public function on_post_transition( $new_status, $old_status, $post ) {
241
- if ( ! is_a( $post, 'WP_Post' ) ) {
242
- return;
243
- }
244
-
245
- if ( 'pending' === $old_status ) {
246
- return;
247
- }
248
-
249
- if ( 'pending' !== $new_status ) {
250
- return;
251
- }
252
-
253
- $this->on_post_pending( $post->ID, $post );
254
- }
255
-
256
- /**
257
- * Setup hooks for custom post types.
258
- *
259
- * @since 1.2
260
- */
261
- function custom_post_type_hooks() {
262
- $post_types = get_post_types( array( 'public' => true ), 'names' );
263
- $post_types = array_diff( $post_types, array( BNFW_Notification::POST_TYPE ) );
264
-
265
- foreach ( $post_types as $post_type ) {
266
- add_action( 'future_' . $post_type, array( $this, 'on_post_scheduled' ), 10, 2 );
267
- }
268
- }
269
-
270
- /**
271
- * importer
272
- */
273
- public function activate() {
274
- require_once dirname( __FILE__ ) . '/includes/import.php';
275
- $importer = new BNFW_Import;
276
- $importer->import();
277
- }
278
-
279
- /**
280
- * Add 'Settings' link below BNFW in Plugins list.
281
- *
282
- * @since 1.0
283
- * @param unknown $links
284
- * @param unknown $file
285
- * @return unknown
286
- */
287
- public function plugin_action_links( $links, $file ) {
288
- $plugin_file = 'bnfw/bnfw.php';
289
- if ( $file == $plugin_file ) {
290
- $settings_link = '<a href="' . esc_url( admin_url( 'edit.php?post_type=bnfw_notification&page=bnfw-settings' ) ) . '">' . esc_html__( 'Settings', 'bnfw' ) . '</a>';
291
- array_unshift( $links, $settings_link );
292
- }
293
- return $links;
294
- }
295
-
296
- /**
297
- * When a new term is created.
298
- *
299
- * @since 1.0
300
- * @param int $term_id
301
- * @param int $tt_id
302
- * @param string $taxonomy
303
- */
304
- public function create_term( $term_id, $tt_id, $taxonomy ) {
305
- $this->send_notification( 'newterm-' . $taxonomy, $term_id );
306
- }
307
-
308
- /**
309
- * Fires when a post is created for the first time.
310
- *
311
- * @param int $post_id Post ID
312
- * @param object $post Post object
313
- * @param bool $update Whether this is an existing post being updated or not.
314
- *
315
- * @since 1.3.1
316
- */
317
- public function insert_post( $post_id, $post, $update ) {
318
- // Some themes like P2, directly insert posts into DB.
319
- $insert_post_themes = apply_filters( 'bnfw_insert_post_themes', array( 'P2', 'Syncope' ) );
320
- $current_theme = wp_get_theme();
321
-
322
- /**
323
- * Whether to trigger insert post hook.
324
- *
325
- * @since 1.4
326
- */
327
- $trigger_insert_post = apply_filters( 'bnfw_trigger_insert_post', false, $post_id, $update );
328
-
329
- if ( in_array( $current_theme->get( 'Name' ), $insert_post_themes ) || $trigger_insert_post ) {
330
- $this->handle_inserted_post( $post_id, $update );
331
- }
332
- }
333
-
334
- /**
335
- * Trigger New Post published notification for ACF forms.
336
- *
337
- * @param string $form ACF Form.
338
- * @param int $post_id Post ID.
339
- */
340
- public function acf_submit_form( $form, $post_id ) {
341
- $this->handle_inserted_post( $post_id );
342
- }
343
-
344
- /**
345
- * Trigger correct notifications for inserted posts.
346
- *
347
- * @param int $post_id Post id.
348
- * @param bool $update Whether the post was updated.
349
- *
350
- * @since 1.6.7
351
- */
352
- private function handle_inserted_post( $post_id, $update ) {
353
- $post = get_post( $post_id );
354
-
355
- if ( ! is_a( $post, 'WP_Post' ) ) {
356
- return;
357
- }
358
-
359
- switch ( $post->post_status ) {
360
- case 'publish':
361
- if ( $update ) {
362
- $this->update_post( $post );
363
- } else {
364
- $this->publish_post( $post );
365
- }
366
- break;
367
-
368
- case 'private':
369
- $this->private_post( $post );
370
- break;
371
-
372
- case 'pending':
373
- $this->on_post_pending( $post_id, $post );
374
- break;
375
-
376
- case 'future':
377
- $this->on_post_scheduled( $post_id, $post );
378
- break;
379
- }
380
- }
381
-
382
- /**
383
- * Fires when a post is created for the first time.
384
- *
385
- * @since 1.0
386
- * @param object $post Post Object
387
- */
388
- function publish_post( $post ) {
389
- $post_id = $post->ID;
390
- $post_type = $post->post_type;
391
-
392
- if ( BNFW_Notification::POST_TYPE != $post_type ) {
393
- $this->send_notification_async( 'new-' . $post_type, $post_id );
394
- }
395
- }
396
-
397
- /**
398
- * Fires when a private post is created.
399
- *
400
- * @since 1.6
401
- * @param object $post Post Object
402
- */
403
- public function private_post( $post ) {
404
- $post_id = $post->ID;
405
- $post_type = $post->post_type;
406
-
407
- if ( BNFW_Notification::POST_TYPE != $post_type ) {
408
- $this->send_notification_async( 'private-' . $post_type, $post_id );
409
- }
410
- }
411
-
412
- /**
413
- * Fires when a post is updated.
414
- *
415
- * @since 1.0
416
- * @param unknown $post
417
- */
418
- public function update_post( $post ) {
419
- if ( $this->is_metabox_request() ) {
420
- return;
421
- }
422
-
423
- $post_id = $post->ID;
424
- $post_type = $post->post_type;
425
-
426
- if ( BNFW_Notification::POST_TYPE != $post_type ) {
427
- $this->send_notification_async( 'update-' . $post_type, $post_id );
428
- }
429
- }
430
-
431
- /**
432
- * Fires when a post is moved publish to trash.
433
- *
434
- */
435
- public function trash_post( $post ) {
436
- if ( $this->is_metabox_request() ) {
437
- return;
438
- }
439
- $post_id = $post->ID;
440
- $post_type = $post->post_type;
441
-
442
- if ( BNFW_Notification::POST_TYPE != $post_type ) {
443
- $this->send_notification_async( 'trash-' . $post_type, $post_id );
444
- }
445
- }
446
-
447
- /**
448
- * Fires when a post is pending for review.
449
- *
450
- * @since 1.1
451
- * @param int $post_id Post ID
452
- * @param object $post Post object
453
- */
454
- public function on_post_pending( $post_id, $post ) {
455
- if ( $this->is_metabox_request() ) {
456
- return;
457
- }
458
-
459
- $post_type = $post->post_type;
460
-
461
- if ( BNFW_Notification::POST_TYPE != $post_type ) {
462
- $this->send_notification_async( 'pending-' . $post_type, $post_id );
463
- }
464
- }
465
-
466
- /**
467
- * On Media Published.
468
- *
469
- * @param int $post_id Attachment post id.
470
- */
471
- public function new_publish_media_notification( $post_id ) {
472
- $post_type = get_post_type( $post_id );
473
-
474
- if ( BNFW_Notification::POST_TYPE != $post_type && $post_type == 'attachment' ) {
475
- $this->send_notification_async( 'new-media', $post_id );
476
- }
477
- }
478
-
479
- /**
480
- * On Media Attachment Data Update.
481
- *
482
- * @param int $post_id Attachment post id.
483
- */
484
- public function media_attachment_data_update_notification( $post_id ) {
485
- $post_type = get_post_type( $post_id );
486
- if ( BNFW_Notification::POST_TYPE != $post_type && $post_type == 'attachment' ) {
487
- $this->send_notification_async( 'update-media', $post_id );
488
- }
489
- }
490
-
491
- /**
492
- * Fires when a post is scheduled.
493
- *
494
- * @since 1.1.5
495
- * @param int $post_id Post ID
496
- * @param object $post Post object
497
- */
498
- function on_post_scheduled( $post_id, $post ) {
499
- // Rest request also triggers the same hook. We can ignore it.
500
- if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
501
- return;
502
- }
503
-
504
- $post_type = $post->post_type;
505
-
506
- if ( BNFW_Notification::POST_TYPE != $post_type ) {
507
- $this->send_notification_async( 'future-' . $post_type, $post_id );
508
- }
509
- }
510
-
511
- /**
512
- * When the status of a comment is changed.
513
- *
514
- * @param string $new_status New status.
515
- * @param string $old_status Old status.
516
- * @param \WP_Comment $comment Comment.
517
- */
518
- public function on_comment_status_change( $new_status, $old_status, $comment ) {
519
- if ( 'approved' !== $new_status ) {
520
- return;
521
- }
522
-
523
- $post = get_post( $comment->comment_post_ID );
524
-
525
- $notification_type = 'approve-' . $post->post_type . '-comment';
526
-
527
- $this->send_notification( $notification_type, $comment->comment_ID, false );
528
-
529
- // Send new comment notification after comment approve
530
- $notification_type = 'new-comment'; // old notification name
531
-
532
- if ( 'post' != $post->post_type ) {
533
- $notification_type = 'comment-' . $post->post_type;
534
- }
535
-
536
- $this->send_notification( $notification_type, $comment->comment_ID );
537
-
538
- // Send comment reply notification after comment approve.
539
- $this->commentsReply( $comment->comment_ID );
540
- }
541
-
542
- /**
543
- * Send notification for new comments
544
- *
545
- * @since 1.0
546
- * @param int $comment_id
547
- */
548
- public function comment_post( $comment_id ) {
549
- $the_comment = get_comment( $comment_id );
550
- $post = get_post( $the_comment->comment_post_ID );
551
-
552
- if ( '1' !== $the_comment->comment_approved ) {
553
- if ( $this->can_send_comment_notification( $the_comment ) ) {
554
- $notification_type = 'moderate-' . $post->post_type . '-comment';
555
- $this->send_notification( $notification_type, $comment_id );
556
- }
557
- } else {
558
- $notification_type = 'new-comment'; // old notification name
559
-
560
- if ( 'post' != $post->post_type ) {
561
- $notification_type = 'comment-' . $post->post_type;
562
- }
563
-
564
- $this->send_notification( $notification_type, $comment_id );
565
-
566
- // comment reply notification.
567
- $this->commentsReply( $comment_id );
568
- }
569
- }
570
-
571
- /**
572
- * Send notification for comments reply
573
- *
574
- * @since 1.0
575
- * @param int $comment_id
576
- */
577
- public function commentsReply( $comment_id ) {
578
- $the_comment = get_comment( $comment_id );
579
- $post = get_post( $the_comment->comment_post_ID );
580
-
581
- // comment reply notification.
582
- if ( $this->can_send_comment_notification( $the_comment ) ) {
583
- if ( $the_comment->comment_parent > 0 ) {
584
- $notification_type = 'reply-comment'; // old notification name
585
- if ( 'post' != $post->post_type ) {
586
- $notification_type = 'commentreply-' . $post->post_type;
587
- }
588
- $notifications = $this->notifier->get_notifications( $notification_type );
589
- if ( count( $notifications ) > 0 ) {
590
- $parent = get_comment( $the_comment->comment_parent );
591
- if ( $parent->comment_author_email != $the_comment->comment_author_email ) {
592
- foreach ( $notifications as $notification ) {
593
- $this->engine->send_comment_reply_email( $this->notifier->read_settings( $notification->ID ), $the_comment, $parent );
594
- }
595
- }
596
- }
597
- }
598
- }
599
- }
600
-
601
- /**
602
- * Send notification for new trackback
603
- *
604
- * @since 1.0
605
- * @param unknown $comment_id
606
- */
607
- function trackback_post( $comment_id ) {
608
- $the_comment = get_comment( $comment_id );
609
- if ( $this->can_send_comment_notification( $the_comment ) ) {
610
- $this->send_notification( 'new-trackback', $comment_id );
611
- }
612
- }
613
-
614
- /**
615
- * Send notification for new pingbacks
616
- *
617
- * @since 1.0
618
- * @param unknown $comment_id
619
- */
620
- function pingback_post( $comment_id ) {
621
- $the_comment = get_comment( $comment_id );
622
- if ( $this->can_send_comment_notification( $the_comment ) ) {
623
- $this->send_notification( 'new-pingback', $comment_id );
624
- }
625
- }
626
-
627
- /**
628
- * Send notification for lost password.
629
- *
630
- * @since 1.0
631
- */
632
- function on_lost_password() {
633
- $user_login = sanitize_text_field( $_POST[ 'user_login' ] );
634
- $user = get_user_by( 'login', $user_login ) ?: get_user_by( 'email', $user_login );
635
- if ( $user ) {
636
- $this->send_notification( 'admin-password', $user->ID );
637
- }
638
- }
639
-
640
- /**
641
- * Change the title of the password reset email that is sent to the user.
642
- *
643
- * @since 1.1
644
- *
645
- * @param string $title
646
- * @param string $user_login
647
- * @param string $user_data
648
- *
649
- * @return string
650
- */
651
- public function change_password_email_title( $title, $user_login = '',
652
- $user_data = '' ) {
653
- $notifications = $this->notifier->get_notifications( 'user-password' );
654
- if ( count( $notifications ) > 0 ) {
655
- // Ideally there should be only one notification for this type.
656
- // If there are multiple notification then we will read data about only the last one
657
- $setting = $this->notifier->read_settings( end( $notifications )->ID );
658
-
659
- if ( '' === $user_data ) {
660
- return $this->engine->handle_shortcodes( $setting[ 'subject' ], 'user-password', $user_data->ID );
661
- } else {
662
- return $this->engine->handle_shortcodes( $setting[ 'subject' ], 'user-password', $user_data->ID );
663
- }
664
- }
665
-
666
- return $title;
667
- }
668
-
669
- /**
670
- * Change the message of the password reset email.
671
- *
672
- * @since 1.1
673
- *
674
- * @param string $message
675
- * @param string $key
676
- * @param string $user_login
677
- * @param string $user_data
678
- *
679
- * @return string
680
- */
681
- public function change_password_email_message( $message, $key,
682
- $user_login = '',
683
- $user_data = '' ) {
684
- $notifications = $this->notifier->get_notifications( 'user-password' );
685
- if ( count( $notifications ) > 0 ) {
686
- // Ideally there should be only one notification for this type.
687
- // If there are multiple notification then we will read data about only the last one
688
- $setting = $this->notifier->read_settings( end( $notifications )->ID );
689
-
690
- $message = $this->engine->handle_password_reset_shortcodes( $setting, $key, $user_login, $user_data );
691
-
692
- if ( 'html' == $setting[ 'email-formatting' ] ) {
693
- add_filter( 'wp_mail_content_type', array( $this, 'set_html_content_type' ) );
694
- if ( 'true' !== $setting[ 'disable-autop' ] ) {
695
- $message = wpautop( $message );
696
- }
697
- } else {
698
- add_filter( 'wp_mail_content_type', array( $this, 'set_text_content_type' ) );
699
- if ( 'text' == $setting[ 'email-formatting' ] ) {
700
- $message = strip_tags( $message );
701
- }
702
- }
703
- } else {
704
- if ( $this->notifier->notification_exists( 'user-password', false ) ) {
705
- // disabled notification exists, so disable the email by returning empty string.
706
- return '';
707
- }
708
- }
709
-
710
- return $message;
711
- }
712
-
713
- /**
714
- * On Password reset.
715
- *
716
- * @param WP_User $user User who's password was changed.
717
- */
718
- public function on_password_reset( $user ) {
719
- $notifications = $this->notifier->get_notifications( 'password-changed' );
720
- foreach ( $notifications as $notification ) {
721
- $this->engine->send_password_changed_email( $this->notifier->read_settings( $notification->ID ), $user );
722
- }
723
- }
724
-
725
- /**
726
- * Should the password changed email be sent?
727
- *
728
- * @param $send
729
- * @param $user
730
- * @param $userdata
731
- *
732
- * @return bool
733
- */
734
- public function should_password_changed_email_be_sent( $send, $user,
735
- $userdata ) {
736
- $bnfw = BNFW::factory();
737
-
738
- if ( ! $send ) {
739
- return $send;
740
- }
741
-
742
- return ! $bnfw->notifier->is_notification_disabled( 'password-changed' );
743
- }
744
-
745
- /**
746
- * On Password Changed.
747
- *
748
- * @since 1.6
749
- *
750
- * @param array $email_data Email Data.
751
- * @param array $user User data.
752
- *
753
- * @return array Modified Email Data
754
- */
755
- public function on_password_changed( $email_data, $user ) {
756
- return $this->handle_filtered_data_notification( 'password-changed', $email_data, $user[ 'ID' ] );
757
- }
758
-
759
- /**
760
- * Should the email changed email be sent?
761
- *
762
- * @param $send
763
- * @param $user
764
- * @param $userdata
765
- *
766
- * @return bool
767
- */
768
- public function should_email_changed_email_be_sent( $send, $user_old_data,
769
- $user_new_data ) {
770
- $bnfw = BNFW::factory();
771
-
772
- if ( $bnfw->notifier->notification_exists( 'admin-email-changed', false ) ) {
773
- $notifications = $bnfw->notifier->get_notifications( 'admin-email-changed' );
774
-
775
- if ( count( $notifications ) > 0 ) {
776
- // Ideally there should be only one notification for this type.
777
- // If there are multiple notification then we will read data about only the last one
778
- $setting = $bnfw->notifier->read_settings( end( $notifications )->ID );
779
- $notification_disabled = apply_filters( 'bnfw_notification_disabled', ( 'true' === $setting[ 'disabled' ] ), $id, $setting );
780
-
781
- if ( ! $notification_disabled ) {
782
-
783
- $setting[ 'message' ] = str_replace( '[user_old_email]', $user_old_data[ 'user_email' ], $setting[ 'message' ] );
784
- $setting[ 'message' ] = str_replace( '[user_new_email]', $user_new_data[ 'user_email' ], $setting[ 'message' ] );
785
- $bnfw->engine->send_notification( $setting, $user_old_data[ 'ID' ] );
786
- }
787
- }
788
- }
789
-
790
- if ( ! $send ) {
791
- return $send;
792
- }
793
-
794
- return ! $bnfw->notifier->is_notification_disabled( 'email-changed' );
795
- }
796
-
797
- /**
798
- * On Email Changed.
799
- *
800
- * @since 1.6
801
- *
802
- * @param array $email_data Email Data.
803
- * @param array $user User data.
804
- *
805
- * @return array Modified Email Data
806
- */
807
- public function on_email_changed( $email_data, $user_old_data,
808
- $user_new_data ) {
809
-
810
- $email = $this->handle_filtered_data_notification( 'email-changed', $email_data, $user_old_data[ 'ID' ] );
811
- $email[ 'message' ] = str_replace( '[user_old_email]', $user_old_data[ 'user_email' ], $email[ 'message' ] );
812
- $email[ 'message' ] = str_replace( '[user_new_email]', $user_new_data[ 'user_email' ], $email[ 'message' ] );
813
- return $email;
814
- }
815
-
816
- public function on_email_changing( $email_text, $new_user_details ) {
817
- $notification_name = 'email-changing';
818
-
819
- $notifications = $this->notifier->get_notifications( $notification_name );
820
- if ( count( $notifications ) > 0 ) {
821
- // Ideally there should be only one notification for this type.
822
- // If there are multiple notification then we will read data about only the last one
823
- $setting = $this->notifier->read_settings( end( $notifications )->ID );
824
-
825
- $email_text = $this->engine->handle_shortcodes( $setting[ 'message' ], $setting[ 'notification' ], $new_user_details[ 'newemail' ] );
826
- $email_text = $this->engine->handle_global_user_shortcodes( $email_text, $new_user_details[ 'newemail' ] );
827
- $email_text = str_replace( '[email_change_confirmation_link]', esc_url( admin_url( 'profile.php?newuseremail=' . $new_user_details[ 'hash' ] ) ), $email_text );
828
- }
829
-
830
- return $email_text;
831
- }
832
-
833
- /**
834
- * Send notification on core updated event.
835
- *
836
- * @since 1.6
837
- *
838
- * @param array $email_data Email Data.
839
- * @param string $type The type of email being sent. Can be one of
840
- * 'success', 'fail', 'manual', 'critical'.
841
- * @param object $core_update The update offer that was attempted.
842
- * @param mixed $result The result for the core update. Can be WP_Error.
843
- *
844
- * @return array Modified Email Data.
845
- */
846
- public function on_core_updated( $email_data, $type, $core_update, $result ) {
847
- $notifications = $this->notifier->get_notifications( 'core-updated' );
848
- if ( count( $notifications ) > 0 ) {
849
- // Ideally there should be only one notification for this type.
850
- // If there are multiple notification then we will read data about only the last one
851
- $setting = $this->notifier->read_settings( end( $notifications )->ID );
852
-
853
- $email_data = $this->engine->handle_core_updated_notification( $email_data, $setting, $type );
854
- }
855
-
856
- return $email_data;
857
- }
858
-
859
- /**
860
- * Process User update notifications.
861
- *
862
- * @since 1.6
863
- *
864
- * @param string $notification_name Notification Name.
865
- * @param array $email_data Email Data.
866
- * @param string|int $extra_data User Id.
867
- *
868
- * @return array Modified Email Data.
869
- */
870
- private function handle_filtered_data_notification( $notification_name,
871
- $email_data, $extra_data ) {
872
- $notifications = $this->notifier->get_notifications( $notification_name );
873
- if ( count( $notifications ) > 0 ) {
874
- // Ideally there should be only one notification for this type.
875
- // If there are multiple notification then we will read data about only the last one
876
- $setting = $this->notifier->read_settings( end( $notifications )->ID );
877
-
878
- $email_data = $this->engine->handle_filtered_data_notification( $email_data, $setting, $extra_data );
879
- }
880
-
881
- return $email_data;
882
- }
883
-
884
- /**
885
- * Set the email formatting to HTML.
886
- *
887
- * @since 1.4
888
- */
889
- public function set_html_content_type() {
890
- return 'text/html';
891
- }
892
-
893
- /**
894
- * Set the email formatting to text.
895
- *
896
- * @since 1.4
897
- */
898
- public function set_text_content_type() {
899
- return 'text/plain';
900
- }
901
-
902
- /**
903
- * Send notification for new users.
904
- *
905
- * @since 1.0
906
- * @param int $user_id
907
- */
908
- public function user_register( $user_id ) {
909
- $this->send_notification( 'admin-user', $user_id );
910
- }
911
-
912
- /**
913
- * Send notification for user when user login.
914
- *
915
- * @since 1.0
916
- * @param string $user_name
917
- * @param object $user_data User object.
918
- */
919
- public function user_login( $user_name, $user_data ) {
920
- $user_id = $user_data->ID;
921
- $notifications = $this->notifier->get_notifications( 'user-login' );
922
-
923
- foreach ( $notifications as $notification ) {
924
- $this->engine->send_user_login_email( $this->notifier->read_settings( $notification->ID ), get_userdata( $user_id ) );
925
- }
926
-
927
- $this->user_login_admin_notification( $user_id );
928
- }
929
-
930
- /**
931
- * Send notification for admin when user login.
932
- *
933
- * @since 1.0
934
- * @param int $user_id
935
- */
936
- public function user_login_admin_notification( $user_id ) {
937
- $notifications = $this->notifier->get_notifications( 'admin-user-login' );
938
-
939
- foreach ( $notifications as $notification ) {
940
- $this->engine->send_user_login_email_for_admin( $this->notifier->read_settings( $notification->ID ), get_userdata( $user_id ) );
941
- }
942
- }
943
-
944
- /**
945
- * Send notification about new users to site admin.
946
- *
947
- * @since 1.7.1
948
- *
949
- * @param array $email_data Email details.
950
- * @param WP_User $user User object.
951
- * @param string $blogname Blog name.
952
- *
953
- * @return array Modified email details.
954
- */
955
- public function handle_user_registered_admin_email( $email_data, $user,
956
- $blogname ) {
957
- return $this->handle_filtered_data_notification( 'admin-user', $email_data, $user->ID );
958
- }
959
-
960
- /**
961
- * New User - Post-registration Email
962
- *
963
- * @since 1.1
964
- * @param int $user_id New user id
965
- */
966
- public function welcome_email( $user_id ) {
967
- $notifications = $this->notifier->get_notifications( 'welcome-email' );
968
- foreach ( $notifications as $notification ) {
969
- $this->engine->send_registration_email( $this->notifier->read_settings( $notification->ID ), get_userdata( $user_id ) );
970
- }
971
- }
972
-
973
- /**
974
- * Send notification when a user role changes.
975
- *
976
- * @since 1.3.9
977
- *
978
- * @param int $user_id User ID
979
- * @param string $new_role New User role
980
- * @param array $old_roles Old User role
981
- */
982
- public function user_role_changed( $user_id, $new_role, $old_roles ) {
983
- if ( ! empty( $old_roles ) ) {
984
- $notifications = $this->notifier->get_notifications( 'user-role' );
985
- foreach ( $notifications as $notification ) {
986
-
987
- /**
988
- * Trigger User Role Changed - For User notification.
989
- *
990
- * @since 1.6.5
991
- */
992
- if ( apply_filters( 'bnfw_trigger_user-role_notification', true, $notification, $new_role, $old_roles ) ) {
993
- $this->engine->send_user_role_changed_email(
994
- $this->notifier->read_settings( $notification->ID ),
995
- $user_id,
996
- $old_roles[ 0 ],
997
- $new_role
998
- );
999
- }
1000
- }
1001
-
1002
- $notifications = $this->notifier->get_notifications( 'admin-role' );
1003
- foreach ( $notifications as $notification ) {
1004
-
1005
- /**
1006
- * Trigger User Role Changed - For User notification.
1007
- *
1008
- * @since 1.6.5
1009
- */
1010
- if ( apply_filters( 'bnfw_trigger_admin-role_notification', true, $notification, $new_role, $old_roles ) ) {
1011
- $setting = $this->notifier->read_settings( $notification->ID );
1012
- $setting[ 'message' ] = $this->engine->handle_user_role_shortcodes( $setting[ 'message' ], $old_roles[ 0 ], $new_role );
1013
- $setting[ 'subject' ] = $this->engine->handle_user_role_shortcodes( $setting[ 'subject' ], $old_roles[ 0 ], $new_role );
1014
-
1015
- $this->engine->send_notification( $setting, $user_id );
1016
- }
1017
- }
1018
- }
1019
- }
1020
-
1021
- /**
1022
- * Send notification when a user role added through Members Plugin.
1023
- *
1024
- * @since 1.8.4
1025
- *
1026
- * @param int $user_id User ID
1027
- * @param string $new_role New User role
1028
- *
1029
- */
1030
- public function user_role_added_from_member_plugin($user_id, $new_role){
1031
-
1032
- global $pagenow;
1033
-
1034
- if($pagenow != 'users.php')
1035
- return;
1036
-
1037
- if(!$user_id)
1038
- return;
1039
-
1040
- $notifications = $this->notifier->get_notifications( 'user-role' );
1041
-
1042
- foreach ( $notifications as $notification ) {
1043
-
1044
- if ( apply_filters( 'bnfw_trigger_user-role_notification', true, $notification, $new_role, null ) ) {
1045
- $this->engine->send_user_role_changed_email(
1046
- $this->notifier->read_settings( $notification->ID ),
1047
- $user_id,
1048
- null,
1049
- $new_role
1050
- );
1051
- }
1052
- }
1053
-
1054
- $notifications_admin = $this->notifier->get_notifications( 'admin-role' );
1055
- foreach ( $notifications_admin as $notification ) {
1056
- if ( apply_filters( 'bnfw_trigger_admin-role_notification', true, $notification, $new_role, null ) ) {
1057
- $setting = $this->notifier->read_settings( $notification->ID );
1058
- $setting[ 'message' ] = $this->engine->handle_user_role_shortcodes( $setting[ 'message' ], null, $new_role );
1059
- $setting[ 'subject' ] = $this->engine->handle_user_role_shortcodes( $setting[ 'subject' ], null, $new_role );
1060
-
1061
- $this->engine->send_notification( $setting, $user_id );
1062
- }
1063
- }
1064
-
1065
- }
1066
-
1067
- /**
1068
- * Send notification when a user role removed through Members Plugin.
1069
- *
1070
- * @since 1.8.4
1071
- *
1072
- * @param int $user_id User ID
1073
- * @param string $old_role New User role
1074
- *
1075
- */
1076
- public function user_role_removed_from_member_plugin($user_id, $old_role){
1077
- global $pagenow;
1078
-
1079
- if($pagenow != 'users.php')
1080
- return;
1081
-
1082
- if(!$user_id)
1083
- return;
1084
-
1085
- $notifications = $this->notifier->get_notifications( 'user-role' );
1086
-
1087
- foreach ( $notifications as $notification ) {
1088
- if ( apply_filters( 'bnfw_trigger_user-role_notification', true, $notification, null, array($old_role) ) ) {
1089
- $this->engine->send_user_role_changed_email(
1090
- $this->notifier->read_settings( $notification->ID ),
1091
- $user_id,
1092
- $old_role,
1093
- null
1094
- );
1095
- }
1096
- }
1097
-
1098
- $notifications_admin = $this->notifier->get_notifications( 'admin-role' );
1099
- foreach ( $notifications_admin as $notification ) {
1100
- if ( apply_filters( 'bnfw_trigger_admin-role_notification', true, $notification, null, array($old_role) ) ) {
1101
- $setting = $this->notifier->read_settings( $notification->ID );
1102
- $setting[ 'message' ] = $this->engine->handle_user_role_shortcodes( $setting[ 'message' ], $old_role, null );
1103
- $setting[ 'subject' ] = $this->engine->handle_user_role_shortcodes( $setting[ 'subject' ], $old_role, null );
1104
-
1105
-
1106
-
1107
- $this->engine->send_notification( $setting, $user_id );
1108
- }
1109
- }
1110
-
1111
- }
1112
-
1113
- /**
1114
- * Send notification when a user role added support User Role Editor by Members Plugin.
1115
- *
1116
- * @since 1.3.9
1117
- *
1118
- * @param int $user_id User ID
1119
- * @param string $new_role New User role
1120
- * @param array $old_roles Old User role
1121
- */
1122
- public function user_role_added( $user_id, $old_user_data ) {
1123
-
1124
- if ( isset( $_POST[ 'members_user_roles' ] ) && ! empty( $_POST[ 'members_user_roles' ] ) ) {
1125
- // Get the current user roles.
1126
- $old_roles = (array) $old_user_data->roles;
1127
-
1128
- // Sanitize the posted roles.
1129
- $new_roles = array_map( 'members_sanitize_role', $_POST[ 'members_user_roles' ] );
1130
-
1131
- sort( $old_roles );
1132
- sort( $new_roles );
1133
- $old_roles_str = implode( '', $old_roles );
1134
- $new_roles_str = implode( '', $new_roles );
1135
- if ( ! empty( $old_roles ) && $old_roles_str !== $new_roles_str ) {
1136
- $notifications = $this->notifier->get_notifications( 'user-role' );
1137
- foreach ( $notifications as $notification ) {
1138
-
1139
- /**
1140
- * Trigger User Role Changed - For User notification.
1141
- *
1142
- * @since 1.6.5
1143
- */
1144
- if ( apply_filters( 'bnfw_trigger_user-role-added_notification', true, $notification, $new_roles, $old_roles ) ) {
1145
- $this->engine->send_user_role_added_email(
1146
- $this->notifier->read_settings( $notification->ID ),
1147
- $user_id,
1148
- $old_roles,
1149
- $new_roles
1150
- );
1151
- }
1152
- }
1153
-
1154
- $notifications = $this->notifier->get_notifications( 'admin-role' );
1155
- foreach ( $notifications as $notification ) {
1156
-
1157
- /**
1158
- * Trigger User Role Changed - For User notification.
1159
- *
1160
- * @since 1.6.5
1161
- */
1162
- if ( apply_filters( 'bnfw_trigger_user-role-added_notification', true, $notification, $new_roles, $old_roles ) ) {
1163
- $setting = $this->notifier->read_settings( $notification->ID );
1164
- $setting[ 'message' ] = $this->engine->handle_user_added_role_shortcodes( $setting[ 'message' ], $old_roles, $new_roles );
1165
- $setting[ 'subject' ] = $this->engine->handle_user_added_role_shortcodes( $setting[ 'subject' ], $old_roles, $new_roles );
1166
-
1167
- $this->engine->send_notification( $setting, $user_id );
1168
- }
1169
- }
1170
- }
1171
- }
1172
- }
1173
-
1174
- /**
1175
- * Sanitizes a role name. This is a wrapper for the `sanitize_key()` WordPress function. Only
1176
- * alphanumeric characters and underscores are allowed. Hyphens are also replaced with underscores.
1177
- *
1178
- * @since 1.0.0
1179
- * @access public
1180
- * @return int
1181
- */
1182
- function members_sanitize_role( $role ) {
1183
-
1184
- $_role = strtolower( $role );
1185
- $_role = preg_replace( '/[^a-z0-9_\-\s]/', '', $_role );
1186
-
1187
- return apply_filters( 'members_sanitize_role', str_replace( ' ', '_', $_role ), $role );
1188
- }
1189
-
1190
- /**
1191
- * Send notification based on type and ref id
1192
- *
1193
- * @since 1.0
1194
- * @param string $type Notification type.
1195
- * @param mixed $ref_id Reference data.
1196
- */
1197
- public function send_notification( $type, $ref_id, $include_disabled = true ) {
1198
- $notifications = $this->notifier->get_notifications( $type , $include_disabled);
1199
- foreach ( $notifications as $notification ) {
1200
- $this->engine->send_notification( $this->notifier->read_settings( $notification->ID ), $ref_id );
1201
- }
1202
- }
1203
-
1204
- /**
1205
- * Send notification async based on type and ref id.
1206
- *
1207
- * @param string $type Notification type.
1208
- * @param mixed $ref_id Reference data.
1209
- */
1210
- public function send_notification_async( $type, $ref_id ) {
1211
- $notifications = $this->notifier->get_notifications( $type, false );
1212
- foreach ( $notifications as $notification ) {
1213
- $transient = get_transient( 'bnfw-async-notifications' );
1214
- if ( ! is_array( $transient ) ) {
1215
- $transient = array();
1216
- }
1217
-
1218
- $notification_data = array(
1219
- 'ref_id' => $ref_id,
1220
- 'notification_id' => $notification->ID,
1221
- 'notification_type' => $type,
1222
- );
1223
-
1224
- if ( ! in_array( $notification_data, $transient ) ) {
1225
- $transient[] = $notification_data;
1226
- set_transient( 'bnfw-async-notifications', $transient, 600 );
1227
- }
1228
- }
1229
- }
1230
-
1231
- /**
1232
- * Can send comment notification or not
1233
- *
1234
- * @since 1.0
1235
- * @param unknown $comment
1236
- * @return unknown
1237
- */
1238
- private function can_send_comment_notification( $comment ) {
1239
- // Returns false if the comment is marked as spam AND admin has enabled suppression of spam
1240
- $suppress_spam = get_option( 'bnfw_suppress_spam' );
1241
- if ( '1' === $suppress_spam && ( 0 === strcmp( $comment->comment_approved, 'spam' ) ) ) {
1242
- return false;
1243
- }
1244
- return true;
1245
- }
1246
-
1247
- /**
1248
- * Handle user request email content.
1249
- *
1250
- * @param string $content Content.
1251
- * @param array $email_data Email data.
1252
- *
1253
- * @return string Modified content.
1254
- */
1255
- public function handle_user_request_email_content( $content, $email_data ) {
1256
- $field = 'message';
1257
- $new_content = '';
1258
-
1259
- switch ( $email_data[ 'description' ] ) {
1260
- case 'Export Personal Data':
1261
- $notification_name = 'ca-export-data';
1262
- $new_content = $this->handle_user_request_notification( $notification_name, $field, $email_data );
1263
- break;
1264
- case 'Erase Personal Data':
1265
- $notification_name = 'ca-erase-data';
1266
- $new_content = $this->handle_user_request_notification( $notification_name, $field, $email_data );
1267
- break;
1268
- }
1269
-
1270
- if ( ! empty( $new_content ) ) {
1271
- return $new_content;
1272
- } else {
1273
- return $content;
1274
- }
1275
- }
1276
-
1277
- /**
1278
- * Handle user request email subject.
1279
- *
1280
- * @param string $subject Subject
1281
- * @param string $blogname Blog name
1282
- * @param array $email_data Email data.
1283
- *
1284
- * @return string Modified subject.
1285
- */
1286
- public function handle_user_request_email_subject( $subject, $blogname,
1287
- $email_data ) {
1288
- $field = 'subject';
1289
- $new_subject = '';
1290
-
1291
- switch ( $email_data[ 'description' ] ) {
1292
- case 'Export Personal Data':
1293
- $notification_name = 'ca-export-data';
1294
- $new_subject = $this->handle_user_request_notification( $notification_name, $field, $email_data );
1295
- break;
1296
- case 'Erase Personal Data':
1297
- $notification_name = 'ca-erase-data';
1298
- $new_subject = $this->handle_user_request_notification( $notification_name, $field, $email_data );
1299
- break;
1300
- }
1301
- if ( ! empty( $new_subject ) ) {
1302
- return $new_subject;
1303
- } else {
1304
- return $subject;
1305
- }
1306
- }
1307
-
1308
- /**
1309
- * Handle user confirmed action email content.
1310
- *
1311
- * @param string $content Content.
1312
- * @param array $email_data Email data.
1313
- *
1314
- * @return string Modified content.
1315
- */
1316
- public function handle_user_confirmed_action_email_content( $content,
1317
- $email_data ) {
1318
- $field = 'message';
1319
- $new_content = '';
1320
-
1321
- switch ( $email_data[ 'description' ] ) {
1322
- case 'Export Personal Data':
1323
- $notification_name = 'uc-export-data';
1324
- $new_content = $this->handle_user_confirmed_action_notification( $notification_name, $field, $email_data );
1325
- break;
1326
- case 'Erase Personal Data':
1327
- $notification_name = 'uc-erase-data';
1328
- $new_content = $this->handle_user_confirmed_action_notification( $notification_name, $field, $email_data );
1329
- break;
1330
- }
1331
-
1332
- if ( ! empty( $new_content ) ) {
1333
- return $new_content;
1334
- } else {
1335
- return $content;
1336
- }
1337
- }
1338
-
1339
- /**
1340
- * Handle data exported email content.
1341
- *
1342
- * @param string $content Content.
1343
- * @param int $request_id
1344
- *
1345
- * @return string Modified content.
1346
- */
1347
- public function handle_data_export_email_content( $content, $request_id,$email_data ) {
1348
-
1349
- $field = 'message';
1350
- $notification_name = 'data-export';
1351
- $new_content = '';
1352
-
1353
- $notifications = $this->notifier->get_notifications( $notification_name );
1354
- if ( count( $notifications ) > 0 ) {
1355
- // Ideally there should be only one notification for this type.
1356
- // If there are multiple notification then we will read data about only the last one
1357
- $setting = $this->notifier->read_settings( end( $notifications )->ID );
1358
-
1359
- $new_content = $this->engine->handle_data_export_email_shortcodes( $setting[ $field ], $setting, $request_id );
1360
- $new_content = $this->engine->handle_global_user_shortcodes( $new_content, $email_data['message_recipient'] );
1361
- }
1362
-
1363
- if ( ! empty( $new_content ) ) {
1364
- return $new_content;
1365
- } else {
1366
- return $content;
1367
- }
1368
- }
1369
-
1370
- public function handle_erasure_complete_email_subject( $subject, $sitename,
1371
- $email_data ) {
1372
- return $this->handle_erasure_complete_email_notification( 'subject', $subject, $email_data );
1373
- }
1374
-
1375
- public function handle_erasure_complete_email_content( $content, $email_data ) {
1376
- if ( isset( $email_data[ 'privacy_policy_url' ] ) ) {
1377
- return $this->handle_erasure_complete_email_notification( 'message', $content, $email_data );
1378
- }
1379
-
1380
- return $content;
1381
- }
1382
-
1383
- protected function handle_erasure_complete_email_notification( $field,
1384
- $content,
1385
- $email_data ) {
1386
- $notification_name = 'data-erased';
1387
- $new_content = '';
1388
- $notifications = $this->notifier->get_notifications( $notification_name );
1389
- if ( count( $notifications ) > 0 ) {
1390
- // Ideally there should be only one notification for this type.
1391
- // If there are multiple notification then we will read data about only the last one
1392
- $setting = $this->notifier->read_settings( end( $notifications )->ID );
1393
- $new_content = $this->engine->handle_shortcodes( $setting[ $field ], $notification_name, $email_data );
1394
- }
1395
- if ( ! empty( $new_content ) ) {
1396
- return $new_content;
1397
- } else {
1398
- return $content;
1399
- }
1400
- }
1401
-
1402
- /**
1403
- * Send notification emails on shutdown.
1404
- */
1405
- public function on_shutdown() {
1406
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1407
- return;
1408
- }
1409
-
1410
- $transient = get_transient( 'bnfw-async-notifications' );
1411
- if ( is_array( $transient ) ) {
1412
- delete_transient( 'bnfw-async-notifications' );
1413
- foreach ( $transient as $id_pairs ) {
1414
- $this->engine->send_notification( $this->notifier->read_settings( $id_pairs[ 'notification_id' ] ), $id_pairs[ 'ref_id' ] );
1415
- }
1416
- }
1417
- }
1418
-
1419
- /**
1420
- * Handle user request notification.
1421
- *
1422
- * @param string $notification_name Notification name.
1423
- * @param string $field Field name.
1424
- * @param array $email_data Email data.
1425
- *
1426
- * @return string Content.
1427
- */
1428
- protected function handle_user_request_notification( $notification_name,
1429
- $field, $email_data ) {
1430
- $notifications = $this->notifier->get_notifications( $notification_name );
1431
- if ( count( $notifications ) > 0 ) {
1432
- // Ideally there should be only one notification for this type.
1433
- // If there are multiple notification then we will read data about only the last one
1434
- $setting = $this->notifier->read_settings( end( $notifications )->ID );
1435
-
1436
- return $this->engine->handle_user_request_email_shortcodes( $setting[ $field ], $setting, $email_data );
1437
- }
1438
-
1439
- return '';
1440
- }
1441
-
1442
- /**
1443
- * Handle user confirmed action notification.
1444
- *
1445
- * @param string $notification_name Notification name.
1446
- * @param string $field Field name.
1447
- * @param array $email_data Email data.
1448
- *
1449
- * @return string Content.
1450
- */
1451
- protected function handle_user_confirmed_action_notification( $notification_name,
1452
- $field,
1453
- $email_data ) {
1454
- $notifications = $this->notifier->get_notifications( $notification_name );
1455
- if ( count( $notifications ) > 0 ) {
1456
- // Ideally there should be only one notification for this type.
1457
- // If there are multiple notification then we will read data about only the last one
1458
- $setting = $this->notifier->read_settings( end( $notifications )->ID );
1459
-
1460
- return $this->engine->handle_user_confirmed_action_email_shortcodes( $setting[ $field ], $setting, $email_data );
1461
- }
1462
-
1463
- return '';
1464
- }
1465
-
1466
- /**
1467
- * Is this a metabox request?
1468
- *
1469
- * Block editor sends duplicate requests on post update.
1470
- *
1471
- * @return bool True if metabox request, False otherwise.
1472
- */
1473
- protected function is_metabox_request() {
1474
- return ( isset( $_GET[ 'meta-box-loader' ] ) || isset( $_GET[ 'meta_box' ] ) );
1475
- }
1476
-
1477
-
1478
- /**
1479
- * Check if Gutenberg is active.
1480
- *
1481
- *
1482
- * @return bool
1483
- * @since 1.3
1484
- */
1485
- public function is_gutenberg_active() {
1486
- $gutenberg = false;
1487
- $block_editor = false;
1488
-
1489
- if ( has_filter( 'replace_editor', 'gutenberg_init' ) ) {
1490
- // Gutenberg is installed and activated.
1491
- $gutenberg = true;
1492
- }
1493
-
1494
- if ( version_compare( $GLOBALS['wp_version'], '5.0-beta', '>' ) ) {
1495
- // Block editor.
1496
- $block_editor = true;
1497
- }
1498
-
1499
- if ( ! $gutenberg && ! $block_editor ) {
1500
- return false;
1501
- }
1502
-
1503
- include_once ABSPATH . 'wp-admin/includes/plugin.php';
1504
-
1505
- if ( ! is_plugin_active( 'classic-editor/classic-editor.php' ) ) {
1506
- return true;
1507
- }
1508
-
1509
- $use_block_editor = ( get_option( 'classic-editor-replace' ) === 'no-replace' );
1510
-
1511
- return $use_block_editor;
1512
- }
1513
-
1514
- }
1515
-
1516
- /* ------------------------------------------------------------------------ *
1517
- * Fire up the plugin
1518
- * ------------------------------------------------------------------------ */
1519
- BNFW::factory();
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin Name: Better Notifications for WP
4
+ * Plugin URI: https://wordpress.org/plugins/bnfw/
5
+ * Description: Supercharge your WordPress notifications using a WYSIWYG editor and shortcodes. Default and new notifications available. Add more power with Add-ons.
6
+ * Version: 1.8.8
7
+ * Requires at least: 4.8
8
+ * Requires PHP: 7.0
9
+ * Author: Made with Fuel
10
+ * Author URI: https://madewithfuel.com/
11
+ * License: GPLv2 or later
12
+ * License URI: http://www.gnu.org/licenses/gpl-2.0.html
13
+ * Text Domain: bnfw
14
+ * Domain Path: /languages
15
+ *
16
+ * @package bnfw
17
+ */
18
+
19
+ /**
20
+ * Copyright © 2022 Made with Fuel Ltd. (hello@betternotificationsforwp.com)
21
+ * This program is free software; you can redistribute it and/or modify
22
+ * it under the terms of the GNU General Public License, version 2, as
23
+ * published by the Free Software Foundation.
24
+ * This program is distributed in the hope that it will be useful,
25
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
26
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
+ * GNU General Public License for more details.
28
+ * You should have received a copy of the GNU General Public License
29
+ * along with this program; if not, write to the Free Software
30
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31
+ */
32
+ if ( ! class_exists( 'BNFW', false ) ) {
33
+ /**
34
+ * BNFW main class.
35
+ */
36
+ class BNFW {
37
+ /**
38
+ * BNFW version.
39
+ *
40
+ * @var string
41
+ */
42
+ public $bnfw_version = '1.8.8';
43
+
44
+ /**
45
+ * Class Constructor.
46
+ *
47
+ * @since 1.0
48
+ */
49
+ public function __construct() {
50
+ $this->bnfw_define_constants();
51
+ $this->load_textdomain();
52
+ $this->includes();
53
+ $this->hooks();
54
+ /**
55
+ * BNFW Notification.
56
+ *
57
+ * @var \BNFW_Notification
58
+ */
59
+ $this->notifier = new BNFW_Notification();
60
+
61
+ /**
62
+ * BNFW Engine.
63
+ *
64
+ * @var \BNFW_Engine
65
+ */
66
+ $this->engine = new BNFW_Engine();
67
+ }
68
+
69
+ /**
70
+ * Factory method to return the instance of the class.
71
+ *
72
+ * Makes sure that only one instance is created.
73
+ *
74
+ * @return \BNFW Instance of the class.
75
+ */
76
+ public static function factory() {
77
+ static $instance = false;
78
+ if ( ! $instance ) {
79
+ $instance = new self();
80
+ }
81
+ return $instance;
82
+ }
83
+
84
+ /**
85
+ * Loads the plugin language files
86
+ *
87
+ * @since 1.0
88
+ */
89
+ public function load_textdomain() {
90
+ // Load localization domain.
91
+ $this->translations = dirname( plugin_basename( __FILE__ ) ) . '/languages/';
92
+ load_plugin_textdomain( 'bnfw', false, $this->translations );
93
+ }
94
+
95
+ /**
96
+ * Include required files.
97
+ *
98
+ * @since 1.0
99
+ */
100
+ public function includes() {
101
+
102
+ // Load license related classes.
103
+ if ( ! class_exists( 'EDD_SL_Plugin_Updater' ) ) {
104
+ require_once 'includes/libraries/class-edd-sl-plugin-updater.php';
105
+ }
106
+
107
+ include_once ABSPATH . 'wp-admin/includes/plugin.php';
108
+
109
+ require_once 'vendor/persist-admin-notices-dismissal/persist-admin-notices-dismissal.php';
110
+
111
+ require_once 'includes/license/class-bnfw-license.php';
112
+ require_once 'includes/license/class-bnfw-license-setting.php';
113
+
114
+ // Load Engine.
115
+ require_once 'includes/engine/class-bnfw-engine.php';
116
+ require_once 'includes/overrides.php';
117
+
118
+ // Load notification post type and notification helpers.
119
+ require_once 'includes/admin/class-bnfw-notification.php';
120
+ require_once 'includes/notification/post-notification.php';
121
+
122
+ // Helpers.
123
+ require_once 'includes/helpers/helpers.php';
124
+ require_once 'includes/helpers/class-bnfw-ajax.php';
125
+
126
+ // Load Admin Pages.
127
+ if ( is_admin() ) {
128
+ require_once 'includes/admin/class-bnfw-settings.php';
129
+ }
130
+ }
131
+ /**
132
+ * Define BNFW Constants.
133
+ */
134
+ private function bnfw_define_constants() {
135
+ define( 'BNFW_VERSION', $this->bnfw_version );
136
+ }
137
+ /**
138
+ * Register Hooks.
139
+ *
140
+ * @since 1.0
141
+ */
142
+ public function hooks() {
143
+ global $wp_version;
144
+
145
+ register_activation_hook( __FILE__, array( $this, 'activate' ) );
146
+
147
+ add_action( 'admin_init', array( 'PAnD', 'init' ) );
148
+ add_action( 'admin_init', array( $this, 'add_capability_to_admin' ) );
149
+
150
+ add_action( 'draft_to_private', array( $this, 'private_post' ) );
151
+ add_action( 'future_to_private', array( $this, 'private_post' ) );
152
+ add_action( 'pending_to_private', array( $this, 'private_post' ) );
153
+ add_action( 'publish_to_private', array( $this, 'private_post' ) );
154
+
155
+ add_action( 'wp_insert_post', array( $this, 'insert_post' ), 10, 3 );
156
+
157
+ add_action( 'publish_to_trash', array( $this, 'trash_post' ) );
158
+
159
+ add_action( 'auto-draft_to_publish', array( $this, 'publish_post' ) );
160
+ add_action( 'draft_to_publish', array( $this, 'publish_post' ) );
161
+ add_action( 'future_to_publish', array( $this, 'publish_post' ) );
162
+ add_action( 'pending_to_publish', array( $this, 'publish_post' ) );
163
+ add_action( 'private_to_publish', array( $this, 'publish_post' ) );
164
+
165
+ add_action( 'publish_to_publish', array( $this, 'update_post' ) );
166
+ add_action( 'private_to_private', array( $this, 'update_post' ) );
167
+
168
+ add_action( 'add_attachment', array( $this, 'new_publish_media_notification' ), 10, 1 );
169
+ add_action( 'edit_attachment', array( $this, 'media_attachment_data_update_notification' ), 10 );
170
+
171
+ add_action( 'transition_post_status', array( $this, 'on_post_transition' ), 10, 3 );
172
+
173
+ add_action( 'init', array( $this, 'custom_post_type_hooks' ), 100 );
174
+ add_action( 'create_term', array( $this, 'create_term' ), 10, 3 );
175
+
176
+ add_action( 'transition_comment_status', array( $this, 'on_comment_status_change' ), 10, 3 );
177
+ add_action( 'comment_post', array( $this, 'comment_post' ) );
178
+ add_action( 'trackback_post', array( $this, 'trackback_post' ) );
179
+ add_action( 'pingback_post', array( $this, 'pingback_post' ) );
180
+
181
+ add_action( 'user_register', array( $this, 'user_register' ) );
182
+
183
+ add_action( 'user_register', array( $this, 'welcome_email' ) );
184
+
185
+ if ( is_plugin_active( 'members/members.php' ) ) {
186
+
187
+ add_action( 'add_user_role', array( $this, 'user_role_added_from_member_plugin' ), 10, 2 );
188
+ add_action( 'remove_user_role', array( $this, 'user_role_removed_from_member_plugin' ), 10, 2 );
189
+ add_action( 'set_user_role', array( $this, 'user_role_changed' ), 10, 3 );
190
+
191
+ add_action( 'profile_update', array( $this, 'user_role_added' ), 10, 2 );
192
+ } else {
193
+ add_action( 'set_user_role', array( $this, 'user_role_changed' ), 10, 3 );
194
+ }
195
+
196
+ add_action( 'wp_login', array( $this, 'user_login' ), 10, 2 );
197
+
198
+ if ( version_compare( $wp_version, '4.4', '>=' ) ) {
199
+ add_filter( 'retrieve_password_title', array( $this, 'change_password_email_title' ), 10, 3 );
200
+ } else {
201
+ add_filter( 'retrieve_password_title', array( $this, 'change_password_email_title' ) );
202
+ }
203
+ add_action( 'lostpassword_post', array( $this, 'on_lost_password' ) );
204
+ add_filter( 'retrieve_password_message', array( $this, 'change_password_email_message' ), 10, 4 );
205
+
206
+ add_action( 'after_password_reset', array( $this, 'on_password_reset' ) );
207
+
208
+ add_filter( 'send_password_change_email', array( $this, 'should_password_changed_email_be_sent' ), 10, 3 );
209
+ add_filter( 'password_change_email', array( $this, 'on_password_changed' ), 10, 2 );
210
+
211
+ add_filter( 'send_email_change_email', array( $this, 'should_email_changed_email_be_sent' ), 10, 3 );
212
+ add_filter( 'email_change_email', array( $this, 'on_email_changed' ), 10, 3 );
213
+ add_filter( 'new_user_email_content', array( $this, 'on_email_changing' ), 10, 2 );
214
+
215
+ add_filter( 'auto_core_update_email', array( $this, 'on_core_updated' ), 10, 4 );
216
+
217
+ add_filter( 'user_request_action_email_content', array( $this, 'handle_user_request_email_content' ), 10, 2 );
218
+ add_filter( 'user_request_action_email_subject', array( $this, 'handle_user_request_email_subject' ), 10, 3 );
219
+
220
+ add_filter( 'user_confirmed_action_email_content', array( $this, 'handle_user_confirmed_action_email_content' ), 10, 2 );
221
+
222
+ add_filter( 'wp_privacy_personal_data_email_content', array( $this, 'handle_data_export_email_content' ), 10, 3 );
223
+
224
+ add_filter( 'user_erasure_complete_email_subject', array( $this, 'handle_erasure_complete_email_subject' ), 10, 3 );
225
+ add_filter( 'user_confirmed_action_email_content', array( $this, 'handle_erasure_complete_email_content' ), 10, 2 );
226
+
227
+ add_filter( 'plugin_action_links', array( $this, 'plugin_action_links' ), 10, 4 );
228
+ add_action( 'shutdown', array( $this, 'on_shutdown' ) );
229
+ }
230
+
231
+ /**
232
+ * Add 'bnfw' capability to admin.
233
+ */
234
+ public function add_capability_to_admin() {
235
+ $admins = get_role( 'administrator' );
236
+
237
+ if ( is_null( $admins ) ) {
238
+ return;
239
+ }
240
+
241
+ if ( ! $admins->has_cap( 'bnfw' ) ) {
242
+ $admins->add_cap( 'bnfw' );
243
+ }
244
+ }
245
+
246
+ /**
247
+ * On post transition.
248
+ *
249
+ * @param string $new_status New post status.
250
+ * @param string $old_status Old post status.
251
+ * @param \WP_Post $post Post object.
252
+ */
253
+ public function on_post_transition( $new_status, $old_status, $post ) {
254
+ if ( ! is_a( $post, 'WP_Post' ) ) {
255
+ return;
256
+ }
257
+
258
+ if ( 'pending' === $old_status ) {
259
+ return;
260
+ }
261
+
262
+ if ( 'pending' !== $new_status ) {
263
+ return;
264
+ }
265
+
266
+ $this->on_post_pending( $post->ID, $post );
267
+ }
268
+
269
+ /**
270
+ * Setup hooks for custom post types.
271
+ *
272
+ * @since 1.2
273
+ */
274
+ public function custom_post_type_hooks() {
275
+ $post_types = get_post_types( array( 'public' => true ), 'names' );
276
+ $post_types = array_diff( $post_types, array( BNFW_Notification::POST_TYPE ) );
277
+
278
+ foreach ( $post_types as $post_type ) {
279
+ add_action( 'future_' . $post_type, array( $this, 'on_post_scheduled' ), 10, 2 );
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Importer.
285
+ */
286
+ public function activate() {
287
+ require_once dirname( __FILE__ ) . '/includes/class-bnfw-import.php';
288
+ $importer = new BNFW_Import();
289
+ $importer->import();
290
+ }
291
+
292
+ /**
293
+ * Add 'Settings' link below BNFW in Plugins list.
294
+ *
295
+ * @since 1.0
296
+ * @param string[] $links An array of plugin action links. By default this can include 'activate',
297
+ * 'deactivate', and 'delete'. With Multisite active this can also include.
298
+ * @param string $file Path to the plugin file relative to the plugins directory.
299
+ * @return array plugin action links.
300
+ */
301
+ public function plugin_action_links( $links, $file ) {
302
+ $plugin_file = 'bnfw/bnfw.php';
303
+ if ( $file === $plugin_file ) {
304
+ $settings_link = '<a href="' . esc_url( admin_url( 'edit.php?post_type=bnfw_notification&page=bnfw-settings' ) ) . '">' . esc_html__( 'Settings', 'bnfw' ) . '</a>';
305
+ array_unshift( $links, $settings_link );
306
+ }
307
+ return $links;
308
+ }
309
+
310
+ /**
311
+ * When a new term is created.
312
+ *
313
+ * @since 1.0
314
+ * @param int $term_id Term ID.
315
+ * @param int $tt_id Term taxonomy ID.
316
+ * @param string $taxonomy Taxonomy slug.
317
+ */
318
+ public function create_term( $term_id, $tt_id, $taxonomy ) {
319
+ $this->send_notification( 'newterm-' . $taxonomy, $term_id );
320
+ }
321
+
322
+ /**
323
+ * Fires when a post is created for the first time.
324
+ *
325
+ * @param int $post_id Post ID.
326
+ * @param object $post Post object.
327
+ * @param bool $update Whether this is an existing post being updated or not.
328
+ *
329
+ * @since 1.3.1
330
+ */
331
+ public function insert_post( $post_id, $post, $update ) {
332
+ // Some themes like P2, directly insert posts into DB.
333
+ $insert_post_themes = apply_filters( 'bnfw_insert_post_themes', array( 'P2', 'Syncope' ) );
334
+ $current_theme = wp_get_theme();
335
+
336
+ /**
337
+ * Whether to trigger insert post hook.
338
+ *
339
+ * @since 1.4
340
+ */
341
+ $trigger_insert_post = apply_filters( 'bnfw_trigger_insert_post', false, $post_id, $update );
342
+
343
+ if ( in_array( $current_theme->get( 'Name' ), $insert_post_themes, true ) || $trigger_insert_post ) {
344
+ $this->handle_inserted_post( $post_id, $update );
345
+ }
346
+ }
347
+
348
+ /**
349
+ * Trigger New Post published notification for ACF forms.
350
+ *
351
+ * @param string $form ACF Form.
352
+ * @param int $post_id Post ID.
353
+ */
354
+ public function acf_submit_form( $form, $post_id ) {
355
+ $this->handle_inserted_post( $post_id );
356
+ }
357
+
358
+ /**
359
+ * Trigger correct notifications for inserted posts.
360
+ *
361
+ * @param int $post_id Post id.
362
+ * @param bool $update Whether the post was updated.
363
+ *
364
+ * @since 1.6.7
365
+ */
366
+ private function handle_inserted_post( $post_id, $update ) {
367
+ $post = get_post( $post_id );
368
+
369
+ if ( ! is_a( $post, 'WP_Post' ) ) {
370
+ return;
371
+ }
372
+
373
+ switch ( $post->post_status ) {
374
+ case 'publish':
375
+ if ( $update ) {
376
+ $this->update_post( $post );
377
+ } else {
378
+ $this->publish_post( $post );
379
+ }
380
+ break;
381
+
382
+ case 'private':
383
+ $this->private_post( $post );
384
+ break;
385
+
386
+ case 'pending':
387
+ $this->on_post_pending( $post_id, $post );
388
+ break;
389
+
390
+ case 'future':
391
+ $this->on_post_scheduled( $post_id, $post );
392
+ break;
393
+ }
394
+ }
395
+
396
+ /**
397
+ * Fires when a post is created for the first time.
398
+ *
399
+ * @since 1.0
400
+ * @param object $post Post Object.
401
+ */
402
+ public function publish_post( $post ) {
403
+ $post_id = $post->ID;
404
+ $post_type = $post->post_type;
405
+
406
+ if ( BNFW_Notification::POST_TYPE !== $post_type ) {
407
+ $this->send_notification_async( 'new-' . $post_type, $post_id );
408
+ }
409
+ }
410
+
411
+ /**
412
+ * Fires when a private post is created.
413
+ *
414
+ * @since 1.6
415
+ * @param object $post Post Object.
416
+ */
417
+ public function private_post( $post ) {
418
+ $post_id = $post->ID;
419
+ $post_type = $post->post_type;
420
+
421
+ if ( BNFW_Notification::POST_TYPE !== $post_type ) {
422
+ $this->send_notification_async( 'private-' . $post_type, $post_id );
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Fires when a post is updated.
428
+ *
429
+ * @since 1.0
430
+ * @param WP_Post $post Post object.
431
+ */
432
+ public function update_post( $post ) {
433
+ if ( $this->is_metabox_request() ) {
434
+ return;
435
+ }
436
+
437
+ $post_id = $post->ID;
438
+ $post_type = $post->post_type;
439
+
440
+ if ( BNFW_Notification::POST_TYPE !== $post_type ) {
441
+ $this->send_notification_async( 'update-' . $post_type, $post_id );
442
+ }
443
+ }
444
+
445
+ /**
446
+ * Fires when a post is moved publish to trash.
447
+ *
448
+ * @param WP_Post $post Post object.
449
+ */
450
+ public function trash_post( $post ) {
451
+ if ( $this->is_metabox_request() ) {
452
+ return;
453
+ }
454
+ $post_id = $post->ID;
455
+ $post_type = $post->post_type;
456
+
457
+ if ( BNFW_Notification::POST_TYPE !== $post_type ) {
458
+ $this->send_notification_async( 'trash-' . $post_type, $post_id );
459
+ }
460
+ }
461
+
462
+ /**
463
+ * Fires when a post is pending for review.
464
+ *
465
+ * @since 1.1
466
+ * @param int $post_id Post ID.
467
+ * @param object $post Post object.
468
+ */
469
+ public function on_post_pending( $post_id, $post ) {
470
+ if ( $this->is_metabox_request() ) {
471
+ return;
472
+ }
473
+
474
+ $post_type = $post->post_type;
475
+
476
+ if ( BNFW_Notification::POST_TYPE !== $post_type ) {
477
+ $this->send_notification_async( 'pending-' . $post_type, $post_id );
478
+ }
479
+ }
480
+
481
+ /**
482
+ * On Media Published.
483
+ *
484
+ * @param int $post_id Attachment post id.
485
+ */
486
+ public function new_publish_media_notification( $post_id ) {
487
+ $post_type = get_post_type( $post_id );
488
+
489
+ if ( BNFW_Notification::POST_TYPE !== $post_type && 'attachment' === $post_type ) {
490
+ $this->send_notification_async( 'new-media', $post_id );
491
+ }
492
+ }
493
+
494
+ /**
495
+ * On Media Attachment Data Update.
496
+ *
497
+ * @param int $post_id Attachment post id.
498
+ */
499
+ public function media_attachment_data_update_notification( $post_id ) {
500
+ $post_type = get_post_type( $post_id );
501
+ if ( BNFW_Notification::POST_TYPE !== $post_type && 'attachment' === $post_type ) {
502
+ $this->send_notification_async( 'update-media', $post_id );
503
+ }
504
+ }
505
+
506
+ /**
507
+ * Fires when a post is scheduled.
508
+ *
509
+ * @since 1.1.5
510
+ * @param int $post_id Post ID.
511
+ * @param object $post Post object.
512
+ */
513
+ public function on_post_scheduled( $post_id, $post ) {
514
+ // Rest request also triggers the same hook. We can ignore it.
515
+ if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
516
+ return;
517
+ }
518
+
519
+ $post_type = $post->post_type;
520
+
521
+ if ( BNFW_Notification::POST_TYPE !== $post_type ) {
522
+ $this->send_notification_async( 'future-' . $post_type, $post_id );
523
+ }
524
+ }
525
+
526
+ /**
527
+ * When the status of a comment is changed.
528
+ *
529
+ * @param string $new_status New status.
530
+ * @param string $old_status Old status.
531
+ * @param \WP_Comment $comment Comment.
532
+ */
533
+ public function on_comment_status_change( $new_status, $old_status, $comment ) {
534
+ if ( 'approved' !== $new_status ) {
535
+ return;
536
+ }
537
+
538
+ $post = get_post( $comment->comment_post_ID );
539
+
540
+ $notification_type = 'approve-' . $post->post_type . '-comment';
541
+
542
+ $this->send_notification( $notification_type, $comment->comment_ID, false );
543
+
544
+ // Send new comment notification after comment approve.
545
+ $notification_type = 'new-comment'; // old notification name.
546
+
547
+ if ( 'post' !== $post->post_type ) {
548
+ $notification_type = 'comment-' . $post->post_type;
549
+ }
550
+
551
+ $this->send_notification( $notification_type, $comment->comment_ID );
552
+
553
+ // Send comment reply notification after comment approve.
554
+ $this->comments_reply( $comment->comment_ID );
555
+ }
556
+
557
+ /**
558
+ * Send notification for new comments
559
+ *
560
+ * @since 1.0
561
+ * @param int $comment_id The comment ID.
562
+ */
563
+ public function comment_post( $comment_id ) {
564
+ $the_comment = get_comment( $comment_id );
565
+ $post = get_post( $the_comment->comment_post_ID );
566
+
567
+ if ( '1' !== $the_comment->comment_approved ) {
568
+ if ( $this->can_send_comment_notification( $the_comment ) ) {
569
+ $notification_type = 'moderate-' . $post->post_type . '-comment';
570
+ $this->send_notification( $notification_type, $comment_id );
571
+ }
572
+ } else {
573
+ $notification_type = 'new-comment'; // old notification name.
574
+
575
+ if ( 'post' !== $post->post_type ) {
576
+ $notification_type = 'comment-' . $post->post_type;
577
+ }
578
+
579
+ $this->send_notification( $notification_type, $comment_id );
580
+
581
+ // comment reply notification.
582
+ $this->comments_reply( $comment_id );
583
+ }
584
+ }
585
+
586
+ /**
587
+ * Send notification for comments reply
588
+ *
589
+ * @since 1.0
590
+ * @param int $comment_id The comment ID.
591
+ */
592
+ public function comments_reply( $comment_id ) {
593
+ $the_comment = get_comment( $comment_id );
594
+ $post = get_post( $the_comment->comment_post_ID );
595
+
596
+ // comment reply notification.
597
+ if ( $this->can_send_comment_notification( $the_comment ) ) {
598
+ if ( $the_comment->comment_parent > 0 ) {
599
+ $notification_type = 'reply-comment'; // old notification name.
600
+ if ( 'post' !== $post->post_type ) {
601
+ $notification_type = 'commentreply-' . $post->post_type;
602
+ }
603
+ $notifications = $this->notifier->get_notifications( $notification_type );
604
+ if ( count( $notifications ) > 0 ) {
605
+ $parent = get_comment( $the_comment->comment_parent );
606
+ if ( $parent->comment_author_email !== $the_comment->comment_author_email ) {
607
+ foreach ( $notifications as $notification ) {
608
+ $this->engine->send_comment_reply_email( $this->notifier->read_settings( $notification->ID ), $the_comment, $parent );
609
+ }
610
+ }
611
+ }
612
+ }
613
+ }
614
+ }
615
+
616
+ /**
617
+ * Send notification for new trackback.
618
+ *
619
+ * @since 1.0
620
+ * @param int $comment_id Trackback ID.
621
+ */
622
+ public function trackback_post( $comment_id ) {
623
+ $the_comment = get_comment( $comment_id );
624
+ if ( $this->can_send_comment_notification( $the_comment ) ) {
625
+ $this->send_notification( 'new-trackback', $comment_id );
626
+ }
627
+ }
628
+
629
+ /**
630
+ * Send notification for new pingbacks
631
+ *
632
+ * @since 1.0
633
+ * @param int $comment_id Comment ID.
634
+ */
635
+ public function pingback_post( $comment_id ) {
636
+ $the_comment = get_comment( $comment_id );
637
+ if ( $this->can_send_comment_notification( $the_comment ) ) {
638
+ $this->send_notification( 'new-pingback', $comment_id );
639
+ }
640
+ }
641
+
642
+ /**
643
+ * Send notification for lost password.
644
+ *
645
+ * @since 1.0
646
+ */
647
+ public function on_lost_password() {
648
+ $user_login = sanitize_text_field( $_POST['user_login'] );// phpcs:ignore
649
+ $user = get_user_by( 'login', $user_login ) ?: get_user_by( 'email', $user_login );// phpcs:ignore
650
+ if ( $user ) {
651
+ $this->send_notification( 'admin-password', $user->ID );
652
+ }
653
+ }
654
+
655
+ /**
656
+ * Change the title of the password reset email that is sent to the user.
657
+ *
658
+ * @since 1.1
659
+ *
660
+ * @param string $title Email subject.
661
+ * @param string $user_login The username for the user.
662
+ * @param string $user_data WP_User object.
663
+ *
664
+ * @return string
665
+ */
666
+ public function change_password_email_title( $title, $user_login = '', $user_data = '' ) {
667
+ $notifications = $this->notifier->get_notifications( 'user-password' );
668
+ if ( count( $notifications ) > 0 ) {
669
+ // Ideally there should be only one notification for this type.
670
+ // If there are multiple notification then we will read data about only the last one.
671
+ $setting = $this->notifier->read_settings( end( $notifications )->ID );
672
+
673
+ if ( '' === $user_data ) {
674
+ return $this->engine->handle_shortcodes( $setting['subject'], 'user-password', $user_data->ID );
675
+ } else {
676
+ return $this->engine->handle_shortcodes( $setting['subject'], 'user-password', $user_data->ID );
677
+ }
678
+ }
679
+
680
+ return $title;
681
+ }
682
+
683
+ /**
684
+ * Change the message of the password reset email.
685
+ *
686
+ * @since 1.1
687
+ *
688
+ * @param string $message Email message.
689
+ * @param string $key The activation key.
690
+ * @param string $user_login The username for the user.
691
+ * @param string $user_data WP_User object.
692
+ *
693
+ * @return string
694
+ */
695
+ public function change_password_email_message( $message, $key, $user_login = '', $user_data = '' ) {
696
+ $notifications = $this->notifier->get_notifications( 'user-password' );
697
+ if ( count( $notifications ) > 0 ) {
698
+ // Ideally there should be only one notification for this type.
699
+ // If there are multiple notification then we will read data about only the last one.
700
+ $setting = $this->notifier->read_settings( end( $notifications )->ID );
701
+
702
+ $message = $this->engine->handle_password_reset_shortcodes( $setting, $key, $user_login, $user_data );
703
+
704
+ if ( 'html' === $setting['email-formatting'] ) {
705
+ add_filter( 'wp_mail_content_type', array( $this, 'set_html_content_type' ) );
706
+ if ( 'true' !== $setting['disable-autop'] ) {
707
+ $message = wpautop( $message );
708
+ }
709
+ } else {
710
+ add_filter( 'wp_mail_content_type', array( $this, 'set_text_content_type' ) );
711
+ if ( 'text' === $setting['email-formatting'] ) {
712
+ $message = wp_strip_all_tags( $message );
713
+ }
714
+ }
715
+ } else {
716
+ if ( $this->notifier->notification_exists( 'user-password', false ) ) {
717
+ // disabled notification exists, so disable the email by returning empty string.
718
+ return '';
719
+ }
720
+ }
721
+
722
+ return $message;
723
+ }
724
+
725
+ /**
726
+ * On Password reset.
727
+ *
728
+ * @param WP_User $user User who's password was changed.
729
+ */
730
+ public function on_password_reset( $user ) {
731
+ $notifications = $this->notifier->get_notifications( 'password-changed' );
732
+ foreach ( $notifications as $notification ) {
733
+ $this->engine->send_password_changed_email( $this->notifier->read_settings( $notification->ID ), $user );
734
+ }
735
+ }
736
+
737
+ /**
738
+ * Should the password changed email be sent?
739
+ *
740
+ * @param bool $send Whether to send the email.
741
+ * @param array $user The original user array.
742
+ * @param array $userdata The updated user array.
743
+ *
744
+ * @return bool
745
+ */
746
+ public function should_password_changed_email_be_sent( $send, $user, $userdata ) {
747
+ $bnfw = BNFW::factory();// phpcs:ignore
748
+
749
+ if ( ! $send ) {
750
+ return $send;
751
+ }
752
+
753
+ return ! $bnfw->notifier->is_notification_disabled( 'password-changed' );
754
+ }
755
+
756
+ /**
757
+ * On Password Changed.
758
+ *
759
+ * @since 1.6
760
+ *
761
+ * @param array $email_data Email Data.
762
+ * @param array $user User data.
763
+ *
764
+ * @return array Modified Email Data
765
+ */
766
+ public function on_password_changed( $email_data, $user ) {
767
+ return $this->handle_filtered_data_notification( 'password-changed', $email_data, $user['ID'] );
768
+ }
769
+
770
+ /**
771
+ * Should the email changed email be sent?
772
+ *
773
+ * @param bool $send Whether to send the email.
774
+ * @param array $user_old_data The original user array.
775
+ * @param array $user_new_data The updated user array.
776
+ *
777
+ * @return bool
778
+ */
779
+ public function should_email_changed_email_be_sent( $send, $user_old_data, $user_new_data ) {
780
+ $bnfw = BNFW::factory();// phpcs:ignore
781
+
782
+ if ( $bnfw->notifier->notification_exists( 'admin-email-changed', false ) ) {
783
+ $notifications = $bnfw->notifier->get_notifications( 'admin-email-changed' );
784
+
785
+ if ( count( $notifications ) > 0 ) {
786
+ // Ideally there should be only one notification for this type.
787
+ // If there are multiple notification then we will read data about only the last one.
788
+ $setting = $bnfw->notifier->read_settings( end( $notifications )->ID );
789
+ $notification_disabled = apply_filters( 'bnfw_notification_disabled', ( 'true' === $setting['disabled'] ), $id, $setting );
790
+
791
+ if ( ! $notification_disabled ) {
792
+
793
+ $setting['message'] = str_replace( '[user_old_email]', $user_old_data['user_email'], $setting['message'] );
794
+ $setting['message'] = str_replace( '[user_new_email]', $user_new_data['user_email'], $setting['message'] );
795
+ $bnfw->engine->send_notification( $setting, $user_old_data['ID'] );
796
+ }
797
+ }
798
+ }
799
+
800
+ if ( ! $send ) {
801
+ return $send;
802
+ }
803
+
804
+ return ! $bnfw->notifier->is_notification_disabled( 'email-changed' );
805
+ }
806
+
807
+ /**
808
+ * On Email Changed.
809
+ *
810
+ * @since 1.6
811
+ *
812
+ * @param array $email_data Email Data.
813
+ * @param array $user_old_data The original user array.
814
+ * @param array $user_new_data The updated user array.
815
+ *
816
+ * @return array Modified Email Data
817
+ */
818
+ public function on_email_changed( $email_data, $user_old_data, $user_new_data ) {
819
+
820
+ $email = $this->handle_filtered_data_notification( 'email-changed', $email_data, $user_old_data['ID'] );
821
+ $email['message'] = str_replace( '[user_old_email]', $user_old_data['user_email'], $email['message'] );
822
+ $email['message'] = str_replace( '[user_new_email]', $user_new_data['user_email'], $email['message'] );
823
+ return $email;
824
+ }
825
+ /**
826
+ * Filters the text of the email sent when a change of user email address is attempted.
827
+ *
828
+ * @param string $email_text Text in the email.
829
+ * @param array $new_user_details {
830
+ * Data relating to the new user email address.
831
+ *
832
+ * @type string $hash The secure hash used in the confirmation link URL.
833
+ * @type string $newemail The proposed new email address.
834
+ * }
835
+ */
836
+ public function on_email_changing( $email_text, $new_user_details ) {
837
+ $notification_name = 'email-changing';
838
+
839
+ $notifications = $this->notifier->get_notifications( $notification_name );
840
+ if ( count( $notifications ) > 0 ) {
841
+ // Ideally there should be only one notification for this type.
842
+ // If there are multiple notification then we will read data about only the last one.
843
+ $setting = $this->notifier->read_settings( end( $notifications )->ID );
844
+
845
+ $email_text = $this->engine->handle_shortcodes( $setting['message'], $setting['notification'], $new_user_details['newemail'] );
846
+ $email_text = $this->engine->handle_global_user_shortcodes( $email_text, $new_user_details['newemail'] );
847
+ $email_text = str_replace( '[email_change_confirmation_link]', esc_url( admin_url( 'profile.php?newuseremail=' . $new_user_details['hash'] ) ), $email_text );
848
+ }
849
+
850
+ return $email_text;
851
+ }
852
+
853
+ /**
854
+ * Send notification on core updated event.
855
+ *
856
+ * @since 1.6
857
+ *
858
+ * @param array $email_data Email Data.
859
+ * @param string $type The type of email being sent. Can be one of
860
+ * 'success', 'fail', 'manual', 'critical'.
861
+ * @param object $core_update The update offer that was attempted.
862
+ * @param mixed $result The result for the core update. Can be WP_Error.
863
+ *
864
+ * @return array Modified Email Data.
865
+ */
866
+ public function on_core_updated( $email_data, $type, $core_update, $result ) {
867
+ $notifications = $this->notifier->get_notifications( 'core-updated' );
868
+ if ( count( $notifications ) > 0 ) {
869
+ // Ideally there should be only one notification for this type.
870
+ // If there are multiple notification then we will read data about only the last one.
871
+ $setting = $this->notifier->read_settings( end( $notifications )->ID );
872
+
873
+ $email_data = $this->engine->handle_core_updated_notification( $email_data, $setting, $type );
874
+ }
875
+
876
+ return $email_data;
877
+ }
878
+
879
+ /**
880
+ * Process User update notifications.
881
+ *
882
+ * @since 1.6
883
+ *
884
+ * @param string $notification_name Notification Name.
885
+ * @param array $email_data Email Data.
886
+ * @param string|int $extra_data User Id.
887
+ *
888
+ * @return array Modified Email Data.
889
+ */
890
+ private function handle_filtered_data_notification( $notification_name,
891
+ $email_data, $extra_data ) {
892
+ $notifications = $this->notifier->get_notifications( $notification_name );
893
+ if ( count( $notifications ) > 0 ) {
894
+ // Ideally there should be only one notification for this type.
895
+ // If there are multiple notification then we will read data about only the last one.
896
+ $setting = $this->notifier->read_settings( end( $notifications )->ID );
897
+
898
+ $email_data = $this->engine->handle_filtered_data_notification( $email_data, $setting, $extra_data );
899
+ }
900
+
901
+ return $email_data;
902
+ }
903
+
904
+ /**
905
+ * Set the email formatting to HTML.
906
+ *
907
+ * @since 1.4
908
+ */
909
+ public function set_html_content_type() {
910
+ return 'text/html';
911
+ }
912
+
913
+ /**
914
+ * Set the email formatting to text.
915
+ *
916
+ * @since 1.4
917
+ */
918
+ public function set_text_content_type() {
919
+ return 'text/plain';
920
+ }
921
+
922
+ /**
923
+ * Send notification for new users.
924
+ *
925
+ * @since 1.0
926
+ * @param int $user_id User ID.
927
+ */
928
+ public function user_register( $user_id ) {
929
+ $this->send_notification( 'admin-user', $user_id );
930
+ }
931
+
932
+ /**
933
+ * Send notification for user when user login.
934
+ *
935
+ * @since 1.0
936
+ * @param string $user_name Username.
937
+ * @param object $user_data User object.
938
+ */
939
+ public function user_login( $user_name, $user_data ) {
940
+ $user_id = $user_data->ID;
941
+ $notifications = $this->notifier->get_notifications( 'user-login' );
942
+
943
+ foreach ( $notifications as $notification ) {
944
+ $this->engine->send_user_login_email( $this->notifier->read_settings( $notification->ID ), get_userdata( $user_id ) );
945
+ }
946
+
947
+ $this->user_login_admin_notification( $user_id );
948
+ }
949
+
950
+ /**
951
+ * Send notification for admin when user login.
952
+ *
953
+ * @since 1.0
954
+ * @param int $user_id User ID.
955
+ */
956
+ public function user_login_admin_notification( $user_id ) {
957
+ $notifications = $this->notifier->get_notifications( 'admin-user-login' );
958
+
959
+ foreach ( $notifications as $notification ) {
960
+ $this->engine->send_user_login_email_for_admin( $this->notifier->read_settings( $notification->ID ), get_userdata( $user_id ) );
961
+ }
962
+ }
963
+
964
+ /**
965
+ * Send notification about new users to site admin.
966
+ *
967
+ * @since 1.7.1
968
+ *
969
+ * @param array $email_data Email details.
970
+ * @param WP_User $user User object.
971
+ * @param string $blogname Blog name.
972
+ *
973
+ * @return array Modified email details.
974
+ */
975
+ public function handle_user_registered_admin_email( $email_data, $user, $blogname ) {
976
+ return $this->handle_filtered_data_notification( 'admin-user', $email_data, $user->ID );
977
+ }
978
+
979
+ /**
980
+ * New User - Post-registration Email
981
+ *
982
+ * @since 1.1
983
+ * @param int $user_id New user id.
984
+ */
985
+ public function welcome_email( $user_id ) {
986
+ $notifications = $this->notifier->get_notifications( 'welcome-email' );
987
+ foreach ( $notifications as $notification ) {
988
+ $this->engine->send_registration_email( $this->notifier->read_settings( $notification->ID ), get_userdata( $user_id ) );
989
+ }
990
+ }
991
+
992
+ /**
993
+ * Send notification when a user role changes.
994
+ *
995
+ * @since 1.3.9
996
+ *
997
+ * @param int $user_id User ID.
998
+ * @param string $new_role New User role.
999
+ * @param array $old_roles Old User role.
1000
+ */
1001
+ public function user_role_changed( $user_id, $new_role, $old_roles ) {
1002
+ if ( ! empty( $old_roles ) ) {
1003
+ $notifications = $this->notifier->get_notifications( 'user-role' );
1004
+ foreach ( $notifications as $notification ) {
1005
+
1006
+ /**
1007
+ * Trigger User Role Changed - For User notification.
1008
+ *
1009
+ * @since 1.6.5
1010
+ */
1011
+ if ( apply_filters( 'bnfw_trigger_user-role_notification', true, $notification, $new_role, $old_roles ) ) {
1012
+ $this->engine->send_user_role_changed_email( $this->notifier->read_settings( $notification->ID ), $user_id, $old_roles[0], $new_role );
1013
+ }
1014
+ }
1015
+ $notifications = $this->notifier->get_notifications( 'admin-role' );
1016
+ foreach ( $notifications as $notification ) {
1017
+
1018
+ /**
1019
+ * Trigger User Role Changed - For User notification.
1020
+ *
1021
+ * @since 1.6.5
1022
+ */
1023
+ if ( apply_filters( 'bnfw_trigger_admin-role_notification', true, $notification, $new_role, $old_roles ) ) {
1024
+ $setting = $this->notifier->read_settings( $notification->ID );
1025
+ $setting['message'] = $this->engine->handle_user_role_shortcodes( $setting['message'], $old_roles[0], $new_role );
1026
+ $setting['subject'] = $this->engine->handle_user_role_shortcodes( $setting['subject'], $old_roles[0], $new_role );
1027
+
1028
+ $this->engine->send_notification( $setting, $user_id );
1029
+ }
1030
+ }
1031
+ }
1032
+ }
1033
+
1034
+ /**
1035
+ * Send notification when a user role added through Members Plugin.
1036
+ *
1037
+ * @since 1.8.4
1038
+ *
1039
+ * @param int $user_id User ID.
1040
+ * @param string $new_role New User role.
1041
+ */
1042
+ public function user_role_added_from_member_plugin( $user_id, $new_role ) {
1043
+
1044
+ global $pagenow;
1045
+
1046
+ if ( 'users.php' !== $pagenow ) {
1047
+ return;
1048
+ }
1049
+ if ( ! $user_id ) {
1050
+ return;
1051
+ }
1052
+
1053
+ $notifications = $this->notifier->get_notifications( 'user-role' );
1054
+
1055
+ foreach ( $notifications as $notification ) {
1056
+ if ( apply_filters( 'bnfw_trigger_user-role_notification', true, $notification, $new_role, null ) ) {
1057
+ $this->engine->send_user_role_changed_email( $this->notifier->read_settings( $notification->ID ), $user_id, null, $new_role );
1058
+ }
1059
+ }
1060
+
1061
+ $notifications_admin = $this->notifier->get_notifications( 'admin-role' );
1062
+ foreach ( $notifications_admin as $notification ) {
1063
+ if ( apply_filters( 'bnfw_trigger_admin-role_notification', true, $notification, $new_role, null ) ) {
1064
+ $setting = $this->notifier->read_settings( $notification->ID );
1065
+ $setting['message'] = $this->engine->handle_user_role_shortcodes( $setting['message'], null, $new_role );
1066
+ $setting['subject'] = $this->engine->handle_user_role_shortcodes( $setting['subject'], null, $new_role );
1067
+
1068
+ $this->engine->send_notification( $setting, $user_id );
1069
+ }
1070
+ }
1071
+
1072
+ }
1073
+
1074
+ /**
1075
+ * Send notification when a user role removed through Members Plugin.
1076
+ *
1077
+ * @since 1.8.4
1078
+ *
1079
+ * @param int $user_id User ID.
1080
+ * @param string $old_role New User role.
1081
+ */
1082
+ public function user_role_removed_from_member_plugin( $user_id, $old_role ) {
1083
+ global $pagenow;
1084
+
1085
+ if ( 'users.php' !== $pagenow ) {
1086
+ return;
1087
+ }
1088
+ if ( ! $user_id ) {
1089
+ return;
1090
+ }
1091
+
1092
+ $notifications = $this->notifier->get_notifications( 'user-role' );
1093
+
1094
+ foreach ( $notifications as $notification ) {
1095
+ if ( apply_filters( 'bnfw_trigger_user-role_notification', true, $notification, null, array( $old_role ) ) ) {
1096
+ $this->engine->send_user_role_changed_email( $this->notifier->read_settings( $notification->ID ), $user_id, $old_role, null );
1097
+ }
1098
+ }
1099
+
1100
+ $notifications_admin = $this->notifier->get_notifications( 'admin-role' );
1101
+ foreach ( $notifications_admin as $notification ) {
1102
+ if ( apply_filters( 'bnfw_trigger_admin-role_notification', true, $notification, null, array( $old_role ) ) ) {
1103
+ $setting = $this->notifier->read_settings( $notification->ID );
1104
+ $setting['message'] = $this->engine->handle_user_role_shortcodes( $setting['message'], $old_role, null );
1105
+ $setting['subject'] = $this->engine->handle_user_role_shortcodes( $setting['subject'], $old_role, null );
1106
+
1107
+ $this->engine->send_notification( $setting, $user_id );
1108
+ }
1109
+ }
1110
+
1111
+ }
1112
+
1113
+ /**
1114
+ * Send notification when a user role added support User Role Editor by Members Plugin.
1115
+ *
1116
+ * @since 1.3.9
1117
+ *
1118
+ * @param int $user_id User ID.
1119
+ * @param array $old_user_data Old User role.
1120
+ */
1121
+ public function user_role_added( $user_id, $old_user_data ) {
1122
+
1123
+ if ( isset( $_POST['members_user_roles'] ) && ! empty( $_POST['members_user_roles'] ) ) {// phpcs:ignore
1124
+ // Get the current user roles.
1125
+ $old_roles = (array) $old_user_data->roles;
1126
+
1127
+ // Sanitize the posted roles.
1128
+ $new_roles = array_map( array( $this, 'bnfw_members_sanitize_role' ), $_POST['members_user_roles'] );// phpcs:ignore
1129
+
1130
+ sort( $old_roles );
1131
+ sort( $new_roles );
1132
+ $old_roles_str = implode( '', $old_roles );
1133
+ $new_roles_str = implode( '', $new_roles );
1134
+ if ( ! empty( $old_roles ) && $old_roles_str !== $new_roles_str ) {
1135
+ $notifications = $this->notifier->get_notifications( 'user-role' );
1136
+ foreach ( $notifications as $notification ) {
1137
+
1138
+ /**
1139
+ * Trigger User Role Changed - For User notification.
1140
+ *
1141
+ * @since 1.6.5
1142
+ */
1143
+ if ( apply_filters( 'bnfw_trigger_user-role-added_notification', true, $notification, $new_roles, $old_roles ) ) {
1144
+ $this->engine->send_user_role_added_email( $this->notifier->read_settings( $notification->ID ), $user_id, $old_roles, $new_roles );
1145
+ }
1146
+ }
1147
+
1148
+ $notifications = $this->notifier->get_notifications( 'admin-role' );
1149
+ foreach ( $notifications as $notification ) {
1150
+
1151
+ /**
1152
+ * Trigger User Role Changed - For User notification.
1153
+ *
1154
+ * @since 1.6.5
1155
+ */
1156
+ if ( apply_filters( 'bnfw_trigger_user-role-added_notification', true, $notification, $new_roles, $old_roles ) ) {
1157
+ $setting = $this->notifier->read_settings( $notification->ID );
1158
+ $setting['message'] = $this->engine->handle_user_added_role_shortcodes( $setting['message'], $old_roles, $new_roles );
1159
+ $setting['subject'] = $this->engine->handle_user_added_role_shortcodes( $setting['subject'], $old_roles, $new_roles );
1160
+
1161
+ $this->engine->send_notification( $setting, $user_id );
1162
+ }
1163
+ }
1164
+ }
1165
+ }
1166
+ }
1167
+
1168
+ /**
1169
+ * Sanitizes a role name. This is a wrapper for the `sanitize_key()` WordPress function. Only
1170
+ * alphanumeric characters and underscores are allowed. Hyphens are also replaced with underscores.
1171
+ *
1172
+ * @since 1.0.0
1173
+ * @access public
1174
+ * @param array $role Posted user role.
1175
+ * @return int
1176
+ */
1177
+ public function bnfw_members_sanitize_role( $role ) {
1178
+
1179
+ $_role = strtolower( $role );
1180
+ $_role = preg_replace( '/[^a-z0-9_\-\s]/', '', $_role );
1181
+
1182
+ return apply_filters( array( $this, 'bnfw_members_sanitize_role' ), str_replace( ' ', '_', $_role ), $role );
1183
+ }
1184
+
1185
+ /**
1186
+ * Send notification based on type and ref id.
1187
+ *
1188
+ * @since 1.0
1189
+ * @param string $type Notification type.
1190
+ * @param mixed $ref_id Reference data.
1191
+ * @param bool $include_disabled Include disabled.
1192
+ */
1193
+ public function send_notification( $type, $ref_id, $include_disabled = true ) {
1194
+ $notifications = $this->notifier->get_notifications( $type, $include_disabled );
1195
+ foreach ( $notifications as $notification ) {
1196
+ $this->engine->send_notification( $this->notifier->read_settings( $notification->ID ), $ref_id );
1197
+ }
1198
+ }
1199
+
1200
+ /**
1201
+ * Send notification async based on type and ref id.
1202
+ *
1203
+ * @param string $type Notification type.
1204
+ * @param mixed $ref_id Reference data.
1205
+ */
1206
+ public function send_notification_async( $type, $ref_id ) {
1207
+ $notifications = $this->notifier->get_notifications( $type, false );
1208
+ foreach ( $notifications as $notification ) {
1209
+ $transient = get_transient( 'bnfw-async-notifications' );
1210
+ if ( ! is_array( $transient ) ) {
1211
+ $transient = array();
1212
+ }
1213
+
1214
+ $notification_data = array(
1215
+ 'ref_id' => $ref_id,
1216
+ 'notification_id' => $notification->ID,
1217
+ 'notification_type' => $type,
1218
+ );
1219
+
1220
+ if ( ! in_array( $notification_data, $transient, true ) ) {
1221
+ $transient[] = $notification_data;
1222
+ set_transient( 'bnfw-async-notifications', $transient, 600 );
1223
+ }
1224
+ }
1225
+ }
1226
+
1227
+ /**
1228
+ * Can send comment notification or not.
1229
+ *
1230
+ * @since 1.0
1231
+ * @param WP_Comment $comment Comment data.
1232
+ * @return bool
1233
+ */
1234
+ private function can_send_comment_notification( $comment ) {
1235
+ // Returns false if the comment is marked as spam AND admin has enabled suppression of spam.
1236
+ $suppress_spam = get_option( 'bnfw_suppress_spam' );
1237
+ if ( '1' === $suppress_spam && ( 0 === strcmp( $comment->comment_approved, 'spam' ) ) ) {
1238
+ return false;
1239
+ }
1240
+ return true;
1241
+ }
1242
+
1243
+ /**
1244
+ * Handle user request email content.
1245
+ *
1246
+ * @param string $content Content.
1247
+ * @param array $email_data Email data.
1248
+ *
1249
+ * @return string Modified content.
1250
+ */
1251
+ public function handle_user_request_email_content( $content, $email_data ) {
1252
+ $field = 'message';
1253
+ $new_content = '';
1254
+
1255
+ switch ( $email_data['description'] ) {
1256
+ case 'Export Personal Data':
1257
+ $notification_name = 'ca-export-data';
1258
+ $new_content = $this->handle_user_request_notification( $notification_name, $field, $email_data );
1259
+ break;
1260
+ case 'Erase Personal Data':
1261
+ $notification_name = 'ca-erase-data';
1262
+ $new_content = $this->handle_user_request_notification( $notification_name, $field, $email_data );
1263
+ break;
1264
+ }
1265
+
1266
+ if ( ! empty( $new_content ) ) {
1267
+ return $new_content;
1268
+ } else {
1269
+ return $content;
1270
+ }
1271
+ }
1272
+
1273
+ /**
1274
+ * Handle user request email subject.
1275
+ *
1276
+ * @param string $subject Subject.
1277
+ * @param string $blogname Blog name.
1278
+ * @param array $email_data Email data.
1279
+ *
1280
+ * @return string Modified subject.
1281
+ */
1282
+ public function handle_user_request_email_subject( $subject, $blogname, $email_data ) {
1283
+ $field = 'subject';
1284
+ $new_subject = '';
1285
+
1286
+ switch ( $email_data['description'] ) {
1287
+ case 'Export Personal Data':
1288
+ $notification_name = 'ca-export-data';
1289
+ $new_subject = $this->handle_user_request_notification( $notification_name, $field, $email_data );
1290
+ break;
1291
+ case 'Erase Personal Data':
1292
+ $notification_name = 'ca-erase-data';
1293
+ $new_subject = $this->handle_user_request_notification( $notification_name, $field, $email_data );
1294
+ break;
1295
+ }
1296
+ if ( ! empty( $new_subject ) ) {
1297
+ return $new_subject;
1298
+ } else {
1299
+ return $subject;
1300
+ }
1301
+ }
1302
+
1303
+ /**
1304
+ * Handle user confirmed action email content.
1305
+ *
1306
+ * @param string $content Content.
1307
+ * @param array $email_data Email data.
1308
+ *
1309
+ * @return string Modified content.
1310
+ */
1311
+ public function handle_user_confirmed_action_email_content( $content, $email_data ) {
1312
+ $field = 'message';
1313
+ $new_content = '';
1314
+
1315
+ switch ( $email_data['description'] ) {
1316
+ case 'Export Personal Data':
1317
+ $notification_name = 'uc-export-data';
1318
+ $new_content = $this->handle_user_confirmed_action_notification( $notification_name, $field, $email_data );
1319
+ break;
1320
+ case 'Erase Personal Data':
1321
+ $notification_name = 'uc-erase-data';
1322
+ $new_content = $this->handle_user_confirmed_action_notification( $notification_name, $field, $email_data );
1323
+ break;
1324
+ }
1325
+
1326
+ if ( ! empty( $new_content ) ) {
1327
+ return $new_content;
1328
+ } else {
1329
+ return $content;
1330
+ }
1331
+ }
1332
+
1333
+ /**
1334
+ * Handle data exported email content.
1335
+ *
1336
+ * @param string $content Text in the email.
1337
+ * @param int $request_id The request ID for this personal data export.
1338
+ * @param array $email_data Data relating to the account action email.
1339
+ *
1340
+ * @return string Modified content.
1341
+ */
1342
+ public function handle_data_export_email_content( $content, $request_id, $email_data ) {
1343
+
1344
+ $field = 'message';
1345
+ $notification_name = 'data-export';
1346
+ $new_content = '';
1347
+
1348
+ $notifications = $this->notifier->get_notifications( $notification_name );
1349
+ if ( count( $notifications ) > 0 ) {
1350
+ // Ideally there should be only one notification for this type.
1351
+ // If there are multiple notification then we will read data about only the last one.
1352
+ $setting = $this->notifier->read_settings( end( $notifications )->ID );
1353
+
1354
+ $new_content = $this->engine->handle_data_export_email_shortcodes( $setting[ $field ], $setting, $request_id );
1355
+ $new_content = $this->engine->handle_global_user_shortcodes( $new_content, $email_data['message_recipient'] );
1356
+ }
1357
+
1358
+ if ( ! empty( $new_content ) ) {
1359
+ return $new_content;
1360
+ } else {
1361
+ return $content;
1362
+ }
1363
+ }
1364
+ /**
1365
+ * Filters the subject of the email sent when an erasure request is completed.
1366
+ *
1367
+ * @param string $subject The email subject.
1368
+ * @param string $sitename The name of the site.
1369
+ * @param array $email_data Data relating to the account action email.
1370
+ */
1371
+ public function handle_erasure_complete_email_subject( $subject, $sitename, $email_data ) {
1372
+ return $this->handle_erasure_complete_email_notification( 'subject', $subject, $email_data );
1373
+ }
1374
+ /**
1375
+ * Filters the body of the data erasure fulfillment notification.
1376
+ *
1377
+ * @param string $content The email content.
1378
+ * @param array $email_data Data relating to the account action email.
1379
+ */
1380
+ public function handle_erasure_complete_email_content( $content, $email_data ) {
1381
+ if ( isset( $email_data['privacy_policy_url'] ) ) {
1382
+ return $this->handle_erasure_complete_email_notification( 'message', $content, $email_data );
1383
+ }
1384
+
1385
+ return $content;
1386
+ }
1387
+ /**
1388
+ * Handles erasure fulfillment notification.
1389
+ *
1390
+ * @param string $field Field name.
1391
+ * @param string $content The email content.
1392
+ * @param array $email_data Data relating to the account action email.
1393
+ */
1394
+ protected function handle_erasure_complete_email_notification( $field, $content, $email_data ) {
1395
+ $notification_name = 'data-erased';
1396
+ $new_content = '';
1397
+ $notifications = $this->notifier->get_notifications( $notification_name );
1398
+ if ( count( $notifications ) > 0 ) {
1399
+ // Ideally there should be only one notification for this type.
1400
+ // If there are multiple notification then we will read data about only the last one.
1401
+ $setting = $this->notifier->read_settings( end( $notifications )->ID );
1402
+ $new_content = $this->engine->handle_shortcodes( $setting[ $field ], $notification_name, $email_data );
1403
+ }
1404
+ if ( ! empty( $new_content ) ) {
1405
+ return $new_content;
1406
+ } else {
1407
+ return $content;
1408
+ }
1409
+ }
1410
+
1411
+ /**
1412
+ * Send notification emails on shutdown.
1413
+ */
1414
+ public function on_shutdown() {
1415
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1416
+ return;
1417
+ }
1418
+
1419
+ $transient = get_transient( 'bnfw-async-notifications' );
1420
+ if ( is_array( $transient ) ) {
1421
+ delete_transient( 'bnfw-async-notifications' );
1422
+ foreach ( $transient as $id_pairs ) {
1423
+ $this->engine->send_notification( $this->notifier->read_settings( $id_pairs['notification_id'] ), $id_pairs['ref_id'] );
1424
+ }
1425
+ }
1426
+ }
1427
+
1428
+ /**
1429
+ * Handle user request notification.
1430
+ *
1431
+ * @param string $notification_name Notification name.
1432
+ * @param string $field Field name.
1433
+ * @param array $email_data Email data.
1434
+ *
1435
+ * @return string Content.
1436
+ */
1437
+ protected function handle_user_request_notification( $notification_name, $field, $email_data ) {
1438
+ $notifications = $this->notifier->get_notifications( $notification_name );
1439
+ if ( count( $notifications ) > 0 ) {
1440
+ // Ideally there should be only one notification for this type.
1441
+ // If there are multiple notification then we will read data about only the last one.
1442
+ $setting = $this->notifier->read_settings( end( $notifications )->ID );
1443
+
1444
+ return $this->engine->handle_user_request_email_shortcodes( $setting[ $field ], $setting, $email_data );
1445
+ }
1446
+
1447
+ return '';
1448
+ }
1449
+
1450
+ /**
1451
+ * Handle user confirmed action notification.
1452
+ *
1453
+ * @param string $notification_name Notification name.
1454
+ * @param string $field Field name.
1455
+ * @param array $email_data Email data.
1456
+ *
1457
+ * @return string Content.
1458
+ */
1459
+ protected function handle_user_confirmed_action_notification( $notification_name, $field, $email_data ) {
1460
+ $notifications = $this->notifier->get_notifications( $notification_name );
1461
+ if ( count( $notifications ) > 0 ) {
1462
+ // Ideally there should be only one notification for this type.
1463
+ // If there are multiple notification then we will read data about only the last one.
1464
+ $setting = $this->notifier->read_settings( end( $notifications )->ID );
1465
+
1466
+ return $this->engine->handle_user_confirmed_action_email_shortcodes( $setting[ $field ], $setting, $email_data );
1467
+ }
1468
+
1469
+ return '';
1470
+ }
1471
+
1472
+ /**
1473
+ * Is this a metabox request?
1474
+ *
1475
+ * Block editor sends duplicate requests on post update.
1476
+ *
1477
+ * @return bool True if metabox request, False otherwise.
1478
+ */
1479
+ protected function is_metabox_request() {
1480
+ return ( isset( $_GET['meta-box-loader'] ) || isset( $_GET['meta_box'] ) );// phpcs:ignore
1481
+ }
1482
+
1483
+ /**
1484
+ * Check if Gutenberg is active.
1485
+ *
1486
+ * @return bool
1487
+ * @since 1.3
1488
+ */
1489
+ public function is_gutenberg_active() {
1490
+ $gutenberg = false;
1491
+ $block_editor = false;
1492
+
1493
+ if ( has_filter( 'replace_editor', 'gutenberg_init' ) ) {
1494
+ // Gutenberg is installed and activated.
1495
+ $gutenberg = true;
1496
+ }
1497
+
1498
+ if ( version_compare( $GLOBALS['wp_version'], '5.0-beta', '>' ) ) {
1499
+ // Block editor.
1500
+ $block_editor = true;
1501
+ }
1502
+
1503
+ if ( ! $gutenberg && ! $block_editor ) {
1504
+ return false;
1505
+ }
1506
+
1507
+ include_once ABSPATH . 'wp-admin/includes/plugin.php';
1508
+
1509
+ if ( ! is_plugin_active( 'classic-editor/classic-editor.php' ) ) {
1510
+ return true;
1511
+ }
1512
+
1513
+ $use_block_editor = ( get_option( 'classic-editor-replace' ) === 'no-replace' );
1514
+
1515
+ return $use_block_editor;
1516
+ }
1517
+
1518
+ }
1519
+ /**
1520
+ * Fire up the plugin.
1521
+ */
1522
+ BNFW::factory();
1523
+ }
includes/admin/bnfw-settings.php DELETED
@@ -1,287 +0,0 @@
1
- <?php
2
- /**
3
- * Register the Admin pages and load the scripts action
4
- */
5
-
6
- /**
7
- * Sub-menu pages
8
- */
9
- function bnfw_admin_menu() {
10
-
11
- // New Notifications Sub-menu
12
- add_submenu_page(
13
- 'edit.php?post_type=bnfw_notification',
14
- esc_html__( 'Notification Settings', 'bnfw' ),
15
- esc_html__( 'Settings', 'bnfw' ),
16
- 'bnfw',
17
- 'bnfw-settings',
18
- 'bnfw_settings_page'
19
- );
20
- }
21
-
22
- // Add the Admin pages to the WordPress menu
23
- add_action( 'admin_menu', 'bnfw_admin_menu' );
24
- add_action( 'admin_menu', 'bnfw_menu_item_links', 12 );
25
- add_action( 'admin_head', 'bnfw_menu_item_link_targets' );
26
-
27
- /* ------------------------------------------------------------------------ *
28
- * Menu Pages
29
- * ------------------------------------------------------------------------ */
30
-
31
- /**
32
- * Settings Page
33
- */
34
- function bnfw_settings_page() {
35
- ob_start(); ?>
36
-
37
- <div class="wrap">
38
- <h2><?php esc_html_e( 'BNFW Settings', 'bnfw' ); ?></h2>
39
-
40
- <form method="post" action="options.php" class="bnfw-form">
41
- <?php
42
- settings_errors();
43
- settings_fields( 'bnfw-settings' );
44
- do_settings_sections( 'bnfw-settings' );
45
-
46
- submit_button( __( 'Save Settings', 'bnfw' ) );
47
- ?>
48
- </form>
49
- </div>
50
-
51
- <?php echo ob_get_clean();
52
- }
53
-
54
- /**
55
- * External Menu Item Links
56
- */
57
- function bnfw_menu_item_links() {
58
- global $submenu;
59
-
60
- if ( current_user_can( 'bnfw' ) ) {
61
- $doc_url = 'https://betternotificationsforwp.com/documentation/';
62
- $store_url = 'https://betternotificationsforwp.com/downloads/';
63
- $support_url = 'https://betternotificationsforwp.com/priority-support/';
64
-
65
- if ( bnfw_is_tracking_allowed() ) {
66
- $doc_url .= '?utm_source=WP%20Admin%20Submenu%20Item%20-%20"Documentation"&amp;utm_medium=referral';
67
- $store_url .= '?utm_source=WP%20Admin%20Submenu%20Item%20-%20"Add-on"&amp;utm_medium=referral';
68
- $support_url .= '?utm_source=WP%20Admin%20Submenu%20Item%20-%20"Priority%20Support"&amp;utm_medium=referral';
69
- }
70
-
71
- // Documentation Link
72
- $submenu['edit.php?post_type=bnfw_notification'][500] = array(
73
- '<div id="bnfw-menu-item-documentation" style="color: #73daeb;">' . __( 'Documentation', 'bnfw' ) . '</div>',
74
- 'bnfw',
75
- $doc_url,
76
- );
77
-
78
- // Add-ons Link
79
- $submenu['edit.php?post_type=bnfw_notification'][600] = array(
80
- '<div id="bnfw-menu-item-addons" style="color: #ff6f59;">' . __( 'Premium Add-ons', 'bnfw' ) . '</div>',
81
- 'bnfw',
82
- $store_url,
83
- );
84
-
85
- // Add-ons Link
86
- $submenu['edit.php?post_type=bnfw_notification'][700] = array(
87
- '<div id="bnfw-menu-item-support" style="color: #f00001;">' . __( 'Priority Support', 'bnfw' ) . '</div>',
88
- 'bnfw',
89
- $support_url,
90
- );
91
- }
92
- }
93
-
94
- function bnfw_menu_item_link_targets() {
95
- ?>
96
- <script type="text/javascript">
97
- jQuery( document ).ready( function ( $ ) {
98
- // Documentation Link
99
- $( '#bnfw-menu-item-documentation' ).parent().attr( 'target', '_blank' );
100
- $( '#bnfw-menu-item-documentation' ).hover( function () {
101
- $( this ).css( 'color', '#a0e6f1' );
102
- }, function () {
103
- $( this ).css( 'color', '#73daeb' );
104
- } );
105
-
106
- // Add-ons Link
107
- $( '#bnfw-menu-item-addons' ).parent().attr( 'target', '_blank' );
108
- $( '#bnfw-menu-item-addons' ).hover( function () {
109
- $( this ).css( 'color', '#ff9b8c' );
110
- }, function () {
111
- $( this ).css( 'color', '#ff6f59' );
112
- } );
113
-
114
- // Priority Support Link
115
- $( '#bnfw-menu-item-support' ).parent().attr( 'target', '_blank' );
116
- $( '#bnfw-menu-item-support' ).hover( function () {
117
- $( this ).css( 'color', '#ff3536' );
118
- }, function () {
119
- $( this ).css( 'color', '#f00001' );
120
- } );
121
- } );
122
- </script>
123
- <?php }
124
-
125
- /* ------------------------------------------------------------------------ *
126
- * Settings Page - Setting Registration
127
- * ------------------------------------------------------------------------ */
128
-
129
- /**
130
- *
131
- */
132
- function bnfw_general_options() {
133
- // Set-up - General Options Section
134
- add_settings_section(
135
- 'bnfw_general_options_section', // Section ID
136
- '', // Title above settings section
137
- 'bnfw_general_options_callback', // Name of function that renders a description of the settings section
138
- 'bnfw-settings' // Page to show on
139
- );
140
-
141
- // Register - Suppress SPAM Checkbox
142
- register_setting(
143
- 'bnfw-settings',
144
- 'bnfw_suppress_spam'
145
- );
146
-
147
- // Suppress notifications for SPAM comments
148
- add_settings_field(
149
- 'bnfw_suppress_spam', // Field ID
150
- esc_html__( 'Suppress SPAM comment notification', 'bnfw' ) . '<div class="bnfw-help-tip"><p>' . esc_html__( 'Comments that are correctly marked as SPAM by a 3rd party plugin (such as Akismet) will not generate a notification if this is ticked.', 'bnfw' ) . '</p></div>', // Label to the left
151
- 'bnfw_suppress_spam_checkbox', // Name of function that renders options on the page
152
- 'bnfw-settings', // Page to show on
153
- 'bnfw_general_options_section', // Associate with which settings section?
154
- array(
155
- esc_html__( 'Don\'t send notifications for comments marked as SPAM', 'bnfw' )
156
- )
157
- );
158
-
159
- // Register - Email Format setting
160
- register_setting(
161
- 'bnfw-settings',
162
- 'bnfw_email_format'
163
- );
164
-
165
- add_settings_field(
166
- 'bnfw_email_format', // Field ID
167
- esc_html__( 'Default Email Format', 'bnfw' ) . '<div class="bnfw-help-tip"><p>' . esc_html__( 'This will apply to all emails sent out via WordPress, even those from other plugins. For more details, please see the ', 'bnfw' ) . '<a href="https://wordpress.org/plugins/bnfw/faq/" target="_blank">FAQ</a>.</p></div>', // Label to the left
168
- 'bnfw_email_format_radio', // Name of function that renders options on the page
169
- 'bnfw-settings', // Page to show on
170
- 'bnfw_general_options_section' // Associate with which settings section?
171
- );
172
-
173
- // Register - Email Format setting
174
- register_setting(
175
- 'bnfw-settings',
176
- 'bnfw_enable_shortcodes'
177
- );
178
-
179
- add_settings_field(
180
- 'bnfw_enable_shortcodes', // Field ID
181
- esc_html__( 'Enable Content Shortcodes?', 'bnfw' ) . '<div class="bnfw-help-tip"><p>' . esc_html__( 'Shortcodes in the post/page content are disabled by default.', 'bnfw' ) . '</p></div>', // Label to the left
182
- 'bnfw_enable_shortcodes_checkbox', // Name of function that renders options on the page
183
- 'bnfw-settings', // Page to show on
184
- 'bnfw_general_options_section', // Associate with which settings section?
185
- array(
186
- esc_html__( 'Enable shortcode output in the page/post content', 'bnfw' ),
187
- )
188
- );
189
-
190
- // Register - Allow tracking setting
191
- register_setting(
192
- 'bnfw-settings',
193
- 'bnfw_allow_tracking'
194
- );
195
-
196
- add_settings_field(
197
- 'bnfw_allow_tracking', // Field ID
198
- esc_html__( 'Allow Usage Tracking?', 'bnfw' ), // Label to the left
199
- 'bnfw_render_allow_tracking', // Name of function that renders options on the page
200
- 'bnfw-settings', // Page to show on
201
- 'bnfw_general_options_section', // Associate with which settings section?
202
- array(
203
- esc_html__( 'Allow Better Notifications for WP to anonymously track how this plugin is used and help make the plugin better.', 'bnfw' )
204
- )
205
- );
206
- }
207
-
208
- add_action( 'admin_init', 'bnfw_general_options', 10 );
209
-
210
- /* ------------------------------------------------------------------------ *
211
- * Settings Page - Settings Section Callbacks
212
- * ------------------------------------------------------------------------ */
213
-
214
- /**
215
- *
216
- */
217
- function bnfw_general_options_callback() {
218
- }
219
-
220
- /* ------------------------------------------------------------------------ *
221
- * Settings Page - Settings Field Callbacks
222
- * ------------------------------------------------------------------------ */
223
-
224
- /**
225
- * Suppress SPAM checkbox.
226
- *
227
- * @since 1.0
228
- *
229
- * @param $args
230
- */
231
- function bnfw_suppress_spam_checkbox( $args ) {
232
- ?>
233
- <input type="checkbox" id="bnfw_suppress_spam" name="bnfw_suppress_spam"
234
- value="1" <?php checked( 1, get_option( 'bnfw_suppress_spam' ), true ); ?>>
235
- <label for="bnfw_suppress_spam"><?php echo esc_html( $args[0] ); ?></label>
236
- <?php
237
- }
238
-
239
- /**
240
- * Show email format radio
241
- *
242
- * @since 1.4
243
- *
244
- * @param array $args
245
- */
246
- function bnfw_email_format_radio( $args ) {
247
- $email_format = get_option( 'bnfw_email_format', 'html' );
248
- ?>
249
- <label>
250
- <input type="radio" value="html"
251
- name="bnfw_email_format" <?php checked( $email_format, 'html', true ); ?>><?php esc_html_e( 'HTML Formatting', 'bnfw' ); ?>
252
- </label>
253
- <br/>
254
- <label>
255
- <input type="radio" value="text"
256
- name="bnfw_email_format" <?php checked( $email_format, 'text', true ); ?>><?php esc_html_e( 'Plain Text', 'bnfw' ); ?>
257
- </label>
258
- <?php
259
- }
260
-
261
- /**
262
- * Render allow tracking checkbox.
263
- *
264
- * @since 1.6
265
- *
266
- * @param array $args
267
- */
268
- function bnfw_render_allow_tracking( $args ) {
269
- ?>
270
- <input type="checkbox" id="bnfw_allow_tracking" name="bnfw_allow_tracking"
271
- value="on" <?php checked( 'on', get_option( 'bnfw_allow_tracking' ), true ); ?>>
272
- <label for="bnfw_allow_tracking"><?php echo esc_html( $args[0] ); ?></label>
273
- <?php
274
- }
275
-
276
- /**
277
- * Render Enable shortcode checkbox.
278
- *
279
- * @param array $args
280
- */
281
- function bnfw_enable_shortcodes_checkbox( $args ) {
282
- ?>
283
- <input type="checkbox" id="bnfw_enable_shortcodes" name="bnfw_enable_shortcodes"
284
- value="1" <?php checked( 1, get_option( 'bnfw_enable_shortcodes' ), true ); ?>>
285
- <label for="bnfw_enable_shortcodes"><?php echo esc_html( $args[0] ); ?></label>
286
- <?php
287
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/admin/class-bnfw-notification.php CHANGED
@@ -1,1651 +1,1679 @@
1
- <?php
2
-
3
- /**
4
- * BNFW Notification.
5
- *
6
- * @since 1.0
7
- */
8
- class BNFW_Notification {
9
-
10
- const POST_TYPE = 'bnfw_notification';
11
- const META_KEY_PREFIX = 'bnfw_';
12
- const TEST_MAIL_ARG = 'test-mail';
13
-
14
- /**
15
- *
16
- */
17
- public function __construct() {
18
- add_action( 'init', array( $this, 'register_post_type' ) );
19
- add_action( 'do_meta_boxes', array( $this, 'remove_meta_boxes' ) );
20
- add_action( 'add_meta_boxes_' . self::POST_TYPE, array( $this, 'add_meta_boxes' ) );
21
- add_action( 'save_post', array( $this, 'save_meta_data' ) );
22
- add_action( 'edit_form_top', array( $this, 'admin_notices' ) );
23
- add_filter( 'post_updated_messages', array( $this, 'post_updated_messages' ) );
24
-
25
- add_filter( 'use_block_editor_for_post_type', array( $this, 'disable_gutenberg_for_notification' ), 10, 2 );
26
-
27
- add_filter( 'bulk_actions-edit-bnfw_notification', array( $this, 'add_custom_edit_action' ) );
28
- add_filter( 'handle_bulk_actions-edit-bnfw_notification', array( $this, 'handle_custom_edit_action' ), 10, 3 );
29
-
30
- // Custom row actions.
31
- add_filter( 'post_row_actions', array( $this, 'custom_row_actions' ), 10, 2 );
32
- add_action( 'admin_init', array( $this, 'handle_actions' ) );
33
-
34
- // Custom columns
35
- add_filter( sprintf( 'manage_%s_posts_columns', self::POST_TYPE ), array( $this, 'columns_header' ) );
36
- add_action( sprintf( 'manage_%s_posts_custom_column', self::POST_TYPE ), array( $this, 'custom_column_row' ), 10, 2 );
37
-
38
- // Enqueue scripts/styles and disables autosave for this post type.
39
- add_action( 'admin_enqueue_scripts', array( $this, 'is_assets_needed' ) );
40
-
41
- add_action( 'admin_notices', array( $this, 'show_help_notice' ) );
42
-
43
- add_action('admin_print_scripts',array($this,'gutenberg_flag'));
44
- }
45
-
46
- /**
47
- * Flag variable to check if gutenberge is active
48
- * added fix for gutenberge
49
- *
50
- * @since 1.3
51
- */
52
- public function gutenberg_flag(){
53
- $bnfw = BNFW::Factory();
54
- ?>
55
- <script type="text/javascript">
56
- var bnfw_gutenberge_is_active = <?php echo ($bnfw->is_gutenberg_active())? 'true;' : 'false;'; ?>
57
- </script>
58
- <?php
59
- }
60
-
61
-
62
- /**
63
- * Register bnfw_notification custom post type.
64
- *
65
- * @since 1.0
66
- */
67
- public function register_post_type() {
68
- register_post_type( self::POST_TYPE, array(
69
- 'labels' => array(
70
- 'name' => esc_html__( 'Notifications', 'bnfw' ),
71
- 'singular_name' => esc_html__( 'Notification', 'bnfw' ),
72
- 'add_new' => esc_html__( 'Add New', 'bnfw' ),
73
- 'menu_name' => esc_html__( 'Notifications', 'bnfw' ),
74
- 'name_admin_bar' => esc_html__( 'Notifications', 'bnfw' ),
75
- 'add_new_item' => esc_html__( 'Add New Notification', 'bnfw' ),
76
- 'edit_item' => esc_html__( 'Edit Notification', 'bnfw' ),
77
- 'new_item' => esc_html__( 'New Notification', 'bnfw' ),
78
- 'view_item' => esc_html__( 'View Notification', 'bnfw' ),
79
- 'search_items' => esc_html__( 'Search Notifications', 'bnfw' ),
80
- 'not_found' => esc_html__( 'No Notifications found', 'bnfw' ),
81
- 'not_found_in_trash' => esc_html__( 'No Notifications found in trash', 'bnfw' ),
82
- 'all_items' => esc_html__( 'All Notifications', 'bnfw' ),
83
- ),
84
- 'public' => false,
85
- 'show_in_nav_menus' => true,
86
- 'show_in_admin_bar' => true,
87
- 'has_archive' => false,
88
- 'show_ui' => true,
89
- 'show_in_menu' => true,
90
- 'menu_icon' => 'dashicons-email-alt',
91
- 'menu_position' => 101,
92
- 'rewrite' => false,
93
- 'map_meta_cap' => false,
94
- 'capabilities' => array(
95
-
96
- // meta caps (don't assign these to roles)
97
- 'edit_post' => 'bnfw',
98
- 'read_post' => 'bnfw',
99
- 'delete_post' => 'bnfw',
100
-
101
- // primitive/meta caps
102
- 'create_posts' => 'bnfw',
103
-
104
- // primitive caps used outside of map_meta_cap()
105
- 'edit_posts' => 'bnfw',
106
- 'edit_others_posts' => 'bnfw',
107
- 'publish_posts' => 'bnfw',
108
- 'read_private_posts' => 'bnfw',
109
-
110
- // primitive caps used inside of map_meta_cap()
111
- 'read' => 'bnfw',
112
- 'delete_posts' => 'bnfw',
113
- 'delete_private_posts' => 'bnfw',
114
- 'delete_published_posts' => 'bnfw',
115
- 'delete_others_posts' => 'bnfw',
116
- 'edit_private_posts' => 'bnfw',
117
- 'edit_published_posts' => 'bnfw',
118
- ),
119
-
120
- // What features the post type supports.
121
- 'supports' => array(
122
- 'title',
123
- ),
124
- ) );
125
- }
126
-
127
- /**
128
- * Remove unwanted meta boxes.
129
- *
130
- * @since 1.0
131
- */
132
- public function remove_meta_boxes() {
133
- remove_meta_box( 'submitdiv', self::POST_TYPE, 'side' );
134
- remove_meta_box( 'slugdiv', self::POST_TYPE, 'normal' );
135
- }
136
-
137
- /**
138
- * Add meta box to the post editor screen.
139
- *
140
- * @since 1.0
141
- */
142
- public function add_meta_boxes() {
143
- global $post;
144
-
145
- add_meta_box(
146
- 'bnfw-post-notification', // Unique ID
147
- esc_html__( 'Notification Settings', 'bnfw' ), // Title
148
- array( $this, 'render_settings_meta_box' ), // Callback function
149
- self::POST_TYPE, // Admin page (or post type)
150
- 'normal', // Context
151
- 'default'
152
- );
153
-
154
- add_meta_box(
155
- 'bnfw_submitdiv',
156
- __( 'Save Notification', 'bnfw' ),
157
- array( $this, 'render_submitdiv' ),
158
- self::POST_TYPE,
159
- 'side',
160
- 'core'
161
- );
162
-
163
- if ( self::POST_TYPE !== get_post_type( $post ) ) {
164
- return;
165
- }
166
-
167
- do_action( 'bnfw_after_metaboxes', $this->read_settings( $post->ID ) );
168
- }
169
-
170
- /**
171
- * Disable Gutenberg for notifications.
172
- *
173
- * @param bool $is_enabled Is Gutenberg enabled?
174
- * @param string $post_type Post Type.
175
- *
176
- * @return bool Should Gutenberg be enabled?
177
- */
178
- public function disable_gutenberg_for_notification( $is_enabled, $post_type ) {
179
- if ( self::POST_TYPE === $post_type ) {
180
- return false;
181
- }
182
-
183
- return $is_enabled;
184
- }
185
-
186
- /**
187
- * Render the settings meta box.
188
- *
189
- * @since 1.0
190
- *
191
- * @param WP_Post $post
192
- */
193
- public function render_settings_meta_box( $post ) {
194
- global $wp_version;
195
-
196
- wp_nonce_field( self::POST_TYPE, self::POST_TYPE . '_nonce' );
197
-
198
- $setting = $this->read_settings( $post->ID );
199
- ?>
200
- <table class="form-table">
201
- <tbody>
202
- <tr valign="top">
203
- <th scope="row">
204
- <label for="notification"><?php esc_html_e( 'Notification For', 'bnfw' ); ?></label>
205
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'E.g. If you select "New Post Published" from the list on the right, this notification will be sent when a new post is published.', 'bnfw' ); ?></p></div>
206
- </th>
207
- <td>
208
- <select name="notification" id="notification" class="select2"
209
- data-placeholder="<?php _e( 'Select the notification type', 'bnfw' ); ?>" style="width:75%">
210
- <optgroup label="<?php _e( 'Admin', 'bnfw' ); ?>">
211
- <option
212
- value="admin-user" <?php selected( 'admin-user', $setting['notification'] ); ?>><?php esc_html_e( 'New User Registration - For Admin', 'bnfw' ); ?></option>
213
- <option
214
- value="admin-password" <?php selected( 'admin-password', $setting['notification'] ); ?>><?php esc_html_e( 'User Lost Password - For Admin', 'bnfw' ); ?></option>
215
- <option
216
- value="admin-password-changed" <?php selected( 'admin-password-changed', $setting['notification'] ); ?>><?php esc_html_e( 'Password Changed - For Admin', 'bnfw' ); ?></option>
217
- <option
218
- value="admin-email-changed" <?php selected( 'admin-email-changed', $setting['notification'] ); ?>><?php esc_html_e( 'User Email Changed - For Admin', 'bnfw' ); ?></option>
219
- <option
220
- value="admin-role" <?php selected( 'admin-role', $setting['notification'] ); ?>><?php esc_html_e( 'User Role Changed - For Admin', 'bnfw' ); ?></option>
221
- <option
222
- value="admin-user-login" <?php selected( 'admin-user-login', $setting['notification'] ); ?>><?php esc_html_e( 'User Logged In - For Admin', 'bnfw' ); ?></option>
223
- <option
224
- value="core-updated" <?php selected( 'core-updated', $setting['notification'] ); ?>><?php esc_html_e( 'WordPress Core Automatic Background Updates', 'bnfw' ); ?></option>
225
-
226
- <?php if ( version_compare( $wp_version, '4.9.6' ) >= 0 ) : ?>
227
- <option value="uc-export-data" <?php selected( 'uc-export-data', $setting['notification'] ); ?>>
228
- <?php esc_html_e( 'Privacy - Confirm Action: Export Data Request - For Admin', 'bnfw' ); ?>
229
- </option>
230
-
231
- <option value="uc-erase-data" <?php selected( 'uc-erase-data', $setting['notification'] ); ?>>
232
- <?php esc_html_e( 'Privacy - Confirm Action: Erase Data Request - For Admin', 'bnfw' ); ?>
233
- </option>
234
- <?php endif; ?>
235
-
236
- <?php do_action( 'bnfw_after_default_notifications', $setting ); ?>
237
- </optgroup>
238
- <?php do_action( 'bnfw_after_default_notifications_optgroup', $setting ); ?>
239
-
240
- <optgroup label="<?php _e( 'Transactional', 'bnfw' ); ?>">
241
- <option
242
- value="new-user" <?php selected( 'new-user', $setting['notification'] ); ?>><?php esc_html_e( 'New User Registration - For User', 'bnfw' ); ?></option>
243
- <option
244
- value="welcome-email" <?php selected( 'welcome-email', $setting['notification'] ); ?>><?php esc_html_e( 'New User - Post-registration Email', 'bnfw' ); ?></option>
245
- <option
246
- value="user-password" <?php selected( 'user-password', $setting['notification'] ); ?>><?php esc_html_e( 'User Lost Password - For User', 'bnfw' ); ?></option>
247
- <option
248
- value="password-changed" <?php selected( 'password-changed', $setting['notification'] ); ?>><?php esc_html_e( 'Password Changed - For User', 'bnfw' ); ?></option>
249
- <option value="email-changing" <?php selected( 'email-changing', $setting['notification'] ); ?>>
250
- <?php esc_html_e( 'User Email Changed Confirmation - For User', 'bnfw' ); ?>
251
- </option>
252
- <option
253
- value="email-changed" <?php selected( 'email-changed', $setting['notification'] ); ?>><?php esc_html_e( 'User Email Changed - For User', 'bnfw' ); ?></option>
254
- <option
255
- value="user-role" <?php selected( 'user-role', $setting['notification'] ); ?>><?php esc_html_e( 'User Role Changed - For User', 'bnfw' ); ?></option>
256
- <option
257
- value="user-login" <?php selected( 'user-login', $setting['notification'] ); ?>><?php esc_html_e( 'User Logged In - For User', 'bnfw' ); ?></option>
258
- <option
259
- value="reply-comment" <?php selected( 'reply-comment', $setting['notification'] ); ?>><?php esc_html_e( 'Comment Reply', 'bnfw' ); ?></option>
260
-
261
- <?php if ( version_compare( $wp_version, '4.9.6' ) >= 0 ) : ?>
262
- <option value="ca-export-data" <?php selected( 'ca-export-data', $setting['notification'] ); ?>>
263
- <?php esc_html_e( 'Privacy - Confirm Action: Export Data Request - For User', 'bnfw' ); ?>
264
- </option>
265
-
266
- <option value="ca-erase-data" <?php selected( 'ca-erase-data', $setting['notification'] ); ?>>
267
- <?php esc_html_e( 'Privacy - Confirm Action: Erase Data Request - For User', 'bnfw' ); ?>
268
- </option>
269
-
270
- <option value="data-export" <?php selected( 'data-export', $setting['notification'] ); ?>>
271
- <?php esc_html_e( 'Privacy - Data Export - For User', 'bnfw' ); ?>
272
- </option>
273
-
274
- <option value="data-erased" <?php selected( 'data-erased', $setting['notification'] ); ?>>
275
- <?php esc_html_e( 'Privacy - Data Erased - For User', 'bnfw' ); ?>
276
- </option>
277
- <?php endif; ?>
278
-
279
- <?php do_action( 'bnfw_after_transactional_notifications', $setting ); ?>
280
- </optgroup>
281
- <?php do_action( 'bnfw_after_transactional_notifications_optgroup', $setting ); ?>
282
-
283
- <optgroup label="Posts">
284
- <option
285
- value="new-post" <?php selected( 'new-post', $setting['notification'] ); ?>><?php esc_html_e( 'New Post Published', 'bnfw' ); ?></option>
286
- <option
287
- value="update-post" <?php selected( 'update-post', $setting['notification'] ); ?>><?php esc_html_e( 'Post Updated', 'bnfw' ); ?></option>
288
- <option
289
- value="pending-post" <?php selected( 'pending-post', $setting['notification'] ); ?>><?php esc_html_e( 'Post Pending Review', 'bnfw' ); ?></option>
290
- <option
291
- value="private-post" <?php selected( 'private-post', $setting['notification'] ); ?>><?php esc_html_e( 'New Private Post', 'bnfw' ); ?></option>
292
- <option
293
- value="future-post" <?php selected( 'future-post', $setting['notification'] ); ?>><?php esc_html_e( 'Post Scheduled', 'bnfw' ); ?></option>
294
- <option
295
- value="trash-post" <?php selected( 'trash-post', $setting['notification'] ); ?>><?php esc_html_e( 'Published Post Moved to Trash', 'bnfw' ); ?></option>
296
- <option value="new-comment" <?php selected( 'new-comment', $setting['notification'] ); ?>>
297
- <?php esc_html_e( 'New Comment', 'bnfw' ); ?>
298
- </option>
299
- <option value="moderate-post-comment" <?php selected( 'moderate-post-comment', $setting['notification'] ); ?>>
300
- <?php esc_html_e( 'New Comment Awaiting Moderation', 'bnfw' ); ?>
301
- </option>
302
- <option value="approve-post-comment" <?php selected( 'approve-post-comment', $setting['notification'] ); ?>>
303
- <?php esc_html_e( 'Post - Comment Approved', 'bnfw' ); ?>
304
- </option>
305
- <option
306
- value="newterm-category" <?php selected( 'newterm-category', $setting['notification'] ); ?>><?php esc_html_e( 'New Category', 'bnfw' ); ?></option>
307
- <option
308
- value="newterm-post_tag" <?php selected( 'newterm-post_tag', $setting['notification'] ); ?>><?php esc_html_e( 'New Tag', 'bnfw' ); ?></option>
309
- <option
310
- value="new-trackback" <?php selected( 'new-trackback', $setting['notification'] ); ?>><?php esc_html_e( 'New Trackback', 'bnfw' ); ?></option>
311
- <option
312
- value="new-pingback" <?php selected( 'new-pingback', $setting['notification'] ); ?>><?php esc_html_e( 'New Pingback', 'bnfw' ); ?></option>
313
- <?php do_action( 'bnfw_after_notification_options', 'post', 'Post', $setting ); ?>
314
- </optgroup>
315
- <?php do_action( 'bnfw_after_notification_options_optgroup', 'post', 'Post', $setting ); ?>
316
-
317
- <optgroup label="Page">
318
- <option
319
- value="new-page" <?php selected( 'new-page', $setting['notification'] ); ?>><?php esc_html_e( 'New Page Published', 'bnfw' ); ?></option>
320
- <option
321
- value="update-page" <?php selected( 'update-page', $setting['notification'] ); ?>><?php esc_html_e( 'Page Updated', 'bnfw' ); ?></option>
322
- <option
323
- value="pending-page" <?php selected( 'pending-page', $setting['notification'] ); ?>><?php esc_html_e( 'Page Pending Review', 'bnfw' ); ?></option>
324
- <option
325
- value="private-page" <?php selected( 'private-page', $setting['notification'] ); ?>><?php esc_html_e( 'New Private Page', 'bnfw' ); ?></option>
326
- <option
327
- value="future-page" <?php selected( 'future-page', $setting['notification'] ); ?>><?php esc_html_e( 'Page Scheduled', 'bnfw' ); ?></option>
328
- <option
329
- value="comment-page" <?php selected( 'comment-page', $setting['notification'] ); ?>><?php esc_html_e( 'Page - New Comment', 'bnfw' ); ?></option>
330
- <option value="moderate-page-comment" <?php selected( 'moderate-page-comment', $setting['notification'] ); ?>>
331
- <?php esc_html_e( 'Page - New Comment Awaiting Moderation', 'bnfw' ); ?>
332
- </option>
333
- <option value="approve-page-comment" <?php selected( 'approve-page-comment', $setting['notification'] ); ?>>
334
- <?php esc_html_e( 'Page - Comment Approved', 'bnfw' ); ?>
335
- </option>
336
- <option
337
- value="commentreply-page" <?php selected( 'commentreply-page', $setting['notification'] ); ?>><?php esc_html_e( 'Page - Comment Reply', 'bnfw' ); ?></option>
338
- <?php do_action( 'bnfw_after_notification_options', 'page', 'Page', $setting ); ?>
339
- </optgroup>
340
- <?php do_action( 'bnfw_after_notification_options_optgroup', 'page', 'Page', $setting ); ?>
341
-
342
- <optgroup label="Media">
343
- <option
344
- value="new-media" <?php selected( 'new-media', $setting['notification'] ); ?>><?php esc_html_e( 'New Media Published', 'bnfw' ); ?></option>
345
- <option
346
- value="update-media" <?php selected( 'update-media', $setting['notification'] ); ?>><?php esc_html_e( 'Media Updated', 'bnfw' ); ?></option>
347
- <option
348
- value="comment-attachment" <?php selected( 'comment-attachment', $setting['notification'] ); ?>><?php esc_html_e( 'Media - New Comment', 'bnfw' ); ?></option>
349
- <option value="approve-attachment-comment" <?php selected( 'approve-attachment-comment', $setting['notification'] ); ?>>
350
- <?php esc_html_e( 'Media - Comment Approved', 'bnfw' ); ?>
351
- </option>
352
- <option value="moderate-attachment-comment" <?php selected( 'moderate-attachment-comment', $setting['notification'] ); ?>>
353
- <?php esc_html_e( 'Media - New Comment Awaiting Moderation', 'bnfw' ); ?></option>
354
- <option
355
- value="commentreply-attachment" <?php selected( 'commentreply-attachment', $setting['notification'] ); ?>><?php esc_html_e( 'Media - Comment Reply', 'bnfw' ); ?></option>
356
- <?php do_action( 'bnfw_after_notification_options', 'media', 'Media', $setting ); ?>
357
- </optgroup>
358
- <?php do_action( 'bnfw_after_notification_options_optgroup', 'media', 'Media', $setting ); ?>
359
-
360
- <?php
361
- $types = apply_filters( 'bnfw_notification_dropdown_posttypes', get_post_types( array(
362
- 'public' => true,
363
- '_builtin' => false,
364
- ), 'names'
365
- ) );
366
-
367
- foreach ( $types as $type ) {
368
- if ( $type != self::POST_TYPE ) {
369
- $post_obj = get_post_type_object( $type );
370
- $label = $post_obj->labels->singular_name;
371
- ?>
372
- <optgroup
373
- label="<?php esc_attr( printf( "%s - '%s'", esc_html__( 'Custom Post Type', 'bnfw' ), $label ) ); ?>">
374
- <option
375
- value="new-<?php echo esc_attr( $type ); ?>" <?php selected( 'new-' . $type, $setting['notification'] ); ?>><?php echo esc_html__( 'New ', 'bnfw' ), "'$label'", esc_html__( ' Published', 'bnfw' ); ?></option>
376
- <option
377
- value="update-<?php echo esc_attr( $type ); ?>" <?php selected( 'update-' . $type, $setting['notification'] ); ?>><?php echo "'$label' " . esc_html__( 'Updated', 'bnfw' ); ?></option>
378
- <option
379
- value="pending-<?php echo esc_attr( $type ); ?>" <?php selected( 'pending-' . $type, $setting['notification'] ); ?>><?php echo "'$label' ", esc_html__( 'Pending Review', 'bnfw' ); ?></option>
380
- <option
381
- value="private-<?php echo esc_attr( $type ); ?>" <?php selected( 'private-' . $type, $setting['notification'] ); ?>><?php echo esc_html__( 'New Private ', 'bnfw' ), "'$label'"; ?></option>
382
- <option
383
- value="future-<?php echo esc_attr( $type ); ?>" <?php selected( 'future-' . $type, $setting['notification'] ); ?>><?php echo "'$label' ", esc_html__( 'Scheduled', 'bnfw' ); ?></option>
384
- <option
385
- value="comment-<?php echo esc_attr( $type ); ?>" <?php selected( 'comment-' . $type, $setting['notification'] ); ?>><?php echo "'$label' ", esc_html__( 'New Comment', 'bnfw' ); ?></option>
386
- <option value="moderate-<?php echo esc_attr( $type ); ?>-comment" <?php selected( 'moderate-' . $type . '-comment', $setting['notification'] ); ?>>
387
- <?php echo "'$label' - ", esc_html__( 'New Comment Awaiting Moderation', 'bnfw' ); ?>
388
- </option>
389
- <option value="approve-<?php echo esc_attr( $type ); ?>-comment" <?php selected( 'approve-' . $type . '-comment', $setting['notification'] ); ?>>
390
- <?php echo "'$label' - ", esc_html__( 'Comment Approved', 'bnfw' ); ?>
391
- </option>
392
- <option
393
- value="commentreply-<?php echo esc_attr( $type ); ?>" <?php selected( 'commentreply-' . $type, $setting['notification'] ); ?>><?php echo "'$label' ", esc_html__( 'Comment Reply', 'bnfw' ); ?></option>
394
- <?php do_action( 'bnfw_after_notification_options', $type, $label, $setting ); ?>
395
- </optgroup>
396
- <?php do_action( 'bnfw_after_notification_options_optgroup', $type, $label, $setting ); ?>
397
-
398
- <?php
399
- }
400
- }
401
-
402
- $taxs = apply_filters( 'bnfw_notification_dropdown_taxonomies', get_taxonomies(
403
- array(
404
- 'public' => true,
405
- '_builtin' => false,
406
- ),
407
- 'objects'
408
- ) );
409
-
410
- if ( count( $taxs ) > 0 ) {
411
- ?>
412
- <optgroup label="<?php esc_html_e( 'Custom Taxonomy', 'bnfw' ); ?>">
413
- <?php
414
- foreach ( $taxs as $tax ) {
415
- $tax_name = 'newterm-' . $tax->name;
416
- ?>
417
- <option
418
- value="<?php echo esc_attr( $tax_name ); ?>" <?php selected( $tax_name, $setting['notification'] ); ?>><?php printf( "%s '%s'", esc_html__( 'New', 'bnfw' ), $tax->labels->name ); ?></option>
419
- <?php
420
- }
421
- ?>
422
- </optgroup>
423
- <?php
424
- }
425
- do_action( 'bnfw_after_notification_optgroups', $setting );
426
- ?>
427
- </select>
428
- </td>
429
- </tr>
430
-
431
- <?php do_action( 'bnfw_after_notification_dropdown', $setting ); ?>
432
-
433
- <tr valign="top" id="user-password-msg">
434
- <td>&nbsp;</td>
435
- <td>
436
- <div>
437
- <p style="margin-top: 0;"><?php esc_html_e( "This notification doesn't support additional email fields due to a limitation in WordPress.", 'bnfw' ); ?></p>
438
- </div>
439
- </td>
440
- </tr>
441
-
442
- <tr valign="top" id="email-formatting">
443
- <th>
444
- <?php esc_html_e( 'Email Formatting', 'bnfw' ); ?>
445
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'How do you want to format the sent email? HTML is recommended as it\'ll show images and links correctly.', 'bnfw' ); ?></p></div>
446
- </th>
447
- <td>
448
- <label style="margin-right: 20px;">
449
- <input type="radio" name="email-formatting"
450
- value="html" <?php checked( 'html', $setting['email-formatting'] ); ?>>
451
- <?php esc_html_e( 'HTML Formatting', 'bnfw' ); ?>
452
- </label>
453
-
454
- <label>
455
- <input type="radio" name="email-formatting"
456
- value="text" <?php checked( 'text', $setting['email-formatting'] ); ?>>
457
- <?php esc_html_e( 'Plain Text', 'bnfw' ); ?>
458
- </label>
459
- </td>
460
- </tr>
461
-
462
- <?php do_action( 'bnfw_after_email_formatting', $setting ); ?>
463
-
464
- <tr valign="top" id="toggle-fields">
465
- <th>
466
- <?php esc_html_e( 'Additional Email Fields', 'bnfw' ); ?>
467
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'This should be fairly self explanatory but if you\'re unsure, tick this checkbox and have a look at the available options. You can always untick it again should you decide you don\'t need to use it.', 'bnfw' ); ?></p></div>
468
- </th>
469
- <td>
470
- <input type="checkbox" id="show-fields" name="show-fields"
471
- value="true" <?php checked( $setting['show-fields'], 'true', true ); ?>>
472
- <label for="show-fields"><?php esc_html_e( 'Set "From" Name & Email, Reply To, CC, BCC', 'bnfw' ); ?></label>
473
- </td>
474
- </tr>
475
-
476
-
477
- <tr valign="top" id="email">
478
- <th scope="row">
479
- <?php esc_html_e( 'From Name and Email', 'bnfw' ); ?>
480
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'If you want to send the email from your site name and email address instead of the default "WordPress" from "wordpress@domain.com", this is where you can do it.', 'bnfw' ); ?></p></div>
481
- </th>
482
- <td>
483
- <input type="text" name="from-name" value="<?php echo esc_attr( $setting['from-name'] ); ?>"
484
- placeholder="<?php _e( 'Site Name', 'bnfw' ); ?>" style="width: 37.35%">
485
- <input type="text" name="from-email" value="<?php echo esc_attr( $setting['from-email'] ); ?>"
486
- placeholder="<?php _e( 'Site Email', 'bnfw' ); ?>" style="width: 37.3%">
487
- </td>
488
- </tr>
489
-
490
-
491
- <tr valign="top" id="reply">
492
- <th scope="row">
493
- <?php esc_html_e( 'Reply To', 'bnfw' ); ?>
494
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'If you want any replies to your email notification to go to another person, fill in this box with their name and email address.', 'bnfw' ); ?></p></div>
495
- </th>
496
- <td>
497
- <input type="text" name="reply-name" value="<?php echo esc_attr( $setting['reply-name'] ); ?>"
498
- placeholder="<?php _e( 'Name', 'bnfw' ); ?>" style="width: 37.35%">
499
- <input type="text" name="reply-email" value="<?php echo esc_attr( $setting['reply-email'] ); ?>"
500
- placeholder="<?php _e( 'Email', 'bnfw' ); ?>" style="width: 37.3%">
501
- </td>
502
- </tr>
503
-
504
- <tr valign="top" id="cc">
505
- <th scope="row">
506
- <?php esc_html_e( 'CC', 'bnfw' ); ?>
507
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'Publicly copy in any other users or user roles to this email.', 'bnfw' ); ?></p></div>
508
- </th>
509
-
510
- <td>
511
- <select multiple name="cc[]" class="<?php echo sanitize_html_class( bnfw_get_user_select_class() ); ?>"
512
- data-placeholder="<?php echo apply_filters( 'bnfw_email_dropdown_placeholder', __( 'Select User Roles / Users', 'bnfw' ) ); ?>" style="width:75%">
513
- <?php bnfw_render_users_dropdown( $setting['cc'] ); ?>
514
- </select>
515
- </td>
516
- </tr>
517
-
518
- <tr valign="top" id="bcc">
519
- <th scope="row">
520
- <?php esc_html_e( 'BCC', 'bnfw' ); ?>
521
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'Privately copy in any other users or user roles to this email.', 'bnfw' ); ?></p></div>
522
- </th>
523
-
524
- <td>
525
- <select multiple name="bcc[]" class="<?php echo sanitize_html_class( bnfw_get_user_select_class() ); ?>"
526
- data-placeholder="<?php echo apply_filters( 'bnfw_email_dropdown_placeholder', __( 'Select User Roles / Users', 'bnfw' ) ); ?>" style="width:75%">
527
- <?php bnfw_render_users_dropdown( $setting['bcc'] ); ?>
528
- </select>
529
- </td>
530
- </tr>
531
-
532
- <?php do_action( 'bnfw_after_additional_email_fields', $setting ); ?>
533
-
534
- <tr valign="top" id="post-author">
535
- <th>
536
- <?php esc_html_e( 'Send to Author', 'bnfw' ); ?>
537
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'E.g. If you want a new post published notification to go to the post author, tick this box.', 'bnfw' ); ?></p></div>
538
- </th>
539
-
540
- <td>
541
- <label>
542
- <input type="checkbox" id="only-post-author" name="only-post-author"
543
- value="true" <?php checked( 'true', $setting['only-post-author'] ); ?>>
544
- <?php esc_html_e( 'Send this notification to the Author', 'bnfw' ); ?>
545
- </label>
546
- </td>
547
- </tr>
548
-
549
- <?php do_action( 'bnfw_after_only_post_author', $setting ); ?>
550
-
551
- <tr valign="top" id="current-user">
552
- <th>
553
- &nbsp;
554
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'E.g. If you\'re an editor and regularly update your posts, you might not want to be emailed about this all the time. Ticking this box will prevent you from receiving emails about your own changes.', 'bnfw' ); ?></p></div>
555
- </th>
556
- <td>
557
- <label>
558
- <input type="checkbox" name="disable-current-user"
559
- value="true" <?php checked( 'true', $setting['disable-current-user'] ); ?>>
560
- <?php esc_html_e( 'Do not send this Notification to the User that triggered it', 'bnfw' ); ?>
561
- </label>
562
- </td>
563
- </tr>
564
-
565
- <?php do_action( 'bnfw_after_disable_current_user', $setting ); ?>
566
-
567
- <tr valign="top" id="users">
568
- <th scope="row">
569
- <?php esc_html_e( 'Send To', 'bnfw' ); ?>
570
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'Choose the users and/or user roles to send this email notification to.', 'bnfw' ); ?></p></div>
571
- </th>
572
- <td>
573
- <select multiple id="users-select" name="users[]"
574
- class="<?php echo sanitize_html_class( bnfw_get_user_select_class() ); ?>"
575
- data-placeholder="<?php echo apply_filters( 'bnfw_email_dropdown_placeholder', __( 'Select User Roles / Users', 'bnfw' ) ); ?>" style="width:75%">
576
- <?php bnfw_render_users_dropdown( $setting['users'] ); ?>
577
- </select>
578
- </td>
579
- </tr>
580
-
581
- <tr valign="top" id="exclude-users">
582
- <th scope="row">
583
- <?php esc_html_e( 'Except For', 'bnfw' ); ?>
584
- <div class="bnfw-help-tip">
585
- <p>
586
- <?php esc_html_e( 'Choose the users and/or user roles that this notification should not be sent to.', 'bnfw' ); ?>
587
- </p>
588
- </div>
589
- </th>
590
- <td>
591
- <select multiple id="exclude-users-select" name="exclude-users[]"
592
- class="<?php echo sanitize_html_class( bnfw_get_user_select_class() ); ?>"
593
- data-placeholder="<?php echo apply_filters( 'bnfw_email_dropdown_placeholder', __( 'Select User Roles / Users', 'bnfw' ) ); ?>" style="width:75%">
594
- <?php bnfw_render_users_dropdown( $setting['exclude-users'] ); ?>
595
- </select>
596
- </td>
597
- </tr>
598
-
599
- <?php
600
- $display = 'none';
601
-
602
- if ( $this->should_show_users_count_msg( $setting ) ) {
603
- $display = 'table-row';
604
- }
605
- ?>
606
- <tr valign="top" id="users-count-msg" style="display: <?php echo esc_attr( $display ); ?>">
607
- <th scope="row">&nbsp;</th>
608
- <td>
609
- <div>
610
- <p>
611
- <?php _e( 'You have chosen to send this notification to over 200 users. Please check the email sending rate limit at your host before sending.', 'bnfw' ); ?>
612
- </p>
613
- </div>
614
- </td>
615
- </tr>
616
-
617
- <?php do_action( 'bnfw_after_send_to', $setting ); ?>
618
-
619
- <tr valign="top" id="subject-wrapper">
620
- <th scope="row">
621
- <?php esc_html_e( 'Subject', 'bnfw' ); ?>
622
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'Notification subject. You can use ', 'bnfw' ); ?><a href="https://betternotificationsforwp.com/documentation/notifications/shortcodes/" target="_blank">shortcodes</a><?php esc_html_e(' here.', 'bnfw' ); ?></p></div>
623
- </th>
624
- <td>
625
- <input type="text" name="subject" id="subject" value="<?php echo esc_attr( $setting['subject'] ); ?>"
626
- style="width:75%;">
627
- </td>
628
- </tr>
629
-
630
- <?php do_action( 'bnfw_after_user_dropdown', $setting ); ?>
631
-
632
- <?php do_action( 'bnfw_before_message_body', $setting ); ?>
633
- <tr valign="top">
634
- <th scope="row">
635
- <?php esc_html_e( 'Message Body', 'bnfw' ); ?>
636
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'Notification message. You can use ', 'bnfw' ); ?><a href="https://betternotificationsforwp.com/documentation/notifications/shortcodes/" target="_blank">shortcodes</a><?php esc_html_e(' here.', 'bnfw' ); ?></p></div>
637
-
638
- <div class="wp-ui-text-highlight">
639
- <p>
640
- <br>
641
- <br>
642
- <br>
643
- <br>
644
- <?php esc_html_e( 'Need some more help?', 'bnfw' ); ?>
645
- </p>
646
- <?php
647
- $doc_url = 'https://betternotificationsforwp.com/documentation/';
648
-
649
- if ( bnfw_is_tracking_allowed() ) {
650
- $doc_url .= "?utm_source=WP%20Admin%20Notification%20Editor%20-%20'Documentation'&amp;utm_medium=referral";
651
- }
652
- ?>
653
- <p>
654
- <a href="#" class="button-secondary" id="insert-default-msg"><?php esc_html_e( 'Insert Default Content', 'bnfw' ); ?></a>
655
- </p>
656
- <p>
657
- <a href="<?php echo $doc_url; ?>"
658
- target="_blank" class="button-secondary"><?php esc_html_e( 'Read Documentation', 'bnfw' ); ?></a>
659
- </p>
660
- <p>
661
- <a href="" target="_blank" id="shortcode-help"
662
- class="button-secondary"><?php esc_html_e( 'Find Shortcodes', 'bnfw' ); ?></a>
663
- </p>
664
- </div>
665
- </th>
666
- <td>
667
- <?php wp_editor( $setting['message'], 'notification_message', array( 'media_buttons' => true ) ); ?>
668
- <p> &nbsp; </p>
669
- <div id="disable-autop">
670
- <label>
671
- <input type="checkbox" name="disable-autop"
672
- value="true" <?php checked( 'true', $setting['disable-autop'] ); ?>>
673
- <?php esc_html_e( 'Stop additional paragraph and line break HTML from being inserted into my notifications', 'bnfw' ); ?>
674
- </label>
675
- </div>
676
- </td>
677
- </tr>
678
-
679
- </tbody>
680
- </table>
681
- <?php
682
- }
683
-
684
- /**
685
- * Should we enqueue assets?
686
- *
687
- * @since 1.0
688
- *
689
- * @param $hook_suffix
690
- */
691
- public function is_assets_needed( $hook_suffix ) {
692
- if ( self::POST_TYPE === get_post_type() || 'bnfw_notification_page_bnfw-settings' === $hook_suffix ) {
693
- // The enqueue assets function may be included from addons.
694
- // We want to disable autosave only for notifications
695
- wp_dequeue_script( 'autosave' );
696
-
697
- $this->enqueue_assets();
698
-
699
- do_action( 'bnfw_after_enqueue_scripts' );
700
- }
701
- }
702
-
703
- /**
704
- * Enqueue assets.
705
- *
706
- * @since 1.4
707
- */
708
- public function enqueue_assets() {
709
- wp_deregister_script( 'select2' );
710
- wp_dequeue_script( 'select2' );
711
- wp_deregister_style( 'select2' );
712
- wp_dequeue_style( 'select2' );
713
-
714
- // Ultimate Member plugin is giving us problems. They should upgrade
715
- wp_deregister_script( 'um_minified' );
716
- wp_dequeue_script( 'um_minified' );
717
- wp_deregister_script( 'um_admin_scripts' );
718
- wp_dequeue_script( 'um_admin_scripts' );
719
-
720
- wp_enqueue_style( 'select2', '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css', array(), '4.0.3' );
721
- wp_enqueue_script( 'select2', '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.full.min.js', array( 'jquery' ), '4.0.3', true );
722
-
723
- wp_enqueue_script( 'bnfw', plugins_url( '../assets/js/bnfw.js', dirname( __FILE__ ) ), array( 'select2' ), '0.1', true );
724
- wp_enqueue_style( 'bnfw', plugins_url( '../assets/css/bnfw.css', dirname( __FILE__ ) ), array( 'dashicons', 'select2' ), '0.1' );
725
-
726
- $strings = array(
727
- 'validation_element' => apply_filters( 'bnfw_validation_element', '#users-select' ),
728
- 'empty_user' => esc_html__( 'You must choose at least one User or User Role to send the notification to before you can save', 'bnfw' ),
729
- 'enableTags' => false,
730
- 'bnfw_users_search_ajax_nonce' => wp_create_nonce( 'bnfw_users_search_ajax_nonce' ),
731
- );
732
-
733
- /**
734
- * Filter the localized array that is sent to scripts.
735
- *
736
- * @since 1.7.0
737
- */
738
- $strings = apply_filters( 'bnfw_localize_script', $strings );
739
-
740
- wp_localize_script( 'bnfw', 'BNFW', $strings );
741
- }
742
-
743
- /**
744
- * Save the meta box's post metadata.
745
- *
746
- * @since 1.0
747
- *
748
- * @param int $post_id The ID of the post being saved.
749
- */
750
- public function save_meta_data( $post_id ) {
751
- if ( self::POST_TYPE !== get_post_type( $post_id ) ) {
752
- return;
753
- }
754
-
755
- // Check nonce.
756
- if ( empty( $_POST[ self::POST_TYPE . '_nonce' ] ) ) {
757
- return;
758
- }
759
-
760
- // Verify nonce.
761
- if ( ! wp_verify_nonce( $_POST[ self::POST_TYPE . '_nonce' ], self::POST_TYPE ) ) {
762
- return;
763
- }
764
-
765
- if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
766
- return;
767
- }
768
-
769
- if ( ! current_user_can( 'bnfw' ) ) {
770
- return;
771
- }
772
-
773
- if ( isset( $_POST['digest-interval'] ) && 'no' != $_POST['digest-interval']) {
774
- $subject = $_POST['subject'];
775
- }else{
776
- $subject = sanitize_text_field( $_POST['subject'] );
777
- }
778
-
779
- $setting = array(
780
- 'notification' => sanitize_text_field( $_POST['notification'] ),
781
- 'subject' => $subject,
782
- 'message' => $_POST['notification_message'],
783
- 'disabled' => isset( $_POST['disabled'] ) ? sanitize_text_field( $_POST['disabled'] ) : 'false',
784
- 'email-formatting' => isset( $_POST['email-formatting'] ) ? sanitize_text_field( $_POST['email-formatting'] ) : 'html',
785
- 'disable-current-user' => isset( $_POST['disable-current-user'] ) ? sanitize_text_field( $_POST['disable-current-user'] ) : 'false',
786
- 'disable-autop' => isset( $_POST['disable-autop'] ) ? sanitize_text_field( $_POST['disable-autop'] ) : 'false',
787
- 'only-post-author' => isset( $_POST['only-post-author'] ) ? sanitize_text_field( $_POST['only-post-author'] ) : 'false',
788
- 'users' => array(),
789
- 'exclude-users' => array(),
790
- );
791
-
792
- if ( isset( $_POST['users'] ) ) {
793
- $setting['users'] = array_map( 'sanitize_text_field', $_POST['users'] );
794
- }
795
-
796
- if ( isset( $_POST['exclude-users'] ) ) {
797
- $setting['exclude-users'] = array_map( 'sanitize_text_field', $_POST['exclude-users'] );
798
- }
799
-
800
- if ( isset( $_POST['show-fields'] ) && 'true' == $_POST['show-fields'] ) {
801
- $setting['show-fields'] = 'true';
802
- $setting['from-name'] = sanitize_text_field( $_POST['from-name'] );
803
- $setting['from-email'] = sanitize_text_field( $_POST['from-email'] );
804
- $setting['reply-name'] = sanitize_text_field( $_POST['reply-name'] );
805
- $setting['reply-email'] = sanitize_text_field( $_POST['reply-email'] );
806
- $setting['cc'] = isset( $_POST['cc'] ) ? array_map( 'sanitize_text_field', $_POST['cc'] ) : '';
807
- $setting['bcc'] = isset( $_POST['bcc'] ) ? array_map( 'sanitize_text_field', $_POST['bcc'] ) : '';
808
- } else {
809
- $setting['show-fields'] = 'false';
810
- }
811
-
812
- $setting = apply_filters( 'bnfw_notification_setting', $setting, $_POST );
813
-
814
- $this->save_settings( $post_id, $setting );
815
-
816
- if ( isset( $_POST['send-test-email'] ) ) {
817
- if ( 'true' == sanitize_text_field( $_POST['send-test-email'] ) ) {
818
- BNFW::factory()->engine->send_test_email( $setting );
819
- add_filter( 'redirect_post_location', array( $this, 'test_mail_sent' ) );
820
- }
821
- }
822
- }
823
-
824
- /**
825
- * Add a query parameter to url if test email was sent.
826
- *
827
- * @since 1.3
828
- */
829
- public function test_mail_sent( $loc ) {
830
- return add_query_arg( self::TEST_MAIL_ARG, 1, $loc );
831
- }
832
-
833
- /**
834
- * Add a notification if a test email was sent.
835
- *
836
- * @since 1.3
837
- */
838
- public function admin_notices() {
839
- if ( isset( $_GET[ self::TEST_MAIL_ARG ] ) ) {
840
- $screen = get_current_screen();
841
- if ( in_array( $screen->post_type, array( self::POST_TYPE ) ) ) {
842
- ?>
843
- <div class="updated below-h2">
844
- <p><?php echo esc_html__( 'Test Notification Sent.', 'bnfw' ); ?></p>
845
- </div>
846
- <?php
847
- }
848
- }
849
- }
850
-
851
- /**
852
- * Save settings in post meta.
853
- *
854
- * @since 1.0
855
- * @access private
856
- *
857
- * @param $post_id
858
- * @param $setting
859
- */
860
- private function save_settings( $post_id, $setting ) {
861
- foreach ( $setting as $key => $value ) {
862
- update_post_meta( $post_id, self::META_KEY_PREFIX . $key, $value );
863
- }
864
- }
865
-
866
- /**
867
- * Read settings from post meta.
868
- *
869
- * @since 1.0
870
- *
871
- * @param int $post_id
872
- *
873
- * @return array
874
- */
875
- public function read_settings( $post_id ) {
876
- $setting = array();
877
- $default = array(
878
- 'notification' => '',
879
- 'from-name' => '',
880
- 'from-email' => '',
881
- 'reply-name' => '',
882
- 'reply-email' => '',
883
- 'cc' => array(),
884
- 'bcc' => array(),
885
- 'users' => array(),
886
- 'exclude-users' => array(),
887
- 'subject' => '',
888
- 'email-formatting' => get_option( 'bnfw_email_format', 'html' ),
889
- 'message' => '',
890
- 'show-fields' => 'false',
891
- 'disable-current-user' => 'false',
892
- 'disable-autop' => 'false',
893
- 'only-post-author' => 'false',
894
- 'disabled' => 'false',
895
- );
896
-
897
- $default = apply_filters( 'bnfw_notification_setting_fields', $default );
898
-
899
- foreach ( $default as $key => $default_value ) {
900
- $value = get_post_meta( $post_id, self::META_KEY_PREFIX . $key, true );
901
- if ( ! empty( $value ) ) {
902
- $setting[ $key ] = $value;
903
- } else {
904
- $setting[ $key ] = $default_value;
905
- }
906
- }
907
-
908
- // compatibility code. This will be removed subsequently
909
- $user_roles = get_post_meta( $post_id, self::META_KEY_PREFIX . 'user-roles', true );
910
- if ( ! empty( $user_roles ) && is_array( $user_roles ) ) {
911
- foreach ( $user_roles as $role ) {
912
- $setting['users'][] = 'role-' . $role;
913
- }
914
-
915
- update_post_meta( $post_id, self::META_KEY_PREFIX . 'users', $setting['users'] );
916
- delete_post_meta( $post_id, self::META_KEY_PREFIX . 'user-roles' );
917
- }
918
-
919
- $setting['id'] = $post_id;
920
-
921
- return $setting;
922
- }
923
-
924
- /**
925
- * Change the post updated message for notification post type.
926
- *
927
- * @since 1.0
928
- *
929
- * @param $messages
930
- *
931
- * @return mixed
932
- */
933
- public function post_updated_messages( $messages ) {
934
- $messages[ self::POST_TYPE ] = array_fill( 0, 11, esc_html__( 'Notification saved.', 'bnfw' ) );
935
-
936
- return $messages;
937
- }
938
-
939
- /**
940
- * Render submit div meta box.
941
- *
942
- * @since 1.0
943
- *
944
- * @param $post
945
- */
946
- public function render_submitdiv( $post ) {
947
- global $post;
948
- ?>
949
- <div class="submitbox" id="submitpost">
950
-
951
- <?php // Hidden submit button early on so that the browser chooses the right button when form is submitted with Return key ?>
952
- <div style="display:none;">
953
- <?php submit_button( esc_html__( 'Save', 'bnfw' ), 'button', 'save' ); ?>
954
- </div>
955
-
956
- <?php // Always publish. ?>
957
- <div class="disable-notification-checkbox" style="padding: 5px 0 10px 0;">
958
- <div class="bnfw-help-tip-container">
959
- <input type="hidden" name="post_status" id="hidden_post_status" value="publish">
960
-
961
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'Use this to enable or disable notifications. If you want to disable a default WordPress notification, just create it on the left, then disable it here.', 'bnfw' ); ?></p></div>
962
-
963
- <?php
964
- $setting = $this->read_settings( $post->ID );
965
- ?>
966
- <label>
967
- <input type="radio" name="disabled"
968
- value="false" <?php checked( $setting['disabled'], 'false', true ); ?>><?php esc_html_e( 'Notification Enabled', 'bnfw' ); ?>
969
- </label>
970
-
971
- <br>
972
-
973
- <label>
974
- <input type="radio" name="disabled"
975
- value="true" <?php checked( $setting['disabled'], 'true', true ); ?>><?php esc_html_e( 'Notification Disabled', 'bnfw' ); ?>
976
- </label>
977
- </div>
978
-
979
- <br>
980
- <br>
981
-
982
- <?php if ( 'publish' == $post->post_status ) { ?>
983
- <div class="bnfw-help-tip-container">
984
- <input type="hidden" name="send-test-email" id="send-test-email" value="false">
985
- <input name="test-email" type="submit" class="button button-secondary button-large" id="test-email"
986
- value="<?php esc_attr_e( 'Send Me a Test Email', 'bnfw' ); ?>">
987
-
988
- <div class="bnfw-help-tip"><p><?php esc_html_e( 'This will send you (the currently logged in user) a notification so that you can check for any issues with formatting – it’s doesn\'t mean that a notification will send correctly in the future. You can read about how to improve email delivery', 'bnfw'); ?> <a href="https://betternotificationsforwp.com/documentation/getting-started/how-to-improve-email-delivery/" target="_blank"><?php esc_html_e( 'here', 'bnfw'); ?></a><?php esc_html_e( '. Shortcodes will not be replaced with content.', 'bnfw' ); ?></p></div>
989
- </div>
990
- <?php } ?>
991
-
992
- </div>
993
-
994
- <div id="major-publishing-actions">
995
-
996
- <div id="delete-action">
997
- <?php
998
- if ( ! EMPTY_TRASH_DAYS ) {
999
- $delete_text = esc_html__( 'Delete Permanently', 'bnfw' );
1000
- } else {
1001
- $delete_text = esc_html__( 'Move to Trash', 'bnfw' );
1002
- }
1003
- ?>
1004
- <a class="submitdelete deletion"
1005
- href="<?php echo esc_url( get_delete_post_link( $post->ID ) ); ?>"><?php echo esc_html( $delete_text ); ?></a>
1006
- </div>
1007
-
1008
- <div id="publishing-action">
1009
- <span class="spinner"></span>
1010
- <input name="original_publish" type="hidden" id="original_publish"
1011
- value="<?php esc_attr_e( 'Save', 'bnfw' ); ?>">
1012
- <input name="save" type="submit" class="button button-primary button-large" id="publish"
1013
- accesskey="p" value="<?php esc_attr_e( 'Save', 'bnfw' ); ?>">
1014
- </div>
1015
- <div class="clear"></div>
1016
-
1017
- </div>
1018
- <!-- #major-publishing-actions -->
1019
-
1020
- <div class="clear"></div>
1021
- </div>
1022
- <!-- #submitpost -->
1023
- <?php
1024
- }
1025
-
1026
- /**
1027
- * Get notifications based on type.
1028
- *
1029
- * @since 1.0
1030
- *
1031
- * @param array|string $types
1032
- * @param bool $exclude_disabled (optional) Whether to exclude disabled notifications or not. True by default.
1033
- *
1034
- * @return array WP_Post objects
1035
- */
1036
- public function get_notifications( $types = array(), $exclude_disabled = true ) {
1037
- if ( ! is_array( $types ) ) {
1038
- $types = array( $types );
1039
- }
1040
-
1041
- $args = array(
1042
- 'post_type' => self::POST_TYPE,
1043
- );
1044
-
1045
- $meta_query = array();
1046
-
1047
- if ( ! empty( $types ) ) {
1048
- $meta_query[] = array(
1049
- 'key' => self::META_KEY_PREFIX . 'notification',
1050
- 'value' => $types,
1051
- 'compare' => 'IN',
1052
- );
1053
- }
1054
-
1055
- if ( $exclude_disabled ) {
1056
- $meta_query[] = array(
1057
- 'key' => self::META_KEY_PREFIX . 'disabled',
1058
- 'value' => 'true',
1059
- 'compare' => '!=',
1060
- );
1061
- }
1062
-
1063
- if ( ! empty( $meta_query ) ) {
1064
- $args['meta_query'] = $meta_query;
1065
- }
1066
-
1067
- $args['posts_per_page'] = -1;
1068
- $args['nopagging'] = true;
1069
-
1070
- $args = apply_filters( 'bnfw_get_notifications_args', $args, $types, $exclude_disabled );
1071
-
1072
- $wp_query = new WP_Query();
1073
- $posts = $wp_query->query( $args );
1074
-
1075
- $posts = apply_filters( 'bnfw_get_notifications_posts', $posts, $args, $types, $exclude_disabled );
1076
-
1077
- return $posts;
1078
- }
1079
-
1080
- /**
1081
- * Are there any disabled notifications for a particular notification type.
1082
- *
1083
- * @param string $type Notification type.
1084
- *
1085
- * @return bool True if disabled, False otherwise.
1086
- */
1087
- public function is_notification_disabled( $type ) {
1088
- $args = array(
1089
- 'post_type' => self::POST_TYPE,
1090
- 'posts_per_page' => - 1,
1091
- 'nopagging' => true,
1092
- 'fields' => 'ids',
1093
- 'meta_query' => array(
1094
- array(
1095
- 'key' => self::META_KEY_PREFIX . 'notification',
1096
- 'value' => $type,
1097
- ),
1098
- array(
1099
- 'key' => self::META_KEY_PREFIX . 'disabled',
1100
- 'value' => 'true',
1101
- ),
1102
- )
1103
- );
1104
-
1105
- $args = apply_filters( 'bnfw_is_notification_disabled_args', $args, $type );
1106
-
1107
- $wp_query = new WP_Query();
1108
- $posts = $wp_query->query( $args );
1109
-
1110
- $posts = apply_filters( 'bnfw_is_notification_disabled_posts', $posts, $args, $type );
1111
-
1112
- return count( $posts ) > 0;
1113
- }
1114
-
1115
- /**
1116
- * Does a particular type of notification exists or not.
1117
- *
1118
- * @since 1.1
1119
- *
1120
- * @param string $type Notification Type.
1121
- * @param bool $exclude_disabled (optional) Whether to exclude disabled notifications or not. True by default.
1122
- *
1123
- * @return bool True if present, False otherwise
1124
- */
1125
- public function notification_exists( $type, $exclude_disabled = true ) {
1126
- $notifications = $this->get_notifications( $type, $exclude_disabled );
1127
-
1128
- if ( count( $notifications ) > 0 ) {
1129
- return true;
1130
- } else {
1131
- return false;
1132
- }
1133
- }
1134
-
1135
- /**
1136
- * Custom columns for this post type.
1137
- *
1138
- * @since 1.0
1139
- * @filter manage_{post_type}_posts_columns
1140
- *
1141
- * @param array $columns
1142
- *
1143
- * @return array
1144
- */
1145
- public function columns_header( $columns ) {
1146
- $columns['type'] = esc_html__( 'Notification Type', 'bnfw' );
1147
- $columns['disabled'] = esc_html__( 'Enabled?', 'bnfw' );
1148
- $columns['subject'] = esc_html__( 'Subject', 'bnfw' );
1149
- $columns['users'] = esc_html__( 'User Roles / Users', 'bnfw' );
1150
- $columns['excluded'] = esc_html__( 'Excluded User Roles / Users', 'bnfw' );
1151
-
1152
- return $columns;
1153
- }
1154
-
1155
- /**
1156
- * Custom column appears in each row.
1157
- *
1158
- * @since 1.0
1159
- * @action manage_{post_type}_posts_custom_column
1160
- *
1161
- * @param string $column Column name
1162
- * @param int $post_id Post ID
1163
- */
1164
- public function custom_column_row( $column, $post_id ) {
1165
- $setting = $this->read_settings( $post_id );
1166
- switch ( $column ) {
1167
- case 'disabled':
1168
- if ( 'true' != $setting['disabled'] ) {
1169
- printf( '<span class="dashicons dashicons-yes"></span>' );
1170
- }
1171
- break;
1172
- case 'type':
1173
- echo $this->get_notification_name( $setting['notification'] );
1174
- break;
1175
- case 'subject':
1176
- echo ! empty( $setting['subject'] ) ? $setting['subject'] : '';
1177
- break;
1178
- case 'users':
1179
- $users = $this->get_names_from_users( $setting['users'] );
1180
- if (!empty($users)) {
1181
- echo implode( ', ', $users );
1182
- }
1183
- else {
1184
- if(isset($setting['new-user-role'])){
1185
- $users = $this->get_names_from_users( $setting['new-user-role'] );
1186
- echo implode( ', ', $users );
1187
- }
1188
- }
1189
-
1190
- if ( 'true' === $setting['only-post-author'] ) {
1191
- echo esc_html__( ', Post Author', 'bnfw' );
1192
- }
1193
-
1194
- break;
1195
- case 'excluded':
1196
- $excluded_users = $this->get_names_from_users( $setting['exclude-users'] );
1197
- echo implode( ', ', $excluded_users );
1198
-
1199
- break;
1200
- }
1201
-
1202
- /**
1203
- * Invoked while displaying a custom column in notification table.
1204
- *
1205
- * @since 1.3.9
1206
- *
1207
- * @param string $column Column name
1208
- * @param int $post_id Post ID
1209
- */
1210
- do_action( 'bnfw_notification_table_column', $column, $post_id );
1211
- }
1212
-
1213
- /**
1214
- * Get names from users.
1215
- *
1216
- * @since 1.2
1217
- */
1218
- private function get_names_from_users( $users ) {
1219
- $user_ids = array();
1220
- $user_roles = array();
1221
- $emails = array();
1222
- $names_from_user_ids = array();
1223
-
1224
- if ( is_array( $users ) ) {
1225
- foreach ( $users as $user ) {
1226
- if ( $this->starts_with( $user, 'role-' ) ) {
1227
- $user_roles[] = ucfirst( str_replace( 'role-', '', $user ) );
1228
- } elseif ( strpos( $user, '@' ) !== false ) {
1229
- $emails[] = $user;
1230
- } elseif ( absint( $user ) > 0 ) {
1231
- $user_ids[] = absint( $user );
1232
- } else {
1233
- $emails[] = $user;
1234
- }
1235
- }
1236
- }
1237
- else {
1238
- // User Roles not associated with a To/CC/BCC field
1239
- $role = get_role( $users );
1240
-
1241
- if ( !empty( $role ) ) {
1242
- $user_roles = array( $role->name );
1243
- }
1244
- }
1245
-
1246
- if ( ! empty( $user_ids ) ) {
1247
- $user_query = new WP_User_Query( array( 'include' => $user_ids ) );
1248
- foreach ( $user_query->results as $user ) {
1249
- $names_from_user_ids[] = $user->user_login;
1250
- }
1251
- }
1252
-
1253
- return array_merge( $user_roles, $names_from_user_ids, $emails );
1254
- }
1255
-
1256
- /**
1257
- * Get name of the notification based on slug.
1258
- *
1259
- * @param string $slug Notification Slug.
1260
- *
1261
- * @return string Notification Name.
1262
- */
1263
- private function get_notification_name( $slug ) {
1264
- $name = '';
1265
- switch ( $slug ) {
1266
- case 'new-comment':
1267
- $name = esc_html__( 'New Comment', 'bnfw' );
1268
- break;
1269
- case 'approve-post-comment':
1270
- $name = esc_html__( 'Post - Comment Approved', 'bnfw' );
1271
- break;
1272
- case 'moderate-comment':
1273
- $name = esc_html__( 'New Comment Awaiting Moderation', 'bnfw' );
1274
- break;
1275
- case 'new-trackback':
1276
- $name = esc_html__( 'New Trackback', 'bnfw' );
1277
- break;
1278
- case 'new-pingback':
1279
- $name = esc_html__( 'New Pingback', 'bnfw' );
1280
- break;
1281
- case 'reply-comment':
1282
- $name = esc_html__( 'Comment Reply', 'bnfw' );
1283
- break;
1284
- case 'user-password':
1285
- $name = esc_html__( 'User Lost Password - For User', 'bnfw' );
1286
- break;
1287
- case 'admin-password':
1288
- $name = esc_html__( 'User Lost Password - For Admin', 'bnfw' );
1289
- break;
1290
- case 'admin-password-changed':
1291
- $name = esc_html__( 'Password Changed - For Admin', 'bnfw' );
1292
- break;
1293
- case 'admin-email-changed':
1294
- $name = esc_html__( 'User Email Changed - For Admin', 'bnfw' );
1295
- break;
1296
- case 'password-changed':
1297
- $name = esc_html__( 'Password Changed - For User', 'bnfw' );
1298
- break;
1299
- case 'email-changing':
1300
- $name = esc_html__( 'User Email Changed Confirmation - For User', 'bnfw' );
1301
- break;
1302
- case 'email-changed':
1303
- $name = esc_html__( 'User Email Changed - For User', 'bnfw' );
1304
- break;
1305
- case 'core-updated':
1306
- $name = esc_html__( 'WordPress Core Automatic Background Updates', 'bnfw' );
1307
- break;
1308
- case 'new-user':
1309
- $name = esc_html__( 'New User Registration - For User', 'bnfw' );
1310
- break;
1311
- case 'user-login':
1312
- $name = esc_html__( 'User Logged In - For User', 'bnfw' );
1313
- break;
1314
- case 'admin-user-login':
1315
- $name = esc_html__( 'User Logged In - For Admin', 'bnfw' );
1316
- break;
1317
- case 'welcome-email':
1318
- $name = esc_html__( 'New User - Post-registration Email', 'bnfw' );
1319
- break;
1320
- case 'admin-user':
1321
- $name = esc_html__( 'New User Registration - For Admin', 'bnfw' );
1322
- break;
1323
- case 'user-role':
1324
- $name = esc_html__( 'User Role Changed - For User', 'bnfw' );
1325
- break;
1326
- case 'admin-role':
1327
- $name = esc_html__( 'User Role Changed - For Admin', 'bnfw' );
1328
- break;
1329
- case 'new-post':
1330
- $name = esc_html__( 'New Post Published', 'bnfw' );
1331
- break;
1332
- case 'update-post':
1333
- $name = esc_html__( 'Post Updated', 'bnfw' );
1334
- break;
1335
- case 'pending-post':
1336
- $name = esc_html__( 'Post Pending Review', 'bnfw' );
1337
- break;
1338
- case 'private-post':
1339
- $name = esc_html__( 'New Private Post', 'bnfw' );
1340
- break;
1341
- case 'future-post':
1342
- $name = esc_html__( 'Post Scheduled', 'bnfw' );
1343
- break;
1344
- case 'trash-post':
1345
- $name = esc_html__( 'Published Post Moved to Trash', 'bnfw' );
1346
- break;
1347
- case 'new-page':
1348
- $name = esc_html__( 'New Page Published', 'bnfw' );
1349
- break;
1350
- case 'newterm-category':
1351
- $name = esc_html__( 'New Category', 'bnfw' );
1352
- break;
1353
- case 'newterm-post_tag':
1354
- $name = esc_html__( 'New Tag', 'bnfw' );
1355
- break;
1356
- case 'ca-export-data':
1357
- $name = esc_html__( 'Privacy – Confirm Action: Export Data Request – For User', 'bnfw' );
1358
- break;
1359
- case 'ca-erase-data':
1360
- $name = esc_html__( 'Privacy Confirm Action: Erase Data Request – For User', 'bnfw' );
1361
- break;
1362
- case 'uc-export-data':
1363
- $name = esc_html__( 'Privacy - Confirm Action: Export Data Request - For Admin', 'bnfw' );
1364
- break;
1365
- case 'uc-erase-data':
1366
- $name = esc_html__( 'Privacy - Confirm Action: Erase Data Request - For Admin', 'bnfw' );
1367
- break;
1368
- case 'data-export':
1369
- $name = esc_html__( 'Privacy - Data Export - For User', 'bnfw' );
1370
- break;
1371
- case 'data-erased':
1372
- $name = esc_html__( 'Privacy - Data Erased - For User', 'bnfw' );
1373
- break;
1374
- case 'new-media':
1375
- $name = esc_html__( 'New Media Published', 'bnfw' );
1376
- break;
1377
- case 'update-media':
1378
- $name = esc_html__( 'Media Updated', 'bnfw' );
1379
- break;
1380
- case 'comment-attachment':
1381
- $name = esc_html__( 'Media - New Comment', 'bnfw' );
1382
- break;
1383
- case 'approve-page-comment':
1384
- $name = esc_html__( 'Page - Comment Approved', 'bnfw' );
1385
- break;
1386
- case 'approve-attachment-comment':
1387
- $name = esc_html__( 'Media - Comment Approved', 'bnfw' );
1388
- break;
1389
- case 'moderate-attachment-comment':
1390
- $name = esc_html__( 'Media - New Comment Awaiting Moderation', 'bnfw' );
1391
- break;
1392
- case 'commentreply-attachment':
1393
- $name = esc_html__( 'Media - Comment Reply', 'bnfw' );
1394
- break;
1395
-
1396
-
1397
- default:
1398
- $splited = explode( '-', $slug );
1399
- $label = $splited[1];
1400
- $post_obj = get_post_type_object( $splited[1] );
1401
-
1402
- if ( null != $post_obj ) {
1403
- $label = $post_obj->labels->singular_name;
1404
- }
1405
-
1406
- switch ( $splited[0] ) {
1407
- case 'new':
1408
- $name = esc_html__( 'New ', 'bnfw' ) . $label . ' ' . esc_html__( 'Published', 'bnfw' );
1409
- break;
1410
- case 'update':
1411
- $name = esc_html__( 'Updated ', 'bnfw' ) . $label;
1412
- break;
1413
- case 'pending':
1414
- $name = $label . esc_html__( ' Pending Review', 'bnfw' );
1415
- break;
1416
- case 'future':
1417
- $name = $label . esc_html__( ' Scheduled', 'bnfw' );
1418
- break;
1419
- case 'private':
1420
- $name = esc_html__( 'New Private ', 'bnfw' ) . $label;
1421
- break;
1422
- case 'comment':
1423
- $name = $label . esc_html__( ' Comment', 'bnfw' );
1424
- break;
1425
- case 'moderate':
1426
- $name = $label . ' - ' . esc_html__( 'New Comment Awaiting Moderation', 'bnfw' );
1427
- break;
1428
- case 'commentreply':
1429
- $name = $label . esc_html__( ' Comment Reply', 'bnfw' );
1430
- break;
1431
- case 'approve':
1432
- $name = $label . esc_html__( ' Comment Approved', 'bnfw' );
1433
- break;
1434
- case 'newterm':
1435
- $tax = get_taxonomy( $splited[1] );
1436
- if ( ! $tax ) {
1437
- $name = esc_html__( 'New Term', 'bnfw' );
1438
- } else {
1439
- $name = esc_html__( 'New Term in ', 'bnfw' ) . $tax->labels->name;
1440
- }
1441
- break;
1442
- }
1443
- break;
1444
- }
1445
-
1446
- $name = apply_filters( 'bnfw_notification_name', $name, $slug );
1447
-
1448
- return $name;
1449
- }
1450
-
1451
- /**
1452
- * Add additional custom edit actions for enabling and disabling notifications in bulk.
1453
- *
1454
- * @param array $bulk_actions Bulk Actions.
1455
- *
1456
- * @return array Modified list of Bulk Actions.
1457
- */
1458
- public function add_custom_edit_action( $bulk_actions ) {
1459
- $bulk_actions['enable_notifications'] = __( 'Enable Notifications', 'bnfw' );
1460
- $bulk_actions['disable_notifications'] = __( 'Disable Notifications', 'bnfw' );
1461
-
1462
- return $bulk_actions;
1463
- }
1464
-
1465
- /**
1466
- * Handle custom edit actions.
1467
- *
1468
- * @param $redirect_to
1469
- * @param $doaction
1470
- * @param $post_ids
1471
- *
1472
- * @return string
1473
- */
1474
- public function handle_custom_edit_action( $redirect_to, $doaction, $post_ids ) {
1475
- if ( 'enable_notifications' !== $doaction && 'disable_notifications' !== $doaction ) {
1476
- return $redirect_to;
1477
- }
1478
-
1479
- $redirect_to = remove_query_arg( array( 'bulk_enable_notifications', 'bulk_disable_notifications', 'bnfw_action' ), $redirect_to );
1480
-
1481
- $meta_value = 'true';
1482
-
1483
- if ( 'enable_notifications' === $doaction ) {
1484
- $meta_value = 'false';
1485
- }
1486
-
1487
- foreach ( $post_ids as $post_id ) {
1488
- update_post_meta( $post_id, self::META_KEY_PREFIX . 'disabled', $meta_value );
1489
- }
1490
-
1491
- $redirect_to = add_query_arg( 'bulk_' . $doaction, count( $post_ids ), $redirect_to );
1492
-
1493
- return $redirect_to;
1494
- }
1495
-
1496
- /**
1497
- * Custom row actions for this post type.
1498
- *
1499
- * @since 1.0
1500
- * @filter post_row_actions
1501
- *
1502
- * @param array $actions
1503
- * @param \WP_Post $post
1504
- *
1505
- * @return array
1506
- */
1507
- public function custom_row_actions( $actions, $post ) {
1508
- if ( self::POST_TYPE === get_post_type( $post ) ) {
1509
- unset( $actions['inline hide-if-no-js'] );
1510
- unset( $actions['view'] );
1511
-
1512
- $notification_disabled = get_post_meta( $post->ID, self::META_KEY_PREFIX . 'disabled', true );
1513
-
1514
- if ( 'true' === $notification_disabled ) {
1515
- $url = add_query_arg(
1516
- array(
1517
- 'notification_id' => $post->ID,
1518
- 'bnfw_action' => 'enable_notification',
1519
- )
1520
- );
1521
- $actions['enable_notification'] = '<a href="' . esc_url( $url ) . '">' . __( 'Enable Notification', 'bnfw' ) . '</a>';
1522
- } else {
1523
- $url = add_query_arg(
1524
- array(
1525
- 'notification_id' => $post->ID,
1526
- 'bnfw_action' => 'disable_notification',
1527
- )
1528
- );
1529
- $actions['disable_notification'] = '<a href="' . esc_url( $url ) . '">' . __( 'Disable Notification', 'bnfw' ) . '</a>';
1530
- }
1531
- }
1532
-
1533
- return $actions;
1534
- }
1535
-
1536
- /**
1537
- * Handle custom actions.
1538
- */
1539
- public function handle_actions() {
1540
- if ( ! isset( $_GET['bnfw_action'] ) || ! isset( $_GET['notification_id'] ) ) {
1541
- return;
1542
- }
1543
-
1544
- $post_id = absint( $_GET['notification_id'] );
1545
- if ( 0 === $post_id ) {
1546
- return;
1547
- }
1548
-
1549
- $action = sanitize_text_field( $_GET['bnfw_action'] );
1550
-
1551
- if ( 'enable_notification' === $action ) {
1552
- update_post_meta( $post_id, self::META_KEY_PREFIX . 'disabled', 'false' );
1553
- }
1554
-
1555
- if ( 'disable_notification' === $action ) {
1556
- update_post_meta( $post_id, self::META_KEY_PREFIX . 'disabled', 'true' );
1557
- }
1558
- }
1559
-
1560
- /**
1561
- * Find if a string starts with another string.
1562
- *
1563
- * @since 1.2
1564
- *
1565
- * @param $haystack
1566
- * @param $needle
1567
- *
1568
- * @return bool
1569
- */
1570
- public function starts_with( $haystack, $needle ) {
1571
- // search backwards starting from haystack length characters from the end
1572
- return '' === $needle || strrpos( $haystack, $needle, - strlen( $haystack ) ) !== false;
1573
- }
1574
-
1575
- /**
1576
- * Display a help notice.
1577
- *
1578
- * @since 1.7
1579
- */
1580
- public function show_help_notice() {
1581
- $screen = get_current_screen();
1582
- if ( ! in_array( $screen->post_type, array( self::POST_TYPE ) ) ) {
1583
- return;
1584
- }
1585
-
1586
- if ( ! empty( $_REQUEST['bnfw_action'] ) && 'enable_notification' === $_REQUEST['bnfw_action'] ) {
1587
- echo '<div id="message" class="updated fade"><p>' . __( 'Enabled 1 Notification.', 'bnfw' ) . '</p></div>';
1588
- }
1589
-
1590
- if ( ! empty( $_REQUEST['bnfw_action'] ) && 'disable_notification' === $_REQUEST['bnfw_action'] ) {
1591
- echo '<div id="message" class="updated fade"><p>' . __( 'Disabled 1 Notification.', 'bnfw' ) . '</p></div>';
1592
- }
1593
-
1594
- if ( ! empty( $_REQUEST['bulk_enable_notifications'] ) ) {
1595
- $enabled_count = intval( $_REQUEST['bulk_enable_notifications'] );
1596
- printf( '<div id="message" class="updated fade"><p>' .
1597
- _n( 'Enabled %s Notification.',
1598
- 'Enabled %s Notifications.',
1599
- $enabled_count,
1600
- 'bnfw'
1601
- ) . '</p></div>', $enabled_count );
1602
- }
1603
-
1604
- if ( ! empty( $_REQUEST['bulk_disable_notifications'] ) ) {
1605
- $disabled_count = intval( $_REQUEST['bulk_disable_notifications'] );
1606
- printf( '<div id="message" class="updated fade"><p>' .
1607
- _n( 'Disabled %s Notification.',
1608
- 'Disabled %s Notifications.',
1609
- $disabled_count,
1610
- 'bnfw'
1611
- ) . '</p></div>', $disabled_count );
1612
- }
1613
-
1614
- if ( ! PAnD::is_admin_notice_active( 'disable-bnfw-help-notice-forever' ) ) {
1615
- return;
1616
- }
1617
-
1618
- ?>
1619
- <div data-dismissible="disable-bnfw-help-notice-forever" class="updated notice notice-success is-dismissible">
1620
- <p>
1621
- <?php _e( 'If you send out notifications with BNFW but don\'t receive them, you may need to install an SMTP plugin to <a href="https://betternotificationsforwp.com/documentation/getting-started/how-to-improve-email-delivery/" target="_blank">improve email deliverability</a>. I recommend using <a href="https://wordpress.org/plugins/post-smtp/" target="_blank">Post SMTP</a> as it\'s easy to set-up or <a href="https://wordpress.org/plugins/email-log/" target="_blank">Email Log</a> to just log and view emails that are sent.', 'bnfw' ); ?>
1622
- </p>
1623
- </div>
1624
- <?php
1625
- }
1626
-
1627
- /**
1628
- * Should the users count message be shown?
1629
- *
1630
- * @since 1.7
1631
- *
1632
- * @param array $setting Notification Setting.
1633
- *
1634
- * @return bool True if message should be shown.
1635
- */
1636
- protected function should_show_users_count_msg( $setting ) {
1637
- $users = $setting['users'];
1638
-
1639
- if ( count( $users ) > 200 ) {
1640
- return true;
1641
- }
1642
-
1643
- $emails = BNFW::factory()->engine->get_emails_from_users( $users );
1644
-
1645
- if ( count( $emails ) > 200 ) {
1646
- return true;
1647
- }
1648
-
1649
- return false;
1650
- }
1651
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BNFW Notification.
4
+ *
5
+ * @since 1.0
6
+ * @package bnfw
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ if ( ! class_exists( 'BNFW_Notification', false ) ) {
12
+ /**
13
+ * BNFW Notification class.
14
+ */
15
+ class BNFW_Notification {
16
+
17
+ const POST_TYPE = 'bnfw_notification';
18
+ const META_KEY_PREFIX = 'bnfw_';
19
+ const TEST_MAIL_ARG = 'test-mail';
20
+
21
+ /**
22
+ * Class contructor.
23
+ */
24
+ public function __construct() {
25
+ add_action( 'init', array( $this, 'register_post_type' ) );
26
+ add_action( 'do_meta_boxes', array( $this, 'remove_meta_boxes' ) );
27
+ add_action( 'add_meta_boxes_' . self::POST_TYPE, array( $this, 'add_meta_boxes' ) );
28
+ add_action( 'save_post', array( $this, 'save_meta_data' ) );
29
+ add_action( 'edit_form_top', array( $this, 'admin_notices' ) );
30
+ add_filter( 'post_updated_messages', array( $this, 'post_updated_messages' ) );
31
+
32
+ add_filter( 'use_block_editor_for_post_type', array( $this, 'disable_gutenberg_for_notification' ), 10, 2 );
33
+
34
+ add_filter( 'bulk_actions-edit-bnfw_notification', array( $this, 'add_custom_edit_action' ) );
35
+ add_filter( 'handle_bulk_actions-edit-bnfw_notification', array( $this, 'handle_custom_edit_action' ), 10, 3 );
36
+
37
+ // Custom row actions.
38
+ add_filter( 'post_row_actions', array( $this, 'custom_row_actions' ), 10, 2 );
39
+ add_action( 'admin_init', array( $this, 'handle_actions' ) );
40
+
41
+ // Custom columns.
42
+ add_filter( sprintf( 'manage_%s_posts_columns', self::POST_TYPE ), array( $this, 'columns_header' ) );
43
+ add_action( sprintf( 'manage_%s_posts_custom_column', self::POST_TYPE ), array( $this, 'custom_column_row' ), 10, 2 );
44
+
45
+ // Enqueue scripts/styles and disables autosave for this post type.
46
+ add_action( 'admin_enqueue_scripts', array( $this, 'is_assets_needed' ) );
47
+
48
+ add_action( 'admin_notices', array( $this, 'show_help_notice' ) );
49
+
50
+ add_action( 'admin_print_scripts', array( $this, 'gutenberg_flag' ) );
51
+ }
52
+
53
+ /**
54
+ * Flag variable to check if gutenberge is active.
55
+ * added fix for gutenberg.
56
+ *
57
+ * @since 1.3
58
+ */
59
+ public function gutenberg_flag() {
60
+ $bnfw = BNFW::Factory();
61
+ ?>
62
+ <script type="text/javascript">
63
+ var bnfw_gutenberge_is_active = <?php echo ( $bnfw->is_gutenberg_active() ) ? 'true;' : 'false;'; ?>
64
+ </script>
65
+ <?php
66
+ }
67
+
68
+
69
+ /**
70
+ * Register bnfw_notification custom post type.
71
+ *
72
+ * @since 1.0
73
+ */
74
+ public function register_post_type() {
75
+ register_post_type(
76
+ self::POST_TYPE,
77
+ array(
78
+ 'labels' => array(
79
+ 'name' => esc_html__( 'Notifications', 'bnfw' ),
80
+ 'singular_name' => esc_html__( 'Notification', 'bnfw' ),
81
+ 'add_new' => esc_html__( 'Add New', 'bnfw' ),
82
+ 'menu_name' => esc_html__( 'Notifications', 'bnfw' ),
83
+ 'name_admin_bar' => esc_html__( 'Notifications', 'bnfw' ),
84
+ 'add_new_item' => esc_html__( 'Add New Notification', 'bnfw' ),
85
+ 'edit_item' => esc_html__( 'Edit Notification', 'bnfw' ),
86
+ 'new_item' => esc_html__( 'New Notification', 'bnfw' ),
87
+ 'view_item' => esc_html__( 'View Notification', 'bnfw' ),
88
+ 'search_items' => esc_html__( 'Search Notifications', 'bnfw' ),
89
+ 'not_found' => esc_html__( 'No Notifications found', 'bnfw' ),
90
+ 'not_found_in_trash' => esc_html__( 'No Notifications found in trash', 'bnfw' ),
91
+ 'all_items' => esc_html__( 'All Notifications', 'bnfw' ),
92
+ ),
93
+ 'public' => false,
94
+ 'show_in_nav_menus' => true,
95
+ 'show_in_admin_bar' => true,
96
+ 'has_archive' => false,
97
+ 'show_ui' => true,
98
+ 'show_in_menu' => true,
99
+ 'menu_icon' => 'dashicons-email-alt',
100
+ 'menu_position' => 101,
101
+ 'rewrite' => false,
102
+ 'map_meta_cap' => false,
103
+ 'capabilities' => array(
104
+ // meta caps (don't assign these to roles).
105
+ 'edit_post' => 'bnfw',
106
+ 'read_post' => 'bnfw',
107
+ 'delete_post' => 'bnfw',
108
+
109
+ // primitive/meta caps.
110
+ 'create_posts' => 'bnfw',
111
+
112
+ // primitive caps used outside of map_meta_cap().
113
+ 'edit_posts' => 'bnfw',
114
+ 'edit_others_posts' => 'bnfw',
115
+ 'publish_posts' => 'bnfw',
116
+ 'read_private_posts' => 'bnfw',
117
+
118
+ // primitive caps used inside of map_meta_cap().
119
+ 'read' => 'bnfw',
120
+ 'delete_posts' => 'bnfw',
121
+ 'delete_private_posts' => 'bnfw',
122
+ 'delete_published_posts' => 'bnfw',
123
+ 'delete_others_posts' => 'bnfw',
124
+ 'edit_private_posts' => 'bnfw',
125
+ 'edit_published_posts' => 'bnfw',
126
+ ),
127
+ // What features the post type supports.
128
+ 'supports' => array(
129
+ 'title',
130
+ ),
131
+ )
132
+ );
133
+ }
134
+
135
+ /**
136
+ * Remove unwanted meta boxes.
137
+ *
138
+ * @since 1.0
139
+ */
140
+ public function remove_meta_boxes() {
141
+ remove_meta_box( 'submitdiv', self::POST_TYPE, 'side' );
142
+ remove_meta_box( 'slugdiv', self::POST_TYPE, 'normal' );
143
+ }
144
+
145
+ /**
146
+ * Add meta box to the post editor screen.
147
+ *
148
+ * @since 1.0
149
+ */
150
+ public function add_meta_boxes() {
151
+ global $post;
152
+
153
+ add_meta_box(
154
+ 'bnfw-post-notification', // Unique ID.
155
+ esc_html__( 'Notification Settings', 'bnfw' ), // Title.
156
+ array( $this, 'render_settings_meta_box' ), // Callback function.
157
+ self::POST_TYPE, // Admin page (or post type).
158
+ 'normal', // Context.
159
+ 'default'
160
+ );
161
+
162
+ add_meta_box(
163
+ 'bnfw_submitdiv',
164
+ __( 'Save Notification', 'bnfw' ),
165
+ array( $this, 'render_submitdiv' ),
166
+ self::POST_TYPE,
167
+ 'side',
168
+ 'core'
169
+ );
170
+
171
+ if ( self::POST_TYPE !== get_post_type( $post ) ) {
172
+ return;
173
+ }
174
+
175
+ do_action( 'bnfw_after_metaboxes', $this->read_settings( $post->ID ) );
176
+ }
177
+
178
+ /**
179
+ * Disable Gutenberg for notifications.
180
+ *
181
+ * @param bool $is_enabled Is Gutenberg enabled?.
182
+ * @param string $post_type Post Type.
183
+ *
184
+ * @return bool Should Gutenberg be enabled?
185
+ */
186
+ public function disable_gutenberg_for_notification( $is_enabled, $post_type ) {
187
+ if ( self::POST_TYPE === $post_type ) {
188
+ return false;
189
+ }
190
+
191
+ return $is_enabled;
192
+ }
193
+
194
+ /**
195
+ * Render the settings meta box.
196
+ *
197
+ * @since 1.0
198
+ *
199
+ * @param WP_Post $post The post object.
200
+ */
201
+ public function render_settings_meta_box( $post ) {
202
+ global $wp_version;
203
+
204
+ wp_nonce_field( self::POST_TYPE, self::POST_TYPE . '_nonce' );
205
+
206
+ $setting = $this->read_settings( $post->ID );
207
+ ?>
208
+ <table class="form-table">
209
+ <tbody>
210
+ <tr valign="top">
211
+ <th scope="row">
212
+ <label for="notification"><?php esc_html_e( 'Notification For', 'bnfw' ); ?></label>
213
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'E.g. If you select "New Post Published" from the list on the right, this notification will be sent when a new post is published.', 'bnfw' ); ?></p></div>
214
+ </th>
215
+ <td>
216
+ <select name="notification" id="notification" class="select2"
217
+ data-placeholder="<?php esc_attr_e( 'Select the notification type', 'bnfw' ); ?>" style="width:75%">
218
+ <optgroup label="<?php esc_html_e( 'Admin', 'bnfw' ); ?>">
219
+ <option
220
+ value="admin-user" <?php selected( 'admin-user', $setting['notification'] ); ?>><?php esc_html_e( 'New User Registration - For Admin', 'bnfw' ); ?></option>
221
+ <option
222
+ value="admin-password" <?php selected( 'admin-password', $setting['notification'] ); ?>><?php esc_html_e( 'User Lost Password - For Admin', 'bnfw' ); ?></option>
223
+ <option
224
+ value="admin-password-changed" <?php selected( 'admin-password-changed', $setting['notification'] ); ?>><?php esc_html_e( 'Password Changed - For Admin', 'bnfw' ); ?></option>
225
+ <option
226
+ value="admin-email-changed" <?php selected( 'admin-email-changed', $setting['notification'] ); ?>><?php esc_html_e( 'User Email Changed - For Admin', 'bnfw' ); ?></option>
227
+ <option
228
+ value="admin-role" <?php selected( 'admin-role', $setting['notification'] ); ?>><?php esc_html_e( 'User Role Changed - For Admin', 'bnfw' ); ?></option>
229
+ <option
230
+ value="admin-user-login" <?php selected( 'admin-user-login', $setting['notification'] ); ?>><?php esc_html_e( 'User Logged In - For Admin', 'bnfw' ); ?></option>
231
+ <option
232
+ value="core-updated" <?php selected( 'core-updated', $setting['notification'] ); ?>><?php esc_html_e( 'WordPress Core Automatic Background Updates', 'bnfw' ); ?></option>
233
+
234
+ <?php if ( version_compare( $wp_version, '4.9.6' ) >= 0 ) : ?>
235
+ <option value="uc-export-data" <?php selected( 'uc-export-data', $setting['notification'] ); ?>>
236
+ <?php esc_html_e( 'Privacy - Confirm Action: Export Data Request - For Admin', 'bnfw' ); ?>
237
+ </option>
238
+
239
+ <option value="uc-erase-data" <?php selected( 'uc-erase-data', $setting['notification'] ); ?>>
240
+ <?php esc_html_e( 'Privacy - Confirm Action: Erase Data Request - For Admin', 'bnfw' ); ?>
241
+ </option>
242
+ <?php endif; ?>
243
+
244
+ <?php do_action( 'bnfw_after_default_notifications', $setting ); ?>
245
+ </optgroup>
246
+ <?php do_action( 'bnfw_after_default_notifications_optgroup', $setting ); ?>
247
+
248
+ <optgroup label="<?php esc_attr_e( 'Transactional', 'bnfw' ); ?>">
249
+ <option
250
+ value="new-user" <?php selected( 'new-user', $setting['notification'] ); ?>><?php esc_html_e( 'New User Registration - For User', 'bnfw' ); ?></option>
251
+ <option
252
+ value="welcome-email" <?php selected( 'welcome-email', $setting['notification'] ); ?>><?php esc_html_e( 'New User - Post-registration Email', 'bnfw' ); ?></option>
253
+ <option
254
+ value="user-password" <?php selected( 'user-password', $setting['notification'] ); ?>><?php esc_html_e( 'User Lost Password - For User', 'bnfw' ); ?></option>
255
+ <option
256
+ value="password-changed" <?php selected( 'password-changed', $setting['notification'] ); ?>><?php esc_html_e( 'Password Changed - For User', 'bnfw' ); ?></option>
257
+ <option value="email-changing" <?php selected( 'email-changing', $setting['notification'] ); ?>>
258
+ <?php esc_html_e( 'User Email Changed Confirmation - For User', 'bnfw' ); ?>
259
+ </option>
260
+ <option
261
+ value="email-changed" <?php selected( 'email-changed', $setting['notification'] ); ?>><?php esc_html_e( 'User Email Changed - For User', 'bnfw' ); ?></option>
262
+ <option
263
+ value="user-role" <?php selected( 'user-role', $setting['notification'] ); ?>><?php esc_html_e( 'User Role Changed - For User', 'bnfw' ); ?></option>
264
+ <option
265
+ value="user-login" <?php selected( 'user-login', $setting['notification'] ); ?>><?php esc_html_e( 'User Logged In - For User', 'bnfw' ); ?></option>
266
+ <option
267
+ value="reply-comment" <?php selected( 'reply-comment', $setting['notification'] ); ?>><?php esc_html_e( 'Comment Reply', 'bnfw' ); ?></option>
268
+
269
+ <?php if ( version_compare( $wp_version, '4.9.6' ) >= 0 ) : ?>
270
+ <option value="ca-export-data" <?php selected( 'ca-export-data', $setting['notification'] ); ?>>
271
+ <?php esc_html_e( 'Privacy - Confirm Action: Export Data Request - For User', 'bnfw' ); ?>
272
+ </option>
273
+
274
+ <option value="ca-erase-data" <?php selected( 'ca-erase-data', $setting['notification'] ); ?>>
275
+ <?php esc_html_e( 'Privacy - Confirm Action: Erase Data Request - For User', 'bnfw' ); ?>
276
+ </option>
277
+
278
+ <option value="data-export" <?php selected( 'data-export', $setting['notification'] ); ?>>
279
+ <?php esc_html_e( 'Privacy - Data Export - For User', 'bnfw' ); ?>
280
+ </option>
281
+
282
+ <option value="data-erased" <?php selected( 'data-erased', $setting['notification'] ); ?>>
283
+ <?php esc_html_e( 'Privacy - Data Erased - For User', 'bnfw' ); ?>
284
+ </option>
285
+ <?php endif; ?>
286
+
287
+ <?php do_action( 'bnfw_after_transactional_notifications', $setting ); ?>
288
+ </optgroup>
289
+ <?php do_action( 'bnfw_after_transactional_notifications_optgroup', $setting ); ?>
290
+
291
+ <optgroup label="Posts">
292
+ <option
293
+ value="new-post" <?php selected( 'new-post', $setting['notification'] ); ?>><?php esc_html_e( 'New Post Published', 'bnfw' ); ?></option>
294
+ <option
295
+ value="update-post" <?php selected( 'update-post', $setting['notification'] ); ?>><?php esc_html_e( 'Post Updated', 'bnfw' ); ?></option>
296
+ <option
297
+ value="pending-post" <?php selected( 'pending-post', $setting['notification'] ); ?>><?php esc_html_e( 'Post Pending Review', 'bnfw' ); ?></option>
298
+ <option
299
+ value="private-post" <?php selected( 'private-post', $setting['notification'] ); ?>><?php esc_html_e( 'New Private Post', 'bnfw' ); ?></option>
300
+ <option
301
+ value="future-post" <?php selected( 'future-post', $setting['notification'] ); ?>><?php esc_html_e( 'Post Scheduled', 'bnfw' ); ?></option>
302
+ <option
303
+ value="trash-post" <?php selected( 'trash-post', $setting['notification'] ); ?>><?php esc_html_e( 'Published Post Moved to Trash', 'bnfw' ); ?></option>
304
+ <option value="new-comment" <?php selected( 'new-comment', $setting['notification'] ); ?>>
305
+ <?php esc_html_e( 'New Comment', 'bnfw' ); ?>
306
+ </option>
307
+ <option value="moderate-post-comment" <?php selected( 'moderate-post-comment', $setting['notification'] ); ?>>
308
+ <?php esc_html_e( 'New Comment Awaiting Moderation', 'bnfw' ); ?>
309
+ </option>
310
+ <option value="approve-post-comment" <?php selected( 'approve-post-comment', $setting['notification'] ); ?>>
311
+ <?php esc_html_e( 'Post - Comment Approved', 'bnfw' ); ?>
312
+ </option>
313
+ <option
314
+ value="newterm-category" <?php selected( 'newterm-category', $setting['notification'] ); ?>><?php esc_html_e( 'New Category', 'bnfw' ); ?></option>
315
+ <option
316
+ value="newterm-post_tag" <?php selected( 'newterm-post_tag', $setting['notification'] ); ?>><?php esc_html_e( 'New Tag', 'bnfw' ); ?></option>
317
+ <option
318
+ value="new-trackback" <?php selected( 'new-trackback', $setting['notification'] ); ?>><?php esc_html_e( 'New Trackback', 'bnfw' ); ?></option>
319
+ <option
320
+ value="new-pingback" <?php selected( 'new-pingback', $setting['notification'] ); ?>><?php esc_html_e( 'New Pingback', 'bnfw' ); ?></option>
321
+ <?php do_action( 'bnfw_after_notification_options', 'post', 'Post', $setting ); ?>
322
+ </optgroup>
323
+ <?php do_action( 'bnfw_after_notification_options_optgroup', 'post', 'Post', $setting ); ?>
324
+
325
+ <optgroup label="Page">
326
+ <option
327
+ value="new-page" <?php selected( 'new-page', $setting['notification'] ); ?>><?php esc_html_e( 'New Page Published', 'bnfw' ); ?></option>
328
+ <option
329
+ value="update-page" <?php selected( 'update-page', $setting['notification'] ); ?>><?php esc_html_e( 'Page Updated', 'bnfw' ); ?></option>
330
+ <option
331
+ value="pending-page" <?php selected( 'pending-page', $setting['notification'] ); ?>><?php esc_html_e( 'Page Pending Review', 'bnfw' ); ?></option>
332
+ <option
333
+ value="private-page" <?php selected( 'private-page', $setting['notification'] ); ?>><?php esc_html_e( 'New Private Page', 'bnfw' ); ?></option>
334
+ <option
335
+ value="future-page" <?php selected( 'future-page', $setting['notification'] ); ?>><?php esc_html_e( 'Page Scheduled', 'bnfw' ); ?></option>
336
+ <option
337
+ value="comment-page" <?php selected( 'comment-page', $setting['notification'] ); ?>><?php esc_html_e( 'Page - New Comment', 'bnfw' ); ?></option>
338
+ <option value="moderate-page-comment" <?php selected( 'moderate-page-comment', $setting['notification'] ); ?>>
339
+ <?php esc_html_e( 'Page - New Comment Awaiting Moderation', 'bnfw' ); ?>
340
+ </option>
341
+ <option value="approve-page-comment" <?php selected( 'approve-page-comment', $setting['notification'] ); ?>>
342
+ <?php esc_html_e( 'Page - Comment Approved', 'bnfw' ); ?>
343
+ </option>
344
+ <option
345
+ value="commentreply-page" <?php selected( 'commentreply-page', $setting['notification'] ); ?>><?php esc_html_e( 'Page - Comment Reply', 'bnfw' ); ?></option>
346
+ <?php do_action( 'bnfw_after_notification_options', 'page', 'Page', $setting ); ?>
347
+ </optgroup>
348
+ <?php do_action( 'bnfw_after_notification_options_optgroup', 'page', 'Page', $setting ); ?>
349
+
350
+ <optgroup label="Media">
351
+ <option
352
+ value="new-media" <?php selected( 'new-media', $setting['notification'] ); ?>><?php esc_html_e( 'New Media Published', 'bnfw' ); ?></option>
353
+ <option
354
+ value="update-media" <?php selected( 'update-media', $setting['notification'] ); ?>><?php esc_html_e( 'Media Updated', 'bnfw' ); ?></option>
355
+ <option
356
+ value="comment-attachment" <?php selected( 'comment-attachment', $setting['notification'] ); ?>><?php esc_html_e( 'Media - New Comment', 'bnfw' ); ?></option>
357
+ <option value="approve-attachment-comment" <?php selected( 'approve-attachment-comment', $setting['notification'] ); ?>>
358
+ <?php esc_html_e( 'Media - Comment Approved', 'bnfw' ); ?>
359
+ </option>
360
+ <option value="moderate-attachment-comment" <?php selected( 'moderate-attachment-comment', $setting['notification'] ); ?>>
361
+ <?php esc_html_e( 'Media - New Comment Awaiting Moderation', 'bnfw' ); ?></option>
362
+ <option
363
+ value="commentreply-attachment" <?php selected( 'commentreply-attachment', $setting['notification'] ); ?>><?php esc_html_e( 'Media - Comment Reply', 'bnfw' ); ?></option>
364
+ <?php do_action( 'bnfw_after_notification_options', 'media', 'Media', $setting ); ?>
365
+ </optgroup>
366
+ <?php do_action( 'bnfw_after_notification_options_optgroup', 'media', 'Media', $setting ); ?>
367
+
368
+ <?php
369
+ $types = apply_filters(
370
+ 'bnfw_notification_dropdown_posttypes',
371
+ get_post_types(
372
+ array(
373
+ 'public' => true,
374
+ '_builtin' => false,
375
+ ),
376
+ 'names'
377
+ )
378
+ );
379
+
380
+ foreach ( $types as $type ) {
381
+ if ( self::POST_TYPE !== $type ) {
382
+ $post_obj = get_post_type_object( $type );
383
+ $label = $post_obj->labels->singular_name;
384
+ ?>
385
+ <optgroup
386
+ label="<?php esc_attr( /* translators: %s Custom post type lable name. */ printf( "%s - '%s'", esc_html__( 'Custom Post Type', 'bnfw' ), esc_html( $label ) ) ); ?>">
387
+ <option
388
+ value="new-<?php echo esc_attr( $type ); ?>" <?php selected( 'new-' . $type, $setting['notification'] ); ?>><?php echo esc_html__( 'New ', 'bnfw' ), "'" . esc_html( $label ) . "'", esc_html__( ' Published', 'bnfw' ); ?></option>
389
+ <option
390
+ value="update-<?php echo esc_attr( $type ); ?>" <?php selected( 'update-' . $type, $setting['notification'] ); ?>><?php echo "'" . esc_html( $label ) . "' " . esc_html__( 'Updated', 'bnfw' ); ?></option>
391
+ <option
392
+ value="pending-<?php echo esc_attr( $type ); ?>" <?php selected( 'pending-' . $type, $setting['notification'] ); ?>><?php echo "'" . esc_html( $label ) . "' ", esc_html__( 'Pending Review', 'bnfw' ); ?></option>
393
+ <option
394
+ value="private-<?php echo esc_attr( $type ); ?>" <?php selected( 'private-' . $type, $setting['notification'] ); ?>><?php echo esc_html__( 'New Private ', 'bnfw' ), "'" . esc_html( $label ) . "'"; ?></option>
395
+ <option
396
+ value="future-<?php echo esc_attr( $type ); ?>" <?php selected( 'future-' . $type, $setting['notification'] ); ?>><?php echo "'" . esc_html( $label ) . "' ", esc_html__( 'Scheduled', 'bnfw' ); ?></option>
397
+ <option
398
+ value="comment-<?php echo esc_attr( $type ); ?>" <?php selected( 'comment-' . $type, $setting['notification'] ); ?>><?php echo "'" . esc_html( $label ) . "' ", esc_html__( 'New Comment', 'bnfw' ); ?></option>
399
+ <option value="moderate-<?php echo esc_attr( $type ); ?>-comment" <?php selected( 'moderate-' . $type . '-comment', $setting['notification'] ); ?>>
400
+ <?php echo "'" . esc_html( $label ) . "' - ", esc_html__( 'New Comment Awaiting Moderation', 'bnfw' ); ?>
401
+ </option>
402
+ <option value="approve-<?php echo esc_attr( $type ); ?>-comment" <?php selected( 'approve-' . $type . '-comment', $setting['notification'] ); ?>>
403
+ <?php echo "'" . esc_html( $label ) . "' - ", esc_html__( 'Comment Approved', 'bnfw' ); ?>
404
+ </option>
405
+ <option
406
+ value="commentreply-<?php echo esc_attr( $type ); ?>" <?php selected( 'commentreply-' . $type, $setting['notification'] ); ?>><?php echo "'" . esc_html( $label ) . "' ", esc_html__( 'Comment Reply', 'bnfw' ); ?></option>
407
+ <?php do_action( 'bnfw_after_notification_options', $type, $label, $setting ); ?>
408
+ </optgroup>
409
+ <?php do_action( 'bnfw_after_notification_options_optgroup', $type, $label, $setting ); ?>
410
+
411
+ <?php
412
+ }
413
+ }
414
+
415
+ $taxs = apply_filters(
416
+ 'bnfw_notification_dropdown_taxonomies',
417
+ get_taxonomies(
418
+ array(
419
+ 'public' => true,
420
+ '_builtin' => false,
421
+ ),
422
+ 'objects'
423
+ )
424
+ );
425
+
426
+ if ( count( $taxs ) > 0 ) {
427
+ ?>
428
+ <optgroup label="<?php esc_html_e( 'Custom Taxonomy', 'bnfw' ); ?>">
429
+ <?php
430
+ foreach ( $taxs as $tax ) {
431
+ $tax_name = 'newterm-' . $tax->name;
432
+ ?>
433
+ <option
434
+ value="<?php echo esc_attr( $tax_name ); ?>" <?php selected( $tax_name, $setting['notification'] ); ?>><?php printf( "%s '%s'", esc_html__( 'New', 'bnfw' ), esc_attr( $tax->labels->name ) ); ?></option>
435
+ <?php
436
+ }
437
+ ?>
438
+ </optgroup>
439
+ <?php
440
+ }
441
+ do_action( 'bnfw_after_notification_optgroups', $setting );
442
+ ?>
443
+ </select>
444
+ </td>
445
+ </tr>
446
+
447
+ <?php do_action( 'bnfw_after_notification_dropdown', $setting ); ?>
448
+
449
+ <tr valign="top" id="user-password-msg">
450
+ <td>&nbsp;</td>
451
+ <td>
452
+ <div>
453
+ <p style="margin-top: 0;"><?php esc_html_e( "This notification doesn't support additional email fields due to a limitation in WordPress.", 'bnfw' ); ?></p>
454
+ </div>
455
+ </td>
456
+ </tr>
457
+
458
+ <tr valign="top" id="email-formatting">
459
+ <th>
460
+ <?php esc_html_e( 'Email Formatting', 'bnfw' ); ?>
461
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'How do you want to format the sent email? HTML is recommended as it\'ll show images and links correctly.', 'bnfw' ); ?></p></div>
462
+ </th>
463
+ <td>
464
+ <label style="margin-right: 20px;">
465
+ <input type="radio" name="email-formatting"
466
+ value="html" <?php checked( 'html', $setting['email-formatting'] ); ?>>
467
+ <?php esc_html_e( 'HTML Formatting', 'bnfw' ); ?>
468
+ </label>
469
+
470
+ <label>
471
+ <input type="radio" name="email-formatting"
472
+ value="text" <?php checked( 'text', $setting['email-formatting'] ); ?>>
473
+ <?php esc_html_e( 'Plain Text', 'bnfw' ); ?>
474
+ </label>
475
+ </td>
476
+ </tr>
477
+
478
+ <?php do_action( 'bnfw_after_email_formatting', $setting ); ?>
479
+
480
+ <tr valign="top" id="toggle-fields">
481
+ <th>
482
+ <?php esc_html_e( 'Additional Email Fields', 'bnfw' ); ?>
483
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'This should be fairly self explanatory but if you\'re unsure, tick this checkbox and have a look at the available options. You can always untick it again should you decide you don\'t need to use it.', 'bnfw' ); ?></p></div>
484
+ </th>
485
+ <td>
486
+ <input type="checkbox" id="show-fields" name="show-fields"
487
+ value="true" <?php checked( $setting['show-fields'], 'true', true ); ?>>
488
+ <label for="show-fields"><?php esc_html_e( 'Set "From" Name & Email, Reply To, CC, BCC', 'bnfw' ); ?></label>
489
+ </td>
490
+ </tr>
491
+
492
+
493
+ <tr valign="top" id="email">
494
+ <th scope="row">
495
+ <?php esc_html_e( 'From Name and Email', 'bnfw' ); ?>
496
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'If you want to send the email from your site name and email address instead of the default "WordPress" from "wordpress@domain.com", this is where you can do it.', 'bnfw' ); ?></p></div>
497
+ </th>
498
+ <td>
499
+ <input type="text" name="from-name" value="<?php echo esc_attr( $setting['from-name'] ); ?>"
500
+ placeholder="<?php esc_attr_e( 'Site Name', 'bnfw' ); ?>" style="width: 37.35%">
501
+ <input type="text" name="from-email" value="<?php echo esc_attr( $setting['from-email'] ); ?>"
502
+ placeholder="<?php esc_attr_e( 'Site Email', 'bnfw' ); ?>" style="width: 37.3%">
503
+ </td>
504
+ </tr>
505
+
506
+
507
+ <tr valign="top" id="reply">
508
+ <th scope="row">
509
+ <?php esc_html_e( 'Reply To', 'bnfw' ); ?>
510
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'If you want any replies to your email notification to go to another person, fill in this box with their name and email address.', 'bnfw' ); ?></p></div>
511
+ </th>
512
+ <td>
513
+ <input type="text" name="reply-name" value="<?php echo esc_attr( $setting['reply-name'] ); ?>"
514
+ placeholder="<?php esc_attr_e( 'Name', 'bnfw' ); ?>" style="width: 37.35%">
515
+ <input type="text" name="reply-email" value="<?php echo esc_attr( $setting['reply-email'] ); ?>"
516
+ placeholder="<?php esc_attr_e( 'Email', 'bnfw' ); ?>" style="width: 37.3%">
517
+ </td>
518
+ </tr>
519
+
520
+ <tr valign="top" id="cc">
521
+ <th scope="row">
522
+ <?php esc_html_e( 'CC', 'bnfw' ); ?>
523
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'Publicly copy in any other users or user roles to this email.', 'bnfw' ); ?></p></div>
524
+ </th>
525
+
526
+ <td>
527
+ <select multiple name="cc[]" class="<?php echo sanitize_html_class( bnfw_get_user_select_class() ); ?>"
528
+ data-placeholder="<?php echo esc_attr( apply_filters( 'bnfw_email_dropdown_placeholder', __( 'Select User Roles / Users', 'bnfw' ) ) ); ?>" style="width:75%">
529
+ <?php bnfw_render_users_dropdown( $setting['cc'] ); ?>
530
+ </select>
531
+ </td>
532
+ </tr>
533
+
534
+ <tr valign="top" id="bcc">
535
+ <th scope="row">
536
+ <?php esc_html_e( 'BCC', 'bnfw' ); ?>
537
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'Privately copy in any other users or user roles to this email.', 'bnfw' ); ?></p></div>
538
+ </th>
539
+
540
+ <td>
541
+ <select multiple name="bcc[]" class="<?php echo sanitize_html_class( bnfw_get_user_select_class() ); ?>"
542
+ data-placeholder="<?php echo esc_attr( apply_filters( 'bnfw_email_dropdown_placeholder', __( 'Select User Roles / Users', 'bnfw' ) ) ); ?>" style="width:75%">
543
+ <?php bnfw_render_users_dropdown( $setting['bcc'] ); ?>
544
+ </select>
545
+ </td>
546
+ </tr>
547
+
548
+ <?php do_action( 'bnfw_after_additional_email_fields', $setting ); ?>
549
+
550
+ <tr valign="top" id="post-author">
551
+ <th>
552
+ <?php esc_html_e( 'Send to Author', 'bnfw' ); ?>
553
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'E.g. If you want a new post published notification to go to the post author, tick this box.', 'bnfw' ); ?></p></div>
554
+ </th>
555
+
556
+ <td>
557
+ <label>
558
+ <input type="checkbox" id="only-post-author" name="only-post-author"
559
+ value="true" <?php checked( 'true', $setting['only-post-author'] ); ?>>
560
+ <?php esc_html_e( 'Send this notification to the Author', 'bnfw' ); ?>
561
+ </label>
562
+ </td>
563
+ </tr>
564
+
565
+ <?php do_action( 'bnfw_after_only_post_author', $setting ); ?>
566
+
567
+ <tr valign="top" id="current-user">
568
+ <th>
569
+ &nbsp;
570
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'E.g. If you\'re an editor and regularly update your posts, you might not want to be emailed about this all the time. Ticking this box will prevent you from receiving emails about your own changes.', 'bnfw' ); ?></p></div>
571
+ </th>
572
+ <td>
573
+ <label>
574
+ <input type="checkbox" name="disable-current-user"
575
+ value="true" <?php checked( 'true', $setting['disable-current-user'] ); ?>>
576
+ <?php esc_html_e( 'Do not send this Notification to the User that triggered it', 'bnfw' ); ?>
577
+ </label>
578
+ </td>
579
+ </tr>
580
+
581
+ <?php do_action( 'bnfw_after_disable_current_user', $setting ); ?>
582
+
583
+ <tr valign="top" id="users">
584
+ <th scope="row">
585
+ <?php esc_html_e( 'Send To', 'bnfw' ); ?>
586
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'Choose the users and/or user roles to send this email notification to.', 'bnfw' ); ?></p></div>
587
+ </th>
588
+ <td>
589
+ <select multiple id="users-select" name="users[]"
590
+ class="<?php echo sanitize_html_class( bnfw_get_user_select_class() ); ?>"
591
+ data-placeholder="<?php echo esc_attr( apply_filters( 'bnfw_email_dropdown_placeholder', __( 'Select User Roles / Users', 'bnfw' ) ) ); ?>" style="width:75%">
592
+ <?php bnfw_render_users_dropdown( $setting['users'] ); ?>
593
+ </select>
594
+ </td>
595
+ </tr>
596
+
597
+ <tr valign="top" id="exclude-users">
598
+ <th scope="row">
599
+ <?php esc_html_e( 'Except For', 'bnfw' ); ?>
600
+ <div class="bnfw-help-tip">
601
+ <p>
602
+ <?php esc_html_e( 'Choose the users and/or user roles that this notification should not be sent to.', 'bnfw' ); ?>
603
+ </p>
604
+ </div>
605
+ </th>
606
+ <td>
607
+ <select multiple id="exclude-users-select" name="exclude-users[]"
608
+ class="<?php echo sanitize_html_class( bnfw_get_user_select_class() ); ?>"
609
+ data-placeholder="<?php echo esc_attr( apply_filters( 'bnfw_email_dropdown_placeholder', __( 'Select User Roles / Users', 'bnfw' ) ) ); ?>" style="width:75%">
610
+ <?php bnfw_render_users_dropdown( $setting['exclude-users'] ); ?>
611
+ </select>
612
+ </td>
613
+ </tr>
614
+
615
+ <?php
616
+ $display = 'none';
617
+
618
+ if ( $this->should_show_users_count_msg( $setting ) ) {
619
+ $display = 'table-row';
620
+ }
621
+ ?>
622
+ <tr valign="top" id="users-count-msg" style="display: <?php echo esc_attr( $display ); ?>">
623
+ <th scope="row">&nbsp;</th>
624
+ <td>
625
+ <div>
626
+ <p>
627
+ <?php esc_html_e( 'You have chosen to send this notification to over 200 users. Please check the email sending rate limit at your host before sending.', 'bnfw' ); ?>
628
+ </p>
629
+ </div>
630
+ </td>
631
+ </tr>
632
+
633
+ <?php do_action( 'bnfw_after_send_to', $setting ); ?>
634
+
635
+ <tr valign="top" id="subject-wrapper">
636
+ <th scope="row">
637
+ <?php esc_html_e( 'Subject', 'bnfw' ); ?>
638
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'Notification subject. You can use ', 'bnfw' ); ?><a href="https://betternotificationsforwp.com/documentation/notifications/shortcodes/" target="_blank">shortcodes</a><?php esc_html_e( ' here.', 'bnfw' ); ?></p></div>
639
+ </th>
640
+ <td>
641
+ <input type="text" name="subject" id="subject" value="<?php echo esc_attr( $setting['subject'] ); ?>"
642
+ style="width:75%;">
643
+ </td>
644
+ </tr>
645
+
646
+ <?php do_action( 'bnfw_after_user_dropdown', $setting ); ?>
647
+
648
+ <?php do_action( 'bnfw_before_message_body', $setting ); ?>
649
+ <tr valign="top">
650
+ <th scope="row">
651
+ <?php esc_html_e( 'Message Body', 'bnfw' ); ?>
652
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'Notification message. You can use ', 'bnfw' ); ?><a href="https://betternotificationsforwp.com/documentation/notifications/shortcodes/" target="_blank">shortcodes</a><?php esc_html_e( ' here.', 'bnfw' ); ?></p></div>
653
+
654
+ <div class="wp-ui-text-highlight">
655
+ <p>
656
+ <br>
657
+ <br>
658
+ <br>
659
+ <br>
660
+ <?php esc_html_e( 'Need some more help?', 'bnfw' ); ?>
661
+ </p>
662
+ <?php
663
+ $doc_url = 'https://betternotificationsforwp.com/documentation/';
664
+
665
+ if ( bnfw_is_tracking_allowed() ) {
666
+ $doc_url .= "?utm_source=WP%20Admin%20Notification%20Editor%20-%20'Documentation'&amp;utm_medium=referral";
667
+ }
668
+ ?>
669
+ <p>
670
+ <a href="#" class="button-secondary" id="insert-default-msg"><?php esc_html_e( 'Insert Default Content', 'bnfw' ); ?></a>
671
+ </p>
672
+ <p>
673
+ <a href="<?php echo esc_url( $doc_url ); ?>"
674
+ target="_blank" class="button-secondary"><?php esc_html_e( 'Read Documentation', 'bnfw' ); ?></a>
675
+ </p>
676
+ <p>
677
+ <a href="" target="_blank" id="shortcode-help"
678
+ class="button-secondary"><?php esc_html_e( 'Find Shortcodes', 'bnfw' ); ?></a>
679
+ </p>
680
+ </div>
681
+ </th>
682
+ <td>
683
+ <?php wp_editor( $setting['message'], 'notification_message', array( 'media_buttons' => true ) ); ?>
684
+ <p> &nbsp; </p>
685
+ <div id="disable-autop">
686
+ <label>
687
+ <input type="checkbox" name="disable-autop"
688
+ value="true" <?php checked( 'true', $setting['disable-autop'] ); ?>>
689
+ <?php esc_html_e( 'Stop additional paragraph and line break HTML from being inserted into my notifications', 'bnfw' ); ?>
690
+ </label>
691
+ </div>
692
+ </td>
693
+ </tr>
694
+
695
+ </tbody>
696
+ </table>
697
+ <?php
698
+ }
699
+
700
+ /**
701
+ * Should we enqueue assets?.
702
+ *
703
+ * @since 1.0
704
+ *
705
+ * @param string $hook_suffix The current admin page.
706
+ */
707
+ public function is_assets_needed( $hook_suffix ) {
708
+ if ( self::POST_TYPE === get_post_type() || 'bnfw_notification_page_bnfw-settings' === $hook_suffix ) {
709
+ // The enqueue assets function may be included from addons.
710
+ // We want to disable autosave only for notifications.
711
+ wp_dequeue_script( 'autosave' );
712
+
713
+ $this->enqueue_assets();
714
+
715
+ do_action( 'bnfw_after_enqueue_scripts' );
716
+ }
717
+ }
718
+
719
+ /**
720
+ * Enqueue assets.
721
+ *
722
+ * @since 1.4
723
+ */
724
+ public function enqueue_assets() {
725
+ wp_deregister_script( 'select2' );
726
+ wp_dequeue_script( 'select2' );
727
+ wp_deregister_style( 'select2' );
728
+ wp_dequeue_style( 'select2' );
729
+
730
+ // Ultimate Member plugin is giving us problems. They should upgrade.
731
+ wp_deregister_script( 'um_minified' );
732
+ wp_dequeue_script( 'um_minified' );
733
+ wp_deregister_script( 'um_admin_scripts' );
734
+ wp_dequeue_script( 'um_admin_scripts' );
735
+
736
+ wp_enqueue_style( 'select2', plugins_url( '../assets/css/select2.min.css', dirname( __FILE__ ) ), array(), BNFW_VERSION );
737
+ wp_enqueue_script( 'select2', plugins_url( '../assets/js/select2.full.min.js', dirname( __FILE__ ) ), array( 'jquery' ), BNFW_VERSION, true );
738
+
739
+ wp_enqueue_script( 'bnfw', plugins_url( '../assets/js/bnfw.js', dirname( __FILE__ ) ), array( 'select2' ), BNFW_VERSION, true );
740
+ wp_enqueue_style( 'bnfw', plugins_url( '../assets/css/bnfw.css', dirname( __FILE__ ) ), array( 'dashicons', 'select2' ), BNFW_VERSION );
741
+
742
+ $strings = array(
743
+ 'validation_element' => apply_filters( 'bnfw_validation_element', '#users-select' ),
744
+ 'empty_user' => esc_html__( 'You must choose at least one User or User Role to send the notification to before you can save', 'bnfw' ),
745
+ 'enableTags' => false,
746
+ 'bnfw_users_search_ajax_nonce' => wp_create_nonce( 'bnfw_users_search_ajax_nonce' ),
747
+ );
748
+
749
+ /**
750
+ * Filter the localized array that is sent to scripts.
751
+ *
752
+ * @since 1.7.0
753
+ */
754
+ $strings = apply_filters( 'bnfw_localize_script', $strings );
755
+
756
+ wp_localize_script( 'bnfw', 'BNFW', $strings );
757
+ }
758
+
759
+ /**
760
+ * Save the meta box's post metadata.
761
+ *
762
+ * @since 1.0
763
+ *
764
+ * @param int $post_id The ID of the post being saved.
765
+ */
766
+ public function save_meta_data( $post_id ) {
767
+ if ( self::POST_TYPE !== get_post_type( $post_id ) ) {
768
+ return;
769
+ }
770
+
771
+ // Check nonce.
772
+ if ( empty( $_POST[ self::POST_TYPE . '_nonce' ] ) ) {
773
+ return;
774
+ }
775
+
776
+ // Verify nonce.
777
+ if ( ! wp_verify_nonce( $_POST[ self::POST_TYPE . '_nonce' ], self::POST_TYPE ) ) {// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
778
+ return;
779
+ }
780
+
781
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
782
+ return;
783
+ }
784
+
785
+ if ( ! current_user_can( 'bnfw' ) ) {
786
+ return;
787
+ }
788
+ if ( isset( $_POST['digest-interval'] ) && 'no' !== $_POST['digest-interval'] ) {
789
+ $subject = isset( $_POST['subject'] ) ? sanitize_text_field( wp_unslash( $_POST['subject'] ) ) : '';
790
+ } else {
791
+ $subject = isset( $_POST['subject'] ) ? sanitize_text_field( wp_unslash( $_POST['subject'] ) ) : '';
792
+ }
793
+
794
+ $setting = array(
795
+ 'notification' => isset( $_POST['notification'] ) ? sanitize_text_field( wp_unslash( $_POST['notification'] ) ) : '',
796
+ 'subject' => $subject,
797
+ 'message' => isset( $_POST['notification_message'] ) ? sanitize_text_field( wp_unslash( $_POST['notification_message'] ) ) : '',
798
+ 'disabled' => isset( $_POST['disabled'] ) ? sanitize_text_field( wp_unslash( $_POST['disabled'] ) ) : 'false',
799
+ 'email-formatting' => isset( $_POST['email-formatting'] ) ? sanitize_text_field( wp_unslash( $_POST['email-formatting'] ) ) : 'html',
800
+ 'disable-current-user' => isset( $_POST['disable-current-user'] ) ? sanitize_text_field( wp_unslash( $_POST['disable-current-user'] ) ) : 'false',
801
+ 'disable-autop' => isset( $_POST['disable-autop'] ) ? sanitize_text_field( wp_unslash( $_POST['disable-autop'] ) ) : 'false',
802
+ 'only-post-author' => isset( $_POST['only-post-author'] ) ? sanitize_text_field( wp_unslash( $_POST['only-post-author'] ) ) : 'false',
803
+ 'users' => array(),
804
+ 'exclude-users' => array(),
805
+ );
806
+
807
+ if ( isset( $_POST['users'] ) ) {
808
+ $setting['users'] = array_map( 'sanitize_text_field', (array) wp_unslash( $_POST['users'] ) );
809
+ }
810
+
811
+ if ( isset( $_POST['exclude-users'] ) ) {
812
+ $setting['exclude-users'] = array_map( 'sanitize_text_field', (array) wp_unslash( $_POST['exclude-users'] ) );
813
+ }
814
+
815
+ if ( isset( $_POST['show-fields'] ) && 'true' === $_POST['show-fields'] ) {
816
+ $setting['show-fields'] = 'true';
817
+ $setting['from-name'] = isset( $_POST['from-name'] ) ? sanitize_text_field( wp_unslash( $_POST['from-name'] ) ) : '';
818
+ $setting['from-email'] = isset( $_POST['from-email'] ) ? sanitize_email( wp_unslash( $_POST['from-email'] ) ) : '';
819
+ $setting['reply-name'] = isset( $_POST['reply-name'] ) ? sanitize_text_field( wp_unslash( $_POST['reply-name'] ) ) : '';
820
+ $setting['reply-email'] = isset( $_POST['reply-email'] ) ? sanitize_email( wp_unslash( $_POST['reply-email'] ) ) : '';
821
+ $setting['cc'] = isset( $_POST['cc'] ) ? array_map( 'sanitize_text_field', (array) wp_unslash( $_POST['cc'] ) ) : '';
822
+ $setting['bcc'] = isset( $_POST['bcc'] ) ? array_map( 'sanitize_text_field', (array) wp_unslash( $_POST['bcc'] ) ) : '';
823
+ } else {
824
+ $setting['show-fields'] = 'false';
825
+ }
826
+
827
+ $setting = apply_filters( 'bnfw_notification_setting', $setting, $_POST );
828
+
829
+ $this->save_settings( $post_id, $setting );
830
+
831
+ if ( isset( $_POST['send-test-email'] ) ) {
832
+ if ( 'true' === sanitize_text_field( wp_unslash( $_POST['send-test-email'] ) ) ) {
833
+ BNFW::factory()->engine->send_test_email( $setting );
834
+ add_filter( 'redirect_post_location', array( $this, 'test_mail_sent' ) );
835
+ }
836
+ }
837
+ }
838
+
839
+ /**
840
+ * Add a query parameter to url if test email was sent.
841
+ *
842
+ * @since 1.3
843
+ * @param string $loc A URL to act upon.
844
+ */
845
+ public function test_mail_sent( $loc ) {
846
+ return add_query_arg( self::TEST_MAIL_ARG, 1, $loc );
847
+ }
848
+
849
+ /**
850
+ * Add a notification if a test email was sent.
851
+ *
852
+ * @since 1.3
853
+ */
854
+ public function admin_notices() {
855
+ if ( isset( $_GET[ self::TEST_MAIL_ARG ] ) ) {// phpcs:ignore WordPress.Security.NonceVerification.Recommended
856
+ $screen = get_current_screen();
857
+ if ( in_array( $screen->post_type, array( self::POST_TYPE ), true ) ) {
858
+ ?>
859
+ <div class="updated below-h2">
860
+ <p><?php echo esc_html__( 'Test Notification Sent.', 'bnfw' ); ?></p>
861
+ </div>
862
+ <?php
863
+ }
864
+ }
865
+ }
866
+
867
+ /**
868
+ * Save settings in post meta.
869
+ *
870
+ * @since 1.0
871
+ * @access private
872
+ *
873
+ * @param int $post_id Post id.
874
+ * @param array $setting An arraif settings options.
875
+ */
876
+ private function save_settings( $post_id, $setting ) {
877
+ foreach ( $setting as $key => $value ) {
878
+ update_post_meta( $post_id, self::META_KEY_PREFIX . $key, $value );
879
+ }
880
+ }
881
+
882
+ /**
883
+ * Read settings from post meta.
884
+ *
885
+ * @since 1.0
886
+ *
887
+ * @param int $post_id Pota id.
888
+ *
889
+ * @return array
890
+ */
891
+ public function read_settings( $post_id ) {
892
+ $setting = array();
893
+ $default = array(
894
+ 'notification' => '',
895
+ 'from-name' => '',
896
+ 'from-email' => '',
897
+ 'reply-name' => '',
898
+ 'reply-email' => '',
899
+ 'cc' => array(),
900
+ 'bcc' => array(),
901
+ 'users' => array(),
902
+ 'exclude-users' => array(),
903
+ 'subject' => '',
904
+ 'email-formatting' => get_option( 'bnfw_email_format', 'html' ),
905
+ 'message' => '',
906
+ 'show-fields' => 'false',
907
+ 'disable-current-user' => 'false',
908
+ 'disable-autop' => 'false',
909
+ 'only-post-author' => 'false',
910
+ 'disabled' => 'false',
911
+ );
912
+
913
+ $default = apply_filters( 'bnfw_notification_setting_fields', $default );
914
+
915
+ foreach ( $default as $key => $default_value ) {
916
+ $value = get_post_meta( $post_id, self::META_KEY_PREFIX . $key, true );
917
+ if ( ! empty( $value ) ) {
918
+ $setting[ $key ] = $value;
919
+ } else {
920
+ $setting[ $key ] = $default_value;
921
+ }
922
+ }
923
+
924
+ // Compatibility code. This will be removed subsequently.
925
+ $user_roles = get_post_meta( $post_id, self::META_KEY_PREFIX . 'user-roles', true );
926
+ if ( ! empty( $user_roles ) && is_array( $user_roles ) ) {
927
+ foreach ( $user_roles as $role ) {
928
+ $setting['users'][] = 'role-' . $role;
929
+ }
930
+
931
+ update_post_meta( $post_id, self::META_KEY_PREFIX . 'users', $setting['users'] );
932
+ delete_post_meta( $post_id, self::META_KEY_PREFIX . 'user-roles' );
933
+ }
934
+
935
+ $setting['id'] = $post_id;
936
+
937
+ return $setting;
938
+ }
939
+
940
+ /**
941
+ * Change the post updated message for notification post type.
942
+ *
943
+ * @since 1.0
944
+ *
945
+ * @param array $messages Post updated messages.
946
+ *
947
+ * @return mixed
948
+ */
949
+ public function post_updated_messages( $messages ) {
950
+ $messages[ self::POST_TYPE ] = array_fill( 0, 11, esc_html__( 'Notification saved.', 'bnfw' ) );
951
+
952
+ return $messages;
953
+ }
954
+
955
+ /**
956
+ * Render submit div meta box.
957
+ *
958
+ * @since 1.0
959
+ *
960
+ * @param $post WP_Post $post The post object.
961
+ */
962
+ public function render_submitdiv( $post ) {
963
+ global $post;
964
+ ?>
965
+ <div class="submitbox" id="submitpost">
966
+
967
+ <?php // Hidden submit button early on so that the browser chooses the right button when form is submitted with Return key. ?>
968
+ <div style="display:none;">
969
+ <?php submit_button( esc_html__( 'Save', 'bnfw' ), 'button', 'save' ); ?>
970
+ </div>
971
+
972
+ <?php // Always publish. ?>
973
+ <div class="disable-notification-checkbox" style="padding: 5px 0 10px 0;">
974
+ <div class="bnfw-help-tip-container">
975
+ <input type="hidden" name="post_status" id="hidden_post_status" value="publish">
976
+
977
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'Use this to enable or disable notifications. If you want to disable a default WordPress notification, just create it on the left, then disable it here.', 'bnfw' ); ?></p></div>
978
+
979
+ <?php
980
+ $setting = $this->read_settings( $post->ID );
981
+ ?>
982
+ <label>
983
+ <input type="radio" name="disabled"
984
+ value="false" <?php checked( $setting['disabled'], 'false', true ); ?>><?php esc_html_e( 'Notification Enabled', 'bnfw' ); ?>
985
+ </label>
986
+
987
+ <br>
988
+
989
+ <label>
990
+ <input type="radio" name="disabled"
991
+ value="true" <?php checked( $setting['disabled'], 'true', true ); ?>><?php esc_html_e( 'Notification Disabled', 'bnfw' ); ?>
992
+ </label>
993
+ </div>
994
+
995
+ <br>
996
+ <br>
997
+
998
+ <?php if ( 'publish' === $post->post_status ) { ?>
999
+ <div class="bnfw-help-tip-container">
1000
+ <input type="hidden" name="send-test-email" id="send-test-email" value="false">
1001
+ <input name="test-email" type="submit" class="button button-secondary button-large" id="test-email"
1002
+ value="<?php esc_attr_e( 'Send Me a Test Email', 'bnfw' ); ?>">
1003
+
1004
+ <div class="bnfw-help-tip"><p><?php esc_html_e( 'This will send you (the currently logged in user) a notification so that you can check for any issues with formatting – it’s doesn\'t mean that a notification will send correctly in the future. You can read about how to improve email delivery', 'bnfw' ); ?> <a href="https://betternotificationsforwp.com/documentation/getting-started/how-to-improve-email-delivery/" target="_blank"><?php esc_html_e( 'here', 'bnfw' ); ?></a><?php esc_html_e( '. Shortcodes will not be replaced with content.', 'bnfw' ); ?></p></div>
1005
+ </div>
1006
+ <?php } ?>
1007
+
1008
+ </div>
1009
+
1010
+ <div id="major-publishing-actions">
1011
+
1012
+ <div id="delete-action">
1013
+ <?php
1014
+ if ( ! EMPTY_TRASH_DAYS ) {
1015
+ $delete_text = esc_html__( 'Delete Permanently', 'bnfw' );
1016
+ } else {
1017
+ $delete_text = esc_html__( 'Move to Trash', 'bnfw' );
1018
+ }
1019
+ ?>
1020
+ <a class="submitdelete deletion"
1021
+ href="<?php echo esc_url( get_delete_post_link( $post->ID ) ); ?>"><?php echo esc_html( $delete_text ); ?></a>
1022
+ </div>
1023
+
1024
+ <div id="publishing-action">
1025
+ <span class="spinner"></span>
1026
+ <input name="original_publish" type="hidden" id="original_publish"
1027
+ value="<?php esc_attr_e( 'Save', 'bnfw' ); ?>">
1028
+ <input name="save" type="submit" class="button button-primary button-large" id="publish"
1029
+ accesskey="p" value="<?php esc_attr_e( 'Save', 'bnfw' ); ?>">
1030
+ </div>
1031
+ <div class="clear"></div>
1032
+
1033
+ </div>
1034
+ <!-- #major-publishing-actions -->
1035
+
1036
+ <div class="clear"></div>
1037
+ </div>
1038
+ <!-- #submitpost -->
1039
+ <?php
1040
+ }
1041
+
1042
+ /**
1043
+ * Get notifications based on type.
1044
+ *
1045
+ * @since 1.0
1046
+ *
1047
+ * @param array|string $types Notification Type.
1048
+ * @param bool $exclude_disabled (optional) Whether to exclude disabled notifications or not. True by default.
1049
+ *
1050
+ * @return array WP_Post objects
1051
+ */
1052
+ public function get_notifications( $types = array(), $exclude_disabled = true ) {
1053
+ if ( ! is_array( $types ) ) {
1054
+ $types = array( $types );
1055
+ }
1056
+
1057
+ $args = array(
1058
+ 'post_type' => self::POST_TYPE,
1059
+ );
1060
+
1061
+ $meta_query = array();
1062
+
1063
+ if ( ! empty( $types ) ) {
1064
+ $meta_query[] = array(
1065
+ 'key' => self::META_KEY_PREFIX . 'notification',
1066
+ 'value' => $types,
1067
+ 'compare' => 'IN',
1068
+ );
1069
+ }
1070
+
1071
+ if ( $exclude_disabled ) {
1072
+ $meta_query[] = array(
1073
+ 'key' => self::META_KEY_PREFIX . 'disabled',
1074
+ 'value' => 'true',
1075
+ 'compare' => '!=',
1076
+ );
1077
+ }
1078
+
1079
+ if ( ! empty( $meta_query ) ) {
1080
+ $args['meta_query'] = $meta_query;
1081
+ }
1082
+
1083
+ $args['posts_per_page'] = -1;
1084
+ $args['nopagging'] = true;
1085
+
1086
+ $args = apply_filters( 'bnfw_get_notifications_args', $args, $types, $exclude_disabled );
1087
+
1088
+ $wp_query = new WP_Query();
1089
+ $posts = $wp_query->query( $args );
1090
+
1091
+ $posts = apply_filters( 'bnfw_get_notifications_posts', $posts, $args, $types, $exclude_disabled );
1092
+
1093
+ return $posts;
1094
+ }
1095
+
1096
+ /**
1097
+ * Are there any disabled notifications for a particular notification type.
1098
+ *
1099
+ * @param string $type Notification type.
1100
+ *
1101
+ * @return bool True if disabled, False otherwise.
1102
+ */
1103
+ public function is_notification_disabled( $type ) {
1104
+ $args = array(
1105
+ 'post_type' => self::POST_TYPE,
1106
+ 'posts_per_page' => - 1,
1107
+ 'nopagging' => true,
1108
+ 'fields' => 'ids',
1109
+ 'meta_query' => array(
1110
+ array(
1111
+ 'key' => self::META_KEY_PREFIX . 'notification',
1112
+ 'value' => $type,
1113
+ ),
1114
+ array(
1115
+ 'key' => self::META_KEY_PREFIX . 'disabled',
1116
+ 'value' => 'true',
1117
+ ),
1118
+ ),
1119
+ );
1120
+
1121
+ $args = apply_filters( 'bnfw_is_notification_disabled_args', $args, $type );
1122
+
1123
+ $wp_query = new WP_Query();
1124
+ $posts = $wp_query->query( $args );
1125
+
1126
+ $posts = apply_filters( 'bnfw_is_notification_disabled_posts', $posts, $args, $type );
1127
+
1128
+ return count( $posts ) > 0;
1129
+ }
1130
+
1131
+ /**
1132
+ * Does a particular type of notification exists or not.
1133
+ *
1134
+ * @since 1.1
1135
+ *
1136
+ * @param string $type Notification Type.
1137
+ * @param bool $exclude_disabled (optional) Whether to exclude disabled notifications or not. True by default.
1138
+ *
1139
+ * @return bool True if present, False otherwise
1140
+ */
1141
+ public function notification_exists( $type, $exclude_disabled = true ) {
1142
+ $notifications = $this->get_notifications( $type, $exclude_disabled );
1143
+
1144
+ if ( count( $notifications ) > 0 ) {
1145
+ return true;
1146
+ } else {
1147
+ return false;
1148
+ }
1149
+ }
1150
+
1151
+ /**
1152
+ * Custom columns for this post type.
1153
+ *
1154
+ * @since 1.0
1155
+ * @filter manage_{post_type}_posts_columns
1156
+ *
1157
+ * @param array $columns The name of the column to display.
1158
+ *
1159
+ * @return array
1160
+ */
1161
+ public function columns_header( $columns ) {
1162
+ $columns['type'] = esc_html__( 'Notification Type', 'bnfw' );
1163
+ $columns['disabled'] = esc_html__( 'Enabled?', 'bnfw' );
1164
+ $columns['subject'] = esc_html__( 'Subject', 'bnfw' );
1165
+ $columns['users'] = esc_html__( 'User Roles / Users', 'bnfw' );
1166
+ $columns['excluded'] = esc_html__( 'Excluded User Roles / Users', 'bnfw' );
1167
+
1168
+ return $columns;
1169
+ }
1170
+
1171
+ /**
1172
+ * Custom column appears in each row.
1173
+ *
1174
+ * @since 1.0
1175
+ * @action manage_{post_type}_posts_custom_column
1176
+ *
1177
+ * @param string $column Column name.
1178
+ * @param int $post_id Post ID.
1179
+ */
1180
+ public function custom_column_row( $column, $post_id ) {
1181
+ $setting = $this->read_settings( $post_id );
1182
+ switch ( $column ) {
1183
+ case 'disabled':
1184
+ if ( 'true' !== $setting['disabled'] ) {
1185
+ printf( '<span class="dashicons dashicons-yes"></span>' );
1186
+ }
1187
+ break;
1188
+ case 'type':
1189
+ echo wp_kses_post( $this->get_notification_name( $setting['notification'] ) );
1190
+ break;
1191
+ case 'subject':
1192
+ echo wp_kses_post( ! empty( $setting['subject'] ) ? $setting['subject'] : '' );
1193
+ break;
1194
+ case 'users':
1195
+ $users = $this->get_names_from_users( $setting['users'] );
1196
+ if ( ! empty( $users ) ) {
1197
+ echo wp_kses_post( implode( ', ', $users ) );
1198
+ } else {
1199
+ if ( isset( $setting['new-user-role'] ) ) {
1200
+ $users = $this->get_names_from_users( $setting['new-user-role'] );
1201
+ echo wp_kses_post( implode( ', ', $users ) );
1202
+ }
1203
+ }
1204
+
1205
+ if ( 'true' === $setting['only-post-author'] ) {
1206
+ echo esc_html__( ', Post Author', 'bnfw' );
1207
+ }
1208
+
1209
+ break;
1210
+ case 'excluded':
1211
+ $excluded_users = $this->get_names_from_users( $setting['exclude-users'] );
1212
+ echo wp_kses_post( implode( ', ', $excluded_users ) );
1213
+
1214
+ break;
1215
+ }
1216
+
1217
+ /**
1218
+ * Invoked while displaying a custom column in notification table.
1219
+ *
1220
+ * @since 1.3.9
1221
+ *
1222
+ * @param string $column Column name
1223
+ * @param int $post_id Post ID
1224
+ */
1225
+ do_action( 'bnfw_notification_table_column', $column, $post_id );
1226
+ }
1227
+
1228
+ /**
1229
+ * Get names from users.
1230
+ *
1231
+ * @since 1.2
1232
+ * @param array $users Users.
1233
+ */
1234
+ private function get_names_from_users( $users ) {
1235
+ $user_ids = array();
1236
+ $user_roles = array();
1237
+ $emails = array();
1238
+ $names_from_user_ids = array();
1239
+
1240
+ if ( is_array( $users ) ) {
1241
+ foreach ( $users as $user ) {
1242
+ if ( $this->starts_with( $user, 'role-' ) ) {
1243
+ $user_roles[] = ucfirst( str_replace( 'role-', '', $user ) );
1244
+ } elseif ( strpos( $user, '@' ) !== false ) {
1245
+ $emails[] = $user;
1246
+ } elseif ( absint( $user ) > 0 ) {
1247
+ $user_ids[] = absint( $user );
1248
+ } else {
1249
+ $emails[] = $user;
1250
+ }
1251
+ }
1252
+ } else {
1253
+ // User Roles not associated with a To/CC/BCC field.
1254
+ $role = get_role( $users );
1255
+
1256
+ if ( ! empty( $role ) ) {
1257
+ $user_roles = array( $role->name );
1258
+ }
1259
+ }
1260
+
1261
+ if ( ! empty( $user_ids ) ) {
1262
+ $user_query = new WP_User_Query( array( 'include' => $user_ids ) );
1263
+ foreach ( $user_query->results as $user ) {
1264
+ $names_from_user_ids[] = $user->user_login;
1265
+ }
1266
+ }
1267
+
1268
+ return array_merge( $user_roles, $names_from_user_ids, $emails );
1269
+ }
1270
+
1271
+ /**
1272
+ * Get name of the notification based on slug.
1273
+ *
1274
+ * @param string $slug Notification Slug.
1275
+ *
1276
+ * @return string Notification Name.
1277
+ */
1278
+ private function get_notification_name( $slug ) {
1279
+ $name = '';
1280
+ switch ( $slug ) {
1281
+ case 'new-comment':
1282
+ $name = esc_html__( 'New Comment', 'bnfw' );
1283
+ break;
1284
+ case 'approve-post-comment':
1285
+ $name = esc_html__( 'Post - Comment Approved', 'bnfw' );
1286
+ break;
1287
+ case 'moderate-comment':
1288
+ $name = esc_html__( 'New Comment Awaiting Moderation', 'bnfw' );
1289
+ break;
1290
+ case 'new-trackback':
1291
+ $name = esc_html__( 'New Trackback', 'bnfw' );
1292
+ break;
1293
+ case 'new-pingback':
1294
+ $name = esc_html__( 'New Pingback', 'bnfw' );
1295
+ break;
1296
+ case 'reply-comment':
1297
+ $name = esc_html__( 'Comment Reply', 'bnfw' );
1298
+ break;
1299
+ case 'user-password':
1300
+ $name = esc_html__( 'User Lost Password - For User', 'bnfw' );
1301
+ break;
1302
+ case 'admin-password':
1303
+ $name = esc_html__( 'User Lost Password - For Admin', 'bnfw' );
1304
+ break;
1305
+ case 'admin-password-changed':
1306
+ $name = esc_html__( 'Password Changed - For Admin', 'bnfw' );
1307
+ break;
1308
+ case 'admin-email-changed':
1309
+ $name = esc_html__( 'User Email Changed - For Admin', 'bnfw' );
1310
+ break;
1311
+ case 'password-changed':
1312
+ $name = esc_html__( 'Password Changed - For User', 'bnfw' );
1313
+ break;
1314
+ case 'email-changing':
1315
+ $name = esc_html__( 'User Email Changed Confirmation - For User', 'bnfw' );
1316
+ break;
1317
+ case 'email-changed':
1318
+ $name = esc_html__( 'User Email Changed - For User', 'bnfw' );
1319
+ break;
1320
+ case 'core-updated':
1321
+ $name = esc_html__( 'WordPress Core Automatic Background Updates', 'bnfw' );
1322
+ break;
1323
+ case 'new-user':
1324
+ $name = esc_html__( 'New User Registration - For User', 'bnfw' );
1325
+ break;
1326
+ case 'user-login':
1327
+ $name = esc_html__( 'User Logged In - For User', 'bnfw' );
1328
+ break;
1329
+ case 'admin-user-login':
1330
+ $name = esc_html__( 'User Logged In - For Admin', 'bnfw' );
1331
+ break;
1332
+ case 'welcome-email':
1333
+ $name = esc_html__( 'New User - Post-registration Email', 'bnfw' );
1334
+ break;
1335
+ case 'admin-user':
1336
+ $name = esc_html__( 'New User Registration - For Admin', 'bnfw' );
1337
+ break;
1338
+ case 'user-role':
1339
+ $name = esc_html__( 'User Role Changed - For User', 'bnfw' );
1340
+ break;
1341
+ case 'admin-role':
1342
+ $name = esc_html__( 'User Role Changed - For Admin', 'bnfw' );
1343
+ break;
1344
+ case 'new-post':
1345
+ $name = esc_html__( 'New Post Published', 'bnfw' );
1346
+ break;
1347
+ case 'update-post':
1348
+ $name = esc_html__( 'Post Updated', 'bnfw' );
1349
+ break;
1350
+ case 'pending-post':
1351
+ $name = esc_html__( 'Post Pending Review', 'bnfw' );
1352
+ break;
1353
+ case 'private-post':
1354
+ $name = esc_html__( 'New Private Post', 'bnfw' );
1355
+ break;
1356
+ case 'future-post':
1357
+ $name = esc_html__( 'Post Scheduled', 'bnfw' );
1358
+ break;
1359
+ case 'trash-post':
1360
+ $name = esc_html__( 'Published Post Moved to Trash', 'bnfw' );
1361
+ break;
1362
+ case 'new-page':
1363
+ $name = esc_html__( 'New Page Published', 'bnfw' );
1364
+ break;
1365
+ case 'newterm-category':
1366
+ $name = esc_html__( 'New Category', 'bnfw' );
1367
+ break;
1368
+ case 'newterm-post_tag':
1369
+ $name = esc_html__( 'New Tag', 'bnfw' );
1370
+ break;
1371
+ case 'ca-export-data':
1372
+ $name = esc_html__( 'Privacy Confirm Action: Export Data Request For User', 'bnfw' );
1373
+ break;
1374
+ case 'ca-erase-data':
1375
+ $name = esc_html__( 'Privacy Confirm Action: Erase Data Request – For User', 'bnfw' );
1376
+ break;
1377
+ case 'uc-export-data':
1378
+ $name = esc_html__( 'Privacy - Confirm Action: Export Data Request - For Admin', 'bnfw' );
1379
+ break;
1380
+ case 'uc-erase-data':
1381
+ $name = esc_html__( 'Privacy - Confirm Action: Erase Data Request - For Admin', 'bnfw' );
1382
+ break;
1383
+ case 'data-export':
1384
+ $name = esc_html__( 'Privacy - Data Export - For User', 'bnfw' );
1385
+ break;
1386
+ case 'data-erased':
1387
+ $name = esc_html__( 'Privacy - Data Erased - For User', 'bnfw' );
1388
+ break;
1389
+ case 'new-media':
1390
+ $name = esc_html__( 'New Media Published', 'bnfw' );
1391
+ break;
1392
+ case 'update-media':
1393
+ $name = esc_html__( 'Media Updated', 'bnfw' );
1394
+ break;
1395
+ case 'comment-attachment':
1396
+ $name = esc_html__( 'Media - New Comment', 'bnfw' );
1397
+ break;
1398
+ case 'approve-page-comment':
1399
+ $name = esc_html__( 'Page - Comment Approved', 'bnfw' );
1400
+ break;
1401
+ case 'approve-attachment-comment':
1402
+ $name = esc_html__( 'Media - Comment Approved', 'bnfw' );
1403
+ break;
1404
+ case 'moderate-attachment-comment':
1405
+ $name = esc_html__( 'Media - New Comment Awaiting Moderation', 'bnfw' );
1406
+ break;
1407
+ case 'commentreply-attachment':
1408
+ $name = esc_html__( 'Media - Comment Reply', 'bnfw' );
1409
+ break;
1410
+ default:
1411
+ $splited = explode( '-', $slug );
1412
+ $label = $splited[1];
1413
+ $post_obj = get_post_type_object( $splited[1] );
1414
+
1415
+ if ( null !== $post_obj ) {
1416
+ $label = $post_obj->labels->singular_name;
1417
+ }
1418
+
1419
+ switch ( $splited[0] ) {
1420
+ case 'new':
1421
+ $name = esc_html__( 'New ', 'bnfw' ) . $label . ' ' . esc_html__( 'Published', 'bnfw' );
1422
+ break;
1423
+ case 'update':
1424
+ $name = esc_html__( 'Updated ', 'bnfw' ) . $label;
1425
+ break;
1426
+ case 'pending':
1427
+ $name = $label . esc_html__( ' Pending Review', 'bnfw' );
1428
+ break;
1429
+ case 'future':
1430
+ $name = $label . esc_html__( ' Scheduled', 'bnfw' );
1431
+ break;
1432
+ case 'private':
1433
+ $name = esc_html__( 'New Private ', 'bnfw' ) . $label;
1434
+ break;
1435
+ case 'comment':
1436
+ $name = $label . esc_html__( ' Comment', 'bnfw' );
1437
+ break;
1438
+ case 'moderate':
1439
+ $name = $label . ' - ' . esc_html__( 'New Comment Awaiting Moderation', 'bnfw' );
1440
+ break;
1441
+ case 'commentreply':
1442
+ $name = $label . esc_html__( ' Comment Reply', 'bnfw' );
1443
+ break;
1444
+ case 'approve':
1445
+ $name = $label . esc_html__( ' Comment Approved', 'bnfw' );
1446
+ break;
1447
+ case 'newterm':
1448
+ $tax = get_taxonomy( $splited[1] );
1449
+ if ( ! $tax ) {
1450
+ $name = esc_html__( 'New Term', 'bnfw' );
1451
+ } else {
1452
+ $name = esc_html__( 'New Term in ', 'bnfw' ) . $tax->labels->name;
1453
+ }
1454
+ break;
1455
+ }
1456
+ break;
1457
+ }
1458
+
1459
+ $name = apply_filters( 'bnfw_notification_name', $name, $slug );
1460
+
1461
+ return $name;
1462
+ }
1463
+
1464
+ /**
1465
+ * Add additional custom edit actions for enabling and disabling notifications in bulk.
1466
+ *
1467
+ * @param array $bulk_actions Bulk Actions.
1468
+ *
1469
+ * @return array Modified list of Bulk Actions.
1470
+ */
1471
+ public function add_custom_edit_action( $bulk_actions ) {
1472
+ $bulk_actions['enable_notifications'] = __( 'Enable Notifications', 'bnfw' );
1473
+ $bulk_actions['disable_notifications'] = __( 'Disable Notifications', 'bnfw' );
1474
+ return $bulk_actions;
1475
+ }
1476
+
1477
+ /**
1478
+ * Handle custom edit actions.
1479
+ *
1480
+ * @param string $redirect_to The redirect URL.
1481
+ * @param string $doaction The action being taken.
1482
+ * @param array $post_ids The items to take the action on. Accepts an array of IDs of posts,
1483
+ * comments, terms, links, plugins, attachments, or users.
1484
+ *
1485
+ * @return string
1486
+ */
1487
+ public function handle_custom_edit_action( $redirect_to, $doaction, $post_ids ) {
1488
+ if ( 'enable_notifications' !== $doaction && 'disable_notifications' !== $doaction ) {
1489
+ return $redirect_to;
1490
+ }
1491
+
1492
+ $redirect_to = remove_query_arg( array( 'bulk_enable_notifications', 'bulk_disable_notifications', 'bnfw_action' ), $redirect_to );
1493
+
1494
+ $meta_value = 'true';
1495
+
1496
+ if ( 'enable_notifications' === $doaction ) {
1497
+ $meta_value = 'false';
1498
+ }
1499
+
1500
+ foreach ( $post_ids as $post_id ) {
1501
+ update_post_meta( $post_id, self::META_KEY_PREFIX . 'disabled', $meta_value );
1502
+ }
1503
+
1504
+ $redirect_to = add_query_arg( 'bulk_' . $doaction, count( $post_ids ), $redirect_to );
1505
+
1506
+ return $redirect_to;
1507
+ }
1508
+
1509
+ /**
1510
+ * Custom row actions for this post type.
1511
+ *
1512
+ * @since 1.0
1513
+ * @filter post_row_actions
1514
+ *
1515
+ * @param array $actions An array of row action links.
1516
+ * @param WP_Post $post The post object.
1517
+ *
1518
+ * @return array
1519
+ */
1520
+ public function custom_row_actions( $actions, $post ) {
1521
+ if ( self::POST_TYPE === get_post_type( $post ) ) {
1522
+ unset( $actions['inline hide-if-no-js'] );
1523
+ unset( $actions['view'] );
1524
+
1525
+ $notification_disabled = get_post_meta( $post->ID, self::META_KEY_PREFIX . 'disabled', true );
1526
+
1527
+ if ( 'true' === $notification_disabled ) {
1528
+ $url = add_query_arg(
1529
+ array(
1530
+ 'notification_id' => $post->ID,
1531
+ 'bnfw_action' => 'enable_notification',
1532
+ )
1533
+ );
1534
+ $actions['enable_notification'] = '<a href="' . esc_url( $url ) . '">' . __( 'Enable Notification', 'bnfw' ) . '</a>';
1535
+ } else {
1536
+ $url = add_query_arg(
1537
+ array(
1538
+ 'notification_id' => $post->ID,
1539
+ 'bnfw_action' => 'disable_notification',
1540
+ )
1541
+ );
1542
+ $actions['disable_notification'] = '<a href="' . esc_url( $url ) . '">' . __( 'Disable Notification', 'bnfw' ) . '</a>';
1543
+ }
1544
+ }
1545
+
1546
+ return $actions;
1547
+ }
1548
+
1549
+ /**
1550
+ * Handle custom actions.
1551
+ */
1552
+ public function handle_actions() {
1553
+ if ( ! isset( $_GET['bnfw_action'] ) || ! isset( $_GET['notification_id'] ) ) {// phpcs:ignore WordPress.Security.NonceVerification.Recommended
1554
+ return;
1555
+ }
1556
+
1557
+ $post_id = absint( $_GET['notification_id'] );// phpcs:ignore WordPress.Security.NonceVerification.Recommended
1558
+ if ( 0 === $post_id ) {
1559
+ return;
1560
+ }
1561
+
1562
+ $action = sanitize_text_field( $_GET['bnfw_action'] );// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
1563
+
1564
+ if ( 'enable_notification' === $action ) {
1565
+ update_post_meta( $post_id, self::META_KEY_PREFIX . 'disabled', 'false' );
1566
+ }
1567
+
1568
+ if ( 'disable_notification' === $action ) {
1569
+ update_post_meta( $post_id, self::META_KEY_PREFIX . 'disabled', 'true' );
1570
+ }
1571
+ }
1572
+
1573
+ /**
1574
+ * Find if a string starts with another string.
1575
+ *
1576
+ * @since 1.2
1577
+ *
1578
+ * @param string $haystack The string to search in.
1579
+ * @param string $needle The substring to search for in the haystack.
1580
+ *
1581
+ * @return bool
1582
+ */
1583
+ public function starts_with( $haystack, $needle ) {
1584
+ // search backwards starting from haystack length characters from the end.
1585
+ return '' === $needle || strrpos( $haystack, $needle, - strlen( $haystack ) ) !== false;
1586
+ }
1587
+
1588
+ /**
1589
+ * Display a help notice.
1590
+ *
1591
+ * @since 1.7
1592
+ */
1593
+ public function show_help_notice() {
1594
+ $screen = get_current_screen();
1595
+ if ( ! in_array( $screen->post_type, array( self::POST_TYPE ), true ) ) {
1596
+ return;
1597
+ }
1598
+
1599
+ if ( ! empty( $_REQUEST['bnfw_action'] ) && 'enable_notification' === $_REQUEST['bnfw_action'] ) {// phpcs:ignore WordPress.Security.NonceVerification.Recommended
1600
+ echo wp_kses_post( '<div id="message" class="updated fade"><p>' . __( 'Enabled 1 Notification.', 'bnfw' ) . '</p></div>' );
1601
+ }
1602
+
1603
+ if ( ! empty( $_REQUEST['bnfw_action'] ) && 'disable_notification' === $_REQUEST['bnfw_action'] ) {// phpcs:ignore WordPress.Security.NonceVerification.Recommended
1604
+ echo wp_kses_post( '<div id="message" class="updated fade"><p>' . __( 'Disabled 1 Notification.', 'bnfw' ) . '</p></div>' );
1605
+ }
1606
+
1607
+ if ( ! empty( $_REQUEST['bulk_enable_notifications'] ) ) {// phpcs:ignore WordPress.Security.NonceVerification.Recommended
1608
+ $enabled_count = intval( $_REQUEST['bulk_enable_notifications'] );// phpcs:ignore WordPress.Security.NonceVerification.Recommended
1609
+ printf(
1610
+ wp_kses_post(
1611
+ '<div id="message" class="updated fade"><p>' .
1612
+ /* translators: %s: enabled notification count */
1613
+ _n(
1614
+ 'Enabled %s Notification.',
1615
+ 'Enabled %s Notifications.',
1616
+ $enabled_count,
1617
+ 'bnfw'
1618
+ ) . '</p></div>',
1619
+ $enabled_count
1620
+ )
1621
+ );
1622
+ }
1623
+
1624
+ if ( ! empty( $_REQUEST['bulk_disable_notifications'] ) ) {// phpcs:ignore WordPress.Security.NonceVerification.Recommended
1625
+ $disabled_count = intval( $_REQUEST['bulk_disable_notifications'] );// phpcs:ignore WordPress.Security.NonceVerification.Recommended
1626
+ printf(
1627
+ wp_kses_post(
1628
+ '<div id="message" class="updated fade"><p>' .
1629
+ /* translators: %s: disabled notification count */
1630
+ _n(
1631
+ 'Disabled %s Notification.',
1632
+ 'Disabled %s Notifications.',
1633
+ $disabled_count,
1634
+ 'bnfw'
1635
+ ) . '</p></div>',
1636
+ $disabled_count
1637
+ )
1638
+ );
1639
+ }
1640
+
1641
+ if ( ! PAnD::is_admin_notice_active( 'disable-bnfw-help-notice-forever' ) ) {
1642
+ return;
1643
+ }
1644
+
1645
+ ?>
1646
+ <div data-dismissible="disable-bnfw-help-notice-forever" class="updated notice notice-success is-dismissible">
1647
+ <p>
1648
+ <?php echo wp_kses_post( __( 'If you send out notifications with BNFW but don\'t receive them, you may need to install an SMTP plugin to <a href="https://betternotificationsforwp.com/documentation/getting-started/how-to-improve-email-delivery/" target="_blank">improve email deliverability</a>. I recommend using <a href="https://wordpress.org/plugins/post-smtp/" target="_blank">Post SMTP</a> as it\'s easy to set-up or <a href="https://wordpress.org/plugins/email-log/" target="_blank">Email Log</a> to just log and view emails that are sent.', 'bnfw' ) ); ?>
1649
+ </p>
1650
+ </div>
1651
+ <?php
1652
+ }
1653
+
1654
+ /**
1655
+ * Should the users count message be shown?
1656
+ *
1657
+ * @since 1.7
1658
+ *
1659
+ * @param array $setting Notification Setting.
1660
+ *
1661
+ * @return bool True if message should be shown.
1662
+ */
1663
+ protected function should_show_users_count_msg( $setting ) {
1664
+ $users = $setting['users'];
1665
+
1666
+ if ( count( $users ) > 200 ) {
1667
+ return true;
1668
+ }
1669
+
1670
+ $emails = BNFW::factory()->engine->get_emails_from_users( $users );
1671
+
1672
+ if ( count( $emails ) > 200 ) {
1673
+ return true;
1674
+ }
1675
+
1676
+ return false;
1677
+ }
1678
+ }
1679
+ }
includes/admin/class-bnfw-settings.php ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Register the Admin pages and load the scripts action
4
+ *
5
+ * @since 1.0
6
+ * @package bnfw
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ if ( ! class_exists( 'BNFW_Settings', false ) ) {
12
+ /**
13
+ * BNFW Notification class.
14
+ */
15
+ class BNFW_Settings {
16
+ /**
17
+ * Class contructor.
18
+ */
19
+ public function __construct() {
20
+ add_action( 'admin_menu', array( $this, 'bnfw_admin_menu' ) );
21
+ add_action( 'admin_menu', array( $this, 'bnfw_menu_item_links' ), 12 );
22
+ add_action( 'admin_head', array( $this, 'bnfw_menu_item_link_targets' ) );
23
+ add_action( 'admin_init', array( $this, 'bnfw_general_options' ), 10 );
24
+ }
25
+ /**
26
+ * Sub-menu pages.
27
+ */
28
+ public function bnfw_admin_menu() {
29
+ // New Notifications Sub-menu.
30
+ add_submenu_page(
31
+ 'edit.php?post_type=bnfw_notification',
32
+ esc_html__( 'Notification Settings', 'bnfw' ),
33
+ esc_html__( 'Settings', 'bnfw' ),
34
+ 'bnfw',
35
+ 'bnfw-settings',
36
+ array( $this, 'bnfw_settings_page' )
37
+ );
38
+ }
39
+ /**
40
+ * Settings Page
41
+ */
42
+ public function bnfw_settings_page() {
43
+ ob_start(); ?>
44
+
45
+ <div class="wrap">
46
+ <h2><?php esc_html_e( 'BNFW Settings', 'bnfw' ); ?></h2>
47
+
48
+ <form method="post" action="options.php" class="bnfw-form">
49
+ <?php
50
+ settings_errors();
51
+ settings_fields( 'bnfw-settings' );
52
+ do_settings_sections( 'bnfw-settings' );
53
+
54
+ submit_button( __( 'Save Settings', 'bnfw' ) );
55
+ ?>
56
+ </form>
57
+ </div>
58
+
59
+ <?php
60
+ echo ob_get_clean(); // phpcs:ignore
61
+ }
62
+ /**
63
+ * External Menu Item Links
64
+ */
65
+ public function bnfw_menu_item_links() {
66
+ global $submenu;
67
+
68
+ if ( current_user_can( 'bnfw' ) ) {
69
+ $doc_url = 'https://betternotificationsforwp.com/documentation/';
70
+ $store_url = 'https://betternotificationsforwp.com/downloads/';
71
+ $support_url = 'https://betternotificationsforwp.com/priority-support/';
72
+
73
+ if ( bnfw_is_tracking_allowed() ) {
74
+ $doc_url .= '?utm_source=WP%20Admin%20Submenu%20Item%20-%20"Documentation"&amp;utm_medium=referral';
75
+ $store_url .= '?utm_source=WP%20Admin%20Submenu%20Item%20-%20"Add-on"&amp;utm_medium=referral';
76
+ $support_url .= '?utm_source=WP%20Admin%20Submenu%20Item%20-%20"Priority%20Support"&amp;utm_medium=referral';
77
+ }
78
+
79
+ // Documentation Link.
80
+ $submenu['edit.php?post_type=bnfw_notification'][500] = array(// phpcs:ignore
81
+ '<div id="bnfw-menu-item-documentation" style="color: #73daeb;">' . __( 'Documentation', 'bnfw' ) . '</div>',
82
+ 'bnfw',
83
+ $doc_url,
84
+ );
85
+
86
+ // Add-ons Link.
87
+ $submenu['edit.php?post_type=bnfw_notification'][600] = array(// phpcs:ignore
88
+ '<div id="bnfw-menu-item-addons" style="color: #ff6f59;">' . __( 'Premium Add-ons', 'bnfw' ) . '</div>',
89
+ 'bnfw',
90
+ $store_url,
91
+ );
92
+
93
+ // Add-ons Link.
94
+ $submenu['edit.php?post_type=bnfw_notification'][700] = array(// phpcs:ignore
95
+ '<div id="bnfw-menu-item-support" style="color: #f00001;">' . __( 'Priority Support', 'bnfw' ) . '</div>',
96
+ 'bnfw',
97
+ $support_url,
98
+ );
99
+ }
100
+ }
101
+ /**
102
+ * Add script in head section for admin pages.
103
+ */
104
+ public function bnfw_menu_item_link_targets() {
105
+ ?>
106
+ <script type="text/javascript">
107
+ jQuery( document ).ready( function ( $ ) {
108
+ // Documentation Link
109
+ $( '#bnfw-menu-item-documentation' ).parent().attr( 'target', '_blank' );
110
+ $( '#bnfw-menu-item-documentation' ).hover( function () {
111
+ $( this ).css( 'color', '#a0e6f1' );
112
+ }, function () {
113
+ $( this ).css( 'color', '#73daeb' );
114
+ } );
115
+
116
+ // Add-ons Link
117
+ $( '#bnfw-menu-item-addons' ).parent().attr( 'target', '_blank' );
118
+ $( '#bnfw-menu-item-addons' ).hover( function () {
119
+ $( this ).css( 'color', '#ff9b8c' );
120
+ }, function () {
121
+ $( this ).css( 'color', '#ff6f59' );
122
+ } );
123
+
124
+ // Priority Support Link
125
+ $( '#bnfw-menu-item-support' ).parent().attr( 'target', '_blank' );
126
+ $( '#bnfw-menu-item-support' ).hover( function () {
127
+ $( this ).css( 'color', '#ff3536' );
128
+ }, function () {
129
+ $( this ).css( 'color', '#f00001' );
130
+ } );
131
+ } );
132
+ </script>
133
+ <?php
134
+ }
135
+ /**
136
+ * Settings Page - Setting Registration.
137
+ */
138
+ public function bnfw_general_options() {
139
+ // Set-up - General Options Section.
140
+ add_settings_section(
141
+ 'bnfw_general_options_section', // Section ID.
142
+ '', // Title above settings section.
143
+ array( $this, 'bnfw_general_options_callback' ), // Name of function that renders a description of the settings section.
144
+ 'bnfw-settings' // Page to show on.
145
+ );
146
+
147
+ // Register - Suppress SPAM Checkbox.
148
+ register_setting(
149
+ 'bnfw-settings',
150
+ 'bnfw_suppress_spam'
151
+ );
152
+
153
+ // Suppress notifications for SPAM comments.
154
+ add_settings_field(
155
+ 'bnfw_suppress_spam', // Field ID.
156
+ esc_html__( 'Suppress SPAM comment notification', 'bnfw' ) . '<div class="bnfw-help-tip"><p>' . esc_html__( 'Comments that are correctly marked as SPAM by a 3rd party plugin (such as Akismet) will not generate a notification if this is ticked.', 'bnfw' ) . '</p></div>', // Label to the left.
157
+ array( $this, 'bnfw_suppress_spam_checkbox' ), // Name of function that renders options on the page.
158
+ 'bnfw-settings', // Page to show on.
159
+ 'bnfw_general_options_section', // Associate with which settings section?.
160
+ array(
161
+ esc_html__( 'Don\'t send notifications for comments marked as SPAM', 'bnfw' ),
162
+ )
163
+ );
164
+
165
+ // Register - Email Format setting.
166
+ register_setting(
167
+ 'bnfw-settings',
168
+ 'bnfw_email_format'
169
+ );
170
+
171
+ add_settings_field(
172
+ 'bnfw_email_format', // Field ID.
173
+ esc_html__( 'Default Email Format', 'bnfw' ) . '<div class="bnfw-help-tip"><p>' . esc_html__( 'This will apply to all emails sent out via WordPress, even those from other plugins. For more details, please see the ', 'bnfw' ) . '<a href="https://wordpress.org/plugins/bnfw/faq/" target="_blank">FAQ</a>.</p></div>', // Label to the left.
174
+ array( $this, 'bnfw_email_format_radio' ), // Name of function that renders options on the page.
175
+ 'bnfw-settings', // Page to show on.
176
+ 'bnfw_general_options_section' // Associate with which settings section?.
177
+ );
178
+
179
+ // Register - Email Format setting.
180
+ register_setting(
181
+ 'bnfw-settings',
182
+ 'bnfw_enable_shortcodes'
183
+ );
184
+
185
+ add_settings_field(
186
+ 'bnfw_enable_shortcodes', // Field ID.
187
+ esc_html__( 'Enable Content Shortcodes?', 'bnfw' ) . '<div class="bnfw-help-tip"><p>' . esc_html__( 'Shortcodes in the post/page content are disabled by default.', 'bnfw' ) . '</p></div>', // Label to the left.
188
+ array( $this, 'bnfw_enable_shortcodes_checkbox' ), // Name of function that renders options on the page.
189
+ 'bnfw-settings', // Page to show on.
190
+ 'bnfw_general_options_section', // Associate with which settings section?.
191
+ array(
192
+ esc_html__( 'Enable shortcode output in the page/post content', 'bnfw' ),
193
+ )
194
+ );
195
+
196
+ // Register - Allow tracking setting.
197
+ register_setting(
198
+ 'bnfw-settings',
199
+ 'bnfw_allow_tracking'
200
+ );
201
+
202
+ add_settings_field(
203
+ 'bnfw_allow_tracking', // Field ID.
204
+ esc_html__( 'Allow Usage Tracking?', 'bnfw' ), // Label to the left.
205
+ array( $this, 'bnfw_render_allow_tracking' ), // Name of function that renders options on the page.
206
+ 'bnfw-settings', // Page to show on.
207
+ 'bnfw_general_options_section', // Associate with which settings section?.
208
+ array(
209
+ esc_html__( 'Allow Better Notifications for WP to anonymously track how this plugin is used and help make the plugin better.', 'bnfw' ),
210
+ )
211
+ );
212
+ }
213
+ /**
214
+ * Callback funtion for general options.
215
+ */
216
+ public function bnfw_general_options_callback() {
217
+ }
218
+ /**
219
+ * Suppress SPAM checkbox.
220
+ *
221
+ * @since 1.0
222
+ *
223
+ * @param array $args Args.
224
+ */
225
+ public function bnfw_suppress_spam_checkbox( $args ) {
226
+ ?>
227
+ <input type="checkbox" id="bnfw_suppress_spam" name="bnfw_suppress_spam"
228
+ value="1" <?php checked( 1, get_option( 'bnfw_suppress_spam' ), true ); ?>>
229
+ <label for="bnfw_suppress_spam"><?php echo esc_html( $args[0] ); ?></label>
230
+ <?php
231
+ }
232
+ /**
233
+ * Show email format radio
234
+ *
235
+ * @since 1.4
236
+ *
237
+ * @param array $args args.
238
+ */
239
+ public function bnfw_email_format_radio( $args ) {
240
+ $email_format = get_option( 'bnfw_email_format', 'html' );
241
+ ?>
242
+ <label>
243
+ <input type="radio" value="html"
244
+ name="bnfw_email_format" <?php checked( $email_format, 'html', true ); ?>><?php esc_html_e( 'HTML Formatting', 'bnfw' ); ?>
245
+ </label>
246
+ <br/>
247
+ <label>
248
+ <input type="radio" value="text"
249
+ name="bnfw_email_format" <?php checked( $email_format, 'text', true ); ?>><?php esc_html_e( 'Plain Text', 'bnfw' ); ?>
250
+ </label>
251
+ <?php
252
+ }
253
+ /**
254
+ * Render allow tracking checkbox.
255
+ *
256
+ * @since 1.6
257
+ *
258
+ * @param array $args args.
259
+ */
260
+ public function bnfw_render_allow_tracking( $args ) {
261
+ ?>
262
+ <input type="checkbox" id="bnfw_allow_tracking" name="bnfw_allow_tracking"
263
+ value="on" <?php checked( 'on', get_option( 'bnfw_allow_tracking' ), true ); ?>>
264
+ <label for="bnfw_allow_tracking"><?php echo esc_html( $args[0] ); ?></label>
265
+ <?php
266
+ }
267
+ /**
268
+ * Render Enable shortcode checkbox.
269
+ *
270
+ * @param array $args Optional. Extra arguments used when outputting the field.
271
+ */
272
+ public function bnfw_enable_shortcodes_checkbox( $args ) {
273
+ ?>
274
+ <input type="checkbox" id="bnfw_enable_shortcodes" name="bnfw_enable_shortcodes"
275
+ value="1" <?php checked( 1, get_option( 'bnfw_enable_shortcodes' ), true ); ?>>
276
+ <label for="bnfw_enable_shortcodes"><?php echo esc_html( $args[0] ); ?></label>
277
+ <?php
278
+ }
279
+ }
280
+ new BNFW_Settings();
281
+ }
includes/class-bnfw-import.php ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Import notification from old plugin.
4
+ *
5
+ * @since 1.0
6
+ * @package bnfw
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ if ( ! class_exists( 'BNFW_Import', false ) ) {
12
+ /**
13
+ * BNFW_Import Class
14
+ */
15
+ class BNFW_Import {
16
+ const EMAIL_OPTION = 'bnfw_custom_email_settings';
17
+ const SETTING_OPTION = 'bnfw_settings';
18
+ /**
19
+ * Holds the events
20
+ *
21
+ * @var array
22
+ */
23
+ private $events = array(
24
+ 'create_term',
25
+ 'publish_post',
26
+ 'comment_post',
27
+ 'user_register',
28
+ 'trackback_post',
29
+ 'pingback_post',
30
+ 'lostpassword_post',
31
+ );
32
+
33
+ /**
34
+ * Import notification from old plugin.
35
+ *
36
+ * @since 1.0
37
+ */
38
+ public function import() {
39
+ global $wp_roles;
40
+ $roles = $wp_roles->get_names();
41
+
42
+ if ( $this->import_needed() ) {
43
+ $old_events = get_option( self::SETTING_OPTION );
44
+ foreach ( $old_events as $event => $value ) {
45
+ if ( '1' === $value ) {
46
+ $event_array = explode( '-', $event );
47
+ if ( 2 === count( $event_array ) ) {
48
+ if ( in_array( $event_array[0], $this->events, true ) && in_array( $event_array[1], array_keys( $roles ), true ) ) {
49
+ $event_array[1] = $roles[ $event_array[1] ];
50
+ $this->insert_notification( $event_array );
51
+ }
52
+ }
53
+ }
54
+ }
55
+ // delete the old options.
56
+ $this->delete_option();
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Check if import is needed.
62
+ *
63
+ * @since 1.0
64
+ * @return unknown
65
+ */
66
+ private function import_needed() {
67
+ if ( get_option( self::EMAIL_OPTION ) && get_option( self::SETTING_OPTION ) ) {
68
+ return true;
69
+ }
70
+
71
+ return false;
72
+ }
73
+
74
+ /**
75
+ * Insert notification.
76
+ *
77
+ * @param mixed $event Event type.
78
+ */
79
+ private function insert_notification( $event ) {
80
+ $post = array(
81
+ 'post_title' => $event[0] . esc_html__( ' for ', 'bnfw' ) . $event[1] . esc_html__( ' (Auto Imported)', 'bnfw' ),
82
+ 'post_type' => BNFW_Notification::POST_TYPE,
83
+ 'post_content' => '',
84
+ 'post_status' => 'publish',
85
+ );
86
+
87
+ $post_id = wp_insert_post( $post );
88
+ if ( $post_id > 0 ) {
89
+ $content = $this->map_notification_content( $event[0] );
90
+ $setting = array(
91
+ 'notification' => $this->map_notification( $event[0] ),
92
+ 'user-roles' => array( $event[1] ),
93
+ 'users' => array(),
94
+ 'subject' => $content['subject'],
95
+ 'message' => $content['body'],
96
+ );
97
+
98
+ foreach ( $setting as $key => $value ) {
99
+ update_post_meta( $post_id, BNFW_Notification::META_KEY_PREFIX . $key, $value );
100
+ }
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Map old notification type to new notification type.
106
+ *
107
+ * @param mixed $event_name Event name.
108
+ *
109
+ * @return unknown
110
+ */
111
+ private function map_notification( $event_name ) {
112
+ switch ( $event_name ) {
113
+ case 'create_term':
114
+ return 'new-category';
115
+ break;
116
+ case 'publish_post':
117
+ return 'new-post';
118
+ break;
119
+ case 'comment_post':
120
+ return 'new-comment';
121
+ break;
122
+ case 'user_register':
123
+ return 'new-user';
124
+ break;
125
+ case 'trackback_post':
126
+ return 'new-trackback';
127
+ break;
128
+ case 'pingback_post':
129
+ return 'new-pingback';
130
+ break;
131
+ case 'lostpassword_post':
132
+ return 'user-password';
133
+ break;
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Map content from old plugin.
139
+ *
140
+ * @param unknown $event_name Event name.
141
+ *
142
+ * @return unknown
143
+ */
144
+ private function map_notification_content( $event_name ) {
145
+ $content = array();
146
+ if ( ! isset( $this->content_map ) ) {
147
+ $this->parse_content();
148
+ }
149
+
150
+ return $this->content_map[ $event_name ];
151
+ }
152
+
153
+ /**
154
+ * Parse content from old plugins setting.
155
+ *
156
+ * @since 1.0
157
+ */
158
+ private function parse_content() {
159
+ $old_content = get_option( self::EMAIL_OPTION );
160
+ $content_map = array();
161
+ foreach ( $old_content as $key => $value ) {
162
+ $key_array = explode( '-', $key );
163
+ if ( 3 === count( $key_array ) ) {
164
+ $content_map[ $key_array[2] ][ $key_array[1] ] = $value;
165
+ }
166
+ }
167
+ $this->content_map = $content_map;
168
+ }
169
+
170
+ /**
171
+ * Delete old plugin database options.
172
+ *
173
+ * @since 1.0
174
+ */
175
+ private function delete_option() {
176
+ delete_option( self::EMAIL_OPTION );
177
+ delete_option( self::SETTING_OPTION );
178
+ }
179
+ }
180
+ }
includes/engine/class-bnfw-engine.php CHANGED
@@ -1,1598 +1,1639 @@
1
- <?php
2
-
3
- /**
4
- * BNFW Engine
5
- *
6
- * @since 1.0
7
- */
8
- class BNFW_Engine {
9
-
10
- /**
11
- * Send test email.
12
- *
13
- * @since 1.2
14
- *
15
- * @param array $setting
16
- */
17
- public function send_test_email( $setting ) {
18
- $subject = __( 'Test Email:', 'bnfw' ) . ' ' . $setting[ 'subject' ];
19
- $message = '<p><strong>' . __( 'This is a test email. All shortcodes below will show in place but not be replaced with content.', 'bnfw' ) . '</strong></p>' . stripslashes( $setting[ 'message' ] );
20
-
21
- if ( 'true' != $setting[ 'disable-autop' ] && 'html' == $setting[ 'email-formatting' ] ) {
22
- $message = wpautop( $message );
23
- }
24
-
25
- $current_user = wp_get_current_user();
26
- $email = $current_user->user_email;
27
-
28
- $headers = array();
29
- if ( 'html' == $setting[ 'email-formatting' ] ) {
30
- $headers[] = 'Content-type: text/html';
31
- $message = apply_filters( 'bnfw_test_email_message', $message, $setting );
32
- } elseif ( 'text' == $setting[ 'email-formatting' ] ) {
33
- $message = strip_tags( $message );
34
- }
35
-
36
- wp_mail( $email, stripslashes( $subject ), $message, $headers );
37
- }
38
-
39
- /**
40
- * Send the notification email.
41
- *
42
- * @since 1.0
43
- * @param array $setting
44
- * @param int $id
45
- */
46
- public function send_notification( $setting, $id ) {
47
- /**
48
- * BNFW - Whether notification is disabled?
49
- *
50
- * @since 1.3.6
51
- */
52
-
53
- $notification_disabled = apply_filters( 'bnfw_notification_disabled', ( 'true' === $setting[ 'disabled' ] ), $id, $setting );
54
-
55
- if ( ! $notification_disabled ) {
56
-
57
- $subject = $this->handle_shortcodes( $setting[ 'subject' ], $setting[ 'notification' ], $id );
58
- $message = $this->handle_shortcodes( $setting[ 'message' ], $setting[ 'notification' ], $id );
59
- $emails = $this->get_emails( $setting, $id );
60
- $headers = $this->get_headers( $emails );
61
-
62
- if ( 'true' != $setting[ 'disable-autop' ] && 'html' == $setting[ 'email-formatting' ] ) {
63
- $message = wpautop( $message );
64
- }
65
-
66
- if ( 'html' == $setting[ 'email-formatting' ] ) {
67
- $headers[] = 'Content-type: text/html';
68
- $message = apply_filters( 'bnfw_notification_message', $message, $setting );
69
- } else {
70
- $headers[] = 'Content-type: text/plain';
71
- if ( 'text' == $setting[ 'email-formatting' ] ) {
72
- $message = strip_tags( $message );
73
- }
74
- }
75
-
76
- $emails = apply_filters( 'bnfw_emails', $emails, $setting, $id );
77
-
78
- $send = apply_filters( 'bnfw_can_send_email', true, $setting, $emails, $subject, $message, $headers );
79
-
80
- if ( ! $send ) {
81
- return;
82
- }
83
-
84
- if ( isset( $emails[ 'to' ] ) && is_array( $emails[ 'to' ] ) ) {
85
- foreach ( $emails[ 'to' ] as $email ) {
86
- wp_mail( $email, stripslashes( $this->handle_global_user_shortcodes( $subject, $email ) ), $this->handle_global_user_shortcodes( $message, $email ), $headers );
87
- }
88
- }
89
- }
90
- }
91
-
92
- /**
93
- * Send new user registration notification email.
94
- *
95
- * @since 1.1
96
- * @param array $setting Notification setting
97
- * @param object $user User object
98
- * @param string $password_url Plain text password in WP < 4.3 and password url in WP > 4.3
99
- */
100
- public function send_registration_email( $setting, $user, $password_url = '' ) {
101
- /**
102
- * Whether to trigger welcome email notification or not.
103
- *
104
- * @since 1.7
105
- */
106
- $trigger_notification = apply_filters( 'bnfw_trigger_welcome-email_notification', true, $setting, $user );
107
-
108
- if ( ! $trigger_notification ) {
109
- return;
110
- }
111
-
112
- $user_id = $user->ID;
113
-
114
- $subject = $this->handle_shortcodes( $setting[ 'subject' ], $setting[ 'notification' ], $user_id );
115
- $message = $this->handle_shortcodes( $setting[ 'message' ], $setting[ 'notification' ], $user_id );
116
-
117
- $subject = str_replace( '[password]', $password_url, $subject );
118
- $message = str_replace( '[password]', $password_url, $message );
119
-
120
- $subject = str_replace( '[password_url]', $password_url, $subject );
121
- $message = str_replace( '[password_url]', $password_url, $message );
122
-
123
- $subject = str_replace( '[login_url]', wp_login_url(), $subject );
124
- $message = str_replace( '[login_url]', wp_login_url(), $message );
125
-
126
- if ( 'true' != $setting[ 'disable-autop' ] && 'html' == $setting[ 'email-formatting' ] ) {
127
- $message = wpautop( $message );
128
- }
129
-
130
- $headers = array();
131
- if ( 'html' == $setting[ 'email-formatting' ] ) {
132
- $headers[] = 'Content-type: text/html';
133
- $message = apply_filters( 'bnfw_registration_email_message', $message, $setting );
134
- } elseif ( 'text' == $setting[ 'email-formatting' ] ) {
135
- $message = strip_tags( $message );
136
- }
137
-
138
- $subject = $this->handle_global_user_shortcodes( $subject, $user->user_email );
139
- $message = $this->handle_global_user_shortcodes( $message, $user->user_email );
140
- wp_mail( $user->user_email, stripslashes( $subject ), $message, $headers );
141
- }
142
-
143
- /**
144
- * Send user login notification email.
145
- *
146
- * @since 1.1
147
- * @param array $setting Notification setting
148
- * @param object $user User object
149
- */
150
- public function send_user_login_email( $setting, $user ) {
151
-
152
- $trigger_notification = apply_filters( 'bnfw_trigger_user-login_notification', true, $setting, $user );
153
-
154
- if ( ! $trigger_notification ) {
155
- return;
156
- }
157
-
158
- $user_id = $user->ID;
159
-
160
- $subject = $this->handle_shortcodes( $setting[ 'subject' ], $setting[ 'notification' ], $user_id );
161
- $message = $this->handle_shortcodes( $setting[ 'message' ], $setting[ 'notification' ], $user_id );
162
- $emails = $this->get_emails( $setting, $user_id );
163
- $headers = $this->get_headers( $emails );
164
-
165
- if ( 'true' != $setting[ 'disable-autop' ] && 'html' == $setting[ 'email-formatting' ] ) {
166
- $message = wpautop( $message );
167
- }
168
-
169
- if ( 'html' == $setting[ 'email-formatting' ] ) {
170
- $headers[] = 'Content-type: text/html';
171
- $message = apply_filters( 'bnfw_notification_message', $message, $setting );
172
- } elseif ( 'text' == $setting[ 'email-formatting' ] ) {
173
- $message = strip_tags( $message );
174
- }
175
-
176
- $subject = $this->handle_global_user_shortcodes( $subject, $user->user_email );
177
- $message = $this->handle_global_user_shortcodes( $message, $user->user_email );
178
-
179
- wp_mail( $user->user_email, stripslashes( $subject ), $message, $headers );
180
- }
181
-
182
- /**
183
- * Send user login notification email for admin.
184
- *
185
- * @since 1.1
186
- * @param array $setting Notification setting
187
- * @param object $user User object
188
- */
189
- public function send_user_login_email_for_admin( $setting, $user ) {
190
-
191
- $trigger_notification = apply_filters( 'bnfw_trigger_user-login_notification', true, $setting, $user );
192
-
193
- if ( ! $trigger_notification ) {
194
- return;
195
- }
196
- $user_id = $user->ID;
197
-
198
- $this->send_notification( $setting, $user_id );
199
- }
200
-
201
- /**
202
- * Send comment reply notification email.
203
- *
204
- * @since 1.3
205
- * @param array $setting Notification setting
206
- * @param object $comment Comment object
207
- * @param object $parent_comment Parent comment object
208
- */
209
- public function send_comment_reply_email( $setting, $comment,
210
- $parent_comment ) {
211
- $comment_id = $comment->comment_ID;
212
-
213
- /**
214
- * BNFW - Whether notification is disabled?
215
- *
216
- * @since 1.3.6
217
- */
218
- $notification_disabled = apply_filters( 'bnfw_notification_disabled', false, $comment_id, $setting );
219
-
220
- if ( ! $notification_disabled ) {
221
- $subject = $this->handle_shortcodes( $setting[ 'subject' ], $setting[ 'notification' ], $comment_id );
222
- $message = $this->handle_shortcodes( $setting[ 'message' ], $setting[ 'notification' ], $comment_id );
223
-
224
- $headers = array();
225
- if ( 'html' == $setting[ 'email-formatting' ] ) {
226
- $headers[] = 'Content-type: text/html';
227
- } elseif ( 'text' == $setting[ 'email-formatting' ] ) {
228
- $message = strip_tags( $message );
229
- }
230
-
231
- if ( 'true' != $setting[ 'disable-autop' ] && 'html' == $setting[ 'email-formatting' ] ) {
232
- $message = wpautop( $message );
233
- $message = apply_filters( 'bnfw_comment_reply_email_message', $message, $setting );
234
- }
235
-
236
- $subject = $this->handle_global_user_shortcodes( $subject, $parent_comment->comment_author_email );
237
- $message = $this->handle_global_user_shortcodes( $message, $parent_comment->comment_author_email );
238
- wp_mail( $parent_comment->comment_author_email, stripslashes( $subject ), $message, $headers );
239
- }
240
- }
241
-
242
- /**
243
- * Send user role changed email.
244
- *
245
- * @since 1.3.9
246
- *
247
- * @param array $setting Notification setting
248
- * @param int $user_id User ID
249
- * @param array $old_role Old User Role.
250
- * @param array $new_role New User Role.
251
- */
252
- public function send_user_role_changed_email( $setting, $user_id, $old_role,
253
- $new_role ) {
254
- $subject = $this->handle_shortcodes( $setting[ 'subject' ], $setting[ 'notification' ], $user_id );
255
- $message = $this->handle_shortcodes( $setting[ 'message' ], $setting[ 'notification' ], $user_id );
256
-
257
- $subject = $this->handle_user_role_shortcodes( $subject, $old_role, $new_role );
258
- $message = $this->handle_user_role_shortcodes( $message, $old_role, $new_role );
259
-
260
- $headers = array();
261
- if ( 'true' != $setting[ 'disable-autop' ] && 'html' == $setting[ 'email-formatting' ] ) {
262
- $message = wpautop( $message );
263
- }
264
-
265
- if ( 'html' == $setting[ 'email-formatting' ] ) {
266
- $headers[] = 'Content-type: text/html';
267
- $message = apply_filters( 'bnfw_user_role_changed_email_message', $message, $setting );
268
- } elseif ( 'text' == $setting[ 'email-formatting' ] ) {
269
- $message = strip_tags( $message );
270
- }
271
-
272
- $user = get_user_by( 'id', $user_id );
273
-
274
- $subject = $this->handle_global_user_shortcodes( $subject, $user->user_email );
275
- $message = $this->handle_global_user_shortcodes( $message, $user->user_email );
276
- wp_mail( $user->user_email, stripslashes( $subject ), $message, $headers );
277
- }
278
-
279
- /**
280
- * Send user role added support User Role Editor by Members Plugin.
281
- *
282
- * @since 1.3.9
283
- *
284
- * @param array $setting Notification setting
285
- * @param int $user_id User ID
286
- * @param array $old_role Old User Role.
287
- * @param array $new_role New User Role.
288
- */
289
- public function send_user_role_added_email( $setting, $user_id, $old_role,
290
- $new_role ) {
291
- $subject = $this->handle_shortcodes( $setting[ 'subject' ], $setting[ 'notification' ], $user_id );
292
- $message = $this->handle_shortcodes( $setting[ 'message' ], $setting[ 'notification' ], $user_id );
293
-
294
- $subject = $this->handle_user_added_role_shortcodes( $subject, $old_role, $new_role );
295
- $message = $this->handle_user_added_role_shortcodes( $message, $old_role, $new_role );
296
-
297
- $headers = array();
298
- if ( 'true' != $setting[ 'disable-autop' ] && 'html' == $setting[ 'email-formatting' ] ) {
299
- $message = wpautop( $message );
300
- }
301
-
302
- if ( 'html' == $setting[ 'email-formatting' ] ) {
303
- $headers[] = 'Content-type: text/html';
304
- $message = apply_filters( 'bnfw_user_role_changed_email_message', $message, $setting );
305
- } elseif ( 'text' == $setting[ 'email-formatting' ] ) {
306
- $message = strip_tags( $message );
307
- }
308
-
309
- $user = get_user_by( 'id', $user_id );
310
-
311
- $subject = $this->handle_global_user_shortcodes( $subject, $user->user_email );
312
- $message = $this->handle_global_user_shortcodes( $message, $user->user_email );
313
- wp_mail( $user->user_email, stripslashes( $subject ), $message, $headers );
314
- }
315
-
316
- /**
317
- * Handle User Role shortcodes.
318
- *
319
- * @param string $message String that needs shortcode processing.
320
- * @param array $old_role Old User Role.
321
- * @param array $new_role New User Role.
322
- *
323
- * @return string Processed string.
324
- */
325
- public function handle_user_role_shortcodes( $message, $old_role, $new_role ) {
326
- $roles = wp_roles();
327
-
328
- $old_role_name = '';
329
- $new_role_name = '';
330
-
331
- if ( isset( $roles->role_names[ $old_role ] ) ) {
332
- $old_role_name = $roles->role_names[ $old_role ];
333
- }
334
-
335
- if ( isset( $roles->role_names[ $new_role ] ) ) {
336
- $new_role_name = $roles->role_names[ $new_role ];
337
- }
338
-
339
- $message = str_replace( '[user_role_old]', $old_role_name, $message );
340
- $message = str_replace( '[user_role_new]', $new_role_name, $message );
341
-
342
- return $message;
343
- }
344
-
345
- /**
346
- * Handle User Added Role shortcodes.
347
- *
348
- * @param string $message String that needs shortcode processing.
349
- * @param array $old_role Old User Role.
350
- * @param array $new_role New User Role.
351
- *
352
- * @return string Processed string.
353
- */
354
- public function handle_user_added_role_shortcodes( $message, $old_roles,
355
- $new_roles ) {
356
- $roles = wp_roles();
357
-
358
- $old_role_name = array();
359
- $new_role_name = array();
360
-
361
- foreach ( $old_roles as $key => $old_role ) {
362
- if ( isset( $roles->role_names[ $old_role ] ) ) {
363
- $old_role_name[] = $roles->role_names[ $old_role ];
364
- }
365
- }
366
- foreach ( $new_roles as $key => $new_role ) {
367
- if ( isset( $roles->role_names[ $new_role ] ) ) {
368
- $new_role_name[] = $roles->role_names[ $new_role ];
369
- }
370
- }
371
-
372
- $message = str_replace( '[user_role_old]', implode( ',', $old_role_name ), $message );
373
- $message = str_replace( '[user_role_new]', implode( ',', $new_role_name ), $message );
374
-
375
- return $message;
376
- }
377
-
378
- /**
379
- * Handle shortcodes for filtered data notifications like `password_changed` and `email_changed`.
380
- *
381
- * @since 1.6
382
- *
383
- * @param array $email_data Email data.
384
- * @param array $setting Notification settings.
385
- * @param string|int $extra_data Extra data.
386
- *
387
- * @return array Modified email data.
388
- */
389
- public function handle_filtered_data_notification( $email_data, $setting,
390
- $extra_data ) {
391
- $email_data[ 'message' ] = $this->handle_shortcodes( $setting[ 'message' ], $setting[ 'notification' ], $extra_data );
392
- $email_data[ 'subject' ] = $this->handle_shortcodes( $setting[ 'subject' ], $setting[ 'notification' ], $extra_data );
393
-
394
- $email_data[ 'message' ] = $this->handle_global_user_shortcodes( $email_data[ 'message' ], $email_data[ 'to' ] );
395
- $email_data[ 'subject' ] = $this->handle_global_user_shortcodes( $email_data[ 'subject' ], $email_data[ 'to' ] );
396
-
397
- if ( 'true' != $setting[ 'disable-autop' ] && 'html' == $setting[ 'email-formatting' ] ) {
398
- $email_data[ 'message' ] = wpautop( $email_data[ 'message' ] );
399
- }
400
-
401
- if ( 'html' == $setting[ 'email-formatting' ] ) {
402
- $headers[] = 'Content-type: text/html';
403
- } else {
404
- $headers[] = 'Content-type: text/plain';
405
- if ( 'text' == $setting[ 'email-formatting' ] ) {
406
- $message = strip_tags( $message );
407
- }
408
- }
409
-
410
- $email_data[ 'headers' ] = $headers;
411
-
412
- return $email_data;
413
- }
414
-
415
- /**
416
- * Handle shortcodes for core updated notification.
417
- *
418
- * @since 1.6
419
- *
420
- * @param array $email_data Email data.
421
- * @param array $setting Notification settings.
422
- * @param string $type Result of update.
423
- *
424
- * @return array Modified email data.
425
- */
426
- public function handle_core_updated_notification( $email_data, $setting,
427
- $type ) {
428
- $email_data[ 'body' ] = $this->handle_shortcodes( $setting[ 'message' ], $setting[ 'notification' ], $type );
429
- $email_data[ 'subject' ] = $this->handle_shortcodes( $setting[ 'subject' ], $setting[ 'notification' ], $type );
430
-
431
- $emails = $this->get_emails( $setting, $type );
432
- $headers = $this->get_headers( $emails );
433
-
434
- $email_data[ 'body' ] = $this->handle_global_user_shortcodes( $email_data[ 'body' ], $emails[ 'to' ][ 0 ] );
435
- $email_data[ 'subject' ] = $this->handle_global_user_shortcodes( $email_data[ 'subject' ], $emails[ 'to' ][ 0 ] );
436
-
437
- if ( 'true' != $setting[ 'disable-autop' ] && 'html' == $setting[ 'email-formatting' ] ) {
438
- $email_data[ 'body' ] = wpautop( $email_data[ 'body' ] );
439
- }
440
-
441
- if ( 'html' == $setting[ 'email-formatting' ] ) {
442
- $headers[] = 'Content-type: text/html';
443
- } else {
444
- $headers[] = 'Content-type: text/plain';
445
- if ( 'text' == $setting[ 'email-formatting' ] ) {
446
- $message = strip_tags( $message );
447
- }
448
- }
449
-
450
- $email_data[ 'headers' ] = $headers;
451
-
452
- return $email_data;
453
- }
454
-
455
- /**
456
- * Handle shortcode for password reset email message.
457
- *
458
- * @since 1.1
459
- *
460
- * @param $setting
461
- * @param $key
462
- * @param $user_login
463
- * @param $user_data
464
- *
465
- * @return mixed|string
466
- */
467
- public function handle_password_reset_shortcodes( $setting, $key,
468
- $user_login, $user_data ) {
469
- $message = '';
470
-
471
- if ( '' != $user_login ) {
472
- // For WordPress version 4.1.0 or less, we could have empty user_login
473
- $message = $this->handle_shortcodes( $setting[ 'message' ], 'user-password', $user_data->ID );
474
- $message = $this->handle_global_user_shortcodes( $message, $user_data->user_email );
475
-
476
- $reset_link = network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' );
477
- $message = str_replace( '[password_reset_link]', $reset_link, $message );
478
- }
479
-
480
- return $message;
481
- }
482
-
483
- /**
484
- * Send Password Changed email.
485
- *
486
- * @param array $setting Notification Setting.
487
- * @param WP_User $user User for whom the password has changed.
488
- */
489
- public function send_password_changed_email( $setting, $user ) {
490
- $user_id = $user->ID;
491
-
492
- $subject = $this->handle_shortcodes( $setting[ 'subject' ], $setting[ 'notification' ], $user_id );
493
- $message = $this->handle_shortcodes( $setting[ 'message' ], $setting[ 'notification' ], $user_id );
494
-
495
- if ( 'true' != $setting[ 'disable-autop' ] && 'html' == $setting[ 'email-formatting' ] ) {
496
- $message = wpautop( $message );
497
- }
498
-
499
- $headers = array();
500
- if ( 'html' == $setting[ 'email-formatting' ] ) {
501
- $headers[] = 'Content-type: text/html';
502
- } elseif ( 'text' == $setting[ 'email-formatting' ] ) {
503
- $message = strip_tags( $message );
504
- }
505
-
506
- $subject = $this->handle_global_user_shortcodes( $subject, $user->user_email );
507
- $message = $this->handle_global_user_shortcodes( $message, $user->user_email );
508
- wp_mail( $user->user_email, stripslashes( $subject ), $message, $headers );
509
- }
510
-
511
- /**
512
- * Generate message for notification.
513
- *
514
- * @since 1.0
515
- * public since @since 1.6
516
- *
517
- * @param string $message String may have shortcode.
518
- * @param string $notification Notification name.
519
- * @param string|int $extra_data Additional data for shortcode.
520
- *
521
- * @return string Processed string.
522
- */
523
- public function handle_shortcodes( $message, $notification, $extra_data ) {
524
-
525
- switch ( $notification ) {
526
- case 'new-comment':
527
- case 'new-trackback':
528
- case 'new-pingback':
529
- case 'reply-comment':
530
- // handle new comments, trackbacks and pingbacks
531
- $message = $this->comment_shortcodes( $message, $extra_data );
532
- $comment = get_comment( $extra_data );
533
- $message = $this->post_shortcodes( $message, $comment->comment_post_ID );
534
- if ( 0 != $comment->user_id ) {
535
- $message = $this->user_shortcodes( $message, $comment->user_id );
536
- }
537
- break;
538
-
539
- case 'admin-password':
540
- case 'admin-password-changed':
541
- case 'admin-email-changed':
542
- case 'admin-user':
543
- case 'welcome-email':
544
- case 'user-login':
545
- $message = $this->user_shortcodes( $message, $extra_data );
546
- break;
547
- case 'admin-user-login':
548
- $message = $this->user_shortcodes( $message, $extra_data );
549
- break;
550
- case 'new-user':
551
- case 'user-role':
552
- case 'admin-role':
553
- case 'password-changed':
554
- // handle users (lost password and new user registration)
555
- $message = $this->user_shortcodes( $message, $extra_data );
556
- break;
557
-
558
- case 'email-changed':
559
- case 'user-password':
560
- // handle users (lost password and new user registration)
561
- $message = $this->user_shortcodes( $message, $extra_data, 'email_' );
562
- break;
563
-
564
- case 'new-category':
565
- // handle new category
566
- $message = $this->taxonomy_shortcodes( $message, 'category', $extra_data );
567
- break;
568
-
569
- case 'new-post_tag':
570
- // handle new tag
571
- $message = $this->taxonomy_shortcodes( $message, 'post_tag', $extra_data );
572
- break;
573
-
574
- case 'core-updated':
575
- // handle core updated type
576
- $message = $this->core_updated_shortcodes( $message, $extra_data );
577
- break;
578
-
579
- case 'data-export':
580
- // handle data export email
581
- $message = $this->data_export_shortcodes( $message, $extra_data );
582
- break;
583
-
584
- case 'data-erased':
585
- // handle data export email
586
- $message = $this->data_erased_shortcodes( $message, $extra_data );
587
- break;
588
-
589
- case 'new-media':
590
- case 'update-media':
591
- $message = $this->post_shortcodes( $message, $extra_data );
592
- $post = get_post( $extra_data );
593
- if ( $post instanceof WP_Post ) {
594
- $message = $this->user_shortcodes( $message, $post->post_author );
595
- }
596
- break;
597
-
598
- default:
599
- $type = explode( '-', $notification, 2 );
600
- if ( 'newterm' == $type[ 0 ] ) {
601
- // handle new terms
602
- $message = $this->taxonomy_shortcodes( $message, $type[ 1 ], $extra_data );
603
- } elseif ( 'new' == $type[ 0 ] || 'update' == $type[ 0 ] || 'pending' == $type[ 0 ] || 'future' == $type[ 0 ] || 'private' == $type[ 0 ] || 'trash' == $type[ 0 ] ) {
604
- // handle new, update and pending posts
605
- $post_types = get_post_types( array( 'public' => true ), 'names' );
606
- $post_types = array_diff( $post_types, array( BNFW_Notification::POST_TYPE ) );
607
-
608
- if ( in_array( $type[ 1 ], $post_types ) ) {
609
- $message = $this->post_shortcodes( $message, $extra_data );
610
- $post = get_post( $extra_data );
611
- if ( $post instanceof WP_Post ) {
612
- $message = $this->user_shortcodes( $message, $post->post_author );
613
- }
614
- }
615
- } elseif ( 'comment' == $type[ 0 ] || 'moderate' == $type[ 0 ] || 'commentreply' == $type[ 0 ] ) {
616
- $message = $this->comment_shortcodes( $message, $extra_data );
617
- $comment = get_comment( $extra_data );
618
- $message = $this->post_shortcodes( $message, $comment->comment_post_ID );
619
- if ( 0 != $comment->user_id ) {
620
- $message = $this->user_shortcodes( $message, $comment->user_id );
621
- }
622
- } elseif ( 'approve' === $type[ 0 ] ) {
623
- // handle Approve comments notification
624
- $message = $this->comment_shortcodes( $message, $extra_data );
625
- $comment = get_comment( $extra_data );
626
- $message = $this->post_shortcodes( $message, $comment->comment_post_ID );
627
- if ( 0 != $comment->user_id ) {
628
- $message = $this->user_shortcodes( $message, $comment->user_id );
629
- }
630
- break;
631
- } elseif ( 'ca' === $type[ 0 ] ) {
632
- $message = $this->confirm_action_shortcodes( $message, $extra_data );
633
- $message = $this->handle_global_user_shortcodes( $message, $extra_data[ 'email' ] );
634
- } elseif ( 'uc' === $type[ 0 ] ) {
635
- $message = $this->confirmed_action_shortcodes( $message, $extra_data );
636
- $message = $this->handle_global_user_shortcodes( $message, $extra_data[ 'admin_email' ] );
637
- }
638
- break;
639
- }
640
-
641
- $message = $this->global_shortcodes( $message );
642
-
643
- $message = apply_filters( 'bnfw_shortcodes', $message, $notification, $extra_data, $this );
644
- return $message;
645
- }
646
-
647
- /**
648
- * Handle Global shortcodes.
649
- *
650
- * @since 1.5
651
- *
652
- * @param string $message String with shortcodes.
653
- *
654
- * @return string String after processing global shortcodes.
655
- */
656
- private function global_shortcodes( $message ) {
657
- $message = str_replace( '[global_site_title]', get_bloginfo( 'name' ), $message );
658
- $message = str_replace( '[global_site_tagline]', get_bloginfo( 'description' ), $message );
659
- $message = str_replace( '[global_site_url]', get_bloginfo( 'url' ), $message );
660
-
661
- $message = str_replace( '[current_time]', current_time( get_option( 'time_format' ) ), $message );
662
- $message = str_replace( '[current_date]', date_i18n( get_option( 'date_format' ), current_time( 'timestamp' ) ), $message );
663
- $message = str_replace( '[admin_email]', get_option( 'admin_email' ), $message );
664
-
665
- return $message;
666
- }
667
-
668
- /**
669
- * Handle Global shortcodes.
670
- *
671
- * @param string $message Message.
672
- * @param string $email Email.
673
- *
674
- * @return string
675
- */
676
- public function handle_global_shortcodes( $message, $email ) {
677
- $message = $this->global_shortcodes( $message );
678
-
679
- return $this->handle_global_user_shortcodes( $message, $email );
680
- }
681
-
682
- /**
683
- * Handle Global User Shortcodes.
684
- *
685
- * @param string $message String to be processed.
686
- * @param string $email Email of the user.
687
- *
688
- * @return string Processed string.
689
- */
690
- public function handle_global_user_shortcodes( $message, $email ) {
691
- $user = get_user_by( 'email', $email );
692
-
693
- if ( false === $user ) {
694
- $message = str_replace( '[global_user_firstname]', $email, $message );
695
- $message = str_replace( '[global_user_lastname]', $email, $message );
696
- $message = str_replace( '[global_user_username]', $email, $message );
697
- } else {
698
- $message = str_replace( '[global_user_firstname]', $user->first_name, $message );
699
- $message = str_replace( '[global_user_lastname]', $user->last_name, $message );
700
- $message = str_replace( '[global_user_username]', $user->user_login, $message );
701
-
702
- $message = $this->user_shortcodes( $message, $user->ID, 'email_' );
703
- }
704
-
705
- $message = str_replace( '[privacy_policy_url]', get_privacy_policy_url(), $message );
706
-
707
- $message = str_replace( array('[global_user_email]','[user_email]'), $email, $message );
708
-
709
- return $message;
710
- }
711
-
712
- /**
713
- * Handle media post shortcodes.
714
- *
715
- * @since 1.0
716
- * @param string $message
717
- * @param int $post_id
718
- * @return string
719
- */
720
- public function media_post_shortcodes( $message, $post ) {
721
- $post_content = $this->may_be_strip_shortcode( $post->post_content );
722
- $post_content = apply_filters( 'the_content', $post_content );
723
- $post_content = str_replace( ']]>', ']]&gt;', $post_content );
724
- $message = str_replace( '[ID]', $post->ID, $message );
725
- $message = str_replace( '[media_date]', bnfw_format_date( $post->post_date ), $message );
726
- $message = str_replace( '[media_date_gmt]', bnfw_format_date( $post->post_date_gmt ), $message );
727
- $message = str_replace( '[media_description]', $post_content, $message );
728
- $message = str_replace( '[media_title]', $post->post_title, $message );
729
- $message = str_replace( '[media_alt_text]', get_post_meta( $post->ID, '_wp_attachment_image_alt', true ), $message );
730
- $message = str_replace( '[media_caption]', $this->may_be_strip_shortcode( get_the_excerpt( $post ) ), $message );
731
- $message = str_replace( '[media_status]', $post->post_status, $message );
732
- $message = str_replace( '[media_modified]', bnfw_format_date( $post->post_modified ), $message );
733
- $message = str_replace( '[media_modified_gmt]', bnfw_format_date( $post->post_modified_gmt ), $message );
734
- $message = str_replace( '[media_content_filtered]', $post->post_content_filtered, $message );
735
- $message = str_replace( '[media_type]', $post->post_type, $message );
736
- $message = str_replace( '[media_mime_type]', $post->post_mime_type, $message );
737
- $message = str_replace( '[media_slug]', $post->post_name, $message );
738
- $dimensions = get_post_meta( $post->ID, '_wp_attachment_metadata', true );
739
- $media_dimensions = $dimensions[ 'width' ] . ' x ' . $dimensions[ 'height' ];
740
- $message = str_replace( '[media_dimensions]', $media_dimensions, $message );
741
- $user_info = get_userdata( $post->post_author );
742
- $message = str_replace( '[media_author]', $user_info->display_name, $message );
743
-
744
- return $message;
745
- }
746
-
747
- /**
748
- * Handle post shortcodes.
749
- *
750
- * @since 1.0
751
- * @param string $message
752
- * @param int $post_id
753
- * @return string
754
- */
755
- public function post_shortcodes( $message, $post_id ) {
756
- $post = get_post( $post_id );
757
-
758
- if ( ! $post instanceof WP_Post ) {
759
- return $message;
760
- }
761
-
762
- if ( $post->post_type == 'attachment' ) {
763
- $message = $this->media_post_shortcodes( $message, $post );
764
- }
765
-
766
- $post_content = $this->may_be_strip_shortcode( $post->post_content );
767
- $post_content = apply_filters( 'the_content', $post_content );
768
- $post_content = str_replace( ']]>', ']]&gt;', $post_content );
769
-
770
- $message = str_replace( '[ID]', $post->ID, $message );
771
- $message = str_replace( '[post_date]', bnfw_format_date( $post->post_date ), $message );
772
- $message = str_replace( '[post_date_gmt]', bnfw_format_date( $post->post_date_gmt ), $message );
773
- $message = str_replace( '[post_content]', $post_content, $message );
774
- $message = str_replace( '[post_title]', $post->post_title, $message );
775
- $message = str_replace( '[post_excerpt]', $this->may_be_strip_shortcode( get_the_excerpt( $post ) ), $message );
776
- $message = str_replace( '[post_status]', $post->post_status, $message );
777
- $message = str_replace( '[comment_status]', $post->comment_status, $message );
778
- $message = str_replace( '[ping_status]', $post->ping_status, $message );
779
- $message = str_replace( '[post_password]', $post->post_password, $message );
780
- $message = str_replace( '[post_name]', $post->post_name, $message );
781
- $message = str_replace( '[post_slug]', $post->post_name, $message );
782
- $message = str_replace( '[to_ping]', $post->to_ping, $message );
783
- $message = str_replace( '[pinged]', $post->pinged, $message );
784
- $message = str_replace( '[post_modified]', bnfw_format_date( $post->post_modified ), $message );
785
- $message = str_replace( '[post_modified_gmt]', bnfw_format_date( $post->post_modified_gmt ), $message );
786
- $message = str_replace( '[post_content_filtered]', $post->post_content_filtered, $message );
787
- $message = str_replace( '[post_parent]', $post->post_parent, $message );
788
- $message = str_replace( '[post_parent_permalink]', get_permalink( $post->post_parent ), $message );
789
- $message = str_replace( '[guid]', $post->guid, $message );
790
- $message = str_replace( '[menu_order]', $post->menu_order, $message );
791
- $message = str_replace( '[post_type]', $post->post_type, $message );
792
- $message = str_replace( '[post_mime_type]', $post->post_mime_type, $message );
793
- $message = str_replace( '[comment_count]', $post->comment_count, $message );
794
- $message = str_replace( '[permalink]', get_permalink( $post->ID ), $message );
795
- $message = str_replace( '[post_type_archive]', get_post_type_archive_link( $post->post_type ), $message );
796
-
797
- $message = str_replace( '[edit_post]', $this->get_edit_post_link( $post->ID, 'return' ), $message );
798
-
799
- $featured_image = '';
800
- if ( has_post_thumbnail( $post->ID ) ) {
801
- $image_url = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'single-post-thumbnail' );
802
- if ( is_array( $image_url ) ) {
803
- $featured_image = $image_url[ 0 ];
804
- }
805
- }
806
- $message = str_replace( '[featured_image]', $featured_image, $message );
807
-
808
- $message = str_replace( '[first_image]', $this->get_first_image( $post->post_content ), $message );
809
-
810
- if ( 'future' == $post->post_status ) {
811
- $message = str_replace( '[post_scheduled_date]', bnfw_format_date( $post->post_date ), $message );
812
- $message = str_replace( '[post_scheduled_date_gmt]', bnfw_format_date( $post->post_date_gmt ), $message );
813
- } else {
814
- $message = str_replace( '[post_scheduled_date]', 'Published', $message );
815
- $message = str_replace( '[post_scheduled_date_gmt]', 'Published', $message );
816
- }
817
-
818
- $categories = wp_get_post_categories( $post_id, array( 'fields' => 'all' ) );
819
-
820
- $message = str_replace( '[post_category]', implode( ', ', wp_list_pluck( $categories, 'name' ) ), $message );
821
-
822
- if ( count( $categories ) > 0 ) {
823
- $message = str_replace(
824
- array(
825
- '[post_category_slug]',
826
- '[post_category_description]',
827
- ),
828
- array(
829
- $categories[ 0 ]->slug,
830
- $categories[ 0 ]->description,
831
- ),
832
- $message
833
- );
834
- }
835
-
836
- $tag_list = implode( ', ', wp_get_post_tags( $post_id, array( 'fields' => 'names' ) ) );
837
- $message = str_replace( '[post_tag]', $tag_list, $message );
838
-
839
- $user_info = get_userdata( $post->post_author );
840
- $message = str_replace( '[post_author]', $user_info->display_name, $message );
841
-
842
- $message = str_replace( '[author_link]', get_author_posts_url( $post->post_author ), $message );
843
-
844
- if ( $last_id = get_post_meta( $post->ID, '_edit_lock', true ) ) {
845
-
846
- $last_id = explode(':',$last_id);
847
- if(count($last_id) > 1){
848
- $last_id = end($last_id);
849
- }
850
-
851
- if ( $post->post_author != $last_id ) {
852
- $last_user_info = get_userdata( $last_id );
853
- } else {
854
- $last_user_info = $user_info;
855
- }
856
-
857
- $message = str_replace( '[post_update_author]', $last_user_info->display_name, $message );
858
- }
859
-
860
- $message = str_replace( '[post_term', '[post_term id="' . $post_id . '"', $message );
861
- add_shortcode( 'post_term', array( $this, 'post_term_shortcode_handler' ) );
862
- $message = do_shortcode( $message );
863
- remove_shortcode( 'post_term', array( $this, 'post_term_shortcode_handler' ) );
864
-
865
- return apply_filters( 'bnfw_shortcodes_post', $message, $post_id );
866
- }
867
-
868
- /**
869
- * Retrieves the edit post link for post.
870
- *
871
- * This is a copy of the built-in function without the user check.
872
- *
873
- * Can be used within the WordPress loop or outside of it. Can be used with
874
- * pages, posts, attachments, and revisions.
875
- *
876
- * @param int|WP_Post $id Optional. Post ID or post object. Default is the global `$post`.
877
- * @param string $context Optional. How to output the '&' character. Default '&amp;'.
878
- * @return string|null The edit post link for the given post. null if the post type is invalid or does
879
- * not allow an editing UI.
880
- */
881
- public function get_edit_post_link( $id = 0, $context = 'display' ) {
882
- if ( ! $post = get_post( $id ) )
883
- return;
884
-
885
- if ( 'revision' === $post->post_type )
886
- $action = '';
887
- elseif ( 'display' == $context )
888
- $action = '&amp;action=edit';
889
- else
890
- $action = '&action=edit';
891
-
892
- $post_type_object = get_post_type_object( $post->post_type );
893
- if ( ! $post_type_object )
894
- return;
895
-
896
- if ( $post_type_object->_edit_link ) {
897
- $link = admin_url( sprintf( $post_type_object->_edit_link . $action, $post->ID ) );
898
- } else {
899
- $link = '';
900
- }
901
-
902
- /**
903
- * Filters the post edit link.
904
- *
905
- * @since 2.3.0
906
- *
907
- * @param string $link The edit link.
908
- * @param int $post_id Post ID.
909
- * @param string $context The link context. If set to 'display' then ampersands
910
- * are encoded.
911
- */
912
- return apply_filters( 'get_edit_post_link', $link, $post->ID, $context );
913
- }
914
-
915
- /**
916
- * Handle post term shortcode.
917
- *
918
- * @param array $atts Shortocde attributes.
919
- *
920
- * @return string Processed string.
921
- */
922
- public function post_term_shortcode_handler( $atts ) {
923
- $atts = shortcode_atts( array(
924
- 'taxonomy' => '',
925
- 'id' => 0,
926
- ), $atts );
927
-
928
- $terms = wp_get_post_terms( $atts[ 'id' ], $atts[ 'taxonomy' ], array( 'fields' => 'names' ) );
929
-
930
- if ( ! is_wp_error( $terms ) ) {
931
- return implode( ', ', $terms );
932
- }
933
-
934
- return '';
935
- }
936
-
937
- /**
938
- * Strip shortcodes, unless disabled.
939
- *
940
- * @param string $content Content who's shortcodes should be stripped.
941
- *
942
- * @return string Processed content.
943
- */
944
- private function may_be_strip_shortcode( $content ) {
945
- $enable_shortcode = get_option( 'bnfw_enable_shortcodes' );
946
-
947
- if ( '1' == $enable_shortcode ) {
948
- return $content;
949
- }
950
-
951
- return strip_shortcodes( $content );
952
- }
953
-
954
- /**
955
- * Handle comment shortcodes.
956
- *
957
- * @since 1.0
958
- *
959
- * @param string $message String to be processed.
960
- * @param int $comment_id Comment id.
961
- *
962
- * @return string Processed string.
963
- */
964
- private function comment_shortcodes( $message, $comment_id ) {
965
- $comment = get_comment( $comment_id );
966
-
967
- $message = str_replace( '[comment_ID]', $comment->comment_ID, $message );
968
- $message = str_replace( '[comment_post_ID]', $comment->comment_post_ID, $message );
969
- $message = str_replace( '[comment_author]', $comment->comment_author, $message );
970
- $message = str_replace( '[comment_author_email]', $comment->comment_author_email, $message );
971
- $message = str_replace( '[comment_author_url]', $comment->comment_author_url, $message );
972
- $message = str_replace( '[comment_author_IP]', $comment->comment_author_IP, $message );
973
- $message = str_replace( '[comment_date]', bnfw_format_date( $comment->comment_date ), $message );
974
- $message = str_replace( '[comment_date_gmt]', bnfw_format_date( $comment->comment_date_gmt ), $message );
975
- $message = str_replace( '[comment_content]', get_comment_text( $comment->comment_ID ), $message );
976
- $message = str_replace( '[comment_karma]', $comment->comment_karma, $message );
977
- $message = str_replace( '[comment_approved]', str_replace( array( '0', '1', 'spam' ), array( 'Awaiting Moderation', 'Approved', 'Spam' ), $comment->comment_approved ), $message );
978
- $message = str_replace( '[comment_agent]', $comment->comment_agent, $message );
979
- $message = str_replace( '[comment_type]', $comment->comment_type, $message );
980
- $message = str_replace( '[comment_parent]', $comment->comment_parent, $message );
981
- $message = str_replace( '[user_id]', $comment->user_id, $message );
982
- $message = str_replace( '[permalink]', get_comment_link( $comment->comment_ID ), $message );
983
- $message = str_replace( '[comment_moderation_link]', admin_url( 'comment.php?action=editcomment&c=' ) . $comment->comment_ID, $message );
984
- $message = str_replace( '[comment_moderation_approve]', '<a href="' . wp_nonce_url( admin_url( "comment.php?action=approve&c={$comment->comment_ID}#wpbody-content" ) ) . '">Approve</a>', $message );
985
- $message = str_replace( '[comment_moderation_spam]', '<a href="' . wp_nonce_url( admin_url( "comment.php?action=spam&c={$comment->comment_ID}#wpbody-content" ) ) . '">Spam</a>', $message );
986
- $message = str_replace( '[comment_moderation_delete]', '<a href="' . wp_nonce_url( admin_url( "comment.php?action=trash&c={$comment->comment_ID}#wpbody-content" ) ) . '">Delete</a>', $message );
987
-
988
- $parent_comment = get_comment( $comment->comment_parent );
989
- if ( $parent_comment instanceof WP_Comment ) {
990
- $message = str_replace( '[comment_parent_content]', $parent_comment->comment_content, $message );
991
- }
992
-
993
- return $message;
994
- }
995
-
996
- /**
997
- * Handle user shortcodes.
998
- *
999
- * @since 1.0
1000
- *
1001
- * @param string $message String to be processed.
1002
- * @param int $user_id User id.
1003
- *
1004
- * @return string Processed string.
1005
- */
1006
- public function user_shortcodes( $message, $user_id, $prefix = '' ) {
1007
- global $wp_roles;
1008
-
1009
- $user_info = get_userdata( $user_id );
1010
-
1011
- if ( ! $user_info instanceof WP_User ) {
1012
- return $message;
1013
- }
1014
-
1015
- // deprecated
1016
- $message = str_replace( '[ID]', $user_info->ID, $message );
1017
- $message = str_replace( '[display_name]', $user_info->display_name, $message );
1018
- $message = str_replace( '[nickname]', $user_info->nickname, $message );
1019
- $message = str_replace( '[commenter_avatar]', get_avatar_url( $user_id ), $message );
1020
-
1021
- $message = str_replace( '[' . $prefix . 'user_id]', $user_info->ID, $message );
1022
- $message = str_replace( '[' . $prefix . 'user_login]', $user_info->user_login, $message );
1023
- $message = str_replace( '[' . $prefix . 'user_nicename]', $user_info->user_nicename, $message );
1024
- $message = str_replace( '[' . $prefix . 'user_email]', $user_info->user_email, $message );
1025
- $message = str_replace( '[' . $prefix . 'user_url]', $user_info->user_url, $message );
1026
- $message = str_replace( '[' . $prefix . 'user_registered]', $user_info->user_registered, $message );
1027
- $message = str_replace( '[' . $prefix . 'user_display_name]', $user_info->display_name, $message );
1028
- $message = str_replace( '[' . $prefix . 'user_firstname]', $user_info->user_firstname, $message );
1029
- $message = str_replace( '[' . $prefix . 'user_lastname]', $user_info->user_lastname, $message );
1030
- $message = str_replace( '[' . $prefix . 'user_nickname]', $user_info->nickname, $message );
1031
- $message = str_replace( '[' . $prefix . 'user_description]', $user_info->user_description, $message );
1032
- $message = str_replace( '[' . $prefix . 'user_avatar]', get_avatar_url( $user_id ), $message );
1033
-
1034
- $roles = array_map( array( $this, 'get_role_label_by_name' ), $user_info->roles );
1035
- $message = str_replace( '[' . $prefix . 'user_role]', implode( ', ', $roles ), $message );
1036
-
1037
- $user_capabilities = bnfw_format_user_capabilities( $user_info->wp_capabilities );
1038
- if ( ! empty( $user_capabilities ) ) {
1039
- $message = str_replace( '[wp_capabilities]', $user_capabilities, $message );
1040
- $message = str_replace( '[' . $prefix . 'user_wp_capabilities]', $user_capabilities, $message );
1041
- }
1042
-
1043
- $message = apply_filters( 'bnfw_shortcodes_user', $message, $user_id, $prefix );
1044
- return $message;
1045
- }
1046
-
1047
- /**
1048
- * Handle taxonomy shortcodes.
1049
- *
1050
- * @access private
1051
- * @since 1.1
1052
- *
1053
- * @param string $message
1054
- * @param string $taxonomy
1055
- * @param int $term_id
1056
- * @return string
1057
- */
1058
- private function taxonomy_shortcodes( $message, $taxonomy, $term_id ) {
1059
- $term_info = get_term( $term_id, $taxonomy );
1060
-
1061
- $message = str_replace( '[slug]', $term_info->slug, $message );
1062
- $message = str_replace( '[name]', $term_info->name, $message );
1063
- $message = str_replace( '[description]', $term_info->description, $message );
1064
-
1065
- return $message;
1066
- }
1067
-
1068
- /**
1069
- * Handle Core Updated Shortcodes.
1070
- *
1071
- * @since 1.6
1072
- *
1073
- * @param string $message Original message with shortcodes.
1074
- * @param string $type The type of email being sent. Can be one of
1075
- * 'success', 'fail', 'manual', 'critical'.
1076
- *
1077
- * @return string Modified content.
1078
- */
1079
- private function core_updated_shortcodes( $message, $type ) {
1080
- $message = str_replace( '[core_update_status]', $type, $message );
1081
-
1082
- return $message;
1083
- }
1084
-
1085
- /**
1086
- * Get the list of emails from the notification settings.
1087
- *
1088
- * @since 1.0
1089
- *
1090
- * @param array $setting Notification settings
1091
- * @param int $id
1092
- * @param bool $process_post_authors
1093
- * @param bool $process_exclude_current_user
1094
- *
1095
- * @return array Emails
1096
- */
1097
- public function get_emails( $setting, $id, $process_post_authors = true,
1098
- $process_exclude_current_user = true ) {
1099
- global $current_user;
1100
-
1101
- $emails = array();
1102
-
1103
- $exclude = null;
1104
- if ( $process_exclude_current_user && 'true' == $setting[ 'disable-current-user' ] ) {
1105
- if ( isset( $current_user->ID ) ) {
1106
- $exclude = $current_user->ID;
1107
- }
1108
- }
1109
-
1110
- $emails[ 'to' ] = array();
1111
-
1112
- if ( ! empty( $setting[ 'users' ] ) ) {
1113
- $emails[ 'to' ] = $this->get_emails_from_users( $setting[ 'users' ], $exclude, $id, $setting );
1114
- }
1115
-
1116
- /**
1117
- * BNFW get to emails.
1118
- */
1119
- if ( $process_post_authors && 'true' === $setting[ 'only-post-author' ] ) {
1120
- $post_id = $id;
1121
-
1122
- if ( bnfw_is_comment_notification( $setting[ 'notification' ] ) ) {
1123
- $comment = get_comment( $id );
1124
- $post_id = $comment->comment_post_ID;
1125
- }
1126
-
1127
- $type = explode( '-', $setting[ 'notification' ], 2 );
1128
- if ( 'approve' == $type[ 0 ] ) {
1129
- if ( ! in_array( $comment->comment_author_email, $emails[ 'to' ] ) ) {
1130
- $emails[ 'to' ][] = $comment->comment_author_email;
1131
- }
1132
- } else {
1133
- if ( $setting[ 'notification' ] == 'user-customfield' || $setting[ 'notification' ] == 'user-customfieldvalue' ) {
1134
- $post_author = $post_id;
1135
- } else {
1136
- $post_author = get_post_field( 'post_author', $post_id );
1137
- }
1138
- $author = get_user_by( 'id', $post_author );
1139
- if ( false !== $author && $post_author != $exclude ) {
1140
- if ( ! in_array( $author->user_email, $emails[ 'to' ] ) ) {
1141
- $emails[ 'to' ][] = $author->user_email;
1142
- }
1143
- }
1144
- }
1145
- }
1146
-
1147
- if ( 'true' == $setting[ 'show-fields' ] ) {
1148
- $default_from_field = get_option( 'blogname' ) . ' <' . get_option( 'admin_email' ) . '>';
1149
-
1150
- if ( ! empty( $setting[ 'from-name' ] ) && ! empty( $setting[ 'from-email' ] ) && is_email( $setting[ 'from-email' ] ) ) {
1151
- $default_from_field = $setting[ 'from-name' ] . ' <' . $setting[ 'from-email' ] . '>';
1152
- }
1153
-
1154
- /**
1155
- * Filter Email From Field.
1156
- */
1157
- $emails[ 'from' ] = apply_filters( 'bnfw_from_field', $default_from_field, $setting, $id, $emails[ 'to' ] );
1158
-
1159
- /**
1160
- * Filter Reply Name Field.
1161
- */
1162
- $emails[ 'reply-name' ] = apply_filters( 'bnfw_reply_name_field', $setting[ 'reply-name' ], $setting, $id, $emails[ 'to' ] );
1163
-
1164
- /**
1165
- * Filter Reply Email Field.
1166
- */
1167
- $emails[ 'reply-email' ] = apply_filters( 'bnfw_reply_email_field', $setting[ 'reply-email' ], $setting, $id, $emails[ 'to' ] );
1168
-
1169
- if ( ! empty( $setting[ 'cc' ] ) ) {
1170
- $emails[ 'cc' ] = $this->get_emails_from_users( $setting[ 'cc' ], $exclude, $id, $setting );
1171
- }
1172
-
1173
- if ( ! empty( $setting[ 'bcc' ] ) ) {
1174
- $emails[ 'bcc' ] = $this->get_emails_from_users( $setting[ 'bcc' ], $exclude, $id, $setting );
1175
- }
1176
- }
1177
-
1178
- $excluded_emails = array();
1179
-
1180
- if ( ! empty( $setting[ 'exclude-users' ] ) ) {
1181
- $excluded_emails = $this->get_emails_from_users( $setting[ 'exclude-users' ] );
1182
- }
1183
-
1184
- if ( ! empty( $excluded_emails ) ) {
1185
- $emails[ 'to' ] = array_diff( $emails[ 'to' ], $excluded_emails );
1186
-
1187
- if ( ! empty( $emails[ 'cc' ] ) ) {
1188
- $emails[ 'cc' ] = array_diff( $emails[ 'cc' ], $excluded_emails );
1189
- }
1190
-
1191
- if ( ! empty( $emails[ 'bcc' ] ) ) {
1192
- $emails[ 'bcc' ] = array_diff( $emails[ 'bcc' ], $excluded_emails );
1193
- }
1194
- }
1195
- $emails[ 'to' ] = apply_filters( 'bnfw_to_emails', $emails[ 'to' ], $setting, $id );
1196
-
1197
- return $emails;
1198
- }
1199
-
1200
- /**
1201
- * Get emails from users.
1202
- *
1203
- * @since 1.2
1204
- *
1205
- * @param array $users Users Array
1206
- * @param int $exclude User id to exclude
1207
- * @param int $post_id Post id.
1208
- * @param array $setting Notification setting.
1209
- *
1210
- * @return array
1211
- */
1212
- public function get_emails_from_users( $users, $exclude = null,
1213
- $post_id = 0, $setting = array() ) {
1214
- $user_ids = array();
1215
- $user_roles = array();
1216
- $non_wp_users = array();
1217
-
1218
- if ( empty( $users ) ) {
1219
- return array();
1220
- }
1221
-
1222
- foreach ( $users as $user ) {
1223
- if ( $this->starts_with( $user, 'role-' ) ) {
1224
- $user_roles[] = str_replace( 'role-', '', $user );
1225
- } elseif ( strpos( $user, '@' ) !== false ) {
1226
- $non_wp_users[] = $user;
1227
- continue;
1228
- } elseif ( absint( $user ) > 0 ) {
1229
- $user_ids[] = absint( $user );
1230
- } else {
1231
- $non_wp_users[] = $user;
1232
- }
1233
- }
1234
-
1235
- if ( null != $exclude ) {
1236
- $user_ids = array_diff( $user_ids, array( $exclude ) );
1237
- }
1238
-
1239
- $emails_from_user_ids = $this->get_emails_from_id( $user_ids );
1240
- $emails_from_user_roles = $this->get_emails_from_role( $user_roles, $exclude );
1241
-
1242
- if ( ! empty( $setting ) ) {
1243
- // for new comment notifications, we need to use post id instead of comment id.
1244
- if ( bnfw_is_comment_notification( $setting[ 'notification' ] ) && $post_id ) {
1245
- $comment = get_comment( $post_id );
1246
- $post_id = $comment->comment_post_ID;
1247
- }
1248
- }
1249
-
1250
- $non_wp_emails = apply_filters( 'bnfw_non_wp_emails', array(), $non_wp_users, $post_id );
1251
-
1252
- return array_merge( $emails_from_user_roles, $emails_from_user_ids, $non_wp_emails );
1253
- }
1254
-
1255
- /**
1256
- * Get user emails by user ids.
1257
- *
1258
- * @since 1.0
1259
- *
1260
- * @param array $user_ids.
1261
- *
1262
- * @return array Emails.
1263
- */
1264
- private function get_emails_from_id( $user_ids ) {
1265
- $email_list = array();
1266
- if ( is_array( $user_ids ) && count( $user_ids ) > 0 ) {
1267
- $user_query = new WP_User_Query( array( 'include' => $user_ids ) );
1268
- foreach ( $user_query->results as $user ) {
1269
- $email_list[] = $user->user_email;
1270
- }
1271
- }
1272
- return $email_list;
1273
- }
1274
-
1275
- /**
1276
- * Get emails of users based on role.
1277
- *
1278
- * @since 1.0
1279
- * @param array $roles User Roles
1280
- * @param int $exclude User id to exclude
1281
- * @return array Email ids
1282
- */
1283
- private function get_emails_from_role( $roles, $exclude = null ) {
1284
- if ( ! is_array( $roles ) ) {
1285
- $roles = array( $roles );
1286
- }
1287
-
1288
- $email_list = array();
1289
- foreach ( $roles as $role ) {
1290
- $role_name = $this->get_role_name_by_label( $role );
1291
- $users = get_users(
1292
- array(
1293
- 'role' => $role_name,
1294
- 'fields' => array( 'user_email', 'ID' ),
1295
- )
1296
- );
1297
-
1298
- foreach ( $users as $user ) {
1299
- if ( null != $exclude ) {
1300
- if ( $user->ID == $exclude ) {
1301
- continue;
1302
- }
1303
- }
1304
-
1305
- if ( ! in_array( $user->user_email, $email_list ) ) {
1306
- $email_list[] = $user->user_email;
1307
- }
1308
- }
1309
- }
1310
-
1311
- return $email_list;
1312
- }
1313
-
1314
- /**
1315
- * Find if a string starts with another string.
1316
- *
1317
- * @since 1.2
1318
- *
1319
- * @param $haystack
1320
- * @param $needle
1321
- *
1322
- * @return bool
1323
- */
1324
- private function starts_with( $haystack, $needle ) {
1325
- // search backwards starting from haystack length characters from the end
1326
- return '' === $needle || strrpos( $haystack, $needle, -strlen( $haystack ) ) !== false;
1327
- }
1328
-
1329
- /**
1330
- * Get User role name by label.
1331
- *
1332
- * @param mixed $role_label
1333
- *
1334
- * @return int|string
1335
- */
1336
- protected function get_role_name_by_label( $role_label ) {
1337
- global $wp_roles;
1338
- foreach ( $wp_roles->roles as $role_name => $role_info ) {
1339
- if ( $role_label == $role_info[ 'name' ] || $role_name == $role_label ) {
1340
- return $role_name;
1341
- }
1342
- }
1343
-
1344
- // There is something wrong
1345
- return '';
1346
- }
1347
-
1348
- /**
1349
- * Get the lable for a user role from name.
1350
- *
1351
- * @param string $role_name Role name
1352
- *
1353
- * @return string Role Label.
1354
- */
1355
- public function get_role_label_by_name( $role_name ) {
1356
- global $wp_roles;
1357
-
1358
- if ( ! isset( $wp_roles->roles[ $role_name ] ) ) {
1359
- return '';
1360
- }
1361
-
1362
- return translate_user_role( $wp_roles->roles[ $role_name ][ 'name' ] );
1363
- }
1364
-
1365
- /**
1366
- * Get first image in post.
1367
- *
1368
- * @param mixed $post_content
1369
- *
1370
- * @return string
1371
- */
1372
- protected function get_first_image( $post_content ) {
1373
- if ( preg_match_all( '/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', $post_content, $matches ) ) {
1374
- return $matches[ 1 ][ 0 ];
1375
- }
1376
- }
1377
-
1378
- /**
1379
- * Generate email headers based on the emails.
1380
- *
1381
- * @since 1.0
1382
- * @param array $emails
1383
- * @return array
1384
- */
1385
- public function get_headers( $emails ) {
1386
- $headers = array();
1387
-
1388
- if ( ! empty( $emails[ 'from' ] ) ) {
1389
- $headers[] = 'From:' . $emails[ 'from' ];
1390
- }
1391
-
1392
- if ( ! empty( $emails[ 'reply-email' ] ) && is_email( $emails[ 'reply-email' ] ) ) {
1393
- $headers[] = 'Reply-To:' . $emails[ 'reply-name' ] . '<' . $emails[ 'reply-email' ] . '>';
1394
- }
1395
-
1396
- if ( ! empty( $emails[ 'cc' ] ) ) {
1397
- $headers[] = 'Cc:' . implode( ',', $emails[ 'cc' ] );
1398
- }
1399
- if ( ! empty( $emails[ 'bcc' ] ) ) {
1400
- $headers[] = 'Bcc:' . implode( ',', $emails[ 'bcc' ] );
1401
- }
1402
-
1403
- /**
1404
- * Filter out mail headers.
1405
- *
1406
- * @param array $headers Headers.
1407
- * @param array $emails Emails.
1408
- */
1409
- return apply_filters( 'bnfw_mail_headers', $headers, $emails );
1410
- }
1411
-
1412
- public function handle_user_request_email_shortcodes( $message, $setting,
1413
- $email_data ) {
1414
- $message = $this->handle_shortcodes( $message, $setting[ 'notification' ], $email_data );
1415
-
1416
- return $message;
1417
- }
1418
-
1419
- public function handle_user_confirmed_action_email_shortcodes( $message,
1420
- $setting,
1421
- $email_data ) {
1422
- $message = $this->handle_shortcodes( $message, $setting[ 'notification' ], $email_data );
1423
-
1424
- return $message;
1425
- }
1426
-
1427
- public function handle_data_export_email_shortcodes( $message, $setting,
1428
- $request_id ) {
1429
- $message = $this->handle_shortcodes( $message, $setting[ 'notification' ], $request_id );
1430
-
1431
- return $message;
1432
- }
1433
-
1434
- protected function confirm_action_shortcodes( $message, $extra_data ) {
1435
- $message = $this->data_request_shortcodes( $message, $extra_data );
1436
- $message = str_replace( '[request_confirmation_link]', $extra_data[ 'confirm_url' ], $message );
1437
- if ( isset( $extra_data[ 'email' ] ) ) {
1438
- $message = str_replace( '[request_email]', $extra_data[ 'email' ], $message );
1439
- }
1440
-
1441
- if ( isset( $extra_data[ 'user_email' ] ) ) {
1442
- $message = str_replace( '[request_email]', $extra_data[ 'user_email' ], $message );
1443
- }
1444
-
1445
- return $message;
1446
- }
1447
-
1448
- protected function confirmed_action_shortcodes( $message, $extra_data ) {
1449
- $message = $this->data_request_shortcodes( $message, $extra_data );
1450
- $message = str_replace( '[data_privacy_requests_url]', $extra_data[ 'manage_url' ], $message );
1451
- $message = str_replace( '[request_email]', $extra_data[ 'user_email' ], $message );
1452
-
1453
- return $message;
1454
- }
1455
-
1456
- protected function data_request_shortcodes( $message, $extra_data ) {
1457
- $message = str_replace( '[data_request_type]', $extra_data[ 'description' ], $message );
1458
-
1459
- return $message;
1460
- }
1461
-
1462
- protected function data_export_shortcodes( $message, $request_id ) {
1463
- $export_file_url = get_post_meta( $request_id, '_export_file_url', true );
1464
-
1465
- $export_file_url = 'Download File: '.$this->get_export_downloadable_url($request_id);
1466
-
1467
- $message = str_replace( '[data_privacy_download_url]', $export_file_url, $message );
1468
-
1469
- $expiration = apply_filters( 'wp_privacy_export_expiration', 3 * DAY_IN_SECONDS );
1470
- $expiration_date = date_i18n( get_option( 'date_format' ), time() + $expiration );
1471
- $message = str_replace( '[data_privacy_download_expiry]', $expiration_date, $message );
1472
-
1473
- return $message;
1474
- }
1475
-
1476
- protected function data_erased_shortcodes( $message, $extra_data ) {
1477
- $privacy_policy_url = (!isset($extra_data[ 'privacy_policy_url' ]))? get_privacy_policy_url() : $extra_data[ 'privacy_policy_url' ];
1478
-
1479
- $message = str_replace( '[privacy_policy_url]', $privacy_policy_url, $message );
1480
- $message = str_replace( '[sitename]', $extra_data[ 'sitename' ], $message );
1481
-
1482
- return $message;
1483
- }
1484
-
1485
- /**
1486
- * Process shortcodes in email.
1487
- *
1488
- * @param $email
1489
- * @param $post_id
1490
- * @param $setting
1491
- *
1492
- * @return string
1493
- */
1494
- public function process_shortcodes_in_email( $email, $post_id, $setting,
1495
- $to_emails ) {
1496
- if ( ! empty( $setting ) ) {
1497
- if ( $this->starts_with( $setting[ 'notification' ], 'comment-' ) || $this->starts_with( $setting[ 'notification' ], 'moderate-' ) ) {
1498
- // for new comment notifications, we need to use post id instead of comment id.
1499
- $post_id = bnfw_get_post_id_from_comment( $post_id );
1500
- }
1501
- }
1502
-
1503
- $email = $this->handle_shortcodes( $email, $setting[ 'notification' ], $post_id );
1504
-
1505
- if ( is_array( $to_emails ) && ! empty( $to_emails ) ) {
1506
- $to_email = $to_emails[ 0 ];
1507
-
1508
- $email = $this->handle_global_user_shortcodes( $email, $to_email );
1509
- }
1510
-
1511
- $processed_emails = array();
1512
- if ( is_email( $email ) ) {
1513
- $processed_emails[] = $email;
1514
- }
1515
-
1516
- $emails = apply_filters( 'bnfw_non_wp_emails', $processed_emails, array( $email ), $post_id );
1517
-
1518
- if ( empty( $emails ) ) {
1519
- return '';
1520
- }
1521
-
1522
- return $emails[ 0 ];
1523
- }
1524
-
1525
- /**
1526
- * Check email content type.
1527
- *
1528
- * @param string $setting Setting.
1529
- * @param string $content Content.
1530
- *
1531
- * @return string Content .
1532
- */
1533
- public function check_email_content_type( $setting, $content ) {
1534
-
1535
- if ( 'html' == $setting[ 'email-formatting' ] ) {
1536
- add_filter( 'wp_mail_content_type', array( $this, 'set_html_content_type' ) );
1537
- if ( 'true' !== $setting[ 'disable-autop' ] ) {
1538
- $content = wpautop( $content );
1539
- }
1540
- } else {
1541
- add_filter( 'wp_mail_content_type', array( $this, 'set_text_content_type' ) );
1542
- $content = strip_tags( $content );
1543
- }
1544
-
1545
- return $content;
1546
- }
1547
-
1548
- /**
1549
- * Set the email formatting to HTML.
1550
- *
1551
- * @since 1.4
1552
- */
1553
- public function set_html_content_type() {
1554
- return 'text/html';
1555
- }
1556
-
1557
- /**
1558
- * Set the email formatting to text.
1559
- *
1560
- * @since 1.4
1561
- */
1562
- public function set_text_content_type() {
1563
- return 'text/plain';
1564
- }
1565
-
1566
- /**
1567
- * Get user's download URL from data export request
1568
- *
1569
- * @since 1.8.4
1570
- * @param int $user_email
1571
- * @return string $download_url | string error message
1572
- */
1573
- public function get_export_downloadable_url($request_id = null){
1574
- if(!$request_id)
1575
- return;
1576
-
1577
- global $wpdb;
1578
- $table = $wpdb->prefix.'posts';
1579
- $query = 'SELECT ID FROM '.$table.' WHERE `post_type` = "user_request" AND `ID` = '.$request_id;
1580
-
1581
- $query = apply_filters('export_downloadable_url_query',$query,$request_id);
1582
-
1583
- $get_id = $wpdb->get_var($query);
1584
-
1585
- $file = get_post_meta($get_id,'_export_file_name',true);
1586
- $upload_url = wp_upload_dir();
1587
- $dl_url = $upload_url['baseurl'].'/wp-personal-data-exports/'.$file;
1588
-
1589
- $dl_url = apply_filters('export_downloadable_url_return',$dl_url);
1590
-
1591
- if($dl_url)
1592
- return $dl_url;
1593
- else
1594
- return __('Error: Download link is not available please contact support');
1595
-
1596
- }
1597
-
1598
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BNFW Engine.
4
+ *
5
+ * @since 1.0
6
+ * @package bnfw
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ if ( ! class_exists( 'BNFW_Engine', false ) ) {
12
+ /**
13
+ * BNFW Engine class.
14
+ */
15
+ class BNFW_Engine {
16
+
17
+ /**
18
+ * Send test email.
19
+ *
20
+ * @since 1.2
21
+ *
22
+ * @param array $setting Settings.
23
+ */
24
+ public function send_test_email( $setting ) {
25
+ $subject = __( 'Test Email:', 'bnfw' ) . ' ' . $setting['subject'];
26
+ $message = '<p><strong>' . __( 'This is a test email. All shortcodes below will show in place but not be replaced with content.', 'bnfw' ) . '</strong></p>' . stripslashes( $setting['message'] );
27
+
28
+ if ( 'true' !== $setting['disable-autop'] && 'html' === $setting['email-formatting'] ) {
29
+ $message = wpautop( $message );
30
+ }
31
+
32
+ $current_user = wp_get_current_user();
33
+ $email = $current_user->user_email;
34
+
35
+ $headers = array();
36
+ if ( 'html' === $setting['email-formatting'] ) {
37
+ $headers[] = 'Content-type: text/html';
38
+ $message = apply_filters( 'bnfw_test_email_message', $message, $setting );
39
+ } elseif ( 'text' === $setting['email-formatting'] ) {
40
+ $message = wp_strip_all_tags( $message );
41
+ }
42
+
43
+ wp_mail( $email, stripslashes( $subject ), $message, $headers );
44
+ }
45
+
46
+ /**
47
+ * Send the notification email.
48
+ *
49
+ * @since 1.0
50
+ * @param array $setting Setting options.
51
+ * @param int $id Id.
52
+ */
53
+ public function send_notification( $setting, $id ) {
54
+ /**
55
+ * BNFW - Whether notification is disabled?
56
+ *
57
+ * @since 1.3.6
58
+ */
59
+
60
+ $notification_disabled = apply_filters( 'bnfw_notification_disabled', ( 'true' === $setting['disabled'] ), $id, $setting );
61
+
62
+ if ( ! $notification_disabled ) {
63
+
64
+ $subject = $this->handle_shortcodes( $setting['subject'], $setting['notification'], $id );
65
+ $message = $this->handle_shortcodes( $setting['message'], $setting['notification'], $id );
66
+ $emails = $this->get_emails( $setting, $id );
67
+ $headers = $this->get_headers( $emails );
68
+
69
+ if ( 'true' !== $setting['disable-autop'] && 'html' === $setting['email-formatting'] ) {
70
+ $message = wpautop( $message );
71
+ }
72
+
73
+ if ( 'html' === $setting['email-formatting'] ) {
74
+ $headers[] = 'Content-type: text/html';
75
+ $message = apply_filters( 'bnfw_notification_message', $message, $setting );
76
+ } else {
77
+ $headers[] = 'Content-type: text/plain';
78
+ if ( 'text' === $setting['email-formatting'] ) {
79
+ $message = wp_strip_all_tags( $message );
80
+ }
81
+ }
82
+
83
+ $emails = apply_filters( 'bnfw_emails', $emails, $setting, $id );
84
+
85
+ $send = apply_filters( 'bnfw_can_send_email', true, $setting, $emails, $subject, $message, $headers );
86
+
87
+ if ( ! $send ) {
88
+ return;
89
+ }
90
+
91
+ if ( isset( $emails['to'] ) && is_array( $emails['to'] ) ) {
92
+ foreach ( $emails['to'] as $email ) {
93
+ wp_mail( $email, stripslashes( $this->handle_global_user_shortcodes( $subject, $email ) ), $this->handle_global_user_shortcodes( $message, $email ), $headers );
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Send new user registration notification email.
101
+ *
102
+ * @since 1.1
103
+ * @param array $setting Notification setting.
104
+ * @param object $user User object.
105
+ * @param string $password_url Plain text password in WP < 4.3 and password url in WP > 4.3.
106
+ */
107
+ public function send_registration_email( $setting, $user, $password_url = '' ) {
108
+ /**
109
+ * Whether to trigger welcome email notification or not.
110
+ *
111
+ * @since 1.7
112
+ */
113
+ $trigger_notification = apply_filters( 'bnfw_trigger_welcome-email_notification', true, $setting, $user );
114
+
115
+ if ( ! $trigger_notification ) {
116
+ return;
117
+ }
118
+
119
+ $user_id = $user->ID;
120
+
121
+ $subject = $this->handle_shortcodes( $setting['subject'], $setting['notification'], $user_id );
122
+ $message = $this->handle_shortcodes( $setting['message'], $setting['notification'], $user_id );
123
+
124
+ $subject = str_replace( '[password]', $password_url, $subject );
125
+ $message = str_replace( '[password]', $password_url, $message );
126
+
127
+ $subject = str_replace( '[password_url]', $password_url, $subject );
128
+ $message = str_replace( '[password_url]', $password_url, $message );
129
+
130
+ $subject = str_replace( '[login_url]', wp_login_url(), $subject );
131
+ $message = str_replace( '[login_url]', wp_login_url(), $message );
132
+
133
+ if ( 'true' !== $setting['disable-autop'] && 'html' === $setting['email-formatting'] ) {
134
+ $message = wpautop( $message );
135
+ }
136
+
137
+ $headers = array();
138
+ if ( 'html' === $setting['email-formatting'] ) {
139
+ $headers[] = 'Content-type: text/html';
140
+ $message = apply_filters( 'bnfw_registration_email_message', $message, $setting );
141
+ } elseif ( 'text' === $setting['email-formatting'] ) {
142
+ $message = wp_strip_all_tags( $message );
143
+ }
144
+
145
+ $subject = $this->handle_global_user_shortcodes( $subject, $user->user_email );
146
+ $message = $this->handle_global_user_shortcodes( $message, $user->user_email );
147
+ wp_mail( $user->user_email, stripslashes( $subject ), $message, $headers );
148
+ }
149
+
150
+ /**
151
+ * Send user login notification email.
152
+ *
153
+ * @since 1.1
154
+ * @param array $setting Notification setting.
155
+ * @param object $user User object.
156
+ */
157
+ public function send_user_login_email( $setting, $user ) {
158
+
159
+ $trigger_notification = apply_filters( 'bnfw_trigger_user-login_notification', true, $setting, $user );
160
+
161
+ if ( ! $trigger_notification ) {
162
+ return;
163
+ }
164
+
165
+ $user_id = $user->ID;
166
+
167
+ $subject = $this->handle_shortcodes( $setting['subject'], $setting['notification'], $user_id );
168
+ $message = $this->handle_shortcodes( $setting['message'], $setting['notification'], $user_id );
169
+ $emails = $this->get_emails( $setting, $user_id );
170
+ $headers = $this->get_headers( $emails );
171
+
172
+ if ( 'true' !== $setting['disable-autop'] && 'html' === $setting['email-formatting'] ) {
173
+ $message = wpautop( $message );
174
+ }
175
+
176
+ if ( 'html' === $setting['email-formatting'] ) {
177
+ $headers[] = 'Content-type: text/html';
178
+ $message = apply_filters( 'bnfw_notification_message', $message, $setting );
179
+ } elseif ( 'text' === $setting['email-formatting'] ) {
180
+ $message = wp_strip_all_tags( $message );
181
+ }
182
+
183
+ $subject = $this->handle_global_user_shortcodes( $subject, $user->user_email );
184
+ $message = $this->handle_global_user_shortcodes( $message, $user->user_email );
185
+
186
+ wp_mail( $user->user_email, stripslashes( $subject ), $message, $headers );
187
+ }
188
+
189
+ /**
190
+ * Send user login notification email for admin.
191
+ *
192
+ * @since 1.1
193
+ * @param array $setting Notification setting.
194
+ * @param object $user User object.
195
+ */
196
+ public function send_user_login_email_for_admin( $setting, $user ) {
197
+
198
+ $trigger_notification = apply_filters( 'bnfw_trigger_user-login_notification', true, $setting, $user );
199
+
200
+ if ( ! $trigger_notification ) {
201
+ return;
202
+ }
203
+ $user_id = $user->ID;
204
+
205
+ $this->send_notification( $setting, $user_id );
206
+ }
207
+
208
+ /**
209
+ * Send comment reply notification email.
210
+ *
211
+ * @since 1.3
212
+ * @param array $setting Notification setting.
213
+ * @param object $comment Comment object.
214
+ * @param object $parent_comment Parent comment object.
215
+ */
216
+ public function send_comment_reply_email( $setting, $comment, $parent_comment ) {
217
+ $comment_id = $comment->comment_ID;
218
+
219
+ /**
220
+ * BNFW - Whether notification is disabled?
221
+ *
222
+ * @since 1.3.6
223
+ */
224
+ $notification_disabled = apply_filters( 'bnfw_notification_disabled', false, $comment_id, $setting );
225
+
226
+ if ( ! $notification_disabled ) {
227
+ $subject = $this->handle_shortcodes( $setting['subject'], $setting['notification'], $comment_id );
228
+ $message = $this->handle_shortcodes( $setting['message'], $setting['notification'], $comment_id );
229
+ $headers = array();
230
+ if ( 'html' === $setting['email-formatting'] ) {
231
+ $headers[] = 'Content-type: text/html';
232
+ } elseif ( 'text' === $setting['email-formatting'] ) {
233
+ $message = wp_strip_all_tags( $message );
234
+ }
235
+ if ( 'true' !== $setting['disable-autop'] && 'html' === $setting['email-formatting'] ) {
236
+ $message = wpautop( $message );
237
+ $message = apply_filters( 'bnfw_comment_reply_email_message', $message, $setting );
238
+ }
239
+
240
+ $subject = $this->handle_global_user_shortcodes( $subject, $parent_comment->comment_author_email );
241
+ $message = $this->handle_global_user_shortcodes( $message, $parent_comment->comment_author_email );
242
+ wp_mail( $parent_comment->comment_author_email, stripslashes( $subject ), $message, $headers );
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Send user role changed email.
248
+ *
249
+ * @since 1.3.9
250
+ *
251
+ * @param array $setting Notification setting.
252
+ * @param int $user_id User ID.
253
+ * @param array $old_role Old User Role.
254
+ * @param array $new_role New User Role.
255
+ */
256
+ public function send_user_role_changed_email( $setting, $user_id, $old_role, $new_role ) {
257
+ $subject = $this->handle_shortcodes( $setting['subject'], $setting['notification'], $user_id );
258
+ $message = $this->handle_shortcodes( $setting['message'], $setting['notification'], $user_id );
259
+
260
+ $subject = $this->handle_user_role_shortcodes( $subject, $old_role, $new_role );
261
+ $message = $this->handle_user_role_shortcodes( $message, $old_role, $new_role );
262
+ $headers = array();
263
+ if ( 'true' !== $setting['disable-autop'] && 'html' === $setting['email-formatting'] ) {
264
+ $message = wpautop( $message );
265
+ }
266
+
267
+ if ( 'html' === $setting['email-formatting'] ) {
268
+ $headers[] = 'Content-type: text/html';
269
+ $message = apply_filters( 'bnfw_user_role_changed_email_message', $message, $setting );
270
+ } elseif ( 'text' === $setting['email-formatting'] ) {
271
+ $message = wp_strip_all_tags( $message );
272
+ }
273
+
274
+ $user = get_user_by( 'id', $user_id );
275
+ $subject = $this->handle_global_user_shortcodes( $subject, $user->user_email );
276
+ $message = $this->handle_global_user_shortcodes( $message, $user->user_email );
277
+ wp_mail( $user->user_email, stripslashes( $subject ), $message, $headers );
278
+ }
279
+
280
+ /**
281
+ * Send user role added support User Role Editor by Members Plugin.
282
+ *
283
+ * @since 1.3.9
284
+ *
285
+ * @param array $setting Notification setting.
286
+ * @param int $user_id User ID.
287
+ * @param array $old_role Old User Role.
288
+ * @param array $new_role New User Role.
289
+ */
290
+ public function send_user_role_added_email( $setting, $user_id, $old_role, $new_role ) {
291
+ $subject = $this->handle_shortcodes( $setting['subject'], $setting['notification'], $user_id );
292
+ $message = $this->handle_shortcodes( $setting['message'], $setting['notification'], $user_id );
293
+
294
+ $subject = $this->handle_user_added_role_shortcodes( $subject, $old_role, $new_role );
295
+ $message = $this->handle_user_added_role_shortcodes( $message, $old_role, $new_role );
296
+
297
+ $headers = array();
298
+ if ( 'true' !== $setting['disable-autop'] && 'html' === $setting['email-formatting'] ) {
299
+ $message = wpautop( $message );
300
+ }
301
+
302
+ if ( 'html' === $setting['email-formatting'] ) {
303
+ $headers[] = 'Content-type: text/html';
304
+ $message = apply_filters( 'bnfw_user_role_changed_email_message', $message, $setting );
305
+ } elseif ( 'text' === $setting['email-formatting'] ) {
306
+ $message = wp_strip_all_tags( $message );
307
+ }
308
+
309
+ $user = get_user_by( 'id', $user_id );
310
+
311
+ $subject = $this->handle_global_user_shortcodes( $subject, $user->user_email );
312
+ $message = $this->handle_global_user_shortcodes( $message, $user->user_email );
313
+ wp_mail( $user->user_email, stripslashes( $subject ), $message, $headers );
314
+ }
315
+
316
+ /**
317
+ * Handle User Role shortcodes.
318
+ *
319
+ * @param string $message String that needs shortcode processing.
320
+ * @param array $old_role Old User Role.
321
+ * @param array $new_role New User Role.
322
+ *
323
+ * @return string Processed string.
324
+ */
325
+ public function handle_user_role_shortcodes( $message, $old_role, $new_role ) {
326
+ $roles = wp_roles();
327
+
328
+ $old_role_name = '';
329
+ $new_role_name = '';
330
+
331
+ if ( isset( $roles->role_names[ $old_role ] ) ) {
332
+ $old_role_name = $roles->role_names[ $old_role ];
333
+ }
334
+
335
+ if ( isset( $roles->role_names[ $new_role ] ) ) {
336
+ $new_role_name = $roles->role_names[ $new_role ];
337
+ }
338
+
339
+ $message = str_replace( '[user_role_old]', $old_role_name, $message );
340
+ $message = str_replace( '[user_role_new]', $new_role_name, $message );
341
+
342
+ return $message;
343
+ }
344
+
345
+ /**
346
+ * Handle User Added Role shortcodes.
347
+ *
348
+ * @param string $message String that needs shortcode processing.
349
+ * @param array $old_roles Old User Role.
350
+ * @param array $new_roles New User Role.
351
+ *
352
+ * @return string Processed string.
353
+ */
354
+ public function handle_user_added_role_shortcodes( $message, $old_roles, $new_roles ) {
355
+ $roles = wp_roles();
356
+ $old_role_name = array();
357
+ $new_role_name = array();
358
+
359
+ foreach ( $old_roles as $key => $old_role ) {
360
+ if ( isset( $roles->role_names[ $old_role ] ) ) {
361
+ $old_role_name[] = $roles->role_names[ $old_role ];
362
+ }
363
+ }
364
+ foreach ( $new_roles as $key => $new_role ) {
365
+ if ( isset( $roles->role_names[ $new_role ] ) ) {
366
+ $new_role_name[] = $roles->role_names[ $new_role ];
367
+ }
368
+ }
369
+
370
+ $message = str_replace( '[user_role_old]', implode( ',', $old_role_name ), $message );
371
+ $message = str_replace( '[user_role_new]', implode( ',', $new_role_name ), $message );
372
+
373
+ return $message;
374
+ }
375
+
376
+ /**
377
+ * Handle shortcodes for filtered data notifications like `password_changed` and `email_changed`.
378
+ *
379
+ * @since 1.6
380
+ *
381
+ * @param array $email_data Email data.
382
+ * @param array $setting Notification settings.
383
+ * @param string|int $extra_data Extra data.
384
+ *
385
+ * @return array Modified email data.
386
+ */
387
+ public function handle_filtered_data_notification( $email_data, $setting, $extra_data ) {
388
+ $email_data['message'] = $this->handle_shortcodes( $setting['message'], $setting['notification'], $extra_data );
389
+ $email_data['subject'] = $this->handle_shortcodes( $setting['subject'], $setting['notification'], $extra_data );
390
+
391
+ $email_data['message'] = $this->handle_global_user_shortcodes( $email_data['message'], $email_data['to'] );
392
+ $email_data['subject'] = $this->handle_global_user_shortcodes( $email_data['subject'], $email_data['to'] );
393
+
394
+ if ( 'true' !== $setting['disable-autop'] && 'html' === $setting['email-formatting'] ) {
395
+ $email_data['message'] = wpautop( $email_data['message'] );
396
+ }
397
+ if ( 'html' === $setting['email-formatting'] ) {
398
+ $headers[] = 'Content-type: text/html';
399
+ } else {
400
+ $headers[] = 'Content-type: text/plain';
401
+ if ( 'text' === $setting['email-formatting'] ) {
402
+ $message = wp_strip_all_tags( $message );
403
+ }
404
+ }
405
+ $email_data['headers'] = $headers;
406
+
407
+ return $email_data;
408
+ }
409
+
410
+ /**
411
+ * Handle shortcodes for core updated notification.
412
+ *
413
+ * @since 1.6
414
+ *
415
+ * @param array $email_data Email data.
416
+ * @param array $setting Notification settings.
417
+ * @param string $type Result of update.
418
+ *
419
+ * @return array Modified email data.
420
+ */
421
+ public function handle_core_updated_notification( $email_data, $setting, $type ) {
422
+ $email_data['body'] = $this->handle_shortcodes( $setting['message'], $setting['notification'], $type );
423
+ $email_data['subject'] = $this->handle_shortcodes( $setting['subject'], $setting['notification'], $type );
424
+
425
+ $emails = $this->get_emails( $setting, $type );
426
+ $headers = $this->get_headers( $emails );
427
+
428
+ $email_data['body'] = $this->handle_global_user_shortcodes( $email_data['body'], $emails['to'][0] );
429
+ $email_data['subject'] = $this->handle_global_user_shortcodes( $email_data['subject'], $emails['to'][0] );
430
+
431
+ if ( 'true' !== $setting['disable-autop'] && 'html' === $setting['email-formatting'] ) {
432
+ $email_data['body'] = wpautop( $email_data['body'] );
433
+ }
434
+
435
+ if ( 'html' === $setting['email-formatting'] ) {
436
+ $headers[] = 'Content-type: text/html';
437
+ } else {
438
+ $headers[] = 'Content-type: text/plain';
439
+ if ( 'text' === $setting['email-formatting'] ) {
440
+ $message = wp_strip_all_tags( $message );
441
+ }
442
+ }
443
+
444
+ $email_data['headers'] = $headers;
445
+
446
+ return $email_data;
447
+ }
448
+
449
+ /**
450
+ * Handle shortcode for password reset email message.
451
+ *
452
+ * @since 1.1
453
+ *
454
+ * @param string $setting Notification settings.
455
+ * @param string $key The activation key.
456
+ * @param string $user_login The username for the user.
457
+ * @param WP_User $user_data WP_User object.
458
+ *
459
+ * @return mixed|string
460
+ */
461
+ public function handle_password_reset_shortcodes( $setting, $key, $user_login, $user_data ) {
462
+ $message = '';
463
+
464
+ if ( '' !== $user_login ) {
465
+ // For WordPress version 4.1.0 or less, we could have empty user_login.
466
+ $message = $this->handle_shortcodes( $setting['message'], 'user-password', $user_data->ID );
467
+ $message = $this->handle_global_user_shortcodes( $message, $user_data->user_email );
468
+
469
+ $reset_link = network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' );
470
+ $message = str_replace( '[password_reset_link]', $reset_link, $message );
471
+ }
472
+
473
+ return $message;
474
+ }
475
+
476
+ /**
477
+ * Send Password Changed email.
478
+ *
479
+ * @param array $setting Notification Setting.
480
+ * @param WP_User $user User for whom the password has changed.
481
+ */
482
+ public function send_password_changed_email( $setting, $user ) {
483
+ $user_id = $user->ID;
484
+
485
+ $subject = $this->handle_shortcodes( $setting['subject'], $setting['notification'], $user_id );
486
+ $message = $this->handle_shortcodes( $setting['message'], $setting['notification'], $user_id );
487
+
488
+ if ( 'true' !== $setting['disable-autop'] && 'html' === $setting['email-formatting'] ) {
489
+ $message = wpautop( $message );
490
+ }
491
+
492
+ $headers = array();
493
+ if ( 'html' === $setting['email-formatting'] ) {
494
+ $headers[] = 'Content-type: text/html';
495
+ } elseif ( 'text' === $setting['email-formatting'] ) {
496
+ $message = wp_strip_all_tags( $message );
497
+ }
498
+
499
+ $subject = $this->handle_global_user_shortcodes( $subject, $user->user_email );
500
+ $message = $this->handle_global_user_shortcodes( $message, $user->user_email );
501
+ wp_mail( $user->user_email, stripslashes( $subject ), $message, $headers );
502
+ }
503
+
504
+ /**
505
+ * Generate message for notification.
506
+ *
507
+ * @since 1.0
508
+ * public since @since 1.6
509
+ *
510
+ * @param string $message String may have shortcode.
511
+ * @param string $notification Notification name.
512
+ * @param string|int $extra_data Additional data for shortcode.
513
+ *
514
+ * @return string Processed string.
515
+ */
516
+ public function handle_shortcodes( $message, $notification, $extra_data ) {
517
+
518
+ switch ( $notification ) {
519
+ case 'new-comment':
520
+ case 'new-trackback':
521
+ case 'new-pingback':
522
+ case 'reply-comment':
523
+ // handle new comments, trackbacks and pingbacks.
524
+ $message = $this->comment_shortcodes( $message, $extra_data );
525
+ $comment = get_comment( $extra_data );
526
+ $message = $this->post_shortcodes( $message, $comment->comment_post_ID );
527
+ if ( 0 !== $comment->user_id ) {
528
+ $message = $this->user_shortcodes( $message, $comment->user_id );
529
+ }
530
+ break;
531
+
532
+ case 'admin-password':
533
+ case 'admin-password-changed':
534
+ case 'admin-email-changed':
535
+ case 'admin-user':
536
+ case 'welcome-email':
537
+ case 'user-login':
538
+ $message = $this->user_shortcodes( $message, $extra_data );
539
+ break;
540
+ case 'admin-user-login':
541
+ $message = $this->user_shortcodes( $message, $extra_data );
542
+ break;
543
+ case 'new-user':
544
+ case 'user-role':
545
+ case 'admin-role':
546
+ case 'password-changed':
547
+ // handle users (lost password and new user registration).
548
+ $message = $this->user_shortcodes( $message, $extra_data );
549
+ break;
550
+
551
+ case 'email-changed':
552
+ case 'user-password':
553
+ // handle users (lost password and new user registration).
554
+ $message = $this->user_shortcodes( $message, $extra_data, 'email_' );
555
+ break;
556
+
557
+ case 'new-category':
558
+ // handle new category.
559
+ $message = $this->taxonomy_shortcodes( $message, 'category', $extra_data );
560
+ break;
561
+
562
+ case 'new-post_tag':
563
+ // handle new tag.
564
+ $message = $this->taxonomy_shortcodes( $message, 'post_tag', $extra_data );
565
+ break;
566
+
567
+ case 'core-updated':
568
+ // handle core updated type.
569
+ $message = $this->core_updated_shortcodes( $message, $extra_data );
570
+ break;
571
+
572
+ case 'data-export':
573
+ // handle data export email.
574
+ $message = $this->data_export_shortcodes( $message, $extra_data );
575
+ break;
576
+
577
+ case 'data-erased':
578
+ // handle data export email.
579
+ $message = $this->data_erased_shortcodes( $message, $extra_data );
580
+ break;
581
+
582
+ case 'new-media':
583
+ case 'update-media':
584
+ $message = $this->post_shortcodes( $message, $extra_data );
585
+ $post = get_post( $extra_data );
586
+ if ( $post instanceof WP_Post ) {
587
+ $message = $this->user_shortcodes( $message, $post->post_author );
588
+ }
589
+ break;
590
+
591
+ default:
592
+ $type = explode( '-', $notification, 2 );
593
+ if ( 'newterm' === $type[0] ) {
594
+ // handle new terms.
595
+ $message = $this->taxonomy_shortcodes( $message, $type[1], $extra_data );
596
+ } elseif ( 'new' === $type[0] || 'update' === $type[0] || 'pending' === $type[0] || 'future' === $type[0] || 'private' === $type[0] || 'trash' === $type[0] ) {
597
+ // handle new, update and pending posts.
598
+ $post_types = get_post_types( array( 'public' => true ), 'names' );
599
+ $post_types = array_diff( $post_types, array( BNFW_Notification::POST_TYPE ) );
600
+
601
+ if ( in_array( $type[1], $post_types, true ) ) {
602
+ $message = $this->post_shortcodes( $message, $extra_data );
603
+ $post = get_post( $extra_data );
604
+ if ( $post instanceof WP_Post ) {
605
+ $message = $this->user_shortcodes( $message, $post->post_author );
606
+ }
607
+ }
608
+ } elseif ( 'comment' === $type[0] || 'moderate' === $type[0] || 'commentreply' === $type[0] ) {
609
+ $message = $this->comment_shortcodes( $message, $extra_data );
610
+ $comment = get_comment( $extra_data );
611
+ $message = $this->post_shortcodes( $message, $comment->comment_post_ID );
612
+ if ( 0 !== $comment->user_id ) {
613
+ $message = $this->user_shortcodes( $message, $comment->user_id );
614
+ }
615
+ } elseif ( 'approve' === $type[0] ) {
616
+ // handle Approve comments notification.
617
+ $message = $this->comment_shortcodes( $message, $extra_data );
618
+ $comment = get_comment( $extra_data );
619
+ $message = $this->post_shortcodes( $message, $comment->comment_post_ID );
620
+ if ( 0 !== $comment->user_id ) {
621
+ $message = $this->user_shortcodes( $message, $comment->user_id );
622
+ }
623
+ break;
624
+ } elseif ( 'ca' === $type[0] ) {
625
+ $message = $this->confirm_action_shortcodes( $message, $extra_data );
626
+ $message = $this->handle_global_user_shortcodes( $message, $extra_data['email'] );
627
+ } elseif ( 'uc' === $type[0] ) {
628
+ $message = $this->confirmed_action_shortcodes( $message, $extra_data );
629
+ $message = $this->handle_global_user_shortcodes( $message, $extra_data['admin_email'] );
630
+ }
631
+ break;
632
+ }
633
+
634
+ $message = $this->global_shortcodes( $message );
635
+
636
+ $message = apply_filters( 'bnfw_shortcodes', $message, $notification, $extra_data, $this );
637
+ return $message;
638
+ }
639
+
640
+ /**
641
+ * Handle Global shortcodes.
642
+ *
643
+ * @since 1.5
644
+ *
645
+ * @param string $message String with shortcodes.
646
+ *
647
+ * @return string String after processing global shortcodes.
648
+ */
649
+ private function global_shortcodes( $message ) {
650
+ $message = str_replace( '[global_site_title]', get_bloginfo( 'name' ), $message );
651
+ $message = str_replace( '[global_site_tagline]', get_bloginfo( 'description' ), $message );
652
+ $message = str_replace( '[global_site_url]', get_bloginfo( 'url' ), $message );
653
+
654
+ $message = str_replace( '[current_time]', current_time( get_option( 'time_format' ) ), $message );
655
+ $message = str_replace( '[current_date]', date_i18n( get_option( 'date_format' ), current_time( 'timestamp' ) ), $message );
656
+ $message = str_replace( '[admin_email]', get_option( 'admin_email' ), $message );
657
+
658
+ return $message;
659
+ }
660
+
661
+ /**
662
+ * Handle Global shortcodes.
663
+ *
664
+ * @param string $message Message.
665
+ * @param string $email Email.
666
+ *
667
+ * @return string
668
+ */
669
+ public function handle_global_shortcodes( $message, $email ) {
670
+ $message = $this->global_shortcodes( $message );
671
+
672
+ return $this->handle_global_user_shortcodes( $message, $email );
673
+ }
674
+
675
+ /**
676
+ * Handle Global User Shortcodes.
677
+ *
678
+ * @param string $message String to be processed.
679
+ * @param string $email Email of the user.
680
+ *
681
+ * @return string Processed string.
682
+ */
683
+ public function handle_global_user_shortcodes( $message, $email ) {
684
+ $user = get_user_by( 'email', $email );
685
+
686
+ if ( false === $user ) {
687
+ $message = str_replace( '[global_user_firstname]', $email, $message );
688
+ $message = str_replace( '[global_user_lastname]', $email, $message );
689
+ $message = str_replace( '[global_user_username]', $email, $message );
690
+ } else {
691
+ $message = str_replace( '[global_user_firstname]', $user->first_name, $message );
692
+ $message = str_replace( '[global_user_lastname]', $user->last_name, $message );
693
+ $message = str_replace( '[global_user_username]', $user->user_login, $message );
694
+
695
+ $message = $this->user_shortcodes( $message, $user->ID, 'email_' );
696
+ }
697
+
698
+ $message = str_replace( '[privacy_policy_url]', get_privacy_policy_url(), $message );
699
+
700
+ $message = str_replace( array( '[global_user_email]', '[user_email]' ), $email, $message );
701
+
702
+ return $message;
703
+ }
704
+
705
+ /**
706
+ * Handle media post shortcodes.
707
+ *
708
+ * @since 1.0
709
+ * @param string $message Message.
710
+ * @param WP_Post $post post object.
711
+ * @return string
712
+ */
713
+ public function media_post_shortcodes( $message, $post ) {
714
+ $post_content = $this->may_be_strip_shortcode( $post->post_content );
715
+ $post_content = apply_filters( 'the_content', $post_content );
716
+ $post_content = str_replace( ']]>', ']]&gt;', $post_content );
717
+ $message = str_replace( '[ID]', $post->ID, $message );
718
+ $message = str_replace( '[media_date]', bnfw_format_date( $post->post_date ), $message );
719
+ $message = str_replace( '[media_date_gmt]', bnfw_format_date( $post->post_date_gmt ), $message );
720
+ $message = str_replace( '[media_description]', $post_content, $message );
721
+ $message = str_replace( '[media_title]', $post->post_title, $message );
722
+ $message = str_replace( '[media_alt_text]', get_post_meta( $post->ID, '_wp_attachment_image_alt', true ), $message );
723
+ $message = str_replace( '[media_caption]', $this->may_be_strip_shortcode( get_the_excerpt( $post ) ), $message );
724
+ $message = str_replace( '[media_status]', $post->post_status, $message );
725
+ $message = str_replace( '[media_modified]', bnfw_format_date( $post->post_modified ), $message );
726
+ $message = str_replace( '[media_modified_gmt]', bnfw_format_date( $post->post_modified_gmt ), $message );
727
+ $message = str_replace( '[media_content_filtered]', $post->post_content_filtered, $message );
728
+ $message = str_replace( '[media_type]', $post->post_type, $message );
729
+ $message = str_replace( '[media_mime_type]', $post->post_mime_type, $message );
730
+ $message = str_replace( '[media_slug]', $post->post_name, $message );
731
+ $dimensions = get_post_meta( $post->ID, '_wp_attachment_metadata', true );
732
+ $media_dimensions = $dimensions['width'] . ' x ' . $dimensions['height'];
733
+ $message = str_replace( '[media_dimensions]', $media_dimensions, $message );
734
+ $user_info = get_userdata( $post->post_author );
735
+ $message = str_replace( '[media_author]', $user_info->display_name, $message );
736
+
737
+ return $message;
738
+ }
739
+
740
+ /**
741
+ * Handle post shortcodes.
742
+ *
743
+ * @since 1.0
744
+ * @param string $message String to be processed.
745
+ * @param int $post_id Post id.
746
+ * @return string
747
+ */
748
+ public function post_shortcodes( $message, $post_id ) {
749
+ $post = get_post( $post_id );
750
+
751
+ if ( ! $post instanceof WP_Post ) {
752
+ return $message;
753
+ }
754
+
755
+ if ( 'attachment' === $post->post_type ) {
756
+ $message = $this->media_post_shortcodes( $message, $post );
757
+ }
758
+
759
+ $post_content = $this->may_be_strip_shortcode( $post->post_content );
760
+ $post_content = apply_filters( 'the_content', $post_content );
761
+ $post_content = str_replace( ']]>', ']]&gt;', $post_content );
762
+
763
+ $message = str_replace( '[ID]', $post->ID, $message );
764
+ $message = str_replace( '[post_date]', bnfw_format_date( $post->post_date ), $message );
765
+ $message = str_replace( '[post_date_gmt]', bnfw_format_date( $post->post_date_gmt ), $message );
766
+ $message = str_replace( '[post_content]', $post_content, $message );
767
+ $message = str_replace( '[post_title]', $post->post_title, $message );
768
+ $message = str_replace( '[post_excerpt]', $this->may_be_strip_shortcode( get_the_excerpt( $post ) ), $message );
769
+ $message = str_replace( '[post_status]', $post->post_status, $message );
770
+ $message = str_replace( '[comment_status]', $post->comment_status, $message );
771
+ $message = str_replace( '[ping_status]', $post->ping_status, $message );
772
+ $message = str_replace( '[post_password]', $post->post_password, $message );
773
+ $message = str_replace( '[post_name]', $post->post_name, $message );
774
+ $message = str_replace( '[post_slug]', $post->post_name, $message );
775
+ $message = str_replace( '[to_ping]', $post->to_ping, $message );
776
+ $message = str_replace( '[pinged]', $post->pinged, $message );
777
+ $message = str_replace( '[post_modified]', bnfw_format_date( $post->post_modified ), $message );
778
+ $message = str_replace( '[post_modified_gmt]', bnfw_format_date( $post->post_modified_gmt ), $message );
779
+ $message = str_replace( '[post_content_filtered]', $post->post_content_filtered, $message );
780
+ $message = str_replace( '[post_parent]', $post->post_parent, $message );
781
+ $message = str_replace( '[post_parent_permalink]', get_permalink( $post->post_parent ), $message );
782
+ $message = str_replace( '[guid]', $post->guid, $message );
783
+ $message = str_replace( '[menu_order]', $post->menu_order, $message );
784
+ $message = str_replace( '[post_type]', $post->post_type, $message );
785
+ $message = str_replace( '[post_mime_type]', $post->post_mime_type, $message );
786
+ $message = str_replace( '[comment_count]', $post->comment_count, $message );
787
+ $message = str_replace( '[permalink]', get_permalink( $post->ID ), $message );
788
+ $message = str_replace( '[post_type_archive]', get_post_type_archive_link( $post->post_type ), $message );
789
+
790
+ $message = str_replace( '[edit_post]', $this->get_edit_post_link( $post->ID, 'return' ), $message );
791
+
792
+ $featured_image = '';
793
+ if ( has_post_thumbnail( $post->ID ) ) {
794
+ $image_url = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'single-post-thumbnail' );
795
+ if ( is_array( $image_url ) ) {
796
+ $featured_image = $image_url[0];
797
+ }
798
+ }
799
+ $message = str_replace( '[featured_image]', $featured_image, $message );
800
+
801
+ $message = str_replace( '[first_image]', $this->get_first_image( $post->post_content ), $message );
802
+
803
+ if ( 'future' === $post->post_status ) {
804
+ $message = str_replace( '[post_scheduled_date]', bnfw_format_date( $post->post_date ), $message );
805
+ $message = str_replace( '[post_scheduled_date_gmt]', bnfw_format_date( $post->post_date_gmt ), $message );
806
+ } else {
807
+ $message = str_replace( '[post_scheduled_date]', 'Published', $message );
808
+ $message = str_replace( '[post_scheduled_date_gmt]', 'Published', $message );
809
+ }
810
+
811
+ $categories = wp_get_post_categories( $post_id, array( 'fields' => 'all' ) );
812
+
813
+ $message = str_replace( '[post_category]', implode( ', ', wp_list_pluck( $categories, 'name' ) ), $message );
814
+
815
+ if ( count( $categories ) > 0 ) {
816
+ $message = str_replace(
817
+ array(
818
+ '[post_category_slug]',
819
+ '[post_category_description]',
820
+ ),
821
+ array(
822
+ $categories[0]->slug,
823
+ $categories[0]->description,
824
+ ),
825
+ $message
826
+ );
827
+ }
828
+
829
+ $tag_list = implode( ', ', wp_get_post_tags( $post_id, array( 'fields' => 'names' ) ) );
830
+ $message = str_replace( '[post_tag]', $tag_list, $message );
831
+
832
+ $user_info = get_userdata( $post->post_author );
833
+ $message = str_replace( '[post_author]', $user_info->display_name, $message );
834
+
835
+ $message = str_replace( '[author_link]', get_author_posts_url( $post->post_author ), $message );
836
+ $last_id = get_post_meta( $post->ID, '_edit_lock', true );
837
+ if ( $last_id ) {
838
+ $last_id = explode( ':', $last_id );
839
+ if ( count( $last_id ) > 1 ) {
840
+ $last_id = end( $last_id );
841
+ }
842
+
843
+ if ( $post->post_author !== $last_id ) {
844
+ $last_user_info = get_userdata( $last_id );
845
+ } else {
846
+ $last_user_info = $user_info;
847
+ }
848
+
849
+ $message = str_replace( '[post_update_author]', $last_user_info->display_name, $message );
850
+ }
851
+
852
+ $message = str_replace( '[post_term', '[post_term id="' . $post_id . '"', $message );
853
+ add_shortcode( 'post_term', array( $this, 'post_term_shortcode_handler' ) );
854
+ $message = do_shortcode( $message );
855
+ remove_shortcode( 'post_term', array( $this, 'post_term_shortcode_handler' ) );
856
+
857
+ return apply_filters( 'bnfw_shortcodes_post', $message, $post_id );
858
+ }
859
+
860
+ /**
861
+ * Retrieves the edit post link for post.
862
+ *
863
+ * This is a copy of the built-in function without the user check.
864
+ *
865
+ * Can be used within the WordPress loop or outside of it. Can be used with
866
+ * pages, posts, attachments, and revisions.
867
+ *
868
+ * @param int|WP_Post $id Optional. Post ID or post object. Default is the global `$post`.
869
+ * @param string $context Optional. How to output the '&' character. Default '&amp;'.
870
+ * @return string|null The edit post link for the given post. null if the post type is invalid or does
871
+ * not allow an editing UI.
872
+ */
873
+ public function get_edit_post_link( $id = 0, $context = 'display' ) {
874
+ $post = get_post( $id );
875
+ if ( ! $post ) {
876
+ return;
877
+ }
878
+
879
+ if ( 'revision' === $post->post_type ) {
880
+ $action = '';
881
+ } elseif ( 'display' === $context ) {
882
+ $action = '&amp;action=edit';
883
+ } else {
884
+ $action = '&action=edit';
885
+ }
886
+
887
+ $post_type_object = get_post_type_object( $post->post_type );
888
+ if ( ! $post_type_object ) {
889
+ return;
890
+ }
891
+
892
+ if ( $post_type_object->_edit_link ) {
893
+ $link = admin_url( sprintf( $post_type_object->_edit_link . $action, $post->ID ) );
894
+ } else {
895
+ $link = '';
896
+ }
897
+
898
+ /**
899
+ * Filters the post edit link.
900
+ *
901
+ * @since 2.3.0
902
+ *
903
+ * @param string $link The edit link.
904
+ * @param int $post_id Post ID.
905
+ * @param string $context The link context. If set to 'display' then ampersands
906
+ * are encoded.
907
+ */
908
+ return apply_filters( 'get_edit_post_link', $link, $post->ID, $context );
909
+ }
910
+
911
+ /**
912
+ * Handle post term shortcode.
913
+ *
914
+ * @param array $atts Shortocde attributes.
915
+ *
916
+ * @return string Processed string.
917
+ */
918
+ public function post_term_shortcode_handler( $atts ) {
919
+ $atts = shortcode_atts(
920
+ array(
921
+ 'taxonomy' => '',
922
+ 'id' => 0,
923
+ ),
924
+ $atts
925
+ );
926
+
927
+ $terms = wp_get_post_terms( $atts['id'], $atts['taxonomy'], array( 'fields' => 'names' ) );
928
+
929
+ if ( ! is_wp_error( $terms ) ) {
930
+ return implode( ', ', $terms );
931
+ }
932
+
933
+ return '';
934
+ }
935
+
936
+ /**
937
+ * Strip shortcodes, unless disabled.
938
+ *
939
+ * @param string $content Content who's shortcodes should be stripped.
940
+ *
941
+ * @return string Processed content.
942
+ */
943
+ private function may_be_strip_shortcode( $content ) {
944
+ $enable_shortcode = get_option( 'bnfw_enable_shortcodes' );
945
+
946
+ if ( '1' === $enable_shortcode ) {
947
+ return $content;
948
+ }
949
+
950
+ return strip_shortcodes( $content );
951
+ }
952
+
953
+ /**
954
+ * Handle comment shortcodes.
955
+ *
956
+ * @since 1.0
957
+ *
958
+ * @param string $message String to be processed.
959
+ * @param int $comment_id Comment id.
960
+ *
961
+ * @return string Processed string.
962
+ */
963
+ private function comment_shortcodes( $message, $comment_id ) {
964
+ $comment = get_comment( $comment_id );
965
+
966
+ $message = str_replace( '[comment_ID]', $comment->comment_ID, $message );
967
+ $message = str_replace( '[comment_post_ID]', $comment->comment_post_ID, $message );
968
+ $message = str_replace( '[comment_author]', $comment->comment_author, $message );
969
+ $message = str_replace( '[comment_author_email]', $comment->comment_author_email, $message );
970
+ $message = str_replace( '[comment_author_url]', $comment->comment_author_url, $message );
971
+ $message = str_replace( '[comment_author_IP]', $comment->comment_author_IP, $message );
972
+ $message = str_replace( '[comment_date]', bnfw_format_date( $comment->comment_date ), $message );
973
+ $message = str_replace( '[comment_date_gmt]', bnfw_format_date( $comment->comment_date_gmt ), $message );
974
+ $message = str_replace( '[comment_content]', get_comment_text( $comment->comment_ID ), $message );
975
+ $message = str_replace( '[comment_karma]', $comment->comment_karma, $message );
976
+ $message = str_replace( '[comment_approved]', str_replace( array( '0', '1', 'spam' ), array( 'Awaiting Moderation', 'Approved', 'Spam' ), $comment->comment_approved ), $message );
977
+ $message = str_replace( '[comment_agent]', $comment->comment_agent, $message );
978
+ $message = str_replace( '[comment_type]', $comment->comment_type, $message );
979
+ $message = str_replace( '[comment_parent]', $comment->comment_parent, $message );
980
+ $message = str_replace( '[user_id]', $comment->user_id, $message );
981
+ $message = str_replace( '[permalink]', get_comment_link( $comment->comment_ID ), $message );
982
+ $message = str_replace( '[comment_moderation_link]', admin_url( 'comment.php?action=editcomment&c=' ) . $comment->comment_ID, $message );
983
+ $message = str_replace( '[comment_moderation_approve]', '<a href="' . wp_nonce_url( admin_url( "comment.php?action=approve&c={$comment->comment_ID}#wpbody-content" ) ) . '">Approve</a>', $message );
984
+ $message = str_replace( '[comment_moderation_spam]', '<a href="' . wp_nonce_url( admin_url( "comment.php?action=spam&c={$comment->comment_ID}#wpbody-content" ) ) . '">Spam</a>', $message );
985
+ $message = str_replace( '[comment_moderation_delete]', '<a href="' . wp_nonce_url( admin_url( "comment.php?action=trash&c={$comment->comment_ID}#wpbody-content" ) ) . '">Delete</a>', $message );
986
+
987
+ $parent_comment = get_comment( $comment->comment_parent );
988
+ if ( $parent_comment instanceof WP_Comment ) {
989
+ $message = str_replace( '[comment_parent_content]', $parent_comment->comment_content, $message );
990
+ }
991
+
992
+ return $message;
993
+ }
994
+
995
+ /**
996
+ * Handle user shortcodes.
997
+ *
998
+ * @since 1.0
999
+ *
1000
+ * @param string $message String to be processed.
1001
+ * @param int $user_id User id.
1002
+ * @param string $prefix Prefix.
1003
+ *
1004
+ * @return string Processed string.
1005
+ */
1006
+ public function user_shortcodes( $message, $user_id, $prefix = '' ) {
1007
+ global $wp_roles;
1008
+
1009
+ $user_info = get_userdata( $user_id );
1010
+
1011
+ if ( ! $user_info instanceof WP_User ) {
1012
+ return $message;
1013
+ }
1014
+
1015
+ // deprecated.
1016
+ $message = str_replace( '[ID]', $user_info->ID, $message );
1017
+ $message = str_replace( '[display_name]', $user_info->display_name, $message );
1018
+ $message = str_replace( '[nickname]', $user_info->nickname, $message );
1019
+ $message = str_replace( '[commenter_avatar]', get_avatar_url( $user_id ), $message );
1020
+
1021
+ $message = str_replace( '[' . $prefix . 'user_id]', $user_info->ID, $message );
1022
+ $message = str_replace( '[' . $prefix . 'user_login]', $user_info->user_login, $message );
1023
+ $message = str_replace( '[' . $prefix . 'user_nicename]', $user_info->user_nicename, $message );
1024
+ $message = str_replace( '[' . $prefix . 'user_email]', $user_info->user_email, $message );
1025
+ $message = str_replace( '[' . $prefix . 'user_url]', $user_info->user_url, $message );
1026
+ $message = str_replace( '[' . $prefix . 'user_registered]', $user_info->user_registered, $message );
1027
+ $message = str_replace( '[' . $prefix . 'user_display_name]', $user_info->display_name, $message );
1028
+ $message = str_replace( '[' . $prefix . 'user_firstname]', $user_info->user_firstname, $message );
1029
+ $message = str_replace( '[' . $prefix . 'user_lastname]', $user_info->user_lastname, $message );
1030
+ $message = str_replace( '[' . $prefix . 'user_nickname]', $user_info->nickname, $message );
1031
+ $message = str_replace( '[' . $prefix . 'user_description]', $user_info->user_description, $message );
1032
+ $message = str_replace( '[' . $prefix . 'user_avatar]', get_avatar_url( $user_id ), $message );
1033
+
1034
+ $roles = array_map( array( $this, 'get_role_label_by_name' ), $user_info->roles );
1035
+ $message = str_replace( '[' . $prefix . 'user_role]', implode( ', ', $roles ), $message );
1036
+
1037
+ $user_capabilities = bnfw_format_user_capabilities( $user_info->wp_capabilities );
1038
+ if ( ! empty( $user_capabilities ) ) {
1039
+ $message = str_replace( '[wp_capabilities]', $user_capabilities, $message );
1040
+ $message = str_replace( '[' . $prefix . 'user_wp_capabilities]', $user_capabilities, $message );
1041
+ }
1042
+
1043
+ $message = apply_filters( 'bnfw_shortcodes_user', $message, $user_id, $prefix );
1044
+ return $message;
1045
+ }
1046
+
1047
+ /**
1048
+ * Handle taxonomy shortcodes.
1049
+ *
1050
+ * @access private
1051
+ * @since 1.1
1052
+ *
1053
+ * @param string $message String to be processed.
1054
+ * @param string $taxonomy Taxonomy name that `$term` is part of.
1055
+ * @param int $term_id Term ID.
1056
+ * @return string
1057
+ */
1058
+ private function taxonomy_shortcodes( $message, $taxonomy, $term_id ) {
1059
+ $term_info = get_term( $term_id, $taxonomy );
1060
+
1061
+ $message = str_replace( '[slug]', $term_info->slug, $message );
1062
+ $message = str_replace( '[name]', $term_info->name, $message );
1063
+ $message = str_replace( '[description]', $term_info->description, $message );
1064
+
1065
+ return $message;
1066
+ }
1067
+
1068
+ /**
1069
+ * Handle Core Updated Shortcodes.
1070
+ *
1071
+ * @since 1.6
1072
+ *
1073
+ * @param string $message Original message with shortcodes.
1074
+ * @param string $type The type of email being sent. Can be one of
1075
+ * 'success', 'fail', 'manual', 'critical'.
1076
+ *
1077
+ * @return string Modified content.
1078
+ */
1079
+ private function core_updated_shortcodes( $message, $type ) {
1080
+ $message = str_replace( '[core_update_status]', $type, $message );
1081
+
1082
+ return $message;
1083
+ }
1084
+
1085
+ /**
1086
+ * Get the list of emails from the notification settings.
1087
+ *
1088
+ * @since 1.0
1089
+ *
1090
+ * @param array $setting Notification settings.
1091
+ * @param int $id ID to be processed.
1092
+ * @param bool $process_post_authors If post author needs to be get notification.
1093
+ * @param bool $process_exclude_current_user If current user needs to be excluded.
1094
+ *
1095
+ * @return array Emails
1096
+ */
1097
+ public function get_emails( $setting, $id, $process_post_authors = true, $process_exclude_current_user = true ) {
1098
+ global $current_user;
1099
+
1100
+ $emails = array();
1101
+
1102
+ $exclude = null;
1103
+ if ( $process_exclude_current_user && 'true' === $setting['disable-current-user'] ) {
1104
+ if ( isset( $current_user->ID ) ) {
1105
+ $exclude = $current_user->ID;
1106
+ }
1107
+ }
1108
+
1109
+ $emails['to'] = array();
1110
+
1111
+ if ( ! empty( $setting['users'] ) ) {
1112
+ $emails['to'] = $this->get_emails_from_users( $setting['users'], $exclude, $id, $setting );
1113
+ }
1114
+
1115
+ /**
1116
+ * BNFW get to emails.
1117
+ */
1118
+ if ( $process_post_authors && 'true' === $setting['only-post-author'] ) {
1119
+ $post_id = $id;
1120
+
1121
+ if ( bnfw_is_comment_notification( $setting['notification'] ) ) {
1122
+ $comment = get_comment( $id );
1123
+ $post_id = $comment->comment_post_ID;
1124
+ }
1125
+
1126
+ $type = explode( '-', $setting['notification'], 2 );
1127
+ if ( 'approve' === $type[0] ) {
1128
+ if ( ! in_array( $comment->comment_author_email, $emails['to'], true ) ) {
1129
+ $emails['to'][] = $comment->comment_author_email;
1130
+ }
1131
+ } else {
1132
+ if ( 'user-customfield' === $setting['notification'] || 'user-customfieldvalue' === $setting['notification'] ) {
1133
+ $post_author = $post_id;
1134
+ } else {
1135
+ $post_author = get_post_field( 'post_author', $post_id );
1136
+ }
1137
+ $author = get_user_by( 'id', $post_author );
1138
+ if ( false !== $author && $post_author !== $exclude ) {
1139
+ if ( ! in_array( $author->user_email, $emails['to'], true ) ) {
1140
+ $emails['to'][] = $author->user_email;
1141
+ }
1142
+ }
1143
+ }
1144
+ }
1145
+
1146
+ if ( 'true' === $setting['show-fields'] ) {
1147
+ $default_from_field = get_option( 'blogname' ) . ' <' . get_option( 'admin_email' ) . '>';
1148
+
1149
+ if ( ! empty( $setting['from-name'] ) && ! empty( $setting['from-email'] ) && is_email( $setting['from-email'] ) ) {
1150
+ $default_from_field = $setting['from-name'] . ' <' . $setting['from-email'] . '>';
1151
+ }
1152
+
1153
+ /**
1154
+ * Filter Email From Field.
1155
+ */
1156
+ $emails['from'] = apply_filters( 'bnfw_from_field', $default_from_field, $setting, $id, $emails['to'] );
1157
+
1158
+ /**
1159
+ * Filter Reply Name Field.
1160
+ */
1161
+ $emails['reply-name'] = apply_filters( 'bnfw_reply_name_field', $setting['reply-name'], $setting, $id, $emails['to'] );
1162
+
1163
+ /**
1164
+ * Filter Reply Email Field.
1165
+ */
1166
+ $emails['reply-email'] = apply_filters( 'bnfw_reply_email_field', $setting['reply-email'], $setting, $id, $emails['to'] );
1167
+
1168
+ if ( ! empty( $setting['cc'] ) ) {
1169
+ $emails['cc'] = $this->get_emails_from_users( $setting['cc'], $exclude, $id, $setting );
1170
+ }
1171
+
1172
+ if ( ! empty( $setting['bcc'] ) ) {
1173
+ $emails['bcc'] = $this->get_emails_from_users( $setting['bcc'], $exclude, $id, $setting );
1174
+ }
1175
+ }
1176
+
1177
+ $excluded_emails = array();
1178
+
1179
+ if ( ! empty( $setting['exclude-users'] ) ) {
1180
+ $excluded_emails = $this->get_emails_from_users( $setting['exclude-users'] );
1181
+ }
1182
+
1183
+ if ( ! empty( $excluded_emails ) ) {
1184
+ $emails['to'] = array_diff( $emails['to'], $excluded_emails );
1185
+
1186
+ if ( ! empty( $emails['cc'] ) ) {
1187
+ $emails['cc'] = array_diff( $emails['cc'], $excluded_emails );
1188
+ }
1189
+
1190
+ if ( ! empty( $emails['bcc'] ) ) {
1191
+ $emails['bcc'] = array_diff( $emails['bcc'], $excluded_emails );
1192
+ }
1193
+ }
1194
+ $emails['to'] = apply_filters( 'bnfw_to_emails', $emails['to'], $setting, $id );
1195
+
1196
+ return $emails;
1197
+ }
1198
+
1199
+ /**
1200
+ * Get emails from users.
1201
+ *
1202
+ * @since 1.2
1203
+ *
1204
+ * @param array $users Users Array.
1205
+ * @param int $exclude User id to exclude.
1206
+ * @param int $post_id Post id.
1207
+ * @param array $setting Notification setting.
1208
+ *
1209
+ * @return array
1210
+ */
1211
+ public function get_emails_from_users( $users, $exclude = null, $post_id = 0, $setting = array() ) {
1212
+ $user_ids = array();
1213
+ $user_roles = array();
1214
+ $non_wp_users = array();
1215
+
1216
+ if ( empty( $users ) ) {
1217
+ return array();
1218
+ }
1219
+
1220
+ foreach ( $users as $user ) {
1221
+ if ( $this->starts_with( $user, 'role-' ) ) {
1222
+ $user_roles[] = str_replace( 'role-', '', $user );
1223
+ } elseif ( strpos( $user, '@' ) !== false ) {
1224
+ $non_wp_users[] = $user;
1225
+ continue;
1226
+ } elseif ( absint( $user ) > 0 ) {
1227
+ $user_ids[] = absint( $user );
1228
+ } else {
1229
+ $non_wp_users[] = $user;
1230
+ }
1231
+ }
1232
+
1233
+ if ( null !== $exclude ) {
1234
+ $user_ids = array_diff( $user_ids, array( $exclude ) );
1235
+ }
1236
+
1237
+ $emails_from_user_ids = $this->get_emails_from_id( $user_ids );
1238
+ $emails_from_user_roles = $this->get_emails_from_role( $user_roles, $exclude );
1239
+
1240
+ if ( ! empty( $setting ) ) {
1241
+ // for new comment notifications, we need to use post id instead of comment id.
1242
+ if ( bnfw_is_comment_notification( $setting['notification'] ) && $post_id ) {
1243
+ $comment = get_comment( $post_id );
1244
+ $post_id = $comment->comment_post_ID;
1245
+ }
1246
+ }
1247
+
1248
+ $non_wp_emails = apply_filters( 'bnfw_non_wp_emails', array(), $non_wp_users, $post_id );
1249
+
1250
+ return array_merge( $emails_from_user_roles, $emails_from_user_ids, $non_wp_emails );
1251
+ }
1252
+
1253
+ /**
1254
+ * Get user emails by user ids.
1255
+ *
1256
+ * @since 1.0
1257
+ *
1258
+ * @param array $user_ids An array of user IDs.
1259
+ *
1260
+ * @return array Emails.
1261
+ */
1262
+ private function get_emails_from_id( $user_ids ) {
1263
+ $email_list = array();
1264
+ if ( is_array( $user_ids ) && count( $user_ids ) > 0 ) {
1265
+ $user_query = new WP_User_Query( array( 'include' => $user_ids ) );
1266
+ foreach ( $user_query->results as $user ) {
1267
+ $email_list[] = $user->user_email;
1268
+ }
1269
+ }
1270
+ return $email_list;
1271
+ }
1272
+
1273
+ /**
1274
+ * Get emails of users based on role.
1275
+ *
1276
+ * @since 1.0
1277
+ * @param array $roles User Roles.
1278
+ * @param int $exclude User id to exclude.
1279
+ * @return array Email ids
1280
+ */
1281
+ private function get_emails_from_role( $roles, $exclude = null ) {
1282
+ if ( ! is_array( $roles ) ) {
1283
+ $roles = array( $roles );
1284
+ }
1285
+
1286
+ $email_list = array();
1287
+ foreach ( $roles as $role ) {
1288
+ $role_name = $this->get_role_name_by_label( $role );
1289
+ $users = get_users(
1290
+ array(
1291
+ 'role' => $role_name,
1292
+ 'fields' => array( 'user_email', 'ID' ),
1293
+ )
1294
+ );
1295
+
1296
+ foreach ( $users as $user ) {
1297
+ if ( null !== $exclude ) {
1298
+ if ( $user->ID === $exclude ) {
1299
+ continue;
1300
+ }
1301
+ }
1302
+
1303
+ if ( ! in_array( $user->user_email, $email_list, true ) ) {
1304
+ $email_list[] = $user->user_email;
1305
+ }
1306
+ }
1307
+ }
1308
+
1309
+ return $email_list;
1310
+ }
1311
+
1312
+ /**
1313
+ * Find if a string starts with another string.
1314
+ *
1315
+ * @since 1.2
1316
+ *
1317
+ * @param string $haystack The string to search in.
1318
+ * @param string $needle The substring to search for in the haystack.
1319
+ *
1320
+ * @return bool
1321
+ */
1322
+ private function starts_with( $haystack, $needle ) {
1323
+ // search backwards starting from haystack length characters from the end.
1324
+ return '' === $needle || strrpos( $haystack, $needle, -strlen( $haystack ) ) !== false;
1325
+ }
1326
+
1327
+ /**
1328
+ * Get User role name by label.
1329
+ *
1330
+ * @param mixed $role_label Role label.
1331
+ *
1332
+ * @return int|string
1333
+ */
1334
+ protected function get_role_name_by_label( $role_label ) {
1335
+ global $wp_roles;
1336
+ foreach ( $wp_roles->roles as $role_name => $role_info ) {
1337
+ if ( $role_label === $role_info['name'] || $role_name === $role_label ) {
1338
+ return $role_name;
1339
+ }
1340
+ }
1341
+
1342
+ // There is something wrong.
1343
+ return '';
1344
+ }
1345
+
1346
+ /**
1347
+ * Get the lable for a user role from name.
1348
+ *
1349
+ * @param string $role_name Role name.
1350
+ *
1351
+ * @return string Role Label.
1352
+ */
1353
+ public function get_role_label_by_name( $role_name ) {
1354
+ global $wp_roles;
1355
+
1356
+ if ( ! isset( $wp_roles->roles[ $role_name ] ) ) {
1357
+ return '';
1358
+ }
1359
+
1360
+ return translate_user_role( $wp_roles->roles[ $role_name ]['name'] );
1361
+ }
1362
+
1363
+ /**
1364
+ * Get first image in post.
1365
+ *
1366
+ * @param mixed $post_content Post content.
1367
+ *
1368
+ * @return string
1369
+ */
1370
+ protected function get_first_image( $post_content ) {
1371
+ if ( preg_match_all( '/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', $post_content, $matches ) ) {
1372
+ return $matches[1][0];
1373
+ }
1374
+ }
1375
+
1376
+ /**
1377
+ * Generate email headers based on the emails.
1378
+ *
1379
+ * @since 1.0
1380
+ * @param array $emails Emails.
1381
+ * @return array
1382
+ */
1383
+ public function get_headers( $emails ) {
1384
+ $headers = array();
1385
+
1386
+ if ( ! empty( $emails['from'] ) ) {
1387
+ $headers[] = 'From:' . $emails['from'];
1388
+ }
1389
+
1390
+ if ( ! empty( $emails['reply-email'] ) && is_email( $emails['reply-email'] ) ) {
1391
+ $headers[] = 'Reply-To:' . $emails['reply-name'] . '<' . $emails['reply-email'] . '>';
1392
+ }
1393
+
1394
+ if ( ! empty( $emails['cc'] ) ) {
1395
+ $headers[] = 'Cc:' . implode( ',', $emails['cc'] );
1396
+ }
1397
+ if ( ! empty( $emails['bcc'] ) ) {
1398
+ $headers[] = 'Bcc:' . implode( ',', $emails['bcc'] );
1399
+ }
1400
+
1401
+ /**
1402
+ * Filter out mail headers.
1403
+ *
1404
+ * @param array $headers Headers.
1405
+ * @param array $emails Emails.
1406
+ */
1407
+ return apply_filters( 'bnfw_mail_headers', $headers, $emails );
1408
+ }
1409
+ /**
1410
+ * Handles user shortcode.
1411
+ *
1412
+ * @param string $message String to be processed.
1413
+ * @param array $setting Notification settings.
1414
+ * @param array $email_data Email data.
1415
+ * @return string
1416
+ */
1417
+ public function handle_user_request_email_shortcodes( $message, $setting, $email_data ) {
1418
+ $message = $this->handle_shortcodes( $message, $setting['notification'], $email_data );
1419
+
1420
+ return $message;
1421
+ }
1422
+ /**
1423
+ * Handles user confiemd action shortcode.
1424
+ *
1425
+ * @param string $message String to be processed.
1426
+ * @param array $setting Notification settings.
1427
+ * @param array $email_data Email data.
1428
+ * @return string
1429
+ */
1430
+ public function handle_user_confirmed_action_email_shortcodes( $message, $setting, $email_data ) {
1431
+ $message = $this->handle_shortcodes( $message, $setting['notification'], $email_data );
1432
+
1433
+ return $message;
1434
+ }
1435
+ /**
1436
+ * Handles user export shortcode.
1437
+ *
1438
+ * @param string $message String to be processed.
1439
+ * @param array $setting Notification settings.
1440
+ * @param int $request_id Request ID.
1441
+ * @return string
1442
+ */
1443
+ public function handle_data_export_email_shortcodes( $message, $setting, $request_id ) {
1444
+ $message = $this->handle_shortcodes( $message, $setting['notification'], $request_id );
1445
+ return $message;
1446
+ }
1447
+ /**
1448
+ * Handles user export shortcode.
1449
+ *
1450
+ * @param string $message String to be processed.
1451
+ * @param array $extra_data Extra data.
1452
+ * @return string
1453
+ */
1454
+ protected function confirm_action_shortcodes( $message, $extra_data ) {
1455
+ $message = $this->data_request_shortcodes( $message, $extra_data );
1456
+ $message = str_replace( '[request_confirmation_link]', $extra_data['confirm_url'], $message );
1457
+ if ( isset( $extra_data['email'] ) ) {
1458
+ $message = str_replace( '[request_email]', $extra_data['email'], $message );
1459
+ }
1460
+
1461
+ if ( isset( $extra_data['user_email'] ) ) {
1462
+ $message = str_replace( '[request_email]', $extra_data['user_email'], $message );
1463
+ }
1464
+
1465
+ return $message;
1466
+ }
1467
+ /**
1468
+ * Handles user export shortcode.
1469
+ *
1470
+ * @param string $message String to be processed.
1471
+ * @param array $extra_data Extra data.
1472
+ * @return string
1473
+ */
1474
+ protected function confirmed_action_shortcodes( $message, $extra_data ) {
1475
+ $message = $this->data_request_shortcodes( $message, $extra_data );
1476
+ $message = str_replace( '[data_privacy_requests_url]', $extra_data['manage_url'], $message );
1477
+ $message = str_replace( '[request_email]', $extra_data['user_email'], $message );
1478
+
1479
+ return $message;
1480
+ }
1481
+ /**
1482
+ * Handles data request shortcode.
1483
+ *
1484
+ * @param string $message String to be processed.
1485
+ * @param array $extra_data Extra data.
1486
+ * @return string
1487
+ */
1488
+ protected function data_request_shortcodes( $message, $extra_data ) {
1489
+ $message = str_replace( '[data_request_type]', $extra_data['description'], $message );
1490
+
1491
+ return $message;
1492
+ }
1493
+ /**
1494
+ * Handles data export shortcode.
1495
+ *
1496
+ * @param string $message String to be processed.
1497
+ * @param int $request_id Resuest ID.
1498
+ * @return string
1499
+ */
1500
+ protected function data_export_shortcodes( $message, $request_id ) {
1501
+ $export_file_url = get_post_meta( $request_id, '_export_file_url', true );
1502
+
1503
+ $export_file_url = 'Download File: ' . $this->get_export_downloadable_url( $request_id );
1504
+
1505
+ $message = str_replace( '[data_privacy_download_url]', $export_file_url, $message );
1506
+
1507
+ $expiration = apply_filters( 'wp_privacy_export_expiration', 3 * DAY_IN_SECONDS );
1508
+ $expiration_date = date_i18n( get_option( 'date_format' ), time() + $expiration );
1509
+ $message = str_replace( '[data_privacy_download_expiry]', $expiration_date, $message );
1510
+
1511
+ return $message;
1512
+ }
1513
+ /**
1514
+ * Handles data erased shortcode.
1515
+ *
1516
+ * @param string $message String to be processed.
1517
+ * @param array $extra_data Extra data.
1518
+ * @return string
1519
+ */
1520
+ protected function data_erased_shortcodes( $message, $extra_data ) {
1521
+ $privacy_policy_url = ( ! isset( $extra_data['privacy_policy_url'] ) ) ? get_privacy_policy_url() : $extra_data['privacy_policy_url'];
1522
+
1523
+ $message = str_replace( '[privacy_policy_url]', $privacy_policy_url, $message );
1524
+ $message = str_replace( '[sitename]', $extra_data['sitename'], $message );
1525
+
1526
+ return $message;
1527
+ }
1528
+ /**
1529
+ * Process shortcodes in email.
1530
+ *
1531
+ * @param array $email Emails.
1532
+ * @param int $post_id Post ID.
1533
+ * @param array $setting Notification settings.
1534
+ * @param array $to_emails Array of to emails.
1535
+ *
1536
+ * @return string
1537
+ */
1538
+ public function process_shortcodes_in_email( $email, $post_id, $setting, $to_emails ) {
1539
+ if ( ! empty( $setting ) ) {
1540
+ if ( $this->starts_with( $setting['notification'], 'comment-' ) || $this->starts_with( $setting['notification'], 'moderate-' ) ) {
1541
+ // For new comment notifications, we need to use post id instead of comment id.
1542
+ $post_id = bnfw_get_post_id_from_comment( $post_id );
1543
+ }
1544
+ }
1545
+
1546
+ $email = $this->handle_shortcodes( $email, $setting['notification'], $post_id );
1547
+
1548
+ if ( is_array( $to_emails ) && ! empty( $to_emails ) ) {
1549
+ $to_email = $to_emails[0];
1550
+
1551
+ $email = $this->handle_global_user_shortcodes( $email, $to_email );
1552
+ }
1553
+
1554
+ $processed_emails = array();
1555
+ if ( is_email( $email ) ) {
1556
+ $processed_emails[] = $email;
1557
+ }
1558
+
1559
+ $emails = apply_filters( 'bnfw_non_wp_emails', $processed_emails, array( $email ), $post_id );
1560
+
1561
+ if ( empty( $emails ) ) {
1562
+ return '';
1563
+ }
1564
+
1565
+ return $emails[0];
1566
+ }
1567
+
1568
+ /**
1569
+ * Check email content type.
1570
+ *
1571
+ * @param string $setting Setting.
1572
+ * @param string $content Content.
1573
+ *
1574
+ * @return string Content .
1575
+ */
1576
+ public function check_email_content_type( $setting, $content ) {
1577
+
1578
+ if ( 'html' === $setting['email-formatting'] ) {
1579
+ add_filter( 'wp_mail_content_type', array( $this, 'set_html_content_type' ) );
1580
+ if ( 'true' !== $setting['disable-autop'] ) {
1581
+ $content = wpautop( $content );
1582
+ }
1583
+ } else {
1584
+ add_filter( 'wp_mail_content_type', array( $this, 'set_text_content_type' ) );
1585
+ $content = wp_strip_all_tags( $content );
1586
+ }
1587
+
1588
+ return $content;
1589
+ }
1590
+
1591
+ /**
1592
+ * Set the email formatting to HTML.
1593
+ *
1594
+ * @since 1.4
1595
+ */
1596
+ public function set_html_content_type() {
1597
+ return 'text/html';
1598
+ }
1599
+
1600
+ /**
1601
+ * Set the email formatting to text.
1602
+ *
1603
+ * @since 1.4
1604
+ */
1605
+ public function set_text_content_type() {
1606
+ return 'text/plain';
1607
+ }
1608
+
1609
+ /**
1610
+ * Get user's download URL from data export request.
1611
+ *
1612
+ * @since 1.8.4
1613
+ * @param int $request_id Request ID.
1614
+ * @return string $download_url | string error message
1615
+ */
1616
+ public function get_export_downloadable_url( $request_id = null ) {
1617
+ if ( ! $request_id ) {
1618
+ return;
1619
+ }
1620
+
1621
+ global $wpdb;
1622
+ $table = $wpdb->prefix . 'posts';
1623
+ $query = 'SELECT ID FROM ' . $table . ' WHERE `post_type` = "user_request" AND `ID` = ' . $request_id;
1624
+ $query = apply_filters( 'export_downloadable_url_query', $query, $request_id );
1625
+ $get_id = $wpdb->get_var( $query ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
1626
+ $file = get_post_meta( $get_id, '_export_file_name', true );
1627
+ $upload_url = wp_upload_dir();
1628
+ $dl_url = $upload_url['baseurl'] . '/wp-personal-data-exports/' . $file;
1629
+ $dl_url = apply_filters( 'export_downloadable_url_return', $dl_url );
1630
+
1631
+ if ( $dl_url ) {
1632
+ return $dl_url;
1633
+ } else {
1634
+ return __( 'Error: Download link is not available please contact support' );
1635
+ }
1636
+ }
1637
+
1638
+ }
1639
+ }
includes/helpers/ajax-helpers.php DELETED
@@ -1,68 +0,0 @@
1
- <?php
2
- /**
3
- * BNFW AJAX Helper functions.
4
- *
5
- * @since 1.4
6
- */
7
-
8
- /**
9
- * BNFW Search User AJAX Handler.
10
- *
11
- * @since 1.3.6
12
- */
13
- function bnfw_search_users() {
14
- check_ajax_referer( 'bnfw_users_search_ajax_nonce', 'bnfw_security' );
15
- if ( ! current_user_can( 'bnfw' ) ) {
16
- wp_die( -1 );
17
- }
18
- global $wp_roles;
19
-
20
- $roles_data = array();
21
- $user_count = count_users();
22
- $roles = $wp_roles->get_names();
23
- foreach ( $roles as $role_slug => $role_name ) {
24
- $count = 0;
25
- if ( isset( $user_count['avail_roles'][ $role_slug ] ) ) {
26
- $count = $user_count['avail_roles'][ $role_slug ];
27
- }
28
-
29
- $roles_data[] = array(
30
- 'id' => 'role-' . $role_slug,
31
- 'text' => $role_name . ' (' . $count . ' Users)',
32
- );
33
- }
34
-
35
- $data = array(
36
- array(
37
- 'id' => 1,
38
- 'text' => esc_html__( 'User Roles', 'bnfw' ),
39
- 'children' => $roles_data,
40
- ),
41
- );
42
-
43
- $query = sanitize_text_field( $_GET['query'] );
44
- $users = get_users( array(
45
- 'order_by' => 'email',
46
- 'search' => "$query*",
47
- 'number' => 100,
48
- 'fields' => array( 'ID', 'user_login' ),
49
- ) );
50
-
51
- $user_data = array();
52
- foreach ( $users as $user ) {
53
- $user_data[] = array(
54
- 'id' => $user->ID,
55
- 'text' => $user->user_login,
56
- );
57
- }
58
-
59
- $data[] = array(
60
- 'id' => 2,
61
- 'text' => esc_html__( 'Users', 'bnfw' ),
62
- 'children' => $user_data,
63
- );
64
-
65
- echo json_encode( $data );
66
- wp_die();
67
- }
68
- add_action( 'wp_ajax_bnfw_search_users', 'bnfw_search_users' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/helpers/class-bnfw-ajax.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BNFW AJAX Helper functions.
4
+ *
5
+ * @class BNFW_AJAX
6
+ * @package bnfw
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ if ( ! class_exists( 'BNFW_AJAX', false ) ) {
12
+ /**
13
+ * BNFW_AJAX class.
14
+ */
15
+ class BNFW_AJAX {
16
+ /**
17
+ * Hook in ajax handlers.
18
+ */
19
+ public static function init() {
20
+ add_action( 'wp_ajax_bnfw_search_users', array( __CLASS__, 'bnfw_search_users' ) );
21
+ }
22
+ /**
23
+ * BNFW Search User AJAX Handler.
24
+ */
25
+ public static function bnfw_search_users() {
26
+ check_ajax_referer( 'bnfw_users_search_ajax_nonce', 'bnfw_security' );
27
+ if ( ! current_user_can( 'bnfw' ) ) {
28
+ wp_die( -1 );
29
+ }
30
+ global $wp_roles;
31
+ $roles_data = array();
32
+ $user_count = count_users();
33
+ $roles = $wp_roles->get_names();
34
+ foreach ( $roles as $role_slug => $role_name ) {
35
+ $count = 0;
36
+ if ( isset( $user_count['avail_roles'][ $role_slug ] ) ) {
37
+ $count = $user_count['avail_roles'][ $role_slug ];
38
+ }
39
+ $roles_data[] = array(
40
+ 'id' => 'role-' . $role_slug,
41
+ 'text' => $role_name . ' (' . $count . ' Users)',
42
+ );
43
+ }
44
+ $data = array(
45
+ array(
46
+ 'id' => 1,
47
+ 'text' => esc_html__( 'User Roles', 'bnfw' ),
48
+ 'children' => $roles_data,
49
+ ),
50
+ );
51
+ $query = isset( $_GET['query'] ) ? sanitize_text_field( wp_unslash( $_GET['query'] ) ) : '';
52
+ $users = get_users(
53
+ array(
54
+ 'order_by' => 'email',
55
+ 'search' => "$query*",
56
+ 'number' => 100,
57
+ 'fields' => array( 'ID', 'user_login' ),
58
+ )
59
+ );
60
+ $user_data = array();
61
+ foreach ( $users as $user ) {
62
+ $user_data[] = array(
63
+ 'id' => $user->ID,
64
+ 'text' => $user->user_login,
65
+ );
66
+ }
67
+ $data[] = array(
68
+ 'id' => 2,
69
+ 'text' => esc_html__( 'Users', 'bnfw' ),
70
+ 'children' => $user_data,
71
+ );
72
+ echo wp_json_encode( $data );
73
+ wp_die();
74
+ }
75
+ }
76
+ BNFW_AJAX::init();
77
+ }
includes/helpers/helpers.php CHANGED
@@ -1,205 +1,245 @@
1
- <?php
2
- /**
3
- * General BNFW Helpers.
4
- *
5
- * @since 1.3.6
6
- */
7
-
8
- defined( 'ABSPATH' ) || exit; // Exit if accessed directly
9
-
10
- /**
11
- * Dynamically determine the class name for select2 user dropdown based on user count.
12
- *
13
- * @since 1.3.6
14
- */
15
- function bnfw_get_user_select_class() {
16
- $user_count = count_users();
17
-
18
- if ( $user_count['total_users'] > 200 ) {
19
- return 'user-ajax-select2';
20
- } else {
21
- return 'user-select2';
22
- }
23
- }
24
-
25
- /**
26
- * Render users dropdown.
27
- *
28
- * @since 1.3.6
29
- *
30
- * @param $selected_users
31
- */
32
- function bnfw_render_users_dropdown( $selected_users ) {
33
- global $wp_roles;
34
-
35
- $non_wp_users = $selected_users;
36
- $user_count = count_users();
37
- ?>
38
- <optgroup label="<?php _e( 'User Roles', 'bnfw' ); ?>">
39
- <?php
40
- $roles = $wp_roles->get_names();
41
-
42
- foreach ( $roles as $role_slug => $role_name ) {
43
- $selected = selected( true, in_array( 'role-' . $role_slug, $selected_users ), false );
44
-
45
- if ( ! empty( $selected ) ) {
46
- $non_wp_users = array_diff( $non_wp_users, array( 'role-' . $role_slug ) );
47
- }
48
-
49
- // Compatibility code, which will be eventually removed.
50
- $selected_old = selected( true, in_array( 'role-' . $role_name, $selected_users ), false );
51
- if ( ! empty( $selected_old ) ) {
52
- $selected = $selected_old;
53
- }
54
-
55
- $count = 0;
56
- if ( isset( $user_count['avail_roles'][ $role_slug ] ) ) {
57
- $count = $user_count['avail_roles'][ $role_slug ];
58
- }
59
- echo '<option value="role-', esc_attr( $role_slug ), '" ', $selected, '>', esc_html( $role_name ), ' (', $count, ' ' . __( 'Users', 'bnfw' ) . ')', '</option>';
60
- }
61
- ?>
62
- </optgroup>
63
-
64
- <optgroup label="<?php _e( 'Users', 'bnfw' ); ?>">
65
- <?php
66
- $args = array(
67
- 'order_by' => 'email',
68
- 'fields' => array( 'ID', 'user_login' ),
69
- 'number' => 200,
70
- );
71
-
72
- // if there are more than 200 users then use AJAX to load them dynamically.
73
- // So just get only the selected users.
74
- if ( $user_count['total_users'] > 200 ) {
75
- $selected_user_ids = array();
76
- foreach ( $selected_users as $selected_user ) {
77
- if ( absint( $selected_user ) > 0 ) {
78
- $selected_user_ids[] = $selected_user;
79
- }
80
- }
81
-
82
- if ( $selected_user_ids > 0 ) {
83
- $args['include'] = $selected_user_ids;
84
- }
85
- }
86
-
87
- $users = get_users( $args );
88
-
89
- foreach ( $users as $user ) {
90
- $selected = selected( true, in_array( $user->ID, $selected_users ), false );
91
-
92
- if ( ! empty( $selected ) ) {
93
- $non_wp_users = array_diff( $non_wp_users, array( $user->ID ) );
94
- }
95
-
96
- echo '<option value="', esc_attr( $user->ID ), '" ', $selected, '>', esc_html( $user->user_login ), '</option>';
97
- }
98
-
99
- ?>
100
- </optgroup>
101
-
102
- <?php if ( ! empty( $non_wp_users ) ) { ?>
103
- <optgroup label="<?php _e( 'Non WordPress Users', 'bnfw' ); ?>">
104
- <?php foreach ( $non_wp_users as $non_wp_user ) {
105
- echo '<option value="', esc_attr( $non_wp_user ), '" selected >', esc_html( $non_wp_user ), '</option>';
106
- }
107
- ?>
108
- </optgroup>
109
- <?php }
110
- }
111
-
112
- /**
113
- * Find whether the notification name is a comment notification.
114
- *
115
- * @param string $notification_name Notification Name.
116
- *
117
- * @return bool True if it is a comment notification, False otherwise.
118
- */
119
- function bnfw_is_comment_notification( $notification_name ) {
120
- $is_comment_notification = false;
121
-
122
- switch ( $notification_name ) {
123
- case 'new-comment':
124
- case 'new-trackback':
125
- case 'new-pingback':
126
- case 'reply-comment':
127
- $is_comment_notification = true;
128
- break;
129
-
130
- default:
131
- $type = explode( '-', $notification_name, 2 );
132
- if ( 'comment' == $type[0] || 'moderate' === $type[0] || 'approve' == $type[0] ) {
133
- $is_comment_notification = true;
134
- }
135
- break;
136
- }
137
-
138
- return $is_comment_notification;
139
- }
140
-
141
- /**
142
- * Format user capabilities.
143
- *
144
- * @param array $wp_capabilities User capabilities.
145
- *
146
- * @return string Formatted capabilities.
147
- */
148
- function bnfw_format_user_capabilities( $wp_capabilities ) {
149
- $capabilities = array();
150
-
151
- if ( is_array( $wp_capabilities ) ) {
152
- foreach ( $wp_capabilities as $capability => $enabled ) {
153
- if ( $enabled ) {
154
- $capabilities[] = $capability;
155
- }
156
- }
157
- }
158
-
159
- return implode( ', ', $capabilities );
160
- }
161
-
162
- /**
163
- * Has the user opted-in for tracking?
164
- *
165
- * @return bool True if tracking is allowed, False otherwise.
166
- */
167
- function bnfw_is_tracking_allowed() {
168
- $tracking_allowed = false;
169
-
170
- if ( get_option( 'bnfw_allow_tracking' ) == 'on' ) {
171
- $tracking_allowed = true;
172
- }
173
-
174
- return $tracking_allowed;
175
- }
176
-
177
- /**
178
- * Get post id from comment id.
179
- *
180
- * @param int $comment_id Comment ID for which we need Post ID.
181
- * @return int Post ID. 0 if invalid comment id.
182
- */
183
- function bnfw_get_post_id_from_comment( $comment_id ) {
184
- $comment = get_comment( $comment_id );
185
-
186
- if ( null !== $comment ) {
187
- return $comment->comment_post_ID;
188
- }
189
-
190
- return 0;
191
- }
192
-
193
- /**
194
- * Format date based on date format stored in options.
195
- *
196
- * @param string $date Date.
197
- *
198
- * @return string Formatted date.
199
- */
200
- function bnfw_format_date( $date ) {
201
- $date_format = get_option( 'date_format' );
202
- $time_format = get_option( 'time_format' );
203
-
204
- return date( $date_format . ' ' . $time_format, strtotime( $date ) );
205
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * General BNFW Helpers.
4
+ *
5
+ * @since 1.3.6
6
+ * @package bnfw
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
10
+
11
+ if ( ! function_exists( 'bnfw_get_user_select_class' ) ) {
12
+ /**
13
+ * Dynamically determine the class name for select2 user dropdown based on user count.
14
+ *
15
+ * @since 1.3.6
16
+ */
17
+ function bnfw_get_user_select_class() {
18
+ $user_count = count_users();
19
+
20
+ if ( $user_count['total_users'] > 200 ) {
21
+ return 'user-ajax-select2';
22
+ } else {
23
+ return 'user-select2';
24
+ }
25
+ }
26
+ }
27
+
28
+ if ( ! function_exists( 'bnfw_expanded_alowed_tags' ) ) {
29
+ /**
30
+ * Get allowed html for wp_kses.
31
+ *
32
+ * @return array
33
+ */
34
+ function bnfw_expanded_alowed_tags() {
35
+ $allowed_html['select'] = array(
36
+ 'class' => array(),
37
+ 'id' => array(),
38
+ 'name' => array(),
39
+ 'value' => array(),
40
+ 'type' => array(),
41
+ );
42
+ // select options.
43
+ $allowed_html['option'] = array(
44
+ 'selected' => array(),
45
+ );
46
+ return $allowed_html;
47
+ }
48
+ }
49
+
50
+ if ( ! function_exists( 'bnfw_render_users_dropdown' ) ) {
51
+ /**
52
+ * Render users dropdown.
53
+ *
54
+ * @since 1.3.6
55
+ *
56
+ * @param array $selected_users Selected users.
57
+ */
58
+ function bnfw_render_users_dropdown( $selected_users ) {
59
+ global $wp_roles;
60
+ $allowed_html = bnfw_expanded_alowed_tags();
61
+
62
+ $non_wp_users = $selected_users;
63
+ $user_count = count_users();
64
+ ?>
65
+ <optgroup label="<?php esc_attr_e( 'User Roles', 'bnfw' ); ?>">
66
+ <?php
67
+ $roles = $wp_roles->get_names();
68
+
69
+ foreach ( $roles as $role_slug => $role_name ) {
70
+ $selected = selected( true, in_array( 'role-' . $role_slug, $selected_users, true ), false );
71
+
72
+ if ( ! empty( $selected ) ) {
73
+ $non_wp_users = array_diff( $non_wp_users, array( 'role-' . $role_slug ) );
74
+ }
75
+
76
+ // Compatibility code, which will be eventually removed.
77
+ $selected_old = selected( true, in_array( 'role-' . $role_name, $selected_users, true ), false );
78
+ if ( ! empty( $selected_old ) ) {
79
+ $selected = $selected_old;
80
+ }
81
+
82
+ $count = 0;
83
+ if ( isset( $user_count['avail_roles'][ $role_slug ] ) ) {
84
+ $count = $user_count['avail_roles'][ $role_slug ];
85
+ }
86
+ echo wp_kses( '<option value="role-', esc_attr( $role_slug ), '" ', $selected, '>', esc_html( $role_name ), ' (', $count, ' ' . __( 'Users', 'bnfw' ) . ')', '</option>', $allowed_html );
87
+ }
88
+ ?>
89
+ </optgroup>
90
+
91
+ <optgroup label="<?php esc_attr_e( 'Users', 'bnfw' ); ?>">
92
+ <?php
93
+ $args = array(
94
+ 'order_by' => 'email',
95
+ 'fields' => array( 'ID', 'user_login' ),
96
+ 'number' => 200,
97
+ );
98
+
99
+ // if there are more than 200 users then use AJAX to load them dynamically.
100
+ // So just get only the selected users.
101
+ if ( $user_count['total_users'] > 200 ) {
102
+ $selected_user_ids = array();
103
+ foreach ( $selected_users as $selected_user ) {
104
+ if ( absint( $selected_user ) > 0 ) {
105
+ $selected_user_ids[] = $selected_user;
106
+ }
107
+ }
108
+
109
+ if ( $selected_user_ids > 0 ) {
110
+ $args['include'] = $selected_user_ids;
111
+ }
112
+ }
113
+
114
+ $users = get_users( $args );
115
+
116
+ foreach ( $users as $user ) {
117
+ $selected = selected( true, in_array( $user->ID, $selected_users, true ), false );
118
+
119
+ if ( ! empty( $selected ) ) {
120
+ $non_wp_users = array_diff( $non_wp_users, array( $user->ID ) );
121
+ }
122
+
123
+ echo wp_kses( '<option value="', esc_attr( $user->ID ), '" ', $selected, '>', esc_html( $user->user_login ), '</option>', $allowed_html );
124
+ }
125
+
126
+ ?>
127
+ </optgroup>
128
+
129
+ <?php if ( ! empty( $non_wp_users ) ) { ?>
130
+ <optgroup label="<?php esc_attr_e( 'Non WordPress Users', 'bnfw' ); ?>">
131
+ <?php
132
+ foreach ( $non_wp_users as $non_wp_user ) {
133
+ echo '<option value="', esc_attr( $non_wp_user ), '" selected >', esc_html( $non_wp_user ), '</option>';
134
+ }
135
+ ?>
136
+ </optgroup>
137
+ <?php
138
+ }
139
+ }
140
+ }
141
+
142
+ if ( ! function_exists( 'bnfw_is_comment_notification' ) ) {
143
+ /**
144
+ * Find whether the notification name is a comment notification.
145
+ *
146
+ * @param string $notification_name Notification Name.
147
+ *
148
+ * @return bool True if it is a comment notification, False otherwise.
149
+ */
150
+ function bnfw_is_comment_notification( $notification_name ) {
151
+ $is_comment_notification = false;
152
+
153
+ switch ( $notification_name ) {
154
+ case 'new-comment':
155
+ case 'new-trackback':
156
+ case 'new-pingback':
157
+ case 'reply-comment':
158
+ $is_comment_notification = true;
159
+ break;
160
+
161
+ default:
162
+ $type = explode( '-', $notification_name, 2 );
163
+ if ( 'comment' === $type[0] || 'moderate' === $type[0] || 'approve' === $type[0] ) {
164
+ $is_comment_notification = true;
165
+ }
166
+ break;
167
+ }
168
+
169
+ return $is_comment_notification;
170
+ }
171
+ }
172
+
173
+ if ( ! function_exists( 'bnfw_format_user_capabilities' ) ) {
174
+ /**
175
+ * Format user capabilities.
176
+ *
177
+ * @param array $wp_capabilities User capabilities.
178
+ *
179
+ * @return string Formatted capabilities.
180
+ */
181
+ function bnfw_format_user_capabilities( $wp_capabilities ) {
182
+ $capabilities = array();
183
+
184
+ if ( is_array( $wp_capabilities ) ) {
185
+ foreach ( $wp_capabilities as $capability => $enabled ) {
186
+ if ( $enabled ) {
187
+ $capabilities[] = $capability;
188
+ }
189
+ }
190
+ }
191
+
192
+ return implode( ', ', $capabilities );
193
+ }
194
+ }
195
+
196
+ if ( ! function_exists( 'bnfw_is_tracking_allowed' ) ) {
197
+ /**
198
+ * Has the user opted-in for tracking?
199
+ *
200
+ * @return bool True if tracking is allowed, False otherwise.
201
+ */
202
+ function bnfw_is_tracking_allowed() {
203
+ $tracking_allowed = false;
204
+
205
+ if ( get_option( 'bnfw_allow_tracking' ) === 'on' ) {
206
+ $tracking_allowed = true;
207
+ }
208
+
209
+ return $tracking_allowed;
210
+ }
211
+ }
212
+
213
+ if ( ! function_exists( 'bnfw_get_post_id_from_comment' ) ) {
214
+ /**
215
+ * Get post id from comment id.
216
+ *
217
+ * @param int $comment_id Comment ID for which we need Post ID.
218
+ * @return int Post ID. 0 if invalid comment id.
219
+ */
220
+ function bnfw_get_post_id_from_comment( $comment_id ) {
221
+ $comment = get_comment( $comment_id );
222
+
223
+ if ( null !== $comment ) {
224
+ return $comment->comment_post_ID;
225
+ }
226
+
227
+ return 0;
228
+ }
229
+ }
230
+
231
+ if ( ! function_exists( 'bnfw_format_date' ) ) {
232
+ /**
233
+ * Format date based on date format stored in options.
234
+ *
235
+ * @param string $date Date.
236
+ *
237
+ * @return string Formatted date.
238
+ */
239
+ function bnfw_format_date( $date ) {
240
+ $date_format = get_option( 'date_format' );
241
+ $time_format = get_option( 'time_format' );
242
+
243
+ return date( $date_format . ' ' . $time_format, strtotime( $date ) );
244
+ }
245
+ }
includes/import.php DELETED
@@ -1,169 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Import notification from old plugin.
5
- *
6
- * @since 1.0
7
- */
8
- class BNFW_Import {
9
- const EMAIL_OPTION = 'bnfw_custom_email_settings';
10
- const SETTING_OPTION = 'bnfw_settings';
11
- private $events = array(
12
- 'create_term',
13
- 'publish_post',
14
- 'comment_post',
15
- 'user_register',
16
- 'trackback_post',
17
- 'pingback_post',
18
- 'lostpassword_post',
19
- );
20
-
21
- /**
22
- * Import notification from old plugin.
23
- *
24
- * @since 1.0
25
- */
26
- public function import() {
27
- global $wp_roles;
28
- $roles = $wp_roles->get_names();
29
-
30
- if ( $this->import_needed() ) {
31
- $old_events = get_option( self::SETTING_OPTION );
32
- foreach ( $old_events as $event => $value ) {
33
- if ( '1' == $value ) {
34
- $event_array = explode( '-', $event );
35
- if ( 2 == count( $event_array ) ) {
36
- if ( in_array( $event_array[0], $this->events ) && in_array( $event_array[1], array_keys( $roles ) ) ) {
37
- $event_array[1] = $roles[ $event_array[1] ];
38
- $this->insert_notification( $event_array );
39
- }
40
- }
41
- }
42
- }
43
- // delete the old options
44
- $this->delete_option();
45
- }
46
- }
47
-
48
- /**
49
- * Check if import is needed.
50
- *
51
- * @since 1.0
52
- * @return unknown
53
- */
54
- private function import_needed() {
55
- if ( get_option( self::EMAIL_OPTION ) && get_option( self::SETTING_OPTION ) ) {
56
- return true;
57
- }
58
-
59
- return false;
60
- }
61
-
62
- /**
63
- * Insert notification.
64
- *
65
- * @param mixed $event
66
- */
67
- private function insert_notification( $event ) {
68
- $post = array(
69
- 'post_title' => $event[0] . esc_html__( ' for ', 'bnfw' ) . $event[1] . esc_html__( ' (Auto Imported)', 'bnfw' ),
70
- 'post_type' => BNFW_Notification::POST_TYPE,
71
- 'post_content' => '',
72
- 'post_status' => 'publish',
73
- );
74
-
75
- $post_id = wp_insert_post( $post );
76
- if ( $post_id > 0 ) {
77
- $content = $this->map_notification_content( $event[0] );
78
- $setting = array(
79
- 'notification' => $this->map_notification( $event[0] ),
80
- 'user-roles' => array( $event[1] ),
81
- 'users' => array(),
82
- 'subject' => $content['subject'],
83
- 'message' => $content['body'],
84
- );
85
-
86
- foreach ( $setting as $key => $value ) {
87
- update_post_meta( $post_id, BNFW_Notification::META_KEY_PREFIX . $key, $value );
88
- }
89
- }
90
- }
91
-
92
- /**
93
- * Map old notification type to new notification type.
94
- *
95
- * @param mixed $event_name
96
- *
97
- * @return unknown
98
- */
99
- private function map_notification( $event_name ) {
100
- switch ( $event_name ) {
101
- case 'create_term':
102
- return 'new-category';
103
- break;
104
- case 'publish_post':
105
- return 'new-post';
106
- break;
107
- case 'comment_post':
108
- return 'new-comment';
109
- break;
110
- case 'user_register':
111
- return 'new-user';
112
- break;
113
- case 'trackback_post':
114
- return 'new-trackback';
115
- break;
116
- case 'pingback_post':
117
- return 'new-pingback';
118
- break;
119
- case 'lostpassword_post':
120
- return 'user-password';
121
- break;
122
- }
123
- }
124
-
125
- /**
126
- * Map content from old plugin.
127
- *
128
- * @param unknown $event_name
129
- *
130
- * @return unknown
131
- */
132
- private function map_notification_content( $event_name ) {
133
- $content = array();
134
- if ( ! isset( $this->content_map ) ) {
135
- $this->parse_content();
136
- }
137
-
138
- return $this->content_map[ $event_name ];
139
- }
140
-
141
- /**
142
- * Parse content from old plugins setting.
143
- *
144
- * @since 1.0
145
- */
146
- private function parse_content() {
147
- $old_content = get_option( self::EMAIL_OPTION );
148
- $content_map = array();
149
- foreach ( $old_content as $key => $value ) {
150
- $key_array = explode( '-', $key );
151
- if ( 3 == count( $key_array ) ) {
152
- $content_map[ $key_array[2] ][ $key_array[1] ] = $value;
153
- }
154
- }
155
- $this->content_map = $content_map;
156
- }
157
-
158
- /**
159
- * Delete old plugin database options.
160
- *
161
- * @since 1.0
162
- */
163
- private function delete_option() {
164
- delete_option( self::EMAIL_OPTION );
165
- delete_option( self::SETTING_OPTION );
166
- }
167
- }
168
-
169
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/libraries/EDD_SL_Plugin_Updater.php DELETED
@@ -1,619 +0,0 @@
1
- <?php
2
-
3
- // Exit if accessed directly
4
- if ( ! defined( 'ABSPATH' ) ) exit;
5
-
6
- /**
7
- * Allows plugins to use their own update API.
8
- *
9
- * @author Easy Digital Downloads
10
- * @version 1.8.0
11
- */
12
- class EDD_SL_Plugin_Updater {
13
-
14
- private $api_url = '';
15
- private $api_data = array();
16
- private $name = '';
17
- private $slug = '';
18
- private $version = '';
19
- private $wp_override = false;
20
- private $cache_key = '';
21
- private $beta = false;
22
- private $health_check_timeout = 5;
23
-
24
- /**
25
- * Class constructor.
26
- *
27
- * @uses plugin_basename()
28
- * @uses hook()
29
- *
30
- * @param string $_api_url The URL pointing to the custom API endpoint.
31
- * @param string $_plugin_file Path to the plugin file.
32
- * @param array $_api_data Optional data to send with API calls.
33
- */
34
- public function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
35
-
36
- global $edd_plugin_data;
37
-
38
- $this->api_url = trailingslashit( $_api_url );
39
- $this->api_data = $_api_data;
40
- $this->name = plugin_basename( $_plugin_file );
41
- $this->slug = basename( $_plugin_file, '.php' );
42
- $this->version = $_api_data['version'];
43
- $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
44
- $this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
45
- $this->cache_key = 'edd_sl_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) );
46
-
47
- $edd_plugin_data[ $this->slug ] = $this->api_data;
48
-
49
- /**
50
- * Fires after the $edd_plugin_data is setup.
51
- *
52
- * @since x.x.x
53
- *
54
- * @param array $edd_plugin_data Array of EDD SL plugin data.
55
- */
56
- do_action( 'post_edd_sl_plugin_updater_setup', $edd_plugin_data );
57
-
58
- // Set up hooks.
59
- $this->init();
60
-
61
- }
62
-
63
- /**
64
- * Set up WordPress filters to hook into WP's update process.
65
- *
66
- * @uses add_filter()
67
- *
68
- * @return void
69
- */
70
- public function init() {
71
-
72
- add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
73
- add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
74
- remove_action( 'after_plugin_row_' . $this->name, 'wp_plugin_update_row', 10 );
75
- add_action( 'after_plugin_row_' . $this->name, array( $this, 'show_update_notification' ), 10, 2 );
76
- add_action( 'admin_init', array( $this, 'show_changelog' ) );
77
-
78
- }
79
-
80
- /**
81
- * Check for Updates at the defined API endpoint and modify the update array.
82
- *
83
- * This function dives into the update API just when WordPress creates its update array,
84
- * then adds a custom API call and injects the custom plugin data retrieved from the API.
85
- * It is reassembled from parts of the native WordPress plugin update code.
86
- * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
87
- *
88
- * @uses api_request()
89
- *
90
- * @param array $_transient_data Update array build by WordPress.
91
- * @return array Modified update array with custom plugin data.
92
- */
93
- public function check_update( $_transient_data ) {
94
-
95
- global $pagenow;
96
-
97
- if ( ! is_object( $_transient_data ) ) {
98
- $_transient_data = new stdClass;
99
- }
100
-
101
- if ( 'plugins.php' == $pagenow && is_multisite() ) {
102
- return $_transient_data;
103
- }
104
-
105
- if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
106
- return $_transient_data;
107
- }
108
-
109
- $current = $this->get_repo_api_data();
110
- if ( false !== $current && is_object( $current ) && isset( $current->new_version ) ) {
111
- if ( version_compare( $this->version, $current->new_version, '<' ) ) {
112
- $_transient_data->response[ $this->name ] = $current;
113
- } else {
114
- // Populating the no_update information is required to support auto-updates in WordPress 5.5.
115
- $_transient_data->no_update[ $this->name ] = $current;
116
- }
117
- }
118
- $_transient_data->last_checked = time();
119
- $_transient_data->checked[ $this->name ] = $this->version;
120
-
121
- return $_transient_data;
122
- }
123
-
124
- /**
125
- * Get repo API data from store.
126
- * Save to cache.
127
- *
128
- * @return \stdClass
129
- */
130
- public function get_repo_api_data() {
131
- $version_info = $this->get_cached_version_info();
132
-
133
- if ( false === $version_info ) {
134
- $version_info = $this->api_request(
135
- 'plugin_latest_version',
136
- array(
137
- 'slug' => $this->slug,
138
- 'beta' => $this->beta,
139
- )
140
- );
141
- if ( ! $version_info ) {
142
- return false;
143
- }
144
-
145
- // This is required for your plugin to support auto-updates in WordPress 5.5.
146
- $version_info->plugin = $this->name;
147
- $version_info->id = $this->name;
148
-
149
- $this->set_version_info_cache( $version_info );
150
- }
151
-
152
- return $version_info;
153
- }
154
-
155
- /**
156
- * show update nofication row -- needed for multisite subsites, because WP won't tell you otherwise!
157
- *
158
- * @param string $file
159
- * @param array $plugin
160
- */
161
- public function show_update_notification( $file, $plugin ) {
162
-
163
- if ( is_network_admin() ) {
164
- return;
165
- }
166
-
167
- if( ! current_user_can( 'update_plugins' ) ) {
168
- return;
169
- }
170
-
171
- if( ! is_multisite() ) {
172
- return;
173
- }
174
-
175
- if ( $this->name != $file ) {
176
- return;
177
- }
178
-
179
- // Remove our filter on the site transient
180
- remove_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ), 10 );
181
-
182
- $update_cache = get_site_transient( 'update_plugins' );
183
-
184
- $update_cache = is_object( $update_cache ) ? $update_cache : new stdClass();
185
-
186
- if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->name ] ) ) {
187
-
188
- $version_info = $this->get_repo_api_data();
189
-
190
- if ( false === $version_info ) {
191
- $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) );
192
-
193
- // Since we disabled our filter for the transient, we aren't running our object conversion on banners, sections, or icons. Do this now:
194
- if ( isset( $version_info->banners ) && ! is_array( $version_info->banners ) ) {
195
- $version_info->banners = $this->convert_object_to_array( $version_info->banners );
196
- }
197
-
198
- if ( isset( $version_info->sections ) && ! is_array( $version_info->sections ) ) {
199
- $version_info->sections = $this->convert_object_to_array( $version_info->sections );
200
- }
201
-
202
- if ( isset( $version_info->icons ) && ! is_array( $version_info->icons ) ) {
203
- $version_info->icons = $this->convert_object_to_array( $version_info->icons );
204
- }
205
-
206
- if ( isset( $version_info->contributors ) && ! is_array( $version_info->contributors ) ) {
207
- $version_info->contributors = $this->convert_object_to_array( $version_info->contributors );
208
- }
209
-
210
- $this->set_version_info_cache( $version_info );
211
- }
212
-
213
- if ( ! is_object( $version_info ) ) {
214
- return;
215
- }
216
-
217
- if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
218
- $update_cache->response[ $this->name ] = $version_info;
219
- } else {
220
- $update_cache->no_update[ $this->name ] = $version_info;
221
- }
222
-
223
- $update_cache->last_checked = time();
224
- $update_cache->checked[ $this->name ] = $this->version;
225
-
226
- set_site_transient( 'update_plugins', $update_cache );
227
-
228
- } else {
229
-
230
- $version_info = $update_cache->response[ $this->name ];
231
-
232
- }
233
-
234
- // Restore our filter
235
- add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
236
-
237
- if ( ! empty( $update_cache->response[ $this->name ] ) && version_compare( $this->version, $version_info->new_version, '<' ) ) {
238
-
239
- // build a plugin list row, with update notification
240
- $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
241
- # <tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange">
242
- echo '<tr class="plugin-update-tr" id="' . $this->slug . '-update" data-slug="' . $this->slug . '" data-plugin="' . $this->slug . '/' . $file . '">';
243
- echo '<td colspan="3" class="plugin-update colspanchange">';
244
- echo '<div class="update-message notice inline notice-warning notice-alt">';
245
-
246
- $changelog_link = self_admin_url( 'index.php?edd_sl_action=view_plugin_changelog&plugin=' . $this->name . '&slug=' . $this->slug . '&TB_iframe=true&width=772&height=911' );
247
-
248
- if ( empty( $version_info->download_link ) ) {
249
- printf(
250
- __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s.', 'easy-digital-downloads' ),
251
- esc_html( $version_info->name ),
252
- '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
253
- esc_html( $version_info->new_version ),
254
- '</a>'
255
- );
256
- } else {
257
- printf(
258
- __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s or %5$supdate now%6$s.', 'easy-digital-downloads' ),
259
- esc_html( $version_info->name ),
260
- '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
261
- esc_html( $version_info->new_version ),
262
- '</a>',
263
- '<a href="' . esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $this->name, 'upgrade-plugin_' . $this->name ) ) .'">',
264
- '</a>'
265
- );
266
- }
267
-
268
- do_action( "in_plugin_update_message-{$file}", $plugin, $version_info );
269
-
270
- echo '</div></td></tr>';
271
- }
272
- }
273
-
274
- /**
275
- * Updates information on the "View version x.x details" page with custom data.
276
- *
277
- * @uses api_request()
278
- *
279
- * @param mixed $_data
280
- * @param string $_action
281
- * @param object $_args
282
- * @return object $_data
283
- */
284
- public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
285
-
286
- if ( $_action != 'plugin_information' ) {
287
-
288
- return $_data;
289
-
290
- }
291
-
292
- if ( ! isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) {
293
-
294
- return $_data;
295
-
296
- }
297
-
298
- $to_send = array(
299
- 'slug' => $this->slug,
300
- 'is_ssl' => is_ssl(),
301
- 'fields' => array(
302
- 'banners' => array(),
303
- 'reviews' => false,
304
- 'icons' => array(),
305
- )
306
- );
307
-
308
- // Get the transient where we store the api request for this plugin for 24 hours
309
- $edd_api_request_transient = $this->get_cached_version_info();
310
-
311
- //If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now.
312
- if ( empty( $edd_api_request_transient ) ) {
313
-
314
- $api_response = $this->api_request( 'plugin_information', $to_send );
315
-
316
- // Expires in 3 hours
317
- $this->set_version_info_cache( $api_response );
318
-
319
- if ( false !== $api_response ) {
320
- $_data = $api_response;
321
- }
322
-
323
- } else {
324
- $_data = $edd_api_request_transient;
325
- }
326
-
327
- // Convert sections into an associative array, since we're getting an object, but Core expects an array.
328
- if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) {
329
- $_data->sections = $this->convert_object_to_array( $_data->sections );
330
- }
331
-
332
- // Convert banners into an associative array, since we're getting an object, but Core expects an array.
333
- if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) {
334
- $_data->banners = $this->convert_object_to_array( $_data->banners );
335
- }
336
-
337
- // Convert icons into an associative array, since we're getting an object, but Core expects an array.
338
- if ( isset( $_data->icons ) && ! is_array( $_data->icons ) ) {
339
- $_data->icons = $this->convert_object_to_array( $_data->icons );
340
- }
341
-
342
- // Convert contributors into an associative array, since we're getting an object, but Core expects an array.
343
- if ( isset( $_data->contributors ) && ! is_array( $_data->contributors ) ) {
344
- $_data->contributors = $this->convert_object_to_array( $_data->contributors );
345
- }
346
-
347
- if( ! isset( $_data->plugin ) ) {
348
- $_data->plugin = $this->name;
349
- }
350
-
351
- return $_data;
352
- }
353
-
354
- /**
355
- * Convert some objects to arrays when injecting data into the update API
356
- *
357
- * Some data like sections, banners, and icons are expected to be an associative array, however due to the JSON
358
- * decoding, they are objects. This method allows us to pass in the object and return an associative array.
359
- *
360
- * @since 3.6.5
361
- *
362
- * @param stdClass $data
363
- *
364
- * @return array
365
- */
366
- private function convert_object_to_array( $data ) {
367
- if ( ! is_array( $data ) && ! is_object( $data ) ) {
368
- return array();
369
- }
370
- $new_data = array();
371
- foreach ( $data as $key => $value ) {
372
- $new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value;
373
- }
374
-
375
- return $new_data;
376
- }
377
-
378
- /**
379
- * Disable SSL verification in order to prevent download update failures
380
- *
381
- * @param array $args
382
- * @param string $url
383
- * @return object $array
384
- */
385
- public function http_request_args( $args, $url ) {
386
-
387
- $verify_ssl = $this->verify_ssl();
388
- if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
389
- $args['sslverify'] = $verify_ssl;
390
- }
391
- return $args;
392
-
393
- }
394
-
395
- /**
396
- * Calls the API and, if successfull, returns the object delivered by the API.
397
- *
398
- * @uses get_bloginfo()
399
- * @uses wp_remote_post()
400
- * @uses is_wp_error()
401
- *
402
- * @param string $_action The requested action.
403
- * @param array $_data Parameters for the API action.
404
- * @return false|object
405
- */
406
- private function api_request( $_action, $_data ) {
407
-
408
- global $wp_version, $edd_plugin_url_available;
409
-
410
- $verify_ssl = $this->verify_ssl();
411
-
412
- // Do a quick status check on this domain if we haven't already checked it.
413
- $store_hash = md5( $this->api_url );
414
- if ( ! is_array( $edd_plugin_url_available ) || ! isset( $edd_plugin_url_available[ $store_hash ] ) ) {
415
- $test_url_parts = parse_url( $this->api_url );
416
-
417
- $scheme = ! empty( $test_url_parts['scheme'] ) ? $test_url_parts['scheme'] : 'http';
418
- $host = ! empty( $test_url_parts['host'] ) ? $test_url_parts['host'] : '';
419
- $port = ! empty( $test_url_parts['port'] ) ? ':' . $test_url_parts['port'] : '';
420
-
421
- if ( empty( $host ) ) {
422
- $edd_plugin_url_available[ $store_hash ] = false;
423
- } else {
424
- $test_url = $scheme . '://' . $host . $port;
425
- $response = wp_remote_get( $test_url, array( 'timeout' => $this->health_check_timeout, 'sslverify' => $verify_ssl ) );
426
- $edd_plugin_url_available[ $store_hash ] = is_wp_error( $response ) ? false : true;
427
- }
428
- }
429
-
430
- if ( false === $edd_plugin_url_available[ $store_hash ] ) {
431
- return false;
432
- }
433
-
434
- $data = array_merge( $this->api_data, $_data );
435
-
436
- if ( $data['slug'] != $this->slug ) {
437
- return false;
438
- }
439
-
440
- if ( $this->api_url == trailingslashit ( home_url() ) ) {
441
- return false; // Don't allow a plugin to ping itself
442
- }
443
-
444
- $api_params = array(
445
- 'edd_action' => 'get_version',
446
- 'license' => ! empty( $data['license'] ) ? $data['license'] : '',
447
- 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
448
- 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
449
- 'version' => isset( $data['version'] ) ? $data['version'] : false,
450
- 'slug' => $data['slug'],
451
- 'author' => $data['author'],
452
- 'url' => home_url(),
453
- 'beta' => ! empty( $data['beta'] ),
454
- );
455
-
456
- $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) );
457
-
458
- if ( ! is_wp_error( $request ) ) {
459
- $request = json_decode( wp_remote_retrieve_body( $request ) );
460
- }
461
-
462
- if ( $request && isset( $request->sections ) ) {
463
- $request->sections = maybe_unserialize( $request->sections );
464
- } else {
465
- $request = false;
466
- }
467
-
468
- if ( $request && isset( $request->banners ) ) {
469
- $request->banners = maybe_unserialize( $request->banners );
470
- }
471
-
472
- if ( $request && isset( $request->icons ) ) {
473
- $request->icons = maybe_unserialize( $request->icons );
474
- }
475
-
476
- if ( ! empty( $request->sections ) ) {
477
- foreach( $request->sections as $key => $section ) {
478
- $request->$key = (array) $section;
479
- }
480
- }
481
-
482
- return $request;
483
- }
484
-
485
- /**
486
- * If available, show the changelog for sites in a multisite install.
487
- */
488
- public function show_changelog() {
489
-
490
- global $edd_plugin_data;
491
-
492
- if( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' != $_REQUEST['edd_sl_action'] ) {
493
- return;
494
- }
495
-
496
- if( empty( $_REQUEST['plugin'] ) ) {
497
- return;
498
- }
499
-
500
- if( empty( $_REQUEST['slug'] ) ) {
501
- return;
502
- }
503
-
504
- if( ! current_user_can( 'update_plugins' ) ) {
505
- wp_die( __( 'You do not have permission to install plugin updates', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
506
- }
507
-
508
- $data = $edd_plugin_data[ $_REQUEST['slug'] ];
509
- $version_info = $this->get_cached_version_info();
510
-
511
- if( false === $version_info ) {
512
-
513
- $api_params = array(
514
- 'edd_action' => 'get_version',
515
- 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
516
- 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
517
- 'slug' => $_REQUEST['slug'],
518
- 'author' => $data['author'],
519
- 'url' => home_url(),
520
- 'beta' => ! empty( $data['beta'] )
521
- );
522
-
523
- $verify_ssl = $this->verify_ssl();
524
- $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) );
525
-
526
- if ( ! is_wp_error( $request ) ) {
527
- $version_info = json_decode( wp_remote_retrieve_body( $request ) );
528
- }
529
-
530
- if ( ! empty( $version_info ) && isset( $version_info->sections ) ) {
531
- $version_info->sections = maybe_unserialize( $version_info->sections );
532
- } else {
533
- $version_info = false;
534
- }
535
-
536
- if( ! empty( $version_info ) ) {
537
- foreach( $version_info->sections as $key => $section ) {
538
- $version_info->$key = (array) $section;
539
- }
540
- }
541
-
542
- $this->set_version_info_cache( $version_info );
543
-
544
- // Delete the unneeded option
545
- delete_option( md5( 'edd_plugin_' . sanitize_key( $_REQUEST['plugin'] ) . '_' . $this->beta . '_version_info' ) );
546
- }
547
-
548
- if ( isset( $version_info->sections ) ) {
549
- $sections = $this->convert_object_to_array( $version_info->sections );
550
- if ( ! empty( $sections['changelog'] ) ) {
551
- echo '<div style="background:#fff;padding:10px;">' . wp_kses_post( $sections['changelog'] ) . '</div>';
552
- }
553
- }
554
-
555
- exit;
556
- }
557
-
558
- /**
559
- * Gets the plugin's cached version information from the database.
560
- *
561
- * @param string $cache_key
562
- * @return boolean|string
563
- */
564
- public function get_cached_version_info( $cache_key = '' ) {
565
-
566
- if( empty( $cache_key ) ) {
567
- $cache_key = $this->cache_key;
568
- }
569
-
570
- $cache = get_option( $cache_key );
571
-
572
- if( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
573
- return false; // Cache is expired
574
- }
575
-
576
- // We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
577
- $cache['value'] = json_decode( $cache['value'] );
578
- if ( ! empty( $cache['value']->icons ) ) {
579
- $cache['value']->icons = (array) $cache['value']->icons;
580
- }
581
-
582
- return $cache['value'];
583
-
584
- }
585
-
586
- /**
587
- * Adds the plugin version information to the database.
588
- *
589
- * @param string $value
590
- * @param string $cache_key
591
- */
592
- public function set_version_info_cache( $value = '', $cache_key = '' ) {
593
-
594
- if( empty( $cache_key ) ) {
595
- $cache_key = $this->cache_key;
596
- }
597
-
598
- $data = array(
599
- 'timeout' => strtotime( '+3 hours', time() ),
600
- 'value' => json_encode( $value )
601
- );
602
-
603
- update_option( $cache_key, $data, 'no' );
604
-
605
- // Delete the duplicate option
606
- delete_option( 'edd_api_request_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) ) );
607
- }
608
-
609
- /**
610
- * Returns if the SSL of the store should be verified.
611
- *
612
- * @since 1.6.13
613
- * @return bool
614
- */
615
- private function verify_ssl() {
616
- return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
617
- }
618
-
619
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/libraries/class-edd-sl-plugin-updater.php ADDED
@@ -0,0 +1,695 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Hanldles plugin updater.
4
+ *
5
+ * @package bnfw
6
+ */
7
+
8
+ defined( 'ABSPATH' ) || exit;
9
+
10
+ if ( ! class_exists( 'EDD_SL_Plugin_Updater', false ) ) {
11
+ /**
12
+ * Allows plugins to use their own update API.
13
+ *
14
+ * @author Easy Digital Downloads
15
+ * @version 1.8.0
16
+ */
17
+ class EDD_SL_Plugin_Updater {
18
+ /**
19
+ * Holds the custom API endpoint
20
+ *
21
+ * @var string
22
+ */
23
+ private $api_url = '';
24
+ /**
25
+ * Holds the custom API data.
26
+ *
27
+ * @var string
28
+ */
29
+ private $api_data = array();
30
+ /**
31
+ * Holds the basename
32
+ *
33
+ * @var string
34
+ */
35
+ private $name = '';
36
+ /**
37
+ * Holds the API version
38
+ *
39
+ * @var string
40
+ */
41
+ private $slug = '';
42
+ /**
43
+ * Holds the plugin basename
44
+ *
45
+ * @var string
46
+ */
47
+ private $version = '';
48
+ /**
49
+ * WP override
50
+ *
51
+ * @var bool
52
+ */
53
+ private $wp_override = false;
54
+ /**
55
+ * Holds the cache key
56
+ *
57
+ * @var string
58
+ */
59
+ private $cache_key = '';
60
+ /**
61
+ * Holds ahether its bet or not.
62
+ *
63
+ * @var bool
64
+ */
65
+ private $beta = false;
66
+ /**
67
+ * Holds the wp_remote_get timeout.
68
+ *
69
+ * @var bool
70
+ */
71
+ private $health_check_timeout = 5;
72
+
73
+ /**
74
+ * Class constructor.
75
+ *
76
+ * @uses plugin_basename()
77
+ * @uses hook()
78
+ *
79
+ * @param string $_api_url The URL pointing to the custom API endpoint.
80
+ * @param string $_plugin_file Path to the plugin file.
81
+ * @param array $_api_data Optional data to send with API calls.
82
+ */
83
+ public function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
84
+
85
+ global $edd_plugin_data;
86
+
87
+ $this->api_url = trailingslashit( $_api_url );
88
+ $this->api_data = $_api_data;
89
+ $this->name = plugin_basename( $_plugin_file );
90
+ $this->slug = basename( $_plugin_file, '.php' );
91
+ $this->version = $_api_data['version'];
92
+ $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
93
+ $this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
94
+ $this->cache_key = 'edd_sl_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) );// phpcs:ignore
95
+
96
+ $edd_plugin_data[ $this->slug ] = $this->api_data;
97
+
98
+ /**
99
+ * Fires after the $edd_plugin_data is setup.
100
+ *
101
+ * @since x.x.x
102
+ *
103
+ * @param array $edd_plugin_data Array of EDD SL plugin data.
104
+ */
105
+ do_action( 'post_edd_sl_plugin_updater_setup', $edd_plugin_data );
106
+
107
+ // Set up hooks.
108
+ $this->init();
109
+
110
+ }
111
+
112
+ /**
113
+ * Set up WordPress filters to hook into WP's update process.
114
+ *
115
+ * @uses add_filter()
116
+ *
117
+ * @return void
118
+ */
119
+ public function init() {
120
+
121
+ add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
122
+ add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
123
+ remove_action( 'after_plugin_row_' . $this->name, 'wp_plugin_update_row', 10 );
124
+ add_action( 'after_plugin_row_' . $this->name, array( $this, 'show_update_notification' ), 10, 2 );
125
+ add_action( 'admin_init', array( $this, 'show_changelog' ) );
126
+
127
+ }
128
+
129
+ /**
130
+ * Check for Updates at the defined API endpoint and modify the update array.
131
+ *
132
+ * This function dives into the update API just when WordPress creates its update array,
133
+ * then adds a custom API call and injects the custom plugin data retrieved from the API.
134
+ * It is reassembled from parts of the native WordPress plugin update code.
135
+ * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
136
+ *
137
+ * @uses api_request()
138
+ *
139
+ * @param array $_transient_data Update array build by WordPress.
140
+ * @return array Modified update array with custom plugin data.
141
+ */
142
+ public function check_update( $_transient_data ) {
143
+
144
+ global $pagenow;
145
+
146
+ if ( ! is_object( $_transient_data ) ) {
147
+ $_transient_data = new stdClass; // phpcs:ignore
148
+ }
149
+
150
+ if ( 'plugins.php' === $pagenow && is_multisite() ) {
151
+ return $_transient_data;
152
+ }
153
+
154
+ if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
155
+ return $_transient_data;
156
+ }
157
+
158
+ $current = $this->get_repo_api_data();
159
+ if ( false !== $current && is_object( $current ) && isset( $current->new_version ) ) {
160
+ if ( version_compare( $this->version, $current->new_version, '<' ) ) {
161
+ $_transient_data->response[ $this->name ] = $current;
162
+ } else {
163
+ // Populating the no_update information is required to support auto-updates in WordPress 5.5.
164
+ $_transient_data->no_update[ $this->name ] = $current;
165
+ }
166
+ }
167
+ $_transient_data->last_checked = time();
168
+ $_transient_data->checked[ $this->name ] = $this->version;
169
+
170
+ return $_transient_data;
171
+ }
172
+
173
+ /**
174
+ * Get repo API data from store.
175
+ * Save to cache.
176
+ *
177
+ * @return \stdClass
178
+ */
179
+ public function get_repo_api_data() {
180
+ $version_info = $this->get_cached_version_info();
181
+
182
+ if ( false === $version_info ) {
183
+ $version_info = $this->api_request(
184
+ 'plugin_latest_version',
185
+ array(
186
+ 'slug' => $this->slug,
187
+ 'beta' => $this->beta,
188
+ )
189
+ );
190
+ if ( ! $version_info ) {
191
+ return false;
192
+ }
193
+
194
+ // This is required for your plugin to support auto-updates in WordPress 5.5.
195
+ $version_info->plugin = $this->name;
196
+ $version_info->id = $this->name;
197
+
198
+ $this->set_version_info_cache( $version_info );
199
+ }
200
+
201
+ return $version_info;
202
+ }
203
+
204
+ /**
205
+ * Show update nofication row -- needed for multisite subsites, because WP won't tell you otherwise!
206
+ *
207
+ * @param string $file Path to the plugin file relative to the plugins directory.
208
+ * @param array $plugin An array of plugin data.
209
+ */
210
+ public function show_update_notification( $file, $plugin ) {
211
+
212
+ if ( is_network_admin() ) {
213
+ return;
214
+ }
215
+
216
+ if ( ! current_user_can( 'update_plugins' ) ) {
217
+ return;
218
+ }
219
+
220
+ if ( ! is_multisite() ) {
221
+ return;
222
+ }
223
+
224
+ if ( $this->name !== $file ) {
225
+ return;
226
+ }
227
+
228
+ // Remove our filter on the site transient.
229
+ remove_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ), 10 );
230
+
231
+ $update_cache = get_site_transient( 'update_plugins' );
232
+
233
+ $update_cache = is_object( $update_cache ) ? $update_cache : new stdClass();
234
+
235
+ if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->name ] ) ) {
236
+
237
+ $version_info = $this->get_repo_api_data();
238
+
239
+ if ( false === $version_info ) {
240
+ $version_info = $this->api_request(
241
+ 'plugin_latest_version',
242
+ array(
243
+ 'slug' => $this->slug,
244
+ 'beta' => $this->beta,
245
+ )
246
+ );
247
+
248
+ // Since we disabled our filter for the transient, we aren't running our object conversion on banners, sections, or icons. Do this now:.
249
+ if ( isset( $version_info->banners ) && ! is_array( $version_info->banners ) ) {
250
+ $version_info->banners = $this->convert_object_to_array( $version_info->banners );
251
+ }
252
+
253
+ if ( isset( $version_info->sections ) && ! is_array( $version_info->sections ) ) {
254
+ $version_info->sections = $this->convert_object_to_array( $version_info->sections );
255
+ }
256
+
257
+ if ( isset( $version_info->icons ) && ! is_array( $version_info->icons ) ) {
258
+ $version_info->icons = $this->convert_object_to_array( $version_info->icons );
259
+ }
260
+
261
+ if ( isset( $version_info->contributors ) && ! is_array( $version_info->contributors ) ) {
262
+ $version_info->contributors = $this->convert_object_to_array( $version_info->contributors );
263
+ }
264
+
265
+ $this->set_version_info_cache( $version_info );
266
+ }
267
+
268
+ if ( ! is_object( $version_info ) ) {
269
+ return;
270
+ }
271
+
272
+ if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
273
+ $update_cache->response[ $this->name ] = $version_info;
274
+ } else {
275
+ $update_cache->no_update[ $this->name ] = $version_info;
276
+ }
277
+
278
+ $update_cache->last_checked = time();
279
+ $update_cache->checked[ $this->name ] = $this->version;
280
+
281
+ set_site_transient( 'update_plugins', $update_cache );
282
+
283
+ } else {
284
+
285
+ $version_info = $update_cache->response[ $this->name ];
286
+
287
+ }
288
+
289
+ // Restore our filter.
290
+ add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
291
+
292
+ if ( ! empty( $update_cache->response[ $this->name ] ) && version_compare( $this->version, $version_info->new_version, '<' ) ) {
293
+
294
+ // build a plugin list row, with update notification.
295
+ $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
296
+ echo wp_kses_post( '<tr class="plugin-update-tr" id="' . $this->slug . '-update" data-slug="' . $this->slug . '" data-plugin="' . $this->slug . '/' . $file . '">' );
297
+ echo '<td colspan="3" class="plugin-update colspanchange">';
298
+ echo '<div class="update-message notice inline notice-warning notice-alt">';
299
+
300
+ $changelog_link = self_admin_url( 'index.php?edd_sl_action=view_plugin_changelog&plugin=' . $this->name . '&slug=' . $this->slug . '&TB_iframe=true&width=772&height=911' );
301
+
302
+ if ( empty( $version_info->download_link ) ) {
303
+ printf(
304
+ /* translators: %1$s: pluign version info, %2$s: changelog link, %3$s: new version info, %4$s: closing a tag. */
305
+ esc_html__( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s.', 'easy-digital-downloads' ),
306
+ esc_html( $version_info->name ),
307
+ '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
308
+ esc_html( $version_info->new_version ),
309
+ '</a>'
310
+ );
311
+ } else {
312
+ printf(
313
+ /* translators: %1$s: pluign version info, %2$s: changelog link, %3$s: new version info, %4$s: closing a tag, %5$s: update link, %6$s: closing a tag. */
314
+ esc_html__( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s or %5$supdate now%6$s.', 'easy-digital-downloads' ),
315
+ esc_html( $version_info->name ),
316
+ '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
317
+ esc_html( $version_info->new_version ),
318
+ '</a>',
319
+ '<a href="' . esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $this->name, 'upgrade-plugin_' . $this->name ) ) . '">',
320
+ '</a>'
321
+ );
322
+ }
323
+
324
+ do_action( "in_plugin_update_message-{$file}", $plugin, $version_info );// phpcs:ignore
325
+
326
+ echo '</div></td></tr>';
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Updates information on the "View version x.x details" page with custom data.
332
+ *
333
+ * @uses api_request()
334
+ *
335
+ * @param false|object|array $_data The result object or array. Default false.
336
+ * @param string $_action The type of information being requested from the Plugin Installation API.
337
+ * @param object $_args Plugin API arguments.
338
+ * @return object $_data
339
+ */
340
+ public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
341
+
342
+ if ( 'plugin_information' !== $_action ) {
343
+
344
+ return $_data;
345
+
346
+ }
347
+
348
+ if ( ! isset( $_args->slug ) || ( $_args->slug !== $this->slug ) ) {
349
+
350
+ return $_data;
351
+
352
+ }
353
+
354
+ $to_send = array(
355
+ 'slug' => $this->slug,
356
+ 'is_ssl' => is_ssl(),
357
+ 'fields' => array(
358
+ 'banners' => array(),
359
+ 'reviews' => false,
360
+ 'icons' => array(),
361
+ ),
362
+ );
363
+
364
+ // Get the transient where we store the api request for this plugin for 24 hours.
365
+ $edd_api_request_transient = $this->get_cached_version_info();
366
+
367
+ // If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now.
368
+ if ( empty( $edd_api_request_transient ) ) {
369
+
370
+ $api_response = $this->api_request( 'plugin_information', $to_send );
371
+
372
+ // Expires in 3 hours.
373
+ $this->set_version_info_cache( $api_response );
374
+
375
+ if ( false !== $api_response ) {
376
+ $_data = $api_response;
377
+ }
378
+ } else {
379
+ $_data = $edd_api_request_transient;
380
+ }
381
+
382
+ // Convert sections into an associative array, since we're getting an object, but Core expects an array.
383
+ if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) {
384
+ $_data->sections = $this->convert_object_to_array( $_data->sections );
385
+ }
386
+
387
+ // Convert banners into an associative array, since we're getting an object, but Core expects an array.
388
+ if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) {
389
+ $_data->banners = $this->convert_object_to_array( $_data->banners );
390
+ }
391
+
392
+ // Convert icons into an associative array, since we're getting an object, but Core expects an array.
393
+ if ( isset( $_data->icons ) && ! is_array( $_data->icons ) ) {
394
+ $_data->icons = $this->convert_object_to_array( $_data->icons );
395
+ }
396
+
397
+ // Convert contributors into an associative array, since we're getting an object, but Core expects an array.
398
+ if ( isset( $_data->contributors ) && ! is_array( $_data->contributors ) ) {
399
+ $_data->contributors = $this->convert_object_to_array( $_data->contributors );
400
+ }
401
+
402
+ if ( ! isset( $_data->plugin ) ) {
403
+ $_data->plugin = $this->name;
404
+ }
405
+
406
+ return $_data;
407
+ }
408
+
409
+ /**
410
+ * Convert some objects to arrays when injecting data into the update API
411
+ *
412
+ * Some data like sections, banners, and icons are expected to be an associative array, however due to the JSON
413
+ * decoding, they are objects. This method allows us to pass in the object and return an associative array.
414
+ *
415
+ * @since 3.6.5
416
+ *
417
+ * @param stdClass $data Data.
418
+ *
419
+ * @return array
420
+ */
421
+ private function convert_object_to_array( $data ) {
422
+ if ( ! is_array( $data ) && ! is_object( $data ) ) {
423
+ return array();
424
+ }
425
+ $new_data = array();
426
+ foreach ( $data as $key => $value ) {
427
+ $new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value;
428
+ }
429
+
430
+ return $new_data;
431
+ }
432
+
433
+ /**
434
+ * Disable SSL verification in order to prevent download update failures
435
+ *
436
+ * @param array $args An array of args.
437
+ * @param string $url URL.
438
+ * @return object $array
439
+ */
440
+ public function http_request_args( $args, $url ) {
441
+
442
+ $verify_ssl = $this->verify_ssl();
443
+ if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
444
+ $args['sslverify'] = $verify_ssl;
445
+ }
446
+ return $args;
447
+
448
+ }
449
+
450
+ /**
451
+ * Calls the API and, if successfull, returns the object delivered by the API.
452
+ *
453
+ * @uses get_bloginfo()
454
+ * @uses wp_remote_post()
455
+ * @uses is_wp_error()
456
+ *
457
+ * @param string $_action The requested action.
458
+ * @param array $_data Parameters for the API action.
459
+ * @return false|object
460
+ */
461
+ private function api_request( $_action, $_data ) {
462
+
463
+ global $wp_version, $edd_plugin_url_available;
464
+
465
+ $verify_ssl = $this->verify_ssl();
466
+
467
+ // Do a quick status check on this domain if we haven't already checked it.
468
+ $store_hash = md5( $this->api_url );
469
+ if ( ! is_array( $edd_plugin_url_available ) || ! isset( $edd_plugin_url_available[ $store_hash ] ) ) {
470
+ $test_url_parts = parse_url( $this->api_url );
471
+
472
+ $scheme = ! empty( $test_url_parts['scheme'] ) ? $test_url_parts['scheme'] : 'http';
473
+ $host = ! empty( $test_url_parts['host'] ) ? $test_url_parts['host'] : '';
474
+ $port = ! empty( $test_url_parts['port'] ) ? ':' . $test_url_parts['port'] : '';
475
+
476
+ if ( empty( $host ) ) {
477
+ $edd_plugin_url_available[ $store_hash ] = false;
478
+ } else {
479
+ $test_url = $scheme . '://' . $host . $port;
480
+ $response = wp_remote_get(
481
+ $test_url,
482
+ array(
483
+ 'timeout' => $this->health_check_timeout,
484
+ 'sslverify' => $verify_ssl,
485
+ )
486
+ );
487
+ $edd_plugin_url_available[ $store_hash ] = is_wp_error( $response ) ? false : true;
488
+ }
489
+ }
490
+
491
+ if ( false === $edd_plugin_url_available[ $store_hash ] ) {
492
+ return false;
493
+ }
494
+
495
+ $data = array_merge( $this->api_data, $_data );
496
+
497
+ if ( $data['slug'] !== $this->slug ) {
498
+ return false;
499
+ }
500
+
501
+ if ( trailingslashit( home_url() ) === $this->api_url ) {
502
+ return false; // Don't allow a plugin to ping itself.
503
+ }
504
+
505
+ $api_params = array(
506
+ 'edd_action' => 'get_version',
507
+ 'license' => ! empty( $data['license'] ) ? $data['license'] : '',
508
+ 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
509
+ 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
510
+ 'version' => isset( $data['version'] ) ? $data['version'] : false,
511
+ 'slug' => $data['slug'],
512
+ 'author' => $data['author'],
513
+ 'url' => home_url(),
514
+ 'beta' => ! empty( $data['beta'] ),
515
+ );
516
+
517
+ $request = wp_remote_post(
518
+ $this->api_url,
519
+ array(
520
+ 'timeout' => 15,
521
+ 'sslverify' => $verify_ssl,
522
+ 'body' => $api_params,
523
+ )
524
+ );
525
+
526
+ if ( ! is_wp_error( $request ) ) {
527
+ $request = json_decode( wp_remote_retrieve_body( $request ) );
528
+ }
529
+
530
+ if ( $request && isset( $request->sections ) ) {
531
+ $request->sections = maybe_unserialize( $request->sections );
532
+ } else {
533
+ $request = false;
534
+ }
535
+
536
+ if ( $request && isset( $request->banners ) ) {
537
+ $request->banners = maybe_unserialize( $request->banners );
538
+ }
539
+
540
+ if ( $request && isset( $request->icons ) ) {
541
+ $request->icons = maybe_unserialize( $request->icons );
542
+ }
543
+
544
+ if ( ! empty( $request->sections ) ) {
545
+ foreach ( $request->sections as $key => $section ) {
546
+ $request->$key = (array) $section;
547
+ }
548
+ }
549
+
550
+ return $request;
551
+ }
552
+
553
+ /**
554
+ * If available, show the changelog for sites in a multisite install.
555
+ */
556
+ public function show_changelog() {
557
+
558
+ global $edd_plugin_data;
559
+
560
+ if ( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' !== $_REQUEST['edd_sl_action'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
561
+ return;
562
+ }
563
+
564
+ if ( empty( $_REQUEST['plugin'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
565
+ return;
566
+ }
567
+
568
+ if ( empty( $_REQUEST['slug'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
569
+ return;
570
+ }
571
+
572
+ if ( ! current_user_can( 'update_plugins' ) ) {
573
+ wp_die( esc_html__( 'You do not have permission to install plugin updates', 'easy-digital-downloads' ), esc_html__( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
574
+ }
575
+
576
+ $data = $edd_plugin_data[ $_REQUEST['slug'] ]; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
577
+ $version_info = $this->get_cached_version_info();
578
+
579
+ if ( false === $version_info ) {
580
+
581
+ $api_params = array(
582
+ 'edd_action' => 'get_version',
583
+ 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
584
+ 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
585
+ 'slug' => $_REQUEST['slug'], // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
586
+ 'author' => $data['author'],
587
+ 'url' => home_url(),
588
+ 'beta' => ! empty( $data['beta'] ),
589
+ );
590
+
591
+ $verify_ssl = $this->verify_ssl();
592
+ $request = wp_remote_post(
593
+ $this->api_url,
594
+ array(
595
+ 'timeout' => 15,
596
+ 'sslverify' => $verify_ssl,
597
+ 'body' => $api_params,
598
+ )
599
+ );
600
+
601
+ if ( ! is_wp_error( $request ) ) {
602
+ $version_info = json_decode( wp_remote_retrieve_body( $request ) );
603
+ }
604
+
605
+ if ( ! empty( $version_info ) && isset( $version_info->sections ) ) {
606
+ $version_info->sections = maybe_unserialize( $version_info->sections );
607
+ } else {
608
+ $version_info = false;
609
+ }
610
+
611
+ if ( ! empty( $version_info ) ) {
612
+ foreach ( $version_info->sections as $key => $section ) {
613
+ $version_info->$key = (array) $section;
614
+ }
615
+ }
616
+
617
+ $this->set_version_info_cache( $version_info );
618
+
619
+ // Delete the unneeded option.
620
+ delete_option( md5( 'edd_plugin_' . sanitize_key( $_REQUEST['plugin'] ) . '_' . $this->beta . '_version_info' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
621
+ }
622
+
623
+ if ( isset( $version_info->sections ) ) {
624
+ $sections = $this->convert_object_to_array( $version_info->sections );
625
+ if ( ! empty( $sections['changelog'] ) ) {
626
+ echo '<div style="background:#fff;padding:10px;">' . wp_kses_post( $sections['changelog'] ) . '</div>';
627
+ }
628
+ }
629
+
630
+ exit;
631
+ }
632
+
633
+ /**
634
+ * Gets the plugin's cached version information from the database.
635
+ *
636
+ * @param string $cache_key Cache key.
637
+ * @return boolean|string
638
+ */
639
+ public function get_cached_version_info( $cache_key = '' ) {
640
+
641
+ if ( empty( $cache_key ) ) {
642
+ $cache_key = $this->cache_key;
643
+ }
644
+
645
+ $cache = get_option( $cache_key );
646
+
647
+ if ( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
648
+ return false; // Cache is expired.
649
+ }
650
+
651
+ // We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
652
+ $cache['value'] = json_decode( $cache['value'] );
653
+ if ( ! empty( $cache['value']->icons ) ) {
654
+ $cache['value']->icons = (array) $cache['value']->icons;
655
+ }
656
+
657
+ return $cache['value'];
658
+
659
+ }
660
+
661
+ /**
662
+ * Adds the plugin version information to the database.
663
+ *
664
+ * @param string $value Value.
665
+ * @param string $cache_key Cache key.
666
+ */
667
+ public function set_version_info_cache( $value = '', $cache_key = '' ) {
668
+
669
+ if ( empty( $cache_key ) ) {
670
+ $cache_key = $this->cache_key;
671
+ }
672
+
673
+ $data = array(
674
+ 'timeout' => strtotime( '+3 hours', time() ),
675
+ 'value' => wp_json_encode( $value ),
676
+ );
677
+
678
+ update_option( $cache_key, $data, 'no' );
679
+
680
+ // Delete the duplicate option.
681
+ delete_option( 'edd_api_request_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) ) );// phpcs:ignore
682
+ }
683
+
684
+ /**
685
+ * Returns if the SSL of the store should be verified.
686
+ *
687
+ * @since 1.6.13
688
+ * @return bool
689
+ */
690
+ private function verify_ssl() {
691
+ return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
692
+ }
693
+
694
+ }
695
+ }
includes/license/class-bnfw-license-setting.php CHANGED
@@ -1,136 +1,150 @@
1
- <?php
2
- /**
3
- * BNFW License setting Handler.
4
- *
5
- * @since v1.4
6
- */
7
-
8
- defined( 'ABSPATH' ) || exit; // Exit if accessed directly
9
-
10
- /**
11
- * Add License page.
12
- *
13
- * @since 1.4
14
- */
15
- function bnfw_add_license_page() {
16
- add_submenu_page(
17
- 'edit.php?post_type=bnfw_notification',
18
- esc_html__( 'Add-on Licenses', 'bnfw' ),
19
- esc_html__( 'Add-on Licenses', 'bnfw' ),
20
- 'bnfw',
21
- 'bnfw-license',
22
- 'bnfw_render_license_page'
23
- );
24
- }
25
-
26
- add_action( 'admin_menu', 'bnfw_add_license_page', 11 );
27
-
28
- /**
29
- * Render license page.
30
- *
31
- * @since 1.4
32
- */
33
- function bnfw_render_license_page() {
34
- $settings = apply_filters( 'bnfw_settings_licenses', array() );
35
- ob_start(); ?>
36
-
37
- <div class="wrap">
38
- <h2><?php esc_html_e( 'BNFW Add-on Licenses', 'bnfw' ); ?></h2>
39
-
40
- <form method="post" action="options.php" class="bnfw-form">
41
- <?php
42
- settings_errors();
43
- settings_fields( 'bnfw-license-settings' );
44
- do_settings_sections( 'bnfw-license' );
45
-
46
- if ( ! empty( $settings ) ) {
47
- submit_button( esc_html__( 'Save License', 'bnfw' ) );
48
- } else {
49
- $store_url = 'https://betternotificationsforwp.com/downloads/';
50
-
51
- if ( bnfw_is_tracking_allowed() ) {
52
- $store_url .= "?utm_source=WP%20Admin%20Submenu%20Item%20-%20Add-on%20Licenses&amp;utm_medium=referral";
53
- }
54
-
55
- _e( '<br>You have no BNFW Premium Add-ons installed yet.<br>You can buy add-ons from the <a href="' . $store_url . '" target="_blank">Store</a>.<br>Once purchased, install and activate the add-on(s) like you would any other WordPress plugin. Then return here and enter your license key.', 'bnfw' );
56
- }
57
- ?>
58
- </form>
59
- </div>
60
-
61
- <?php echo ob_get_clean();
62
- }
63
-
64
- function bnfw_license_settings() {
65
- $settings = apply_filters( 'bnfw_settings_licenses', array() );
66
-
67
- if ( ! empty( $settings ) ) {
68
-
69
- add_settings_section(
70
- 'bnfw_license_section', // Section ID
71
- esc_html__( '', 'bnfw' ), // Title above settings section
72
- '__return_false', // Name of function that renders a description of the settings section
73
- 'bnfw-license' // Page to show on
74
- );
75
-
76
- foreach ( $settings as $option ) {
77
- $name = isset( $option['name'] ) ? $option['name'] : '';
78
- add_settings_field(
79
- 'bnfw_licenses[' . $option['id'] . ']',
80
- $name,
81
- 'bnfw_license_key_callback',
82
- 'bnfw-license',
83
- 'bnfw_license_section',
84
- array(
85
- 'id' => isset( $option['id'] ) ? $option['id'] : null,
86
- 'desc' => ! empty( $option['desc'] ) ? $option['desc'] : '',
87
- 'name' => isset( $option['name'] ) ? $option['name'] : null,
88
- 'size' => isset( $option['size'] ) ? $option['size'] : null,
89
- 'options' => isset( $option['options'] ) ? $option['options'] : '',
90
- 'std' => isset( $option['std'] ) ? $option['std'] : '',
91
- 'min' => isset( $option['min'] ) ? $option['min'] : null,
92
- 'max' => isset( $option['max'] ) ? $option['max'] : null,
93
- 'step' => isset( $option['step'] ) ? $option['step'] : null,
94
- 'chosen' => isset( $option['chosen'] ) ? $option['chosen'] : null,
95
- 'placeholder' => isset( $option['placeholder'] ) ? $option['placeholder'] : null,
96
- 'allow_blank' => isset( $option['allow_blank'] ) ? $option['allow_blank'] : true,
97
- 'readonly' => isset( $option['readonly'] ) ? $option['readonly'] : false,
98
- 'faux' => isset( $option['faux'] ) ? $option['faux'] : false,
99
- )
100
- );
101
- }
102
-
103
- register_setting(
104
- 'bnfw-license-settings',
105
- 'bnfw_licenses'
106
- );
107
- }
108
- }
109
-
110
- add_action( 'admin_init', 'bnfw_license_settings', 11 );
111
-
112
- /**
113
- * Register the new license field type
114
- *
115
- * @return void
116
- */
117
- function bnfw_license_key_callback( $args ) {
118
- $bnfw_options = get_option( 'bnfw_licenses' );
119
-
120
- if ( isset( $bnfw_options[ $args['id'] ] ) ) {
121
- $value = $bnfw_options[ $args['id'] ];
122
- } else {
123
- $value = isset( $args['std'] ) ? $args['std'] : '';
124
- }
125
-
126
- $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
127
- $html = '<input type="text" class="' . sanitize_html_class( $size ) . '-text" id="bnfw_licenses[' . $args['id'] . ']" name="bnfw_licenses[' . $args['id'] . ']" value="' . esc_attr( $value ) . '">';
128
-
129
- if ( 'valid' == get_option( $args['options']['is_valid_license_option'] ) ) {
130
- $html .= '<input type="submit" class="button-secondary" name="' . $args['id'] . '_deactivate" value="' . esc_attr__( 'Deactivate License', 'bnfw' ) . '">';
131
- }
132
-
133
- $html .= '<label for="bnfw_licenses[' . $args['id'] . ']"> ' . esc_html( $args['desc'] ) . '</label>';
134
-
135
- echo $html;
136
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BNFW License setting Handler.
4
+ *
5
+ * @since v1.4
6
+ * @package bnfw
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
10
+
11
+ if ( ! class_exists( 'BNFW_License_Setting', false ) ) {
12
+ /**
13
+ * BNFW_License_Setting class.
14
+ */
15
+ class BNFW_License_Setting {
16
+ /**
17
+ * Class contructor.
18
+ */
19
+ public function __construct() {
20
+ add_action( 'admin_menu', array( $this, 'bnfw_add_license_page' ), 11 );
21
+ add_action( 'admin_init', array( $this, 'bnfw_license_settings' ), 11 );
22
+ }
23
+ /**
24
+ * Add License page.
25
+ *
26
+ * @since 1.4
27
+ */
28
+ public function bnfw_add_license_page() {
29
+ add_submenu_page(
30
+ 'edit.php?post_type=bnfw_notification',
31
+ esc_html__( 'Add-on Licenses', 'bnfw' ),
32
+ esc_html__( 'Add-on Licenses', 'bnfw' ),
33
+ 'bnfw',
34
+ 'bnfw-license',
35
+ array( $this, 'bnfw_render_license_page' )
36
+ );
37
+ }
38
+ /**
39
+ * Render license page.
40
+ *
41
+ * @since 1.4
42
+ */
43
+ public function bnfw_render_license_page() {
44
+ $settings = apply_filters( 'bnfw_settings_licenses', array() );
45
+ ob_start(); ?>
46
+
47
+ <div class="wrap">
48
+ <h2><?php esc_html_e( 'BNFW Add-on Licenses', 'bnfw' ); ?></h2>
49
+
50
+ <form method="post" action="options.php" class="bnfw-form">
51
+ <?php
52
+ settings_errors();
53
+ settings_fields( 'bnfw-license-settings' );
54
+ do_settings_sections( 'bnfw-license' );
55
+
56
+ if ( ! empty( $settings ) ) {
57
+ submit_button( esc_html__( 'Save License', 'bnfw' ) );
58
+ } else {
59
+ $store_url = 'https://betternotificationsforwp.com/downloads/';
60
+
61
+ if ( bnfw_is_tracking_allowed() ) {
62
+ $store_url .= '?utm_source=WP%20Admin%20Submenu%20Item%20-%20Add-on%20Licenses&amp;utm_medium=referral';
63
+ }
64
+ /* translators: 1: BNFW Store URL */
65
+ echo wp_kses_post( sprintf( __( '<br>You have no BNFW Premium Add-ons installed yet.<br>You can buy add-ons from the <a href="%s" target="_blank">Store</a>.<br>Once purchased, install and activate the add-on(s) like you would any other WordPress plugin. Then return here and enter your license key.', 'bnfw' ), esc_url( $store_url ) ) );
66
+ }
67
+ ?>
68
+ </form>
69
+ </div>
70
+
71
+ <?php
72
+ echo ob_get_clean();
73
+ }
74
+ /**
75
+ * BNFW license settings.
76
+ */
77
+ public function bnfw_license_settings() {
78
+ $settings = apply_filters( 'bnfw_settings_licenses', array() );
79
+
80
+ if ( ! empty( $settings ) ) {
81
+
82
+ add_settings_section(
83
+ 'bnfw_license_section', // Section ID.
84
+ esc_html( '' ), // Title above settings section.
85
+ '__return_false', // Name of function that renders a description of the settings section.
86
+ 'bnfw-license' // Page to show on.
87
+ );
88
+
89
+ foreach ( $settings as $option ) {
90
+ $name = isset( $option['name'] ) ? $option['name'] : '';
91
+ add_settings_field(
92
+ 'bnfw_licenses[' . $option['id'] . ']',
93
+ $name,
94
+ array( $this, 'bnfw_license_key_callback' ),
95
+ 'bnfw-license',
96
+ 'bnfw_license_section',
97
+ array(
98
+ 'id' => isset( $option['id'] ) ? $option['id'] : null,
99
+ 'desc' => ! empty( $option['desc'] ) ? $option['desc'] : '',
100
+ 'name' => isset( $option['name'] ) ? $option['name'] : null,
101
+ 'size' => isset( $option['size'] ) ? $option['size'] : null,
102
+ 'options' => isset( $option['options'] ) ? $option['options'] : '',
103
+ 'std' => isset( $option['std'] ) ? $option['std'] : '',
104
+ 'min' => isset( $option['min'] ) ? $option['min'] : null,
105
+ 'max' => isset( $option['max'] ) ? $option['max'] : null,
106
+ 'step' => isset( $option['step'] ) ? $option['step'] : null,
107
+ 'chosen' => isset( $option['chosen'] ) ? $option['chosen'] : null,
108
+ 'placeholder' => isset( $option['placeholder'] ) ? $option['placeholder'] : null,
109
+ 'allow_blank' => isset( $option['allow_blank'] ) ? $option['allow_blank'] : true,
110
+ 'readonly' => isset( $option['readonly'] ) ? $option['readonly'] : false,
111
+ 'faux' => isset( $option['faux'] ) ? $option['faux'] : false,
112
+ )
113
+ );
114
+ }
115
+
116
+ register_setting(
117
+ 'bnfw-license-settings',
118
+ 'bnfw_licenses'
119
+ );
120
+ }
121
+ }
122
+ /**
123
+ * Register the new license field type
124
+ *
125
+ * @param array $args Args.
126
+ * @return void
127
+ */
128
+ public function bnfw_license_key_callback( $args ) {
129
+ $bnfw_options = get_option( 'bnfw_licenses' );
130
+
131
+ if ( isset( $bnfw_options[ $args['id'] ] ) ) {
132
+ $value = $bnfw_options[ $args['id'] ];
133
+ } else {
134
+ $value = isset( $args['std'] ) ? $args['std'] : '';
135
+ }
136
+
137
+ $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
138
+ $html = '<input type="text" class="' . sanitize_html_class( $size ) . '-text" id="bnfw_licenses[' . $args['id'] . ']" name="bnfw_licenses[' . $args['id'] . ']" value="' . esc_attr( $value ) . '">';
139
+
140
+ if ( 'valid' === get_option( $args['options']['is_valid_license_option'] ) ) {
141
+ $html .= '<input type="submit" class="button-secondary" name="' . $args['id'] . '_deactivate" value="' . esc_attr__( 'Deactivate License', 'bnfw' ) . '">';
142
+ }
143
+
144
+ $html .= '<label for="bnfw_licenses[' . $args['id'] . ']"> ' . esc_html( $args['desc'] ) . '</label>';
145
+
146
+ echo $html; // phpcs:ignore
147
+ }
148
+ }
149
+ new BNFW_License_Setting();
150
+ }
includes/license/class-bnfw-license.php CHANGED
@@ -1,255 +1,293 @@
1
- <?php
2
- /**
3
- * License handler for BNFW
4
- *
5
- * @since 1.4
6
- */
7
-
8
- defined( 'ABSPATH' ) || exit; // Exit if accessed directly
9
-
10
- /**
11
- * BNFW_License Class
12
- */
13
- class BNFW_License {
14
- private $file;
15
- private $license;
16
- private $item_name;
17
- private $item_shortname;
18
- private $version;
19
- private $author;
20
- private $api_url = 'https://betternotificationsforwp.com/';
21
-
22
- /**
23
- * Class constructor
24
- *
25
- * @param string $_file
26
- * @param string $_item_name
27
- * @param string $_version
28
- * @param string $_author
29
- * @param string $_optname
30
- * @param string $_api_url
31
- */
32
- function __construct( $_file, $_item_name, $_version, $_author, $_optname = null, $_api_url = null ) {
33
- $bnfw_options = get_option( 'bnfw_licenses' );
34
-
35
- $this->file = $_file;
36
- $this->item_name = $_item_name;
37
- $this->item_shortname = 'bnfw_' . preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->item_name ) ) );
38
- $this->version = $_version;
39
- $this->license = isset( $bnfw_options[ $this->item_shortname . '_license_key' ] ) ? trim( $bnfw_options[ $this->item_shortname . '_license_key' ] ) : '';
40
- $this->author = $_author;
41
- $this->api_url = is_null( $_api_url ) ? $this->api_url : $_api_url;
42
-
43
- // Setup hooks
44
- $this->hooks();
45
- $this->auto_updater();
46
- }
47
-
48
- /**
49
- * Setup hooks
50
- *
51
- * @access private
52
- * @return void
53
- */
54
- private function hooks() {
55
- // Register settings
56
- add_filter( 'bnfw_settings_licenses', array( $this, 'settings' ), 1 );
57
-
58
- // Activate license key on settings save
59
- add_action( 'admin_init', array( $this, 'activate_license' ) );
60
-
61
- // Deactivate license key
62
- add_action( 'admin_init', array( $this, 'deactivate_license' ) );
63
-
64
- add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'update_plugins_transient_unserialize_icons' ), 99 );
65
- }
66
-
67
- /**
68
- * Filter the transient data for our plugin's icons.
69
- * Since icons are passed back as serialized arrays, we need to unserialize them.
70
- * This has to be run from within your plugin.
71
- *
72
- * Based on code from https://renventura.com/adding-update-icons-for-commercial-plugins/
73
- *
74
- * @param (object) $transient - Full transient data
75
- *
76
- * @return mixed (object) $transient
77
- */
78
- public function update_plugins_transient_unserialize_icons( $transient ) {
79
-
80
- if ( is_object( $transient ) && isset( $transient->response ) && is_array( $transient->response ) ) {
81
-
82
- $basename = plugin_basename( __FILE__ );
83
-
84
- // Received a response for our plugin
85
- $plugin = isset( $transient->response[ $basename ] ) ? $transient->response[ $basename ] : new stdClass;
86
-
87
- // Are there any icons set for the plugin?
88
- if ( isset( $plugin->icons ) ) {
89
- $icons = is_string( $plugin->icons ) ? unserialize( $plugin->icons ) : $plugin->icons;
90
- $transient->response[ $basename ]->icons = $icons;
91
- }
92
- }
93
-
94
- return $transient;
95
- }
96
-
97
- /**
98
- * Auto updater
99
- *
100
- * @access private
101
- * @return void
102
- */
103
- private function auto_updater() {
104
- // Setup the updater
105
- $edd_updater = new EDD_SL_Plugin_Updater(
106
- $this->api_url,
107
- $this->file,
108
- array(
109
- 'version' => $this->version,
110
- 'license' => $this->license,
111
- 'item_name' => $this->item_name,
112
- 'author' => $this->author,
113
- )
114
- );
115
- }
116
-
117
- /**
118
- * Add license field to settings
119
- *
120
- * @access public
121
- *
122
- * @param array $settings
123
- *
124
- * @return array
125
- */
126
- public function settings( $settings ) {
127
- if ( 'Multisite Add-on' === $this->item_name && ! is_multisite() ) {
128
- return $settings;
129
- }
130
-
131
- if ( 'Multisite Add-on' === $this->item_name && is_multisite() ) {
132
- if ( ! is_main_site() ) {
133
- return $settings;
134
- }
135
- }
136
-
137
- $bnfw_license_settings = array(
138
- array(
139
- 'id' => $this->item_shortname . '_license_key',
140
- 'name' => sprintf( esc_html__( '%1$s License Key', 'bnfw' ), $this->item_name ),
141
- 'desc' => '',
142
- 'type' => 'license_key',
143
- 'options' => array( 'is_valid_license_option' => $this->item_shortname . '_license_active' ),
144
- 'size' => 'regular',
145
- ),
146
- );
147
-
148
- return array_merge( $settings, $bnfw_license_settings );
149
- }
150
-
151
- /**
152
- * Activate the license key
153
- *
154
- * @access public
155
- * @return void
156
- */
157
- public function activate_license() {
158
- if ( ! isset( $_POST['bnfw_licenses'] ) ) {
159
- return;
160
- }
161
-
162
- if ( ! isset( $_POST['bnfw_licenses'][ $this->item_shortname . '_license_key' ] ) ) {
163
- return;
164
- }
165
-
166
- if ( 'valid' == get_option( $this->item_shortname . '_license_active' ) ) {
167
- return;
168
- }
169
-
170
- $license = sanitize_text_field( $_POST['bnfw_licenses'][ $this->item_shortname . '_license_key' ] );
171
-
172
- // Data to send to the API
173
- $api_params = array(
174
- 'edd_action' => 'activate_license',
175
- 'license' => $license,
176
- 'item_name' => urlencode( $this->item_name ),
177
- );
178
-
179
- if ( 'Multisite Add-on' === $this->item_name && is_multisite() ) {
180
- $api_params['url'] = get_home_url( get_main_site_id() );
181
- }
182
-
183
- // Call the API
184
- $response = wp_remote_get(
185
- esc_url_raw( add_query_arg( $api_params, $this->api_url ) ),
186
- array(
187
- 'timeout' => 15,
188
- 'body' => $api_params,
189
- 'sslverify' => false,
190
- )
191
- );
192
-
193
- // Make sure there are no errors
194
- if ( is_wp_error( $response ) ) {
195
- return;
196
- }
197
-
198
- // Decode license data
199
- $license_data = json_decode( wp_remote_retrieve_body( $response ) );
200
-
201
- update_option( $this->item_shortname . '_license_active', $license_data->license );
202
- }
203
-
204
- /**
205
- * Deactivate the license key
206
- *
207
- * @access public
208
- * @return void
209
- */
210
- public function deactivate_license() {
211
- if ( ! isset( $_POST['bnfw_licenses'] ) ) {
212
- return;
213
- }
214
-
215
- if ( ! isset( $_POST['bnfw_licenses'][ $this->item_shortname . '_license_key' ] ) ) {
216
- return;
217
- }
218
-
219
- // Run on deactivate button press
220
- if ( isset( $_POST[ $this->item_shortname . '_license_key_deactivate' ] ) ) {
221
-
222
- // Data to send to the API
223
- $api_params = array(
224
- 'edd_action' => 'deactivate_license',
225
- 'license' => $this->license,
226
- 'item_name' => urlencode( $this->item_name ),
227
- );
228
-
229
- if ( 'Multisite Add-on' === $this->item_name && is_multisite() ) {
230
- $api_params['url'] = get_home_url( get_main_site_id() );
231
- }
232
-
233
- // Call the API
234
- $response = wp_remote_get(
235
- esc_url_raw( add_query_arg( $api_params, $this->api_url ) ),
236
- array(
237
- 'timeout' => 15,
238
- 'sslverify' => false,
239
- )
240
- );
241
-
242
- // Make sure there are no errors
243
- if ( is_wp_error( $response ) ) {
244
- return;
245
- }
246
-
247
- // Decode the license data
248
- $license_data = json_decode( wp_remote_retrieve_body( $response ) );
249
-
250
- if ( 'deactivated' == $license_data->license ) {
251
- delete_option( $this->item_shortname . '_license_active' );
252
- }
253
- }
254
- }
255
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * License handler for BNFW
4
+ *
5
+ * @since 1.4
6
+ * @package bnfw
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
10
+
11
+ if ( ! class_exists( 'BNFW_License', false ) ) {
12
+ /**
13
+ * BNFW_License Class
14
+ */
15
+ class BNFW_License {
16
+ /**
17
+ * Holds info about file
18
+ *
19
+ * @var string
20
+ */
21
+ private $file;
22
+ /**
23
+ * Holds the license key
24
+ *
25
+ * @var string
26
+ */
27
+ private $license;
28
+ /**
29
+ * Holds the item name
30
+ *
31
+ * @var string
32
+ */
33
+ private $item_name;
34
+ /**
35
+ * Holds the item shortname
36
+ *
37
+ * @var string
38
+ */
39
+ private $item_shortname;
40
+ /**
41
+ * Holds the plugin version
42
+ *
43
+ * @var string
44
+ */
45
+ private $version;
46
+ /**
47
+ * Holds the info about author
48
+ *
49
+ * @var string
50
+ */
51
+ private $author;
52
+ /**
53
+ * Holds the API URL
54
+ *
55
+ * @var string
56
+ */
57
+ private $api_url = 'https://betternotificationsforwp.com/';
58
+
59
+ /**
60
+ * Class constructor
61
+ *
62
+ * @param string $_file File.
63
+ * @param string $_item_name Item name.
64
+ * @param string $_version Verison.
65
+ * @param string $_author Author.
66
+ * @param string $_optname Optname.
67
+ * @param string $_api_url API URL.
68
+ */
69
+ public function __construct( $_file, $_item_name, $_version, $_author, $_optname = null, $_api_url = null ) {
70
+ $bnfw_options = get_option( 'bnfw_licenses' );
71
+
72
+ $this->file = $_file;
73
+ $this->item_name = $_item_name;
74
+ $this->item_shortname = 'bnfw_' . preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->item_name ) ) );
75
+ $this->version = $_version;
76
+ $this->license = isset( $bnfw_options[ $this->item_shortname . '_license_key' ] ) ? trim( $bnfw_options[ $this->item_shortname . '_license_key' ] ) : '';
77
+ $this->author = $_author;
78
+ $this->api_url = is_null( $_api_url ) ? $this->api_url : $_api_url;
79
+
80
+ // Setup hooks.
81
+ $this->hooks();
82
+ $this->auto_updater();
83
+ }
84
+
85
+ /**
86
+ * Setup hooks
87
+ *
88
+ * @access private
89
+ * @return void
90
+ */
91
+ private function hooks() {
92
+ // Register settings.
93
+ add_filter( 'bnfw_settings_licenses', array( $this, 'settings' ), 1 );
94
+
95
+ // Activate license key on settings save.
96
+ add_action( 'admin_init', array( $this, 'activate_license' ) );
97
+
98
+ // Deactivate license key.
99
+ add_action( 'admin_init', array( $this, 'deactivate_license' ) );
100
+
101
+ add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'update_plugins_transient_unserialize_icons' ), 99 );
102
+ }
103
+
104
+ /**
105
+ * Filter the transient data for our plugin's icons.
106
+ * Since icons are passed back as serialized arrays, we need to unserialize them.
107
+ * This has to be run from within your plugin.
108
+ *
109
+ * Based on code from https://renventura.com/adding-update-icons-for-commercial-plugins/
110
+ *
111
+ * @param mixed $transient New value of site transient.
112
+ *
113
+ * @return mixed (object) $transient
114
+ */
115
+ public function update_plugins_transient_unserialize_icons( $transient ) {
116
+
117
+ if ( is_object( $transient ) && isset( $transient->response ) && is_array( $transient->response ) ) {
118
+
119
+ $basename = plugin_basename( __FILE__ );
120
+
121
+ // Received a response for our plugin.
122
+ $plugin = isset( $transient->response[ $basename ] ) ? $transient->response[ $basename ] : new stdClass();
123
+
124
+ // Are there any icons set for the plugin?
125
+ if ( isset( $plugin->icons ) ) {
126
+ $icons = is_string( $plugin->icons ) ? unserialize( $plugin->icons ) : $plugin->icons; // phpcs:ignore
127
+ $transient->response[ $basename ]->icons = $icons;
128
+ }
129
+ }
130
+
131
+ return $transient;
132
+ }
133
+
134
+ /**
135
+ * Auto updater
136
+ *
137
+ * @access private
138
+ * @return void
139
+ */
140
+ private function auto_updater() {
141
+ // Setup the updater.
142
+ $edd_updater = new EDD_SL_Plugin_Updater(
143
+ $this->api_url,
144
+ $this->file,
145
+ array(
146
+ 'version' => $this->version,
147
+ 'license' => $this->license,
148
+ 'item_name' => $this->item_name,
149
+ 'author' => $this->author,
150
+ )
151
+ );
152
+ }
153
+
154
+ /**
155
+ * Add license field to settings
156
+ *
157
+ * @access public
158
+ *
159
+ * @param array $settings Setting data.
160
+ *
161
+ * @return array
162
+ */
163
+ public function settings( $settings ) {
164
+ if ( 'Multisite Add-on' === $this->item_name && ! is_multisite() ) {
165
+ return $settings;
166
+ }
167
+
168
+ if ( 'Multisite Add-on' === $this->item_name && is_multisite() ) {
169
+ if ( ! is_main_site() ) {
170
+ return $settings;
171
+ }
172
+ }
173
+
174
+ $bnfw_license_settings = array(
175
+ array(
176
+ 'id' => $this->item_shortname . '_license_key',
177
+ 'name' => sprintf( /* translators: %1$s Item name. */ esc_html__( '%1$s License Key', 'bnfw' ), $this->item_name ),
178
+ 'desc' => '',
179
+ 'type' => 'license_key',
180
+ 'options' => array( 'is_valid_license_option' => $this->item_shortname . '_license_active' ),
181
+ 'size' => 'regular',
182
+ ),
183
+ );
184
+
185
+ return array_merge( $settings, $bnfw_license_settings );
186
+ }
187
+
188
+ /**
189
+ * Activate the license key
190
+ *
191
+ * @access public
192
+ * @return void
193
+ */
194
+ public function activate_license() {
195
+ if ( ! isset( $_POST['bnfw_licenses'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
196
+ return;
197
+ }
198
+
199
+ if ( ! isset( $_POST['bnfw_licenses'][ $this->item_shortname . '_license_key' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
200
+ return;
201
+ }
202
+
203
+ if ( 'valid' === get_option( $this->item_shortname . '_license_active' ) ) {
204
+ return;
205
+ }
206
+
207
+ $license = sanitize_text_field( $_POST['bnfw_licenses'][ $this->item_shortname . '_license_key' ] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
208
+
209
+ // Data to send to the API.
210
+ $api_params = array(
211
+ 'edd_action' => 'activate_license',
212
+ 'license' => $license,
213
+ 'item_name' => urlencode( $this->item_name ), // phpcs:ignore
214
+ );
215
+
216
+ if ( 'Multisite Add-on' === $this->item_name && is_multisite() ) {
217
+ $api_params['url'] = get_home_url( get_main_site_id() );
218
+ }
219
+
220
+ // Call the API.
221
+ $response = wp_remote_get(
222
+ esc_url_raw( add_query_arg( $api_params, $this->api_url ) ),
223
+ array(
224
+ 'timeout' => 15,
225
+ 'body' => $api_params,
226
+ 'sslverify' => false,
227
+ )
228
+ );
229
+
230
+ // Make sure there are no errors.
231
+ if ( is_wp_error( $response ) ) {
232
+ return;
233
+ }
234
+
235
+ // Decode license data.
236
+ $license_data = json_decode( wp_remote_retrieve_body( $response ) );
237
+
238
+ update_option( $this->item_shortname . '_license_active', $license_data->license );
239
+ }
240
+
241
+ /**
242
+ * Deactivate the license key
243
+ *
244
+ * @access public
245
+ * @return void
246
+ */
247
+ public function deactivate_license() {
248
+ if ( ! isset( $_POST['bnfw_licenses'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
249
+ return;
250
+ }
251
+
252
+ if ( ! isset( $_POST['bnfw_licenses'][ $this->item_shortname . '_license_key' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
253
+ return;
254
+ }
255
+
256
+ // Run on deactivate button press.
257
+ if ( isset( $_POST[ $this->item_shortname . '_license_key_deactivate' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
258
+
259
+ // Data to send to the API.
260
+ $api_params = array(
261
+ 'edd_action' => 'deactivate_license',
262
+ 'license' => $this->license,
263
+ 'item_name' => urlencode( $this->item_name ), // phpcs:ignore
264
+ );
265
+
266
+ if ( 'Multisite Add-on' === $this->item_name && is_multisite() ) {
267
+ $api_params['url'] = get_home_url( get_main_site_id() );
268
+ }
269
+
270
+ // Call the API.
271
+ $response = wp_remote_get(
272
+ esc_url_raw( add_query_arg( $api_params, $this->api_url ) ),
273
+ array(
274
+ 'timeout' => 15,
275
+ 'sslverify' => false,
276
+ )
277
+ );
278
+
279
+ // Make sure there are no errors.
280
+ if ( is_wp_error( $response ) ) {
281
+ return;
282
+ }
283
+
284
+ // Decode the license data.
285
+ $license_data = json_decode( wp_remote_retrieve_body( $response ) );
286
+
287
+ if ( 'deactivated' === $license_data->license ) {
288
+ delete_option( $this->item_shortname . '_license_active' );
289
+ }
290
+ }
291
+ }
292
+ }
293
+ }
includes/notification/post-notification.php CHANGED
@@ -1,33 +1,36 @@
1
- <?php
2
- /**
3
- * Handle post notifications.
4
- *
5
- * @since 1.3.6
6
- */
7
-
8
- /**
9
- * Define the list of post notifications.
10
- *
11
- * @since 1.3.6
12
- *
13
- * @param array $notifications List of post notifications
14
- * @param string $post_type Post type
15
- * @return array Filtered list of post notifications
16
- */
17
- function bnfw_post_notifications( $notifications, $post_type ) {
18
- $notifications[] = 'new-' . $post_type;
19
- $notifications[] = 'update-' . $post_type;
20
- $notifications[] = 'pending-' . $post_type;
21
- $notifications[] = 'future-' . $post_type;
22
- $notifications[] = 'comment-' . $post_type;
23
- $notifications[] = 'moderate-' . $post_type . '-comment';
24
- $notifications[] = 'approve-' . $post_type . '-comment';
25
- if($post_type == 'post'){
26
- $notifications[] = 'new-comment';
27
- $notifications[] = 'new-trackback';
28
- $notifications[] = 'new-pingback';
29
- $notifications[] = 'approve-comment';
30
- }
31
- return $notifications;
32
- }
33
- add_filter( 'bnfw_post_notifications', 'bnfw_post_notifications', 10, 2 );
 
 
 
1
+ <?php
2
+ /**
3
+ * Handle post notifications.
4
+ *
5
+ * @since 1.3.6
6
+ * @package bnfw
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Define the list of post notifications.
13
+ *
14
+ * @since 1.3.6
15
+ *
16
+ * @param array $notifications List of post notifications.
17
+ * @param string $post_type Post type.
18
+ * @return array Filtered list of post notifications.
19
+ */
20
+ function bnfw_post_notifications( $notifications, $post_type ) {
21
+ $notifications[] = 'new-' . $post_type;
22
+ $notifications[] = 'update-' . $post_type;
23
+ $notifications[] = 'pending-' . $post_type;
24
+ $notifications[] = 'future-' . $post_type;
25
+ $notifications[] = 'comment-' . $post_type;
26
+ $notifications[] = 'moderate-' . $post_type . '-comment';
27
+ $notifications[] = 'approve-' . $post_type . '-comment';
28
+ if ( 'post' === $post_type ) {
29
+ $notifications[] = 'new-comment';
30
+ $notifications[] = 'new-trackback';
31
+ $notifications[] = 'new-pingback';
32
+ $notifications[] = 'approve-comment';
33
+ }
34
+ return $notifications;
35
+ }
36
+ add_filter( 'bnfw_post_notifications', 'bnfw_post_notifications', 10, 2 );
includes/overrides.php CHANGED
@@ -1,193 +1,205 @@
1
- <?php
2
- /**
3
- * Override default WordPress emails
4
- *
5
- */
6
-
7
- /**
8
- * Email login credentials to a newly-registered user.
9
- *
10
- * A new user registration notification is also sent to admin email.
11
- *
12
- * @param int $user_id User ID.
13
- * @param null $deprecated Not used (argument deprecated).
14
- * @param string $notify Optional. Type of notification that should happen. Accepts 'admin' or an empty
15
- * string (admin only), or 'both' (admin and user). The empty string value was kept
16
- * for backward-compatibility purposes with the renamed parameter. Default empty.
17
- */
18
- if ( ! function_exists( 'wp_new_user_notification' ) ) {
19
- function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' ) {
20
- global $wp_version, $wp_hasher;
21
-
22
- $bnfw = BNFW::factory();
23
- $user = get_userdata( $user_id );
24
-
25
- if ( version_compare( $wp_version, '4.3', '>=' ) ) {
26
- // for WordPress 4.3 and above
27
-
28
- if ( version_compare( $wp_version, '4.3', '=' ) ) {
29
- $notify = $deprecated;
30
- } else {
31
- if ( $deprecated !== null ) {
32
- _deprecated_argument( __FUNCTION__, '4.3.1' );
33
- }
34
- }
35
-
36
- // The blogname option is escaped with esc_html on the way into the database in sanitize_option
37
- // we want to reverse this for the plain text arena of emails.
38
- $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
39
-
40
- if ( ! $bnfw->notifier->notification_exists( 'admin-user', false ) ) {
41
- $message = sprintf( esc_html__( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
42
- $message .= sprintf( esc_html__( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
43
- $message .= sprintf( esc_html__( 'E-mail: %s' ), $user->user_email ) . "\r\n";
44
-
45
- $wp_new_user_notification_email_admin = array(
46
- 'to' => get_option( 'admin_email' ),
47
- /* translators: Password change notification email subject. %s: Site title */
48
- 'subject' => __( '[%s] New User Registration' ),
49
- 'message' => $message,
50
- 'headers' => '',
51
- );
52
-
53
- /**
54
- * Filters the contents of the new user notification email sent to the site admin.
55
- *
56
- * @since 4.9.0
57
- *
58
- * @param array $wp_new_user_notification_email {
59
- * Used to build wp_mail().
60
- *
61
- * @type string $to The intended recipient - site admin email address.
62
- * @type string $subject The subject of the email.
63
- * @type string $message The body of the email.
64
- * @type string $headers The headers of the email.
65
- * }
66
- *
67
- * @param WP_User $user User object for new user.
68
- * @param string $blogname The site title.
69
- */
70
- $wp_new_user_notification_email_admin = apply_filters( 'wp_new_user_notification_email_admin', $wp_new_user_notification_email_admin, $user, $blogname );
71
-
72
- @wp_mail(
73
- $wp_new_user_notification_email_admin['to'],
74
- wp_specialchars_decode( sprintf( $wp_new_user_notification_email_admin['subject'], $blogname ) ),
75
- $wp_new_user_notification_email_admin['message'],
76
- $wp_new_user_notification_email_admin['headers']
77
- );
78
- }
79
-
80
- if ( 'admin' === $notify || empty( $notify ) ) {
81
- return;
82
- }
83
-
84
- // Generate something random for a password reset key.
85
- $key = wp_generate_password( 20, false );
86
-
87
- /** This action is documented in wp-login.php */
88
- do_action( 'retrieve_password_key', $user->user_login, $key );
89
-
90
- // Now insert the key, hashed, into the DB.
91
- if ( empty( $wp_hasher ) ) {
92
- require_once ABSPATH . WPINC . '/class-phpass.php';
93
- $wp_hasher = new PasswordHash( 8, true );
94
- }
95
- $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
96
-
97
- wp_update_user(
98
- array(
99
- 'ID' => $user->ID,
100
- 'user_activation_key' => $hashed,
101
- )
102
- );
103
-
104
- if ( $bnfw->notifier->notification_exists( 'new-user', false ) ) {
105
- $notifications = $bnfw->notifier->get_notifications( 'new-user' );
106
- $password_url = network_site_url( 'wp-login.php?action=rp&key=' . $key . '&login=' . rawurlencode( $user->user_login ), 'login' );
107
-
108
- foreach ( $notifications as $notification ) {
109
- $setting = $bnfw->notifier->read_settings( $notification->ID );
110
- $trigger_notification = apply_filters( 'bnfw_trigger_new-user_notification', true, $setting, $user );
111
-
112
- if ( $trigger_notification ) {
113
- $bnfw->engine->send_registration_email( $setting, $user, $password_url );
114
- }
115
- }
116
- } else {
117
- $message = sprintf( esc_html__( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
118
- $message .= esc_html__( 'To set your password, visit the following address:' ) . "\r\n\r\n";
119
- $message .= '<' . network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user->user_login ), 'login' ) . ">\r\n\r\n";
120
-
121
- $message .= wp_login_url() . "\r\n";
122
-
123
- wp_mail( $user->user_email, sprintf( esc_html__( '[%s] Your username and password info' ), $blogname ), $message );
124
- }
125
- } else {
126
-
127
- // for WordPress below 4.3
128
- $plaintext_pass = $deprecated;
129
-
130
- // The blogname option is escaped with esc_html on the way into the database in sanitize_option
131
- // we want to reverse this for the plain text arena of emails.
132
- $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
133
-
134
- if ( ! $bnfw->notifier->notification_exists( 'admin-user', false ) ) {
135
- $message = sprintf( esc_html__( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
136
- $message .= sprintf( esc_html__( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
137
- $message .= sprintf( esc_html__( 'E-mail: %s' ), $user->user_email ) . "\r\n";
138
-
139
- @wp_mail( get_option( 'admin_email' ), sprintf( esc_html__( '[%s] New User Registration' ), $blogname ), $message );
140
- }
141
-
142
- if ( empty( $plaintext_pass ) ) {
143
- return;
144
- }
145
-
146
- if ( $bnfw->notifier->notification_exists( 'new-user', false ) ) {
147
- $notifications = $bnfw->notifier->get_notifications( 'new-user' );
148
- foreach ( $notifications as $notification ) {
149
- $bnfw->engine->send_registration_email( $bnfw->notifier->read_settings( $notification->ID ), $user, $plaintext_pass );
150
- }
151
- } else {
152
- $message = sprintf( esc_html__( 'Username: %s' ), $user->user_login ) . "\r\n";
153
- $message .= sprintf( esc_html__( 'Password: %s' ), $plaintext_pass ) . "\r\n";
154
- $message .= wp_login_url() . "\r\n";
155
-
156
- wp_mail( $user->user_email, sprintf( esc_html__( '[%s] Your username and password' ), $blogname ), $message );
157
- }
158
- }
159
- }
160
- }
161
-
162
- if ( ! function_exists( 'wp_password_change_notification' ) ) {
163
- /**
164
- * Notify the blog admin of a user changing password, normally via email.
165
- *
166
- * @param WP_User $user User object.
167
- */
168
- function wp_password_change_notification( $user ) {
169
- $bnfw = BNFW::factory();
170
-
171
- if ( $bnfw->notifier->notification_exists( 'admin-password-changed', false ) ) {
172
- $notifications = $bnfw->notifier->get_notifications( 'admin-password-changed' );
173
-
174
- if ( count( $notifications ) > 0 ) {
175
- // Ideally there should be only one notification for this type.
176
- // If there are multiple notification then we will read data about only the last one
177
- $bnfw->engine->send_notification( $bnfw->notifier->read_settings( end( $notifications )->ID ), $user->ID );
178
- }
179
- } else {
180
- // send a copy of password change notification to the admin
181
- // but check to see if it's the admin whose password we're changing, and skip this.
182
- if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) ) {
183
- /* translators: %s: user name */
184
- $message = sprintf( __( 'Password changed for user: %s' ), $user->user_login ) . "\r\n";
185
- // The blogname option is escaped with esc_html on the way into the database in sanitize_option
186
- // we want to reverse this for the plain text arena of emails.
187
- $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
188
- /* translators: %s: site title */
189
- wp_mail( get_option( 'admin_email' ), sprintf( __( '[%s] Password Changed' ), $blogname ), $message );
190
- }
191
- }
192
- }
193
- }
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Override default WordPress emails
4
+ *
5
+ * @package bnfw
6
+ */
7
+
8
+ if ( ! function_exists( 'wp_new_user_notification' ) ) {
9
+ /**
10
+ * Email login credentials to a newly-registered user.
11
+ *
12
+ * A new user registration notification is also sent to admin email.
13
+ *
14
+ * @param int $user_id User ID.
15
+ * @param null $deprecated Not used (argument deprecated).
16
+ * @param string $notify Optional. Type of notification that should happen. Accepts 'admin' or an empty
17
+ * string (admin only), or 'both' (admin and user). The empty string value was kept
18
+ * for backward-compatibility purposes with the renamed parameter. Default empty.
19
+ */
20
+ function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' ) {
21
+ global $wp_version, $wp_hasher;
22
+
23
+ $bnfw = BNFW::factory();
24
+ $user = get_userdata( $user_id );
25
+
26
+ if ( version_compare( $wp_version, '4.3', '>=' ) ) {
27
+ // for WordPress 4.3 and above.
28
+
29
+ if ( version_compare( $wp_version, '4.3', '=' ) ) {
30
+ $notify = $deprecated;
31
+ } else {
32
+ if ( null !== $deprecated ) {
33
+ _deprecated_argument( __FUNCTION__, '4.3.1' );
34
+ }
35
+ }
36
+
37
+ // The blogname option is escaped with esc_html on the way into the database in sanitize_option
38
+ // we want to reverse this for the plain text arena of emails.
39
+ $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
40
+
41
+ if ( ! $bnfw->notifier->notification_exists( 'admin-user', false ) ) {
42
+ /* translators: %s site name. */
43
+ $message = sprintf( esc_html__( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
44
+ /* translators: %s username. */
45
+ $message .= sprintf( esc_html__( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
46
+ /* translators: %s email. */
47
+ $message .= sprintf( esc_html__( 'E-mail: %s' ), $user->user_email ) . "\r\n";
48
+
49
+ $wp_new_user_notification_email_admin = array(
50
+ 'to' => get_option( 'admin_email' ),
51
+ /* translators: Password change notification email subject. %s: Site title */
52
+ 'subject' => __( '[%s] New User Registration' ),
53
+ 'message' => $message,
54
+ 'headers' => '',
55
+ );
56
+
57
+ /**
58
+ * Filters the contents of the new user notification email sent to the site admin.
59
+ *
60
+ * @since 4.9.0
61
+ *
62
+ * @param array $wp_new_user_notification_email {
63
+ * Used to build wp_mail().
64
+ *
65
+ * @type string $to The intended recipient - site admin email address.
66
+ * @type string $subject The subject of the email.
67
+ * @type string $message The body of the email.
68
+ * @type string $headers The headers of the email.
69
+ * }
70
+ *
71
+ * @param WP_User $user User object for new user.
72
+ * @param string $blogname The site title.
73
+ */
74
+ $wp_new_user_notification_email_admin = apply_filters( 'wp_new_user_notification_email_admin', $wp_new_user_notification_email_admin, $user, $blogname );
75
+
76
+ if ( isset( $wp_new_user_notification_email_admin['to'] ) && ! empty( $wp_new_user_notification_email_admin['to'] ) ) {
77
+ wp_mail(
78
+ $wp_new_user_notification_email_admin['to'],
79
+ wp_specialchars_decode( sprintf( $wp_new_user_notification_email_admin['subject'], $blogname ) ),
80
+ $wp_new_user_notification_email_admin['message'],
81
+ $wp_new_user_notification_email_admin['headers']
82
+ );
83
+ }
84
+ }
85
+
86
+ if ( 'admin' === $notify || empty( $notify ) ) {
87
+ return;
88
+ }
89
+
90
+ // Generate something random for a password reset key.
91
+ $key = wp_generate_password( 20, false );
92
+
93
+ /** This action is documented in wp-login.php */
94
+ do_action( 'retrieve_password_key', $user->user_login, $key );
95
+
96
+ // Now insert the key, hashed, into the DB.
97
+ if ( empty( $wp_hasher ) ) {
98
+ require_once ABSPATH . WPINC . '/class-phpass.php';
99
+ $wp_hasher = new PasswordHash( 8, true ); // phpcs:ignore
100
+ }
101
+ $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
102
+
103
+ wp_update_user(
104
+ array(
105
+ 'ID' => $user->ID,
106
+ 'user_activation_key' => $hashed,
107
+ )
108
+ );
109
+
110
+ if ( $bnfw->notifier->notification_exists( 'new-user', false ) ) {
111
+ $notifications = $bnfw->notifier->get_notifications( 'new-user' );
112
+ $password_url = network_site_url( 'wp-login.php?action=rp&key=' . $key . '&login=' . rawurlencode( $user->user_login ), 'login' );
113
+
114
+ foreach ( $notifications as $notification ) {
115
+ $setting = $bnfw->notifier->read_settings( $notification->ID );
116
+ $trigger_notification = apply_filters( 'bnfw_trigger_new-user_notification', true, $setting, $user );
117
+
118
+ if ( $trigger_notification ) {
119
+ $bnfw->engine->send_registration_email( $setting, $user, $password_url );
120
+ }
121
+ }
122
+ } else {
123
+ /* translators: %s username. */
124
+ $message = sprintf( esc_html__( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
125
+ $message .= esc_html__( 'To set your password, visit the following address:' ) . "\r\n\r\n";
126
+ $message .= '<' . network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user->user_login ), 'login' ) . ">\r\n\r\n";
127
+
128
+ $message .= wp_login_url() . "\r\n";
129
+ /* translators: %s message. */
130
+ wp_mail( $user->user_email, sprintf( esc_html__( '[%s] Your username and password info' ), $blogname ), $message );
131
+ }
132
+ } else {
133
+
134
+ // for WordPress below 4.3,.
135
+ $plaintext_pass = $deprecated;
136
+
137
+ // The blogname option is escaped with esc_html on the way into the database in sanitize_option
138
+ // we want to reverse this for the plain text arena of emails.
139
+ $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
140
+
141
+ if ( ! $bnfw->notifier->notification_exists( 'admin-user', false ) ) {
142
+ /* translators: %s site name. */
143
+ $message = sprintf( esc_html__( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
144
+ /* translators: %s username. */
145
+ $message .= sprintf( esc_html__( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
146
+ /* translators: %s email. */
147
+ $message .= sprintf( esc_html__( 'E-mail: %s' ), $user->user_email ) . "\r\n";
148
+ /* translators: %s Blogname. */
149
+ wp_mail( get_option( 'admin_email' ), sprintf( esc_html__( '[%s] New User Registration' ), $blogname ), $message );
150
+ }
151
+
152
+ if ( empty( $plaintext_pass ) ) {
153
+ return;
154
+ }
155
+
156
+ if ( $bnfw->notifier->notification_exists( 'new-user', false ) ) {
157
+ $notifications = $bnfw->notifier->get_notifications( 'new-user' );
158
+ foreach ( $notifications as $notification ) {
159
+ $bnfw->engine->send_registration_email( $bnfw->notifier->read_settings( $notification->ID ), $user, $plaintext_pass );
160
+ }
161
+ } else {
162
+ /* translators: %s username. */
163
+ $message = sprintf( esc_html__( 'Username: %s' ), $user->user_login ) . "\r\n";
164
+ /* translators: %s password. */
165
+ $message .= sprintf( esc_html__( 'Password: %s' ), $plaintext_pass ) . "\r\n";
166
+ $message .= wp_login_url() . "\r\n";
167
+ /* translators: %s blogname. */
168
+ wp_mail( $user->user_email, sprintf( esc_html__( '[%s] Your username and password' ), $blogname ), $message );
169
+ }
170
+ }
171
+ }
172
+ }
173
+
174
+ if ( ! function_exists( 'wp_password_change_notification' ) ) {
175
+ /**
176
+ * Notify the blog admin of a user changing password, normally via email.
177
+ *
178
+ * @param WP_User $user User object.
179
+ */
180
+ function wp_password_change_notification( $user ) {
181
+ $bnfw = BNFW::factory();
182
+
183
+ if ( $bnfw->notifier->notification_exists( 'admin-password-changed', false ) ) {
184
+ $notifications = $bnfw->notifier->get_notifications( 'admin-password-changed' );
185
+
186
+ if ( count( $notifications ) > 0 ) {
187
+ // Ideally there should be only one notification for this type.
188
+ // If there are multiple notification then we will read data about only the last one.
189
+ $bnfw->engine->send_notification( $bnfw->notifier->read_settings( end( $notifications )->ID ), $user->ID );
190
+ }
191
+ } else {
192
+ // send a copy of password change notification to the admin
193
+ // but check to see if it's the admin whose password we're changing, and skip this.
194
+ if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) ) {
195
+ /* translators: %s: user name */
196
+ $message = sprintf( __( 'Password changed for user: %s' ), $user->user_login ) . "\r\n";
197
+ // The blogname option is escaped with esc_html on the way into the database in sanitize_option
198
+ // we want to reverse this for the plain text arena of emails.
199
+ $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
200
+ /* translators: %s: site title */
201
+ wp_mail( get_option( 'admin_email' ), sprintf( __( '[%s] Password Changed' ), $blogname ), $message );
202
+ }
203
+ }
204
+ }
205
+ }
vendor/persist-admin-notices-dismissal/persist-admin-notices-dismissal.php CHANGED
@@ -1,187 +1,187 @@
1
- <?php
2
- /**
3
- * Persist Admin notices Dismissal
4
- *
5
- * Copyright (C) 2016 Collins Agbonghama <https://w3guy.com>
6
- *
7
- * This program is free software: you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License as published by
9
- * the Free Software Foundation, either version 3 of the License, or
10
- * (at your option) any later version.
11
- *
12
- * This program is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- * GNU General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU General Public License
18
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
19
- *
20
- * @package Persist Admin notices Dismissal
21
- * @author Collins Agbonghama, Andy Fragen
22
- * @license http://www.gnu.org/licenses GNU General Public License
23
- */
24
-
25
- /**
26
- * Exit if called directly.
27
- */
28
- if ( ! defined( 'ABSPATH' ) ) {
29
- die;
30
- }
31
-
32
- if ( ! class_exists( 'PAnD' ) ) {
33
-
34
- /**
35
- * Class PAnD
36
- */
37
- class PAnD {
38
-
39
- /**
40
- * Init hooks.
41
- */
42
- public static function init() {
43
- add_action( 'admin_enqueue_scripts', array( __CLASS__, 'load_script' ) );
44
- add_action( 'wp_ajax_dismiss_admin_notice', array( __CLASS__, 'dismiss_admin_notice' ) );
45
-
46
- /**
47
- * Filter to activate another filter providing a simpler use case.
48
- *
49
- * @since 1.4.3
50
- *
51
- * @param bool
52
- */
53
- if ( apply_filters( 'pand_theme_loader', false ) ) {
54
- add_filter(
55
- 'pand_dismiss_notice_js_url',
56
- function( $js_url, $composer_path ) {
57
- return get_stylesheet_directory_uri() . $composer_path;
58
- },
59
- 10,
60
- 2
61
- );
62
- }
63
- }
64
-
65
- /**
66
- * Enqueue javascript and variables.
67
- */
68
- public static function load_script() {
69
-
70
- if ( is_customize_preview() ) {
71
- return;
72
- }
73
-
74
- $js_url = plugins_url( 'dismiss-notice.js', __FILE__ );
75
- $composer_path = '/vendor/collizo4sky/persist-admin-notices-dismissal/dismiss-notice.js';
76
-
77
- /**
78
- * Filter dismiss-notice.js URL.
79
- *
80
- * @since 1.4.3
81
- *
82
- * @param string $js_url URL to the Javascript file.
83
- * @param string $composer_path Relative path of Javascript file from composer install.
84
- */
85
- $js_url = apply_filters( 'pand_dismiss_notice_js_url', $js_url, $composer_path );
86
- wp_enqueue_script(
87
- 'dismissible-notices',
88
- $js_url,
89
- array( 'jquery', 'common' ),
90
- false,
91
- true
92
- );
93
-
94
- wp_localize_script(
95
- 'dismissible-notices',
96
- 'dismissible_notice',
97
- array(
98
- 'nonce' => wp_create_nonce( 'dismissible-notice' ),
99
- )
100
- );
101
- }
102
-
103
- /**
104
- * Handles Ajax request to persist notices dismissal.
105
- * Uses check_ajax_referer to verify nonce.
106
- */
107
- public static function dismiss_admin_notice() {
108
- $option_name = isset( $_POST['option_name'] ) ? sanitize_text_field( wp_unslash( $_POST['option_name'] ) ) : '';
109
- $dismissible_length = isset( $_POST['dismissible_length'] ) ? sanitize_text_field( wp_unslash( $_POST['dismissible_length'] ) ) : 0;
110
-
111
- if ( 'forever' !== $dismissible_length ) {
112
- // If $dismissible_length is not an integer default to 1.
113
- $dismissible_length = ( 0 === absint( $dismissible_length ) ) ? 1 : $dismissible_length;
114
- $dismissible_length = strtotime( absint( $dismissible_length ) . ' days' );
115
- }
116
-
117
- check_ajax_referer( 'dismissible-notice', 'nonce' );
118
- self::set_admin_notice_cache( $option_name, $dismissible_length );
119
- wp_die();
120
- }
121
-
122
- /**
123
- * Is admin notice active?
124
- *
125
- * @param string $arg data-dismissible content of notice.
126
- *
127
- * @return bool
128
- */
129
- public static function is_admin_notice_active( $arg ) {
130
- $array = explode( '-', $arg );
131
- $length = array_pop( $array );
132
- $option_name = implode( '-', $array );
133
- $db_record = self::get_admin_notice_cache( $option_name );
134
-
135
- if ( 'forever' === $db_record ) {
136
- return false;
137
- } elseif ( absint( $db_record ) >= time() ) {
138
- return false;
139
- } else {
140
- return true;
141
- }
142
- }
143
-
144
- /**
145
- * Returns admin notice cached timeout.
146
- *
147
- * @access public
148
- *
149
- * @param string|bool $id admin notice name or false.
150
- *
151
- * @return array|bool The timeout. False if expired.
152
- */
153
- public static function get_admin_notice_cache( $id = false ) {
154
- if ( ! $id ) {
155
- return false;
156
- }
157
- $cache_key = 'pand-' . md5( $id );
158
- $timeout = get_site_option( $cache_key );
159
- $timeout = 'forever' === $timeout ? time() + 60 : $timeout;
160
-
161
- if ( empty( $timeout ) || time() > $timeout ) {
162
- return false;
163
- }
164
-
165
- return $timeout;
166
- }
167
-
168
- /**
169
- * Sets admin notice timeout in site option.
170
- *
171
- * @access public
172
- *
173
- * @param string $id Data Identifier.
174
- * @param string|bool $timeout Timeout for admin notice.
175
- *
176
- * @return bool
177
- */
178
- public static function set_admin_notice_cache( $id, $timeout ) {
179
- $cache_key = 'pand-' . md5( $id );
180
- update_site_option( $cache_key, $timeout );
181
-
182
- return true;
183
- }
184
-
185
- }
186
-
187
- }
1
+ <?php
2
+ /**
3
+ * Persist Admin notices Dismissal
4
+ *
5
+ * Copyright (C) 2016 Collins Agbonghama <https://w3guy.com>
6
+ *
7
+ * This program is free software: you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation, either version 3 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+ *
20
+ * @package Persist Admin notices Dismissal
21
+ * @author Collins Agbonghama, Andy Fragen
22
+ * @license http://www.gnu.org/licenses GNU General Public License
23
+ */
24
+
25
+ /**
26
+ * Exit if called directly.
27
+ */
28
+ if ( ! defined( 'ABSPATH' ) ) {
29
+ die;
30
+ }
31
+
32
+ if ( ! class_exists( 'PAnD' ) ) {
33
+
34
+ /**
35
+ * Class PAnD
36
+ */
37
+ class PAnD {
38
+
39
+ /**
40
+ * Init hooks.
41
+ */
42
+ public static function init() {
43
+ add_action( 'admin_enqueue_scripts', array( __CLASS__, 'load_script' ) );
44
+ add_action( 'wp_ajax_dismiss_admin_notice', array( __CLASS__, 'dismiss_admin_notice' ) );
45
+
46
+ /**
47
+ * Filter to activate another filter providing a simpler use case.
48
+ *
49
+ * @since 1.4.3
50
+ *
51
+ * @param bool
52
+ */
53
+ if ( apply_filters( 'pand_theme_loader', false ) ) {
54
+ add_filter(
55
+ 'pand_dismiss_notice_js_url',
56
+ function( $js_url, $composer_path ) {
57
+ return get_stylesheet_directory_uri() . $composer_path;
58
+ },
59
+ 10,
60
+ 2
61
+ );
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Enqueue javascript and variables.
67
+ */
68
+ public static function load_script() {
69
+
70
+ if ( is_customize_preview() ) {
71
+ return;
72
+ }
73
+
74
+ $js_url = plugins_url( 'dismiss-notice.js', __FILE__ );
75
+ $composer_path = '/vendor/collizo4sky/persist-admin-notices-dismissal/dismiss-notice.js';
76
+
77
+ /**
78
+ * Filter dismiss-notice.js URL.
79
+ *
80
+ * @since 1.4.3
81
+ *
82
+ * @param string $js_url URL to the Javascript file.
83
+ * @param string $composer_path Relative path of Javascript file from composer install.
84
+ */
85
+ $js_url = apply_filters( 'pand_dismiss_notice_js_url', $js_url, $composer_path );
86
+ wp_enqueue_script(
87
+ 'dismissible-notices',
88
+ $js_url,
89
+ array( 'jquery', 'common' ),
90
+ false,
91
+ true
92
+ );
93
+
94
+ wp_localize_script(
95
+ 'dismissible-notices',
96
+ 'dismissible_notice',
97
+ array(
98
+ 'nonce' => wp_create_nonce( 'dismissible-notice' ),
99
+ )
100
+ );
101
+ }
102
+
103
+ /**
104
+ * Handles Ajax request to persist notices dismissal.
105
+ * Uses check_ajax_referer to verify nonce.
106
+ */
107
+ public static function dismiss_admin_notice() {
108
+ $option_name = isset( $_POST['option_name'] ) ? sanitize_text_field( wp_unslash( $_POST['option_name'] ) ) : '';
109
+ $dismissible_length = isset( $_POST['dismissible_length'] ) ? sanitize_text_field( wp_unslash( $_POST['dismissible_length'] ) ) : 0;
110
+
111
+ if ( 'forever' !== $dismissible_length ) {
112
+ // If $dismissible_length is not an integer default to 1.
113
+ $dismissible_length = ( 0 === absint( $dismissible_length ) ) ? 1 : $dismissible_length;
114
+ $dismissible_length = strtotime( absint( $dismissible_length ) . ' days' );
115
+ }
116
+
117
+ check_ajax_referer( 'dismissible-notice', 'nonce' );
118
+ self::set_admin_notice_cache( $option_name, $dismissible_length );
119
+ wp_die();
120
+ }
121
+
122
+ /**
123
+ * Is admin notice active?
124
+ *
125
+ * @param string $arg data-dismissible content of notice.
126
+ *
127
+ * @return bool
128
+ */
129
+ public static function is_admin_notice_active( $arg ) {
130
+ $array = explode( '-', $arg );
131
+ $length = array_pop( $array );
132
+ $option_name = implode( '-', $array );
133
+ $db_record = self::get_admin_notice_cache( $option_name );
134
+
135
+ if ( 'forever' === $db_record ) {
136
+ return false;
137
+ } elseif ( absint( $db_record ) >= time() ) {
138
+ return false;
139
+ } else {
140
+ return true;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Returns admin notice cached timeout.
146
+ *
147
+ * @access public
148
+ *
149
+ * @param string|bool $id admin notice name or false.
150
+ *
151
+ * @return array|bool The timeout. False if expired.
152
+ */
153
+ public static function get_admin_notice_cache( $id = false ) {
154
+ if ( ! $id ) {
155
+ return false;
156
+ }
157
+ $cache_key = 'pand-' . md5( $id );
158
+ $timeout = get_site_option( $cache_key );
159
+ $timeout = 'forever' === $timeout ? time() + 60 : $timeout;
160
+
161
+ if ( empty( $timeout ) || time() > $timeout ) {
162
+ return false;
163
+ }
164
+
165
+ return $timeout;
166
+ }
167
+
168
+ /**
169
+ * Sets admin notice timeout in site option.
170
+ *
171
+ * @access public
172
+ *
173
+ * @param string $id Data Identifier.
174
+ * @param string|bool $timeout Timeout for admin notice.
175
+ *
176
+ * @return bool
177
+ */
178
+ public static function set_admin_notice_cache( $id, $timeout ) {
179
+ $cache_key = 'pand-' . md5( $id );
180
+ update_site_option( $cache_key, $timeout );
181
+
182
+ return true;
183
+ }
184
+
185
+ }
186
+
187
+ }