Site Reviews - Version 5.2.0

Version Description

(2020-11-06) =

  • Added Notification Template tags for assigned categories, posts, and users
  • Added Review Assignment setting
  • Changed review assignment in SQL queries to use strict assignments by default (it was previously using loose assignments, use the new "Review Assignment" setting to change this back)
  • Changed the glsr_create_review function to log validation errors to the plugin console
  • Fixed Bulk Editing of reviews that are assigned to post types or users
  • Fixed Multibyte String support
  • Fixed Multisite compatibility
  • Fixed pagination URLs when used on the homepage
  • Fixed rating validation when using a custom maximum rating value
  • Fixed review limits validation for assigned reviews
  • Fixed review migration of invalid 3rd-party reviews (reviews that were previously imported incorrectly)
  • Fixed review name and email fallback values to use those of the logged-in user
  • Fixed the submission date of reviews, it now uses the timezone offset in the WordPress settings
Download this release

Release Info

Developer geminilabs
Plugin Icon 128x128 Site Reviews
Version 5.2.0
Comparing to
See all releases

Code changes from version 5.1.6 to 5.2.0

Files changed (80) hide show
  1. assets/scripts/mce-plugin.js +1 -1
  2. assets/scripts/site-reviews.js +1 -1
  3. autoload.php +7 -2
  4. compatibility.php +0 -11
  5. config/forms/metabox-fields.php +1 -1
  6. config/settings.php +15 -1
  7. helpers.php +2 -1
  8. languages/site-reviews-en_US.mo +0 -0
  9. languages/site-reviews-en_US.po +203 -144
  10. languages/site-reviews.pot +183 -138
  11. plugin/Addons/Addon.php +1 -1
  12. plugin/Addons/Updater.php +3 -2
  13. plugin/Application.php +28 -79
  14. plugin/Commands/CreateReview.php +4 -2
  15. plugin/Commands/RegisterPostType.php +1 -1
  16. plugin/Controllers/AdminController.php +17 -0
  17. plugin/Controllers/Controller.php +2 -2
  18. plugin/Controllers/ListTableColumns/ColumnFilterType.php +2 -2
  19. plugin/Controllers/ListTableColumns/ColumnValueType.php +1 -3
  20. plugin/Controllers/MainController.php +79 -0
  21. plugin/Controllers/MenuController.php +2 -2
  22. plugin/Controllers/MetaboxController.php +1 -1
  23. plugin/Controllers/RestReviewController.php +1 -1
  24. plugin/Controllers/ReviewController.php +78 -21
  25. plugin/Controllers/ToolsController.php +12 -8
  26. plugin/Database.php +61 -13
  27. plugin/Database/NormalizePaginationArgs.php +5 -6
  28. plugin/Database/NormalizeQueryArgs.php +1 -1
  29. plugin/Database/OptionManager.php +2 -2
  30. plugin/Database/ReviewManager.php +0 -1
  31. plugin/Database/Sql.php +1 -2
  32. plugin/Database/SqlSchema.php +211 -113
  33. plugin/Defaults/CreateReviewDefaults.php +2 -2
  34. plugin/Defaults/TemplateTagsDefaults.php +3 -0
  35. plugin/Helpers/Arr.php +3 -3
  36. plugin/Helpers/Url.php +2 -2
  37. plugin/Hooks.php +9 -6
  38. plugin/Install.php +149 -0
  39. plugin/Modules/Avatar.php +2 -2
  40. plugin/Modules/Console.php +1 -0
  41. plugin/Modules/Honeypot.php +1 -0
  42. plugin/Modules/Html/ReviewsHtml.php +1 -2
  43. plugin/Modules/Html/Settings.php +5 -0
  44. plugin/Modules/Migrations/Migrate_5_0_0/MigrateReviews.php +9 -3
  45. plugin/Modules/Migrations/Migrate_5_2_0.php +14 -0
  46. plugin/Modules/Notification.php +33 -0
  47. plugin/Modules/Sanitizer.php +33 -3
  48. plugin/Modules/Schema.php +7 -4
  49. plugin/Modules/Style.php +1 -1
  50. plugin/Modules/System.php +0 -382
  51. plugin/Modules/SystemInfo.php +458 -0
  52. plugin/Modules/Validator/AkismetValidator.php +1 -1
  53. plugin/Modules/Validator/DefaultValidator.php +19 -2
  54. plugin/Modules/Validator/ReviewLimitsValidator.php +1 -10
  55. plugin/Review.php +46 -3
  56. plugin/Role.php +12 -6
  57. plugin/Router.php +1 -1
  58. plugin/Storage.php +12 -0
  59. plugin/Tinymce/TinymceGenerator.php +2 -2
  60. plugin/Widgets/SiteReviewsSummaryWidget.php +2 -2
  61. plugin/Widgets/SiteReviewsWidget.php +2 -2
  62. readme.txt +19 -4
  63. site-reviews.php +1 -2
  64. uninstall.php +129 -48
  65. views/pages/documentation/faq/hide-form-after-submission.php +3 -3
  66. views/pages/documentation/functions/glsr_create_review.php +5 -0
  67. views/pages/documentation/functions/glsr_get_reviews.php +3 -3
  68. views/pages/tools/general.php +6 -2
  69. views/pages/welcome/whatsnew.php +1 -0
  70. views/pages/welcome/whatsnew/v40.php +4 -4
  71. views/pages/welcome/whatsnew/v41.php +4 -4
  72. views/pages/welcome/whatsnew/v42.php +3 -3
  73. views/pages/welcome/whatsnew/v43.php +3 -3
  74. views/pages/welcome/whatsnew/v44.php +3 -3
  75. views/pages/welcome/whatsnew/v45.php +2 -2
  76. views/pages/welcome/whatsnew/v46.php +3 -3
  77. views/pages/welcome/whatsnew/v50.php +1 -1
  78. views/pages/welcome/whatsnew/v51.php +2 -2
  79. views/pages/welcome/whatsnew/v52.php +38 -0
  80. views/partials/notices/addons.php +1 -1
assets/scripts/mce-plugin.js CHANGED
@@ -1 +1 @@
1
- "use strict";window.tinymce.PluginManager.add("glsr_shortcode",function(o){o.addCommand("GLSR_Shortcode",function(){GLSR.shortcode.create(o.id)})});
1
+ !function(o){"use strict";window.tinymce.PluginManager.add("glsr_shortcode",function(o){o.addCommand("GLSR_Shortcode",function(){GLSR.shortcode.create(o.id)})})}();
assets/scripts/site-reviews.js CHANGED
@@ -1,2 +1,2 @@
1
  /*! For license information please see site-reviews.js.LICENSE.txt */
2
- !function(t){var i={};function n(s){if(i[s])return i[s].exports;var e=i[s]={i:s,l:!1,exports:{}};return t[s].call(e.exports,e,e.exports,n),e.l=!0,e.exports}n.m=t,n.c=i,n.d=function(t,i,s){n.o(t,i)||Object.defineProperty(t,i,{enumerable:!0,get:s})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,i){if(1&i&&(t=n(t)),8&i)return t;if(4&i&&"object"==typeof t&&t&&t.__esModule)return t;var s=Object.create(null);if(n.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:t}),2&i&&"string"!=typeof t)for(var e in t)n.d(s,e,function(i){return t[i]}.bind(null,e));return s},n.n=function(t){var i=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(i,"a",i),i},n.o=function(t,i){return Object.prototype.hasOwnProperty.call(t,i)},n.p="/",n(n.s=7)}([,function(t,i){function n(i){return"function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?t.exports=n=function(t){return typeof t}:t.exports=n=function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(i)}t.exports=n},function(t,i,n){var s;!function(n,e,h){"use strict";var o=function(t,i){var n={}.toString.call(t);this.selects="[object String]"===n?e.querySelectorAll(t):"[object NodeList]"===n?t:[t],this.destroy=function(){this.widgets.forEach((function(t){t.h()}))},this.rebuild=function(){this.widgets.forEach((function(t){t.u()}))},this.widgets=[];for(var s=0;s<this.selects.length;s++)if("SELECT"===this.selects[s].tagName&&!this.selects[s]["star-rating"]){var h=new r(this.selects[s],i);void 0!==h.direction&&this.widgets.push(h)}},r=function(t,i){this.el=t,this.v=this._({},this.g,i||{},JSON.parse(t.getAttribute("data-options"))),this.S(),this.stars<1||this.stars>this.v.maxStars||this.u()};r.prototype={g:{classname:"gl-star-rating",clearable:!0,initialText:"Select a Rating",maxStars:10,showText:!0},L:function(){this.R(),this.current=this.selected=this.j(),this.F(),this.G(),this.T(),this.O(this.current),this.M("add"),this.el["star-rating"]=!0},k:function(){this.v.showText&&(this.textEl=this.C(this.widgetEl,{class:this.v.classname+"-text"},!0))},G:function(){var t=this.N(),i=this.C(this.el,{class:this.v.classname+"-stars"},!0);for(var n in t){var s=this.D({"data-value":n,"data-text":t[n]});i.innerHTML+=s.outerHTML}this.widgetEl=i,this.k()},I:function(t){(t<0||isNaN(t))&&(t=0),t>this.stars&&(t=this.stars),this.widgetEl.classList.remove("s"+10*this.current),this.widgetEl.classList.add("s"+10*t),this.v.showText&&(this.textEl.textContent=t<1?this.v.initialText:this.widgetEl.childNodes[t-1].dataset.text),this.current=t},D:function(t){var i=e.createElement("span");for(var n in t=t||{})i.setAttribute(n,t[n]);return i},h:function(){this.M("remove");var t=this.el.parentNode;t.parentNode.replaceChild(this.el,t),delete this.el["star-rating"]},q:function(t,i,n,s){s=s||!1,n.forEach(function(n){this.events&&t[i+"EventListener"](n,this.events[n],s)}.bind(this))},_:function(){var t=[].slice.call(arguments),i=t[0],n=t.slice(1);return Object.keys(n).forEach((function(t){for(var s in n[t])n[t].hasOwnProperty(s)&&(i[s]=n[t][s])})),i},V:function(){var t=!1;try{var i=Object.defineProperty({},"passive",{get:function(){t={passive:!1}}});n.addEventListener("test",null,i)}catch(t){}return t},A:function(t){var i={},n=t.pageX||t.changedTouches[0].pageX,s=this.widgetEl.offsetWidth;return i.ltr=Math.max(n-this.offsetLeft,1),i.rtl=s-i.ltr,Math.min(Math.ceil(i[this.direction]/Math.round(s/this.stars)),this.stars)},N:function(){for(var t=this.el,i={},n={},s=0;s<t.length;s++)this.H(t[s])||(i[t[s].value]=t[s].text);return Object.keys(i).sort().forEach((function(t){n[t]=i[t]})),n},j:function(){return parseInt(this.el.options[Math.max(this.el.selectedIndex,0)].value)||0},M:function(t){var i=this.el.closest("form");i&&"FORM"===i.tagName&&this.q(i,t,["reset"]),"add"===t&&this.el.disabled||(this.q(this.el,t,["change","keydown"]),this.q(this.widgetEl,t,["mousedown","mouseleave","mousemove","mouseover","touchend","touchmove","touchstart"],this.V()))},R:function(){this.events={change:this.P.bind(this),keydown:this.B.bind(this),mousedown:this.U.bind(this),mouseleave:this.W.bind(this),mousemove:this.X.bind(this),mouseover:this.J.bind(this),reset:this.Y.bind(this),touchend:this.U.bind(this),touchmove:this.X.bind(this),touchstart:this.J.bind(this)}},C:function(t,i,n){var s=this.D(i);return t.parentNode.insertBefore(s,!0===n?t.nextSibling:t),s},H:function(t){return null===t.getAttribute("value")||""===t.value},P:function(){this.I(this.j())},B:function(t){if(~["ArrowLeft","ArrowRight"].indexOf(t.key)){var i="ArrowLeft"===t.key?-1:1;"rtl"===this.direction&&(i*=-1),this.O(Math.min(Math.max(this.j()+i,0),this.stars)),this.K()}},U:function(t){t.preventDefault();var i=this.A(t);0!==this.current&&parseFloat(this.selected)===i&&this.v.clearable&&(i=0),this.O(i),this.K()},W:function(t){t.preventDefault(),this.I(this.selected)},X:function(t){t.preventDefault(),this.I(this.A(t))},J:function(t){t.preventDefault();var i=this.widgetEl.getBoundingClientRect();this.offsetLeft=i.left+e.body.scrollLeft},Y:function(){var t=this.el.querySelector("[selected]"),i=t?t.value:"";this.el.value=i,this.selected=parseInt(i)||0,this.I(i)},u:function(){this.el.parentNode.classList.contains(this.v.classname)&&this.h(),this.L()},T:function(){var t=this.el.parentNode;this.direction=n.getComputedStyle(t,null).getPropertyValue("direction"),t.classList.add(this.v.classname+"-"+this.direction)},O:function(t){this.el.value=this.selected=t,this.I(t)},S:function(){var t=this.el;this.stars=0;for(var i=0;i<t.length;i++)if(!this.H(t[i])){if(isNaN(parseFloat(t[i].value))||!isFinite(t[i].value))return void(this.stars=0);this.stars++}},K:function(){this.el.dispatchEvent(new Event("change"))},F:function(){this.C(this.el,{class:this.v.classname,"data-star-rating":""}).appendChild(this.el)}},void 0===(s=function(){return o}.apply(i,[]))||(t.exports=s)}(window,document)},,,,,function(t,i,n){n(28),n(59),n(64),n(66),n(68),n(70),n(72),n(74),n(76),n(78),n(80),n(82),n(84),n(86),n(88),n(90),n(92),n(94),n(96),n(98),n(100),n(102),n(104),n(106),n(108),n(110),n(112),n(114),t.exports=n(116)},,,,,,,,,,,,,,,,,,,,,function(t,i,n){"use strict";n.r(i);var s=n(1),e=n.n(s),h=function(){};h.prototype={get:function(t,i,n){this.$(i),this.xhr.open("GET",t,!0),this.xhr.responseType="text",this.Z(n),this.xhr.send()},tt:function(t){return"json"===this.xhr.responseType||!0===this.xhr.json?t({message:this.xhr.statusText},!1):"text"===this.xhr.responseType?t(this.xhr.statusText):void 0},it:function(t){if(0===this.xhr.status||this.xhr.status>=200&&this.xhr.status<300||304===this.xhr.status){if("json"===this.xhr.responseType)return t(this.xhr.response.data,this.xhr.response.success);if("text"===this.xhr.responseType)return t(this.xhr.responseText);if(!0===this.xhr.json){var i=JSON.parse(this.xhr.response);return t(i.data,i.success)}}else this.tt(t)},isFileSupported:function(){var t=document.createElement("INPUT");return t.type="file","files"in t},isFormDataSupported:function(){return!!window.FormData},isUploadSupported:function(){var t=new XMLHttpRequest;return!!(t&&"upload"in t&&"onprogress"in t.upload)},post:function(t,i,n){this.$(i),this.xhr.open("POST",GLSR.ajaxurl,!0),this.xhr.responseType="json",this.xhr.json=!0,this.Z(n),this.xhr.send(this.nt(t))},$:function(t){this.xhr=new XMLHttpRequest,this.xhr.onload=this.it.bind(this,t),this.xhr.onerror=this.tt.bind(this,t)},st:function(t,i,n){return"object"!==e()(i)||i instanceof Date||i instanceof File?t.append(n,i||""):Object.keys(i).forEach(function(s){i.hasOwnProperty(s)&&(t=this.st(t,i[s],n?n[s]:s))}.bind(this)),t},nt:function(t){var i=new FormData,n=Object.prototype.toString.call(t);return"[object FormData]"===n&&(i=t),"[object HTMLFormElement]"===n&&(i=new FormData(t)),"[object Object]"===n&&Object.keys(t).forEach((function(n){i.append(n,t[n])})),i.append("action",GLSR.action),i.append("_ajax_request",!0),i},Z:function(t){for(var i in(t=t||{})["X-Requested-With"]="XMLHttpRequest",t)t.hasOwnProperty(i)&&this.xhr.setRequestHeader(i,t[i])}};var o=h,r=function(t){this.L(t||document)};r.prototype={config:{hiddenClass:"glsr-hidden",hiddenTextSelector:".glsr-hidden-text",readMoreClass:"glsr-read-more",visibleClass:"glsr-visible"},et:function(t){var i=document.createElement("span"),n=document.createElement("a");n.setAttribute("href","#"),n.setAttribute("data-text",t.getAttribute("data-show-less")),n.innerHTML=t.getAttribute("data-show-more"),n.addEventListener("click",this.ht.bind(this)),i.setAttribute("class",this.config.readMoreClass),i.appendChild(n),t.parentNode.insertBefore(i,t.nextSibling)},ht:function(t){t.preventDefault();var i=t.currentTarget,n=i.parentNode.previousSibling,s=i.getAttribute("data-text");n.classList.toggle(this.config.hiddenClass),n.classList.toggle(this.config.visibleClass),i.setAttribute("data-text",i.innerText),i.innerText=s},L:function(t){for(var i=t.querySelectorAll(this.config.hiddenTextSelector),n=0;n<i.length;n++)this.et(i[n])}};var a=r,u=function(t){this.Form=t,this.counter=0,this.id=-1,this.is_submitting=!1,this.recaptchaEl=t.form.querySelector(".glsr-recaptcha-holder"),this.observer=new MutationObserver(function(t){var i=t.pop();i.target&&"visible"!==i.target.style.visibility&&(this.observer.disconnect(),setTimeout(function(){this.is_submitting||this.Form.ot()}.bind(this),250))}.bind(this))};u.prototype={h:function(){this.counter=0,this.id=-1,this.is_submitting=!1,this.recaptchaEl&&(this.recaptchaEl.innerHTML="")},rt:function(){if(-1!==this.id)return this.counter=0,this.at(this.id),void grecaptcha.execute(this.id);setTimeout(function(){this.counter++,this.ut.call(this.Form,this.counter)}.bind(this),1e3)},at:function(t){var i=window.___grecaptcha_cfg.clients[t];for(var n in i)if(i.hasOwnProperty(n)&&"[object String]"===Object.prototype.toString.call(i[n])){var s=document.querySelector("iframe[name=c-"+i[n]+"]");if(s){this.observer.observe(s.parentElement.parentElement,{attributeFilter:["style"],attributes:!0});break}}},ct:function(){this.Form.form.onsubmit=null,this.h(),this.ft()},ft:function(){this.recaptchaEl&&setTimeout(function(){if("undefined"==typeof grecaptcha||void 0===grecaptcha.render)return this.ft();this.id=grecaptcha.render(this.recaptchaEl,{callback:this.ut.bind(this.Form,this.counter),"expired-callback":this.lt.bind(this),isolated:!0},!0)}.bind(this),250)},lt:function(){this.counter=0,this.is_submitting=!1,-1!==this.id&&grecaptcha.reset(this.id)},ut:function(t){if(this.recaptcha.is_submitting=!0,!this.useAjax)return this.dt(),void this.form.submit();this.ut(t)}};var c=u,f=n(2),l=n.n(f),d=function(t,i,n){t&&i.split(" ").forEach((function(i){t.classList[n?"add":"remove"](i)}))},v=function(t){return"."+t.trim().split(" ").join(".")},m=function(t){var i='input[name="'+t.getAttribute("name")+'"]:checked';return t.validation.form.querySelectorAll(i).length},p={email:{fn:function(t){return!t||/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)}},max:{fn:function(t,i){return!t||("checkbox"===this.type?m(this)<=parseInt(i):parseFloat(t)<=parseFloat(i))}},maxlength:{fn:function(t,i){return!t||t.length<=parseInt(i)}},min:{fn:function(t,i){return!t||("checkbox"===this.type?m(this)>=parseInt(i):parseFloat(t)>=parseFloat(i))}},minlength:{fn:function(t,i){return!t||t.length>=parseInt(i)}},number:{fn:function(t){return!t||!isNaN(parseFloat(t))},priority:2},required:{fn:function(t){return"radio"===this.type||"checkbox"===this.type?m(this):void 0!==t&&""!==t},priority:99,halt:!0}},_=function(t){this.config=GLSR.validationconfig,this.fields=[],this.form=t,this.form.setAttribute("novalidate",""),this.strings=GLSR.validationstrings,this.init()};_.prototype={vt:["required","max","maxlength","min","minlength","pattern"],pt:"input:not([type^=hidden]):not([type^=submit]), select, textarea, [data-glsr-validate]",destroy:function(){for(this.lt();this.fields.length;){var t=this.fields.shift();this._t(t.input),delete t.input.validation}},init:function(){var t=this;[].forEach.call(this.form.querySelectorAll(this.pt),(function(i){t.fields.find((function(t){return t.input.name===i.name}))||"none"!==i.closest(v(t.config.field)).style.display&&t.fields.push(t.wt(i))}))},bt:function(t){t.addEventListener(this.gt(t),this.St.bind(this,t))},Lt:function(t,i,n){[].forEach.call(t,function(t){var s=t.name.replace("data-","");~this.vt.indexOf(s)?this.Rt(i,n,s,t.value):"type"===t.name&&this.Rt(i,n,t.value)}.bind(this))},Rt:function(t,i,n,s){if(p[n]&&(p[n].name=n,t.push(p[n]),s)){var e=s.split(",");e.unshift(null),i[n]=e}},_t:function(t){t.removeEventListener(this.gt(t),this.St.bind(this,t))},lt:function(){for(var t in this.fields)if(this.fields.hasOwnProperty(t)){this.fields[t].errorElements=null;var i=this.fields[t].input.closest(v(this.config.field));d(this.fields[t].input,this.config.input_error,!1),d(this.fields[t].input,this.config.input_valid,!1),d(i,this.config.field_error,!1),d(i,this.config.field_valid,!1)}},gt:function(t){return~["radio","checkbox"].indexOf(t.getAttribute("type"))||"SELECT"===t.nodeName?"change":"input"},wt:function(t){var i={},n=[];return null!==t.offsetParent&&(this.Lt(t.attributes,n,i),this.yt(n),this.bt(t)),t.validation={form:this.form,input:t,params:i,validators:n}},Et:function(t,i){var n=t.input.closest(v(this.config.field));if(d(t.input,this.config.input_error,i),d(t.input,this.config.input_valid,!i),n){d(n,this.config.field_error,i),d(n,this.config.field_valid,!i);var s=n.querySelector(v(this.config.field_message));s.innerHTML=i?t.errors.join("<br>"):"",s.style.display=i?"":"none"}},xt:function(t,i){t.hasOwnProperty("validation")&&this.wt(t),t.validation.errors=i},yt:function(t){t.sort((function(t,i){return(i.priority||1)-(t.priority||1)}))},St:function(t){var i=!0,n=this.fields;for(var s in t instanceof HTMLElement&&(n=[t.validation]),n)if(n.hasOwnProperty(s)){var e=n[s];this.jt(e)?this.Et(e,!1):(i=!1,this.Et(e,!0))}return i},jt:function(t){var i=[],n=!0;for(var s in t.validators)if(t.validators.hasOwnProperty(s)){var e=t.validators[s],h=t.params[e.name]?t.params[e.name]:[];if(h[0]=t.input.value,!e.fn.apply(t.input,h)){n=!1;var o=this.strings[e.name];if(i.push(o.replace(/(\%s)/g,h[1])),!0===e.halt)break}}return t.errors=i,n}};var w=_,b=function(t,i){this.button=i,this.config=GLSR.validationconfig,this.events={submit:this.Ft.bind(this)},this.form=t,this.isActive=!1,this.recaptcha=new c(this),this.stars=null,this.strings=GLSR.validationstrings,this.useAjax=this.Gt(),this.validation=new w(t)};b.prototype={destroy:function(){this.destroyForm(),this.destroyRecaptcha(),this.destroyStarRatings(),this.isActive=!1},destroyForm:function(){this.form.removeEventListener("submit",this.events.submit),this.Tt()},destroyRecaptcha:function(){this.recaptcha.h()},destroyStarRatings:function(){this.stars&&(this.stars.destroy(),delete this.stars)},init:function(){this.isActive||(this.initForm(),this.initStarRatings(),this.initRecaptcha(),this.isActive=!0)},initForm:function(){this.destroyForm(),this.form.addEventListener("submit",this.events.submit)},initRecaptcha:function(){this.recaptcha.ct()},initStarRatings:function(){this.destroyStarRatings(),this.stars=new l.a(this.form.querySelectorAll(".glsr-field-rating select"),{clearable:!1,showText:!1})},dt:function(){this.button.setAttribute("disabled","")},ot:function(){this.button.removeAttribute("disabled")},Ot:function(t,i){var n=!0===i;"unset"!==t.recaptcha?("reset"===t.recaptcha&&this.recaptcha.lt(),n&&(this.recaptcha.lt(),this.form.reset()),this.Mt(t.errors),this.kt(t.message,n),this.ot(),t.form=this.form,document.dispatchEvent(new CustomEvent("site-reviews/after/submission",{detail:t})),n&&""!==t.redirect&&(window.location=t.redirect)):this.recaptcha.rt()},Gt:function(){var t=!0;return[].forEach.call(this.form.elements,(function(i){"file"===i.type&&(t=GLSR.ajax.isFileSupported()&&GLSR.ajax.isUploadSupported())})),t&&!this.form.classList.contains("no-ajax")},Ft:function(t){if(!this.validation.St())return t.preventDefault(),void this.kt(this.strings.errors,!1);this.Tt(),(this.form["g-recaptcha-response"]&&""===this.form["g-recaptcha-response"].value||this.useAjax)&&(t.preventDefault(),this.ut())},Tt:function(){d(this.form,this.config.form_error,!1),this.kt("",null),this.validation.lt()},Mt:function(t){if(t)for(var i in t)if(t.hasOwnProperty(i)){var n=GLSR.nameprefix?GLSR.nameprefix+"["+i+"]":i,s=this.form.querySelector('[name="'+n+'"]');s&&(this.validation.xt(s,t[i]),this.validation.Et(s.validation,"add"))}},kt:function(t,i){var n=this.form.querySelector(v(this.config.form_message));null!==n&&(d(this.form,this.config.form_error,!1===i),d(n,this.config.form_message_failed,!1===i),d(n,this.config.form_message_success,!0===i),n.innerHTML=t)},ut:function(t){GLSR.ajax.isFormDataSupported()?(this.dt(),this.form[GLSR.nameprefix+"[_counter]"].value=t||0,GLSR.ajax.post(this.form,this.Ot.bind(this))):this.kt(this.strings.unsupported,!1)}};var g=function(){for(;GLSR.forms.length;){(t=GLSR.forms.shift()).destroy()}var t,i,n;i=document.querySelectorAll("form.glsr-review-form");for(var s=0;s<i.length;s++)(n=i[s].querySelector("[type=submit]"))&&((t=new b(i[s],n)).init(),GLSR.forms.push(t))},S=g,L=function(t,i){this.paginationEl=t,this.reviewsEl=i,this.R()};L.prototype={config:{hideClass:"glsr-hide",linkSelector:"a.page-numbers",scrollTime:468},Ct:function(){var t=document.getElementById(this.paginationEl.dataset.id);return t||this.reviewsEl},Ot:function(t,i,n){n?(this.paginationEl.innerHTML=i.pagination,this.reviewsEl.innerHTML=i.reviews,this.Nt(this.reviewsEl),this.paginationEl.classList.remove(this.config.hideClass),this.reviewsEl.classList.remove(this.config.hideClass),this.R(),GLSR.urlparameter&&window.history.pushState(null,"",t),new a(this.reviewsEl),document.dispatchEvent(new CustomEvent("site-reviews/after/pagination",{detail:i}))):window.location=t},R:function(){for(var t=this.paginationEl.querySelectorAll(this.config.linkSelector),i=0;i<t.length;i++)t[i].addEventListener("click",this.ht.bind(this))},ht:function(t){var i=this.Ct();if(i){for(var n={},s=0,e=Object.keys(i.dataset);s<e.length;s++){var h=e[s];n[GLSR.nameprefix+"[atts]["+h+"]"]=i.dataset[h]}n[GLSR.nameprefix+"[_action]"]="fetch-paged-reviews",n[GLSR.nameprefix+"[page]"]=t.currentTarget.dataset.page||"",n[GLSR.nameprefix+"[url]"]=t.currentTarget.href||"",this.paginationEl.classList.add(this.config.hideClass),this.reviewsEl.classList.add(this.config.hideClass),t.preventDefault(),GLSR.ajax.post(n,this.Ot.bind(this,t.currentTarget.href))}},Nt:function(t,i){var n;i=i||16;for(var s=0;s<GLSR.ajaxpagination.length;s++)(n=document.querySelector(GLSR.ajaxpagination[s]))&&"fixed"===window.getComputedStyle(n).getPropertyValue("position")&&(i+=n.clientHeight);var e=t.getBoundingClientRect().top-i;e>0||this.Dt({endY:e,offset:window.pageYOffset,startTime:window.performance.now(),startY:t.scrollTop})},Dt:function(t){var i=(window.performance.now()-t.startTime)/this.config.scrollTime;i=i>1?1:i;var n=.5*(1-Math.cos(Math.PI*i)),s=t.startY+(t.endY-t.startY)*n;window.scroll(0,t.offset+s),s!==t.endY&&window.requestAnimationFrame(this.Dt.bind(this,t))}};var R=function(){this.navs=[];var t=document.querySelectorAll(".glsr-ajax-pagination");t.length&&t.forEach(function(t){var i=t.closest(".glsr[data-id="+t.dataset.id);if(i){var n=i.querySelector(".glsr-reviews");n&&this.navs.push(new L(t,n))}}.bind(this))},y=R;window.hasOwnProperty("GLSR")||(window.GLSR={}),window.GLSR.ajax=new o,window.GLSR.forms=[],document.addEventListener("DOMContentLoaded",(function(){for(var t=document.querySelectorAll(".glsr"),i=0;i<t.length;i++){var n=window.getComputedStyle(t[i],null).getPropertyValue("direction");t[i].classList.add("glsr-"+n)}window.GLSR.Forms=S,new S,new y,new a}))},,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,function(t,i){},,,,,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){}]);
1
  /*! For license information please see site-reviews.js.LICENSE.txt */
2
+ !function(t){var i={};function n(s){if(i[s])return i[s].exports;var e=i[s]={i:s,l:!1,exports:{}};return t[s].call(e.exports,e,e.exports,n),e.l=!0,e.exports}n.m=t,n.c=i,n.d=function(t,i,s){n.o(t,i)||Object.defineProperty(t,i,{enumerable:!0,get:s})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,i){if(1&i&&(t=n(t)),8&i)return t;if(4&i&&"object"==typeof t&&t&&t.__esModule)return t;var s=Object.create(null);if(n.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:t}),2&i&&"string"!=typeof t)for(var e in t)n.d(s,e,function(i){return t[i]}.bind(null,e));return s},n.n=function(t){var i=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(i,"a",i),i},n.o=function(t,i){return Object.prototype.hasOwnProperty.call(t,i)},n.p="/",n(n.s=7)}([,function(t,i){function n(i){return"function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?t.exports=n=function(t){return typeof t}:t.exports=n=function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(i)}t.exports=n},function(t,i,n){var s;!function(n,e,h){"use strict";var o=function(t,i){var n={}.toString.call(t);this.selects="[object String]"===n?e.querySelectorAll(t):"[object NodeList]"===n?t:[t],this.destroy=function(){this.widgets.forEach((function(t){t.h()}))},this.rebuild=function(){this.widgets.forEach((function(t){t.u()}))},this.widgets=[];for(var s=0;s<this.selects.length;s++)if("SELECT"===this.selects[s].tagName&&!this.selects[s]["star-rating"]){var h=new r(this.selects[s],i);void 0!==h.direction&&this.widgets.push(h)}},r=function(t,i){this.el=t,this.v=this._({},this.g,i||{},JSON.parse(t.getAttribute("data-options"))),this.S(),this.stars<1||this.stars>this.v.maxStars||this.u()};r.prototype={g:{classname:"gl-star-rating",clearable:!0,initialText:"Select a Rating",maxStars:10,showText:!0},L:function(){this.R(),this.current=this.selected=this.j(),this.F(),this.G(),this.T(),this.O(this.current),this.M("add"),this.el["star-rating"]=!0},k:function(){this.v.showText&&(this.textEl=this.C(this.widgetEl,{class:this.v.classname+"-text"},!0))},G:function(){var t=this.N(),i=this.C(this.el,{class:this.v.classname+"-stars"},!0);for(var n in t){var s=this.D({"data-value":n,"data-text":t[n]});i.innerHTML+=s.outerHTML}this.widgetEl=i,this.k()},I:function(t){(t<0||isNaN(t))&&(t=0),t>this.stars&&(t=this.stars),this.widgetEl.classList.remove("s"+10*this.current),this.widgetEl.classList.add("s"+10*t),this.v.showText&&(this.textEl.textContent=t<1?this.v.initialText:this.widgetEl.childNodes[t-1].dataset.text),this.current=t},D:function(t){var i=e.createElement("span");for(var n in t=t||{})i.setAttribute(n,t[n]);return i},h:function(){this.M("remove");var t=this.el.parentNode;t.parentNode.replaceChild(this.el,t),delete this.el["star-rating"]},q:function(t,i,n,s){s=s||!1,n.forEach(function(n){this.events&&t[i+"EventListener"](n,this.events[n],s)}.bind(this))},_:function(){var t=[].slice.call(arguments),i=t[0],n=t.slice(1);return Object.keys(n).forEach((function(t){for(var s in n[t])n[t].hasOwnProperty(s)&&(i[s]=n[t][s])})),i},V:function(){var t=!1;try{var i=Object.defineProperty({},"passive",{get:function(){t={passive:!1}}});n.addEventListener("test",null,i)}catch(t){}return t},A:function(t){var i={},n=t.pageX||t.changedTouches[0].pageX,s=this.widgetEl.offsetWidth;return i.ltr=Math.max(n-this.offsetLeft,1),i.rtl=s-i.ltr,Math.min(Math.ceil(i[this.direction]/Math.round(s/this.stars)),this.stars)},N:function(){for(var t=this.el,i={},n={},s=0;s<t.length;s++)this.H(t[s])||(i[t[s].value]=t[s].text);return Object.keys(i).sort().forEach((function(t){n[t]=i[t]})),n},j:function(){return parseInt(this.el.options[Math.max(this.el.selectedIndex,0)].value)||0},M:function(t){var i=this.el.closest("form");i&&"FORM"===i.tagName&&this.q(i,t,["reset"]),"add"===t&&this.el.disabled||(this.q(this.el,t,["change","keydown"]),this.q(this.widgetEl,t,["mousedown","mouseleave","mousemove","mouseover","touchend","touchmove","touchstart"],this.V()))},R:function(){this.events={change:this.P.bind(this),keydown:this.B.bind(this),mousedown:this.U.bind(this),mouseleave:this.W.bind(this),mousemove:this.X.bind(this),mouseover:this.J.bind(this),reset:this.Y.bind(this),touchend:this.U.bind(this),touchmove:this.X.bind(this),touchstart:this.J.bind(this)}},C:function(t,i,n){var s=this.D(i);return t.parentNode.insertBefore(s,!0===n?t.nextSibling:t),s},H:function(t){return null===t.getAttribute("value")||""===t.value},P:function(){this.I(this.j())},B:function(t){if(~["ArrowLeft","ArrowRight"].indexOf(t.key)){var i="ArrowLeft"===t.key?-1:1;"rtl"===this.direction&&(i*=-1),this.O(Math.min(Math.max(this.j()+i,0),this.stars)),this.K()}},U:function(t){t.preventDefault();var i=this.A(t);0!==this.current&&parseFloat(this.selected)===i&&this.v.clearable&&(i=0),this.O(i),this.K()},W:function(t){t.preventDefault(),this.I(this.selected)},X:function(t){t.preventDefault(),this.I(this.A(t))},J:function(t){t.preventDefault();var i=this.widgetEl.getBoundingClientRect();this.offsetLeft=i.left+e.body.scrollLeft},Y:function(){var t=this.el.querySelector("[selected]"),i=t?t.value:"";this.el.value=i,this.selected=parseInt(i)||0,this.I(i)},u:function(){this.el.parentNode.classList.contains(this.v.classname)&&this.h(),this.L()},T:function(){var t=this.el.parentNode;this.direction=n.getComputedStyle(t,null).getPropertyValue("direction"),t.classList.add(this.v.classname+"-"+this.direction)},O:function(t){this.el.value=this.selected=t,this.I(t)},S:function(){var t=this.el;this.stars=0;for(var i=0;i<t.length;i++)if(!this.H(t[i])){if(isNaN(parseFloat(t[i].value))||!isFinite(t[i].value))return void(this.stars=0);this.stars++}},K:function(){this.el.dispatchEvent(new Event("change"))},F:function(){this.C(this.el,{class:this.v.classname,"data-star-rating":""}).appendChild(this.el)}},void 0===(s=function(){return o}.apply(i,[]))||(t.exports=s)}(window,document)},,,,,function(t,i,n){n(28),n(59),n(64),n(66),n(68),n(70),n(72),n(74),n(76),n(78),n(80),n(82),n(84),n(86),n(88),n(90),n(92),n(94),n(96),n(98),n(100),n(102),n(104),n(106),n(108),n(110),n(112),n(114),t.exports=n(116)},,,,,,,,,,,,,,,,,,,,,function(t,i,n){"use strict";n.r(i);var s=n(1),e=n.n(s),h=function(){};h.prototype={get:function(t,i,n){this.$(i),this.xhr.open("GET",t,!0),this.xhr.responseType="text",this.Z(n),this.xhr.send()},tt:function(t){return"json"===this.xhr.responseType||!0===this.xhr.json?t({message:this.xhr.statusText},!1):"text"===this.xhr.responseType?t(this.xhr.statusText):void 0},it:function(t){if(0===this.xhr.status||this.xhr.status>=200&&this.xhr.status<300||304===this.xhr.status){if("json"===this.xhr.responseType)return t(this.xhr.response.data,this.xhr.response.success);if("text"===this.xhr.responseType)return t(this.xhr.responseText);if(!0===this.xhr.json){var i=JSON.parse(this.xhr.response);return t(i.data,i.success)}}else this.tt(t)},isFileSupported:function(){var t=document.createElement("INPUT");return t.type="file","files"in t},isFormDataSupported:function(){return!!window.FormData},isUploadSupported:function(){var t=new XMLHttpRequest;return!!(t&&"upload"in t&&"onprogress"in t.upload)},post:function(t,i,n){this.$(i),this.xhr.open("POST",GLSR.ajaxurl,!0),this.xhr.responseType="json",this.xhr.json=!0,this.Z(n),this.xhr.send(this.nt(t))},$:function(t){this.xhr=new XMLHttpRequest,this.xhr.onload=this.it.bind(this,t),this.xhr.onerror=this.tt.bind(this,t)},st:function(t,i,n){return"object"!==e()(i)||i instanceof Date||i instanceof File?t.append(n,i||""):Object.keys(i).forEach(function(s){i.hasOwnProperty(s)&&(t=this.st(t,i[s],n?n[s]:s))}.bind(this)),t},nt:function(t){var i=new FormData,n=Object.prototype.toString.call(t);return"[object FormData]"===n&&(i=t),"[object HTMLFormElement]"===n&&(i=new FormData(t)),"[object Object]"===n&&Object.keys(t).forEach((function(n){i.append(n,t[n])})),i.append("action",GLSR.action),i.append("_ajax_request",!0),i},Z:function(t){for(var i in(t=t||{})["X-Requested-With"]="XMLHttpRequest",t)t.hasOwnProperty(i)&&this.xhr.setRequestHeader(i,t[i])}};var o=h,r=function(t){this.L(t||document)};r.prototype={config:{hiddenClass:"glsr-hidden",hiddenTextSelector:".glsr-hidden-text",readMoreClass:"glsr-read-more",visibleClass:"glsr-visible"},et:function(t){var i=document.createElement("span"),n=document.createElement("a");n.setAttribute("href","#"),n.setAttribute("data-text",t.getAttribute("data-show-less")),n.innerHTML=t.getAttribute("data-show-more"),n.addEventListener("click",this.ht.bind(this)),i.setAttribute("class",this.config.readMoreClass),i.appendChild(n),t.parentNode.insertBefore(i,t.nextSibling)},ht:function(t){t.preventDefault();var i=t.currentTarget,n=i.parentNode.previousSibling,s=i.getAttribute("data-text");n.classList.toggle(this.config.hiddenClass),n.classList.toggle(this.config.visibleClass),i.setAttribute("data-text",i.innerText),i.innerText=s},L:function(t){for(var i=t.querySelectorAll(this.config.hiddenTextSelector),n=0;n<i.length;n++)this.et(i[n])}};var a=r,u=function(t){this.Form=t,this.counter=0,this.id=-1,this.is_submitting=!1,this.recaptchaEl=t.form.querySelector(".glsr-recaptcha-holder"),this.observer=new MutationObserver(function(t){var i=t.pop();i.target&&"visible"!==i.target.style.visibility&&(this.observer.disconnect(),setTimeout(function(){this.is_submitting||this.Form.ot()}.bind(this),250))}.bind(this))};u.prototype={h:function(){this.counter=0,this.id=-1,this.is_submitting=!1,this.recaptchaEl&&(this.recaptchaEl.innerHTML="")},rt:function(){if(-1!==this.id)return this.counter=0,this.at(this.id),void grecaptcha.execute(this.id);setTimeout(function(){this.counter++,this.ut.call(this.Form,this.counter)}.bind(this),1e3)},at:function(t){var i=window.___grecaptcha_cfg.clients[t];for(var n in i)if(i.hasOwnProperty(n)&&"[object String]"===Object.prototype.toString.call(i[n])){var s=document.querySelector("iframe[name=c-"+i[n]+"]");if(s){this.observer.observe(s.parentElement.parentElement,{attributeFilter:["style"],attributes:!0});break}}},ct:function(){this.Form.form.onsubmit=null,this.h(),this.ft()},ft:function(){this.recaptchaEl&&setTimeout(function(){if("undefined"==typeof grecaptcha||void 0===grecaptcha.render)return this.ft();this.id=grecaptcha.render(this.recaptchaEl,{callback:this.ut.bind(this.Form,this.counter),"expired-callback":this.lt.bind(this),isolated:!0},!0)}.bind(this),250)},lt:function(){this.counter=0,this.is_submitting=!1,-1!==this.id&&grecaptcha.reset(this.id)},ut:function(t){if(this.recaptcha.is_submitting=!0,!this.useAjax)return this.dt(),void this.form.submit();this.ut(t)}};var c=u,f=n(2),l=n.n(f),d=function(t,i,n){t&&i.split(" ").forEach((function(i){t.classList[n?"add":"remove"](i)}))},v=function(t){return"."+t.trim().split(" ").join(".")},m=function(t){var i='input[name="'+t.getAttribute("name")+'"]:checked';return t.validation.form.querySelectorAll(i).length},p={email:{fn:function(t){return!t||/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)}},max:{fn:function(t,i){return!t||("checkbox"===this.type?m(this)<=parseInt(i):parseFloat(t)<=parseFloat(i))}},maxlength:{fn:function(t,i){return!t||t.length<=parseInt(i)}},min:{fn:function(t,i){return!t||("checkbox"===this.type?m(this)>=parseInt(i):parseFloat(t)>=parseFloat(i))}},minlength:{fn:function(t,i){return!t||t.length>=parseInt(i)}},number:{fn:function(t){return!t||!isNaN(parseFloat(t))},priority:2},required:{fn:function(t){return"radio"===this.type||"checkbox"===this.type?m(this):void 0!==t&&""!==t},priority:99,halt:!0}},_=function(t){this.config=GLSR.validationconfig,this.fields=[],this.form=t,this.form.setAttribute("novalidate",""),this.strings=GLSR.validationstrings,this.init()};_.prototype={vt:["required","max","maxlength","min","minlength","pattern"],pt:"input:not([type^=hidden]):not([type^=submit]), select, textarea, [data-glsr-validate]",destroy:function(){for(this.lt();this.fields.length;){var t=this.fields.shift();this._t(t.input),delete t.input.validation}},init:function(){var t=this;[].forEach.call(this.form.querySelectorAll(this.pt),(function(i){t.fields.find((function(t){return t.input.name===i.name}))||"none"!==i.closest(v(t.config.field)).style.display&&t.fields.push(t.wt(i))}))},bt:function(t){t.addEventListener(this.gt(t),this.St.bind(this,t))},Lt:function(t,i,n){[].forEach.call(t,function(t){var s=t.name.replace("data-","");~this.vt.indexOf(s)?this.Rt(i,n,s,t.value):"type"===t.name&&this.Rt(i,n,t.value)}.bind(this))},Rt:function(t,i,n,s){if(p[n]&&(p[n].name=n,t.push(p[n]),s)){var e=s.split(",");e.unshift(null),i[n]=e}},_t:function(t){t.removeEventListener(this.gt(t),this.St.bind(this,t))},lt:function(){for(var t in this.fields)if(this.fields.hasOwnProperty(t)){this.fields[t].errorElements=null;var i=this.fields[t].input.closest(v(this.config.field));d(this.fields[t].input,this.config.input_error,!1),d(this.fields[t].input,this.config.input_valid,!1),d(i,this.config.field_error,!1),d(i,this.config.field_valid,!1)}},gt:function(t){return~["radio","checkbox"].indexOf(t.getAttribute("type"))||"SELECT"===t.nodeName?"change":"input"},wt:function(t){var i={},n=[];return null!==t.offsetParent&&(this.Lt(t.attributes,n,i),this.yt(n),this.bt(t)),t.validation={form:this.form,input:t,params:i,validators:n}},Et:function(t,i){var n=t.input.closest(v(this.config.field));if(d(t.input,this.config.input_error,i),d(t.input,this.config.input_valid,!i),n){d(n,this.config.field_error,i),d(n,this.config.field_valid,!i);var s=n.querySelector(v(this.config.field_message));s.innerHTML=i?t.errors.join("<br>"):"",s.style.display=i?"":"none"}},xt:function(t,i){t.hasOwnProperty("validation")&&this.wt(t),t.validation.errors=i},yt:function(t){t.sort((function(t,i){return(i.priority||1)-(t.priority||1)}))},St:function(t){var i=!0,n=this.fields;for(var s in t instanceof HTMLElement&&(n=[t.validation]),n)if(n.hasOwnProperty(s)){var e=n[s];this.jt(e)?this.Et(e,!1):(i=!1,this.Et(e,!0))}return i},jt:function(t){var i=[],n=!0;for(var s in t.validators)if(t.validators.hasOwnProperty(s)){var e=t.validators[s],h=t.params[e.name]?t.params[e.name]:[];if(h[0]=t.input.value,!e.fn.apply(t.input,h)){n=!1;var o=this.strings[e.name];if(i.push(o.replace(/(\%s)/g,h[1])),!0===e.halt)break}}return t.errors=i,n}};var w=_,b=function(t,i){this.button=i,this.config=GLSR.validationconfig,this.events={submit:this.Ft.bind(this)},this.form=t,this.isActive=!1,this.recaptcha=new c(this),this.stars=null,this.strings=GLSR.validationstrings,this.useAjax=this.Gt(),this.validation=new w(t)};b.prototype={destroy:function(){this.destroyForm(),this.destroyRecaptcha(),this.destroyStarRatings(),this.isActive=!1},destroyForm:function(){this.form.removeEventListener("submit",this.events.submit),this.Tt()},destroyRecaptcha:function(){this.recaptcha.h()},destroyStarRatings:function(){this.stars&&(this.stars.destroy(),delete this.stars)},init:function(){this.isActive||(this.initForm(),this.initStarRatings(),this.initRecaptcha(),this.isActive=!0)},initForm:function(){this.destroyForm(),this.form.addEventListener("submit",this.events.submit)},initRecaptcha:function(){this.recaptcha.ct()},initStarRatings:function(){this.destroyStarRatings(),this.stars=new l.a(this.form.querySelectorAll(".glsr-field-rating select"),{clearable:!1,showText:!1})},dt:function(){this.button.setAttribute("disabled","")},ot:function(){this.button.removeAttribute("disabled")},Ot:function(t,i){var n=!0===i;"unset"!==t.recaptcha?("reset"===t.recaptcha&&this.recaptcha.lt(),n&&(this.recaptcha.lt(),this.form.reset()),this.Mt(t.errors),this.kt(t.message,n),this.ot(),t.form=this.form,document.dispatchEvent(new CustomEvent("site-reviews/after/submission",{detail:t})),n&&""!==t.redirect&&(window.location=t.redirect)):this.recaptcha.rt()},Gt:function(){var t=!0;return[].forEach.call(this.form.elements,(function(i){"file"===i.type&&(t=GLSR.ajax.isFileSupported()&&GLSR.ajax.isUploadSupported())})),t&&!this.form.classList.contains("no-ajax")},Ft:function(t){if(!this.validation.St())return t.preventDefault(),void this.kt(this.strings.errors,!1);this.Tt(),(this.form["g-recaptcha-response"]&&""===this.form["g-recaptcha-response"].value||this.useAjax)&&(t.preventDefault(),this.ut())},Tt:function(){d(this.form,this.config.form_error,!1),this.kt("",null),this.validation.lt()},Mt:function(t){if(t)for(var i in t)if(t.hasOwnProperty(i)){var n=GLSR.nameprefix?GLSR.nameprefix+"["+i+"]":i,s=this.form.querySelector('[name="'+n+'"]');s&&(this.validation.xt(s,t[i]),this.validation.Et(s.validation,"add"))}},kt:function(t,i){var n=this.form.querySelector(v(this.config.form_message));null!==n&&(d(this.form,this.config.form_error,!1===i),d(n,this.config.form_message_failed,!1===i),d(n,this.config.form_message_success,!0===i),n.innerHTML=t)},ut:function(t){GLSR.ajax.isFormDataSupported()?(this.dt(),this.form[GLSR.nameprefix+"[_counter]"].value=t||0,GLSR.ajax.post(this.form,this.Ot.bind(this))):this.kt(this.strings.unsupported,!1)}};var g=function(){for(;GLSR.forms.length;){(t=GLSR.forms.shift()).destroy()}var t,i,n;i=document.querySelectorAll("form.glsr-review-form");for(var s=0;s<i.length;s++)(n=i[s].querySelector("[type=submit]"))&&((t=new b(i[s],n)).init(),GLSR.forms.push(t))},S=g,L=function(t,i){this.paginationEl=t,this.reviewsEl=i,this.R()};L.prototype={config:{hideClass:"glsr-hide",linkSelector:"a.page-numbers",scrollTime:468},Ct:function(){var t=document.getElementById(this.paginationEl.dataset.id);return t||this.reviewsEl},Ot:function(t,i,n){n?(this.paginationEl.innerHTML=i.pagination,this.reviewsEl.innerHTML=i.reviews,this.Nt(this.reviewsEl),this.paginationEl.classList.remove(this.config.hideClass),this.reviewsEl.classList.remove(this.config.hideClass),this.R(),GLSR.urlparameter&&window.history.pushState(null,"",t),new a(this.reviewsEl),document.dispatchEvent(new CustomEvent("site-reviews/after/pagination",{detail:i}))):window.location=t},R:function(){for(var t=this.paginationEl.querySelectorAll(this.config.linkSelector),i=0;i<t.length;i++)t[i].addEventListener("click",this.ht.bind(this))},ht:function(t){var i=this.Ct();if(i){for(var n={},s=0,e=Object.keys(i.dataset);s<e.length;s++){var h=e[s];n[GLSR.nameprefix+"[atts]["+h+"]"]=i.dataset[h]}n[GLSR.nameprefix+"[_action]"]="fetch-paged-reviews",n[GLSR.nameprefix+"[page]"]=t.currentTarget.dataset.page||"",n[GLSR.nameprefix+"[url]"]=t.currentTarget.href||"",this.paginationEl.classList.add(this.config.hideClass),this.reviewsEl.classList.add(this.config.hideClass),t.preventDefault(),GLSR.ajax.post(n,this.Ot.bind(this,t.currentTarget.href))}},Nt:function(t,i){var n;i=i||16;for(var s=0;s<GLSR.ajaxpagination.length;s++)(n=document.querySelector(GLSR.ajaxpagination[s]))&&"fixed"===window.getComputedStyle(n).getPropertyValue("position")&&(i+=n.clientHeight);var e=t.getBoundingClientRect().top-i;e>0||this.Dt({endY:e,offset:window.pageYOffset,startTime:window.performance.now(),startY:t.scrollTop})},Dt:function(t){var i=(window.performance.now()-t.startTime)/this.config.scrollTime;i=i>1?1:i;var n=.5*(1-Math.cos(Math.PI*i)),s=t.startY+(t.endY-t.startY)*n;window.scroll(0,t.offset+s),s!==t.endY&&window.requestAnimationFrame(this.Dt.bind(this,t))}};var R=function(){this.navs=[];var t=document.querySelectorAll(".glsr-ajax-pagination");t.length&&t.forEach(function(t){var i=t.closest(".glsr[data-id="+t.dataset.id);if(i){var n=i.querySelector(".glsr-reviews");n&&this.navs.push(new L(t,n))}}.bind(this))},y=R;window.hasOwnProperty("GLSR")||(window.GLSR={}),window.GLSR.ajax=new o,window.GLSR.forms=[],document.addEventListener("DOMContentLoaded",(function(){for(var t=document.querySelectorAll(".glsr"),i=0;i<t.length;i++){var n=window.getComputedStyle(t[i],null).getPropertyValue("direction");t[i].classList.add("glsr-"+n)}window.GLSR.Forms=S,new S,new y,new a}))},,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,function(t,i){},,,,,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){},,function(t,i){}]);
autoload.php CHANGED
@@ -2,12 +2,17 @@
2
 
3
  defined('ABSPATH') || die;
4
 
5
- if (!function_exists('wp_hash')) {
6
- require_once ABSPATH.WPINC.'/pluggable.php';
 
 
 
 
7
  }
8
 
9
  spl_autoload_register(function ($className) {
10
  $classMap = [
 
11
  'WP_Posts_List_Table' => ABSPATH.'wp-admin/includes/class-wp-posts-list-table.php',
12
  ];
13
  if (array_key_exists($className, $classMap) && file_exists($classMap[$className])) {
2
 
3
  defined('ABSPATH') || die;
4
 
5
+ /**
6
+ * Provide a partial, native PHP implementation for the Mbstring extension.
7
+ * @see https://github.com/symfony/polyfill-mbstring
8
+ */
9
+ if (!extension_loaded('mbstring')) {
10
+ require_once __DIR__.'/vendors/symfony/polyfill-mbstring/bootstrap.php';
11
  }
12
 
13
  spl_autoload_register(function ($className) {
14
  $classMap = [
15
+ 'WP_Debug_Data' => ABSPATH.'wp-admin/includes/class-wp-debug-data.php',
16
  'WP_Posts_List_Table' => ABSPATH.'wp-admin/includes/class-wp-posts-list-table.php',
17
  ];
18
  if (array_key_exists($className, $classMap) && file_exists($classMap[$className])) {
compatibility.php CHANGED
@@ -43,17 +43,6 @@ add_action('members_register_caps', function () {
43
  ]);
44
  });
45
 
46
- /**
47
- * Provide a partial, native PHP implementation for the Mbstring extension.
48
- * @return bool
49
- * @see https://github.com/symfony/polyfill-mbstring
50
- */
51
- add_action('plugins_loaded', function () {
52
- if (glsr()->filterBool('support/multibyte', true)) {
53
- require_once __DIR__.'/vendors/symfony/polyfill-mbstring/bootstrap.php';
54
- }
55
- });
56
-
57
  /**
58
  * Exclude the reCAPTCHA script from being defered
59
  * @param array $scriptHandles
43
  ]);
44
  });
45
 
 
 
 
 
 
 
 
 
 
 
 
46
  /**
47
  * Exclude the reCAPTCHA script from being defered
48
  * @param array $scriptHandles
config/forms/metabox-fields.php CHANGED
@@ -7,7 +7,7 @@ return [
7
  ],
8
  'type' => [
9
  'label' => esc_html_x('Type', 'admin-text', 'site-reviews'),
10
- 'options' => glsr()->reviewTypes,
11
  'type' => 'select',
12
  ],
13
  'name' => [
7
  ],
8
  'type' => [
9
  'label' => esc_html_x('Type', 'admin-text', 'site-reviews'),
10
+ 'options' => glsr()->retrieve('review_types'),
11
  'type' => 'select',
12
  ],
13
  'name' => [
config/settings.php CHANGED
@@ -172,6 +172,20 @@ return [
172
  ],
173
  'type' => 'select',
174
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  'settings.reviews.assigned_links' => [
176
  'default' => 'no',
177
  'description' => _x('Display a link to the assigned posts of a review.', 'admin-text', 'site-reviews'),
@@ -433,7 +447,7 @@ return [
433
  ],
434
  'settings.submissions.limit' => [
435
  'default' => '',
436
- 'description' => _x('Limits the number of reviews that can be submitted to one-per-person. If you are assigning reviews, then the limit will be applied to the assigned page or category.', 'admin-text', 'site-reviews'),
437
  'label' => _x('Limit Reviews', 'admin-text', 'site-reviews'),
438
  'options' => [
439
  '' => _x('No Limit', 'admin-text', 'site-reviews'),
172
  ],
173
  'type' => 'select',
174
  ],
175
+ 'settings.reviews.assignment' => [
176
+ 'default' => 'strict',
177
+ 'description' => sprintf('%s<br>%s<br>%s',
178
+ _x('This setting determines how the assigned options work in the reviews and summary shortcodes and blocks.', 'admin-text', 'site-reviews'),
179
+ _x('"Loose Assignment" means <code>display reviews that are assigned to this OR this</code>.', 'admin-text', 'site-reviews'),
180
+ _x('"Strict Assignment" means <code>display reviews that are assigned to this AND this</code>.', 'admin-text', 'site-reviews')
181
+ ),
182
+ 'label' => _x('Review Assignment', 'admin-text', 'site-reviews'),
183
+ 'options' => [
184
+ 'loose' => _x('Loose Assignment', 'admin-text', 'site-reviews'),
185
+ 'strict' => _x('Strict Assignment', 'admin-text', 'site-reviews'),
186
+ ],
187
+ 'type' => 'select',
188
+ ],
189
  'settings.reviews.assigned_links' => [
190
  'default' => 'no',
191
  'description' => _x('Display a link to the assigned posts of a review.', 'admin-text', 'site-reviews'),
447
  ],
448
  'settings.submissions.limit' => [
449
  'default' => '',
450
+ 'description' => _x('Limits the number of reviews that can be submitted to one-per-person. If you are assigning reviews, then the limit will be applied to the assigned page and/or category.', 'admin-text', 'site-reviews'),
451
  'label' => _x('Limit Reviews', 'admin-text', 'site-reviews'),
452
  'options' => [
453
  '' => _x('No Limit', 'admin-text', 'site-reviews'),
helpers.php CHANGED
@@ -70,7 +70,8 @@ function glsr($alias = null, array $parameters = [])
70
  */
71
  function glsr_create_review($reviewValues = [])
72
  {
73
- $request = new Request(Arr::consolidate($reviewValues));
 
74
  $command = new CreateReview($request);
75
  return $command->isValid()
76
  ? glsr(ReviewManager::class)->create($command)
70
  */
71
  function glsr_create_review($reviewValues = [])
72
  {
73
+ $values = Arr::removeEmptyValues(Arr::consolidate($reviewValues));
74
+ $request = new Request($values);
75
  $command = new CreateReview($request);
76
  return $command->isValid()
77
  ? glsr(ReviewManager::class)->create($command)
languages/site-reviews-en_US.mo CHANGED
Binary file
languages/site-reviews-en_US.po CHANGED
@@ -30,7 +30,7 @@ msgstr ""
30
  msgid "%s is <strong>deprecated</strong> since version %s! Use %s instead."
31
  msgstr "%s is <strong>deprecated</strong> since version %s! Use %s instead."
32
 
33
- #: config/settings.php:224, plugin/Modules/Html/ReviewsHtml.php:127
34
  msgid "There are no reviews yet. Be the first one to write one."
35
  msgstr "There are no reviews yet. Be the first one to write one."
36
 
@@ -82,11 +82,11 @@ msgstr "This review is based on my own experience and is my genuine opinion."
82
  msgid "Show more"
83
  msgstr "Show more"
84
 
85
- #: plugin/Commands/CreateReview.php:155
86
  msgid "Your review has been submitted!"
87
  msgstr "Your review has been submitted!"
88
 
89
- #: plugin/Commands/CreateReview.php:160
90
  msgid ""
91
  "Your review could not be submitted and the error has been logged. Please "
92
  "notify the site admin."
@@ -126,7 +126,7 @@ msgstr "This field must have between %s and %s characters."
126
  msgid "This field requires a valid e-mail address."
127
  msgstr "This field requires a valid e-mail address."
128
 
129
- #: plugin/Defaults/ValidationStringsDefaults.php:19, plugin/Modules/Validator/DefaultValidator.php:52
130
  msgid "Please fix the submission errors."
131
  msgstr "Please fix the submission errors."
132
 
@@ -208,7 +208,7 @@ msgid_plural "%s years ago"
208
  msgstr[0] "%s year ago"
209
  msgstr[1] "%s years ago"
210
 
211
- #: plugin/Modules/Notification.php:71
212
  msgid "Anonymous"
213
  msgstr "Anonymous"
214
 
@@ -256,7 +256,7 @@ msgstr "The reCAPTCHA failed to load, please refresh the page and try again."
256
  msgid "The reCAPTCHA verification failed, please try again."
257
  msgstr "The reCAPTCHA verification failed, please try again."
258
 
259
- #: plugin/Modules/Validator/ReviewLimitsValidator.php:43
260
  msgid "You have already submitted a review."
261
  msgstr "You have already submitted a review."
262
 
@@ -788,17 +788,59 @@ msgctxt "admin-text"
788
  msgid "Initial with a period and a space"
789
  msgstr "Initial with a period and a space"
790
 
791
- #: config/settings.php:177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
792
  msgctxt "admin-text"
793
  msgid "Display a link to the assigned posts of a review."
794
  msgstr "Display a link to the assigned posts of a review."
795
 
796
- #: config/settings.php:178
797
  msgctxt "admin-text"
798
  msgid "Enable Assigned Links"
799
  msgstr "Enable Assigned Links"
800
 
801
- #: config/settings.php:183
802
  msgctxt "admin-text"
803
  msgid ""
804
  "Display reviewer avatars. These are generated from the email address of the "
@@ -807,52 +849,52 @@ msgstr ""
807
  "Display reviewer avatars. These are generated from the email address of the "
808
  "reviewer using <a href=\"https://gravatar.com\">Gravatar</a>."
809
 
810
- #: config/settings.php:184
811
  msgctxt "admin-text"
812
  msgid "Enable Avatars"
813
  msgstr "Enable Avatars"
814
 
815
- #: config/settings.php:192
816
  msgctxt "admin-text"
817
  msgid "Regenerate the avatar whenever a local review is shown?"
818
  msgstr "Regenerate the avatar whenever a local review is shown?"
819
 
820
- #: config/settings.php:193
821
  msgctxt "admin-text"
822
  msgid "Regenerate Avatars"
823
  msgstr "Regenerate Avatars"
824
 
825
- #: config/settings.php:201
826
  msgctxt "admin-text"
827
  msgid "Set the avatar size in pixels."
828
  msgstr "Set the avatar size in pixels."
829
 
830
- #: config/settings.php:202
831
  msgctxt "admin-text"
832
  msgid "Avatar Size"
833
  msgstr "Avatar Size"
834
 
835
- #: config/settings.php:207
836
  msgctxt "admin-text"
837
  msgid "Display an excerpt instead of the full review."
838
  msgstr "Display an excerpt instead of the full review."
839
 
840
- #: config/settings.php:208
841
  msgctxt "admin-text"
842
  msgid "Enable Excerpts"
843
  msgstr "Enable Excerpts"
844
 
845
- #: config/settings.php:216
846
  msgctxt "admin-text"
847
  msgid "Set the excerpt word length."
848
  msgstr "Set the excerpt word length."
849
 
850
- #: config/settings.php:217
851
  msgctxt "admin-text"
852
  msgid "Excerpt Length"
853
  msgstr "Excerpt Length"
854
 
855
- #: config/settings.php:222
856
  msgctxt "admin-text"
857
  msgid ""
858
  "Display the fallback text when there are no reviews to display. This can be "
@@ -863,17 +905,17 @@ msgstr ""
863
  "changed on the %s page. You may also override this by using the "
864
  "\"fallback\" option on the shortcode. The default fallback text is: %s"
865
 
866
- #: config/settings.php:223, plugin/Controllers/MenuController.php:118
867
  msgctxt "admin-text"
868
  msgid "Translations"
869
  msgstr "Translations"
870
 
871
- #: config/settings.php:226
872
  msgctxt "admin-text"
873
  msgid "Enable Fallback Text"
874
  msgstr "Enable Fallback Text"
875
 
876
- #: config/settings.php:232
877
  msgctxt "admin-text"
878
  msgid ""
879
  "Paginated URLs include the %s URL parameter. If you would like to keep the "
@@ -884,273 +926,273 @@ msgstr ""
884
  "pagination links but prevent search engines from indexing them, add the "
885
  "following lines to your %s file instead: %s"
886
 
887
- #: config/settings.php:239
888
  msgctxt "admin-text"
889
  msgid "Enable Paginated URLs"
890
  msgstr "Enable Paginated URLs"
891
 
892
- #: config/settings.php:244, config/settings.php:264, config/settings.php:282, config/settings.php:300, config/settings.php:318, config/settings.php:339, config/settings.php:349, config/settings.php:359, config/settings.php:369, config/settings.php:383, config/settings.php:394, config/settings.php:405, config/settings.php:415
893
  msgctxt "admin-text"
894
  msgid "Custom Field name"
895
  msgstr "Custom Field name"
896
 
897
- #: config/settings.php:245
898
  msgctxt "admin-text"
899
  msgid "Default Schema Type"
900
  msgstr "Default Schema Type"
901
 
902
- #: config/settings.php:247
903
  msgctxt "admin-text"
904
  msgid "Local Business"
905
  msgstr "Local Business"
906
 
907
- #: config/settings.php:248
908
  msgctxt "admin-text"
909
  msgid "Product"
910
  msgstr "Product"
911
 
912
- #: config/settings.php:249
913
  msgctxt "admin-text"
914
  msgid "Custom"
915
  msgstr "Custom"
916
 
917
- #: config/settings.php:258
918
  msgctxt "admin-text"
919
  msgid "View more information on schema types here"
920
  msgstr "View more information on schema types here"
921
 
922
- #: config/settings.php:259
923
  msgctxt "admin-text"
924
  msgid "Custom Schema Type"
925
  msgstr "Custom Schema Type"
926
 
927
- #: config/settings.php:265
928
  msgctxt "admin-text"
929
  msgid "Default Name"
930
  msgstr "Default Name"
931
 
932
- #: config/settings.php:267
933
  msgctxt "admin-text"
934
  msgid "Use the assigned or current page title"
935
  msgstr "Use the assigned or current page title"
936
 
937
- #: config/settings.php:268
938
  msgctxt "admin-text"
939
  msgid "Enter a custom title"
940
  msgstr "Enter a custom title"
941
 
942
- #: config/settings.php:277
943
  msgctxt "admin-text"
944
  msgid "Custom Name"
945
  msgstr "Custom Name"
946
 
947
- #: config/settings.php:283
948
  msgctxt "admin-text"
949
  msgid "Default Description"
950
  msgstr "Default Description"
951
 
952
- #: config/settings.php:285
953
  msgctxt "admin-text"
954
  msgid "Use the assigned or current page excerpt"
955
  msgstr "Use the assigned or current page excerpt"
956
 
957
- #: config/settings.php:286
958
  msgctxt "admin-text"
959
  msgid "Enter a custom description"
960
  msgstr "Enter a custom description"
961
 
962
- #: config/settings.php:295
963
  msgctxt "admin-text"
964
  msgid "Custom Description"
965
  msgstr "Custom Description"
966
 
967
- #: config/settings.php:301
968
  msgctxt "admin-text"
969
  msgid "Default URL"
970
  msgstr "Default URL"
971
 
972
- #: config/settings.php:303
973
  msgctxt "admin-text"
974
  msgid "Use the assigned or current page URL"
975
  msgstr "Use the assigned or current page URL"
976
 
977
- #: config/settings.php:304
978
  msgctxt "admin-text"
979
  msgid "Enter a custom URL"
980
  msgstr "Enter a custom URL"
981
 
982
- #: config/settings.php:313
983
  msgctxt "admin-text"
984
  msgid "Custom URL"
985
  msgstr "Custom URL"
986
 
987
- #: config/settings.php:319
988
  msgctxt "admin-text"
989
  msgid "Default Image"
990
  msgstr "Default Image"
991
 
992
- #: config/settings.php:321
993
  msgctxt "admin-text"
994
  msgid "Use the featured image of the assigned or current page"
995
  msgstr "Use the featured image of the assigned or current page"
996
 
997
- #: config/settings.php:322
998
  msgctxt "admin-text"
999
  msgid "Enter a custom image URL"
1000
  msgstr "Enter a custom image URL"
1001
 
1002
- #: config/settings.php:331
1003
  msgctxt "admin-text"
1004
  msgid "Custom Image URL"
1005
  msgstr "Custom Image URL"
1006
 
1007
- #: config/settings.php:340
1008
  msgctxt "admin-text"
1009
  msgid "Address"
1010
  msgstr "Address"
1011
 
1012
- #: config/settings.php:341
1013
  msgctxt "admin-text"
1014
  msgid "60 29th Street #343, San Francisco, CA 94110, US"
1015
  msgstr "60 29th Street #343, San Francisco, CA 94110, US"
1016
 
1017
- #: config/settings.php:350
1018
  msgctxt "admin-text"
1019
  msgid "Telephone Number"
1020
  msgstr "Telephone Number"
1021
 
1022
- #: config/settings.php:351
1023
  msgctxt "admin-text"
1024
  msgid "+1 (877) 273-3049"
1025
  msgstr "+1 (877) 273-3049"
1026
 
1027
- #: config/settings.php:360
1028
  msgctxt "admin-text"
1029
  msgid "Price Range"
1030
  msgstr "Price Range"
1031
 
1032
- #: config/settings.php:361
1033
  msgctxt "admin-text"
1034
  msgid "$$-$$$"
1035
  msgstr "$$-$$$"
1036
 
1037
- #: config/settings.php:370
1038
  msgctxt "admin-text"
1039
  msgid "Offer Type"
1040
  msgstr "Offer Type"
1041
 
1042
- #: config/settings.php:372
1043
  msgctxt "admin-text"
1044
  msgid "AggregateOffer"
1045
  msgstr "AggregateOffer"
1046
 
1047
- #: config/settings.php:373
1048
  msgctxt "admin-text"
1049
  msgid "Offer"
1050
  msgstr "Offer"
1051
 
1052
- #: config/settings.php:384
1053
  msgctxt "admin-text"
1054
  msgid "Price"
1055
  msgstr "Price"
1056
 
1057
- #: config/settings.php:395
1058
  msgctxt "admin-text"
1059
  msgid "Low Price"
1060
  msgstr "Low Price"
1061
 
1062
- #: config/settings.php:406
1063
  msgctxt "admin-text"
1064
  msgid "High Price"
1065
  msgstr "High Price"
1066
 
1067
- #: config/settings.php:416
1068
  msgctxt "admin-text"
1069
  msgid "Price Currency"
1070
  msgstr "Price Currency"
1071
 
1072
- #: config/settings.php:417
1073
  msgctxt "admin-text"
1074
  msgid "USD"
1075
  msgstr "USD"
1076
 
1077
- #: config/settings.php:422
1078
  msgctxt "admin-text"
1079
  msgid "Choose which fields should be required in the review form."
1080
  msgstr "Choose which fields should be required in the review form."
1081
 
1082
- #: config/settings.php:423
1083
  msgctxt "admin-text"
1084
  msgid "Required Fields"
1085
  msgstr "Required Fields"
1086
 
1087
- #: config/settings.php:425, config/forms/metabox-fields.php:5, plugin/Defaults/PostTypeColumnDefaults.php:25, plugin/Defaults/RevisionFieldsDefaults.php:16, plugin/Tinymce/SiteReviewsTinymce.php:30
1088
  msgctxt "admin-text"
1089
  msgid "Rating"
1090
  msgstr "Rating"
1091
 
1092
- #: config/settings.php:426, plugin/Tinymce/SiteReviewsFormTinymce.php:16, plugin/Tinymce/SiteReviewsSummaryTinymce.php:17, plugin/Tinymce/SiteReviewsTinymce.php:17, plugin/Widgets/SiteReviewsFormWidget.php:20, plugin/Widgets/SiteReviewsSummaryWidget.php:20, plugin/Widgets/SiteReviewsWidget.php:20
1093
  msgctxt "admin-text"
1094
  msgid "Title"
1095
  msgstr "Title"
1096
 
1097
- #: config/settings.php:427, plugin/Defaults/PostTypeLabelDefaults.php:15
1098
  msgctxt "admin-text"
1099
  msgid "Review"
1100
  msgstr "Review"
1101
 
1102
- #: config/settings.php:428, config/forms/metabox-fields.php:14, plugin/Controllers/PrivacyController.php:128, plugin/Defaults/PostTypeColumnDefaults.php:20, plugin/Defaults/RevisionFieldsDefaults.php:18
1103
  msgctxt "admin-text"
1104
  msgid "Name"
1105
  msgstr "Name"
1106
 
1107
- #: config/settings.php:429, config/forms/metabox-fields.php:18, plugin/Controllers/PrivacyController.php:129, plugin/Defaults/PostTypeColumnDefaults.php:21, plugin/Defaults/RevisionFieldsDefaults.php:19
1108
  msgctxt "admin-text"
1109
  msgid "Email"
1110
  msgstr "Email"
1111
 
1112
- #: config/settings.php:430
1113
  msgctxt "admin-text"
1114
  msgid "Terms"
1115
  msgstr "Terms"
1116
 
1117
- #: config/settings.php:436
1118
  msgctxt "admin-text"
1119
  msgid ""
1120
  "Limits the number of reviews that can be submitted to one-per-person. If "
1121
  "you are assigning reviews, then the limit will be applied to the assigned "
1122
- "page or category."
1123
  msgstr ""
1124
  "Limits the number of reviews that can be submitted to one-per-person. If "
1125
  "you are assigning reviews, then the limit will be applied to the assigned "
1126
- "page or category."
1127
 
1128
- #: config/settings.php:437
1129
  msgctxt "admin-text"
1130
  msgid "Limit Reviews"
1131
  msgstr "Limit Reviews"
1132
 
1133
- #: config/settings.php:439
1134
  msgctxt "admin-text"
1135
  msgid "No Limit"
1136
  msgstr "No Limit"
1137
 
1138
- #: config/settings.php:440
1139
  msgctxt "admin-text"
1140
  msgid "By Email Address"
1141
  msgstr "By Email Address"
1142
 
1143
- #: config/settings.php:441
1144
  msgctxt "admin-text"
1145
  msgid "By IP Address"
1146
  msgstr "By IP Address"
1147
 
1148
- #: config/settings.php:442
1149
  msgctxt "admin-text"
1150
  msgid "By Username (will only work for registered users)"
1151
  msgstr "By Username (will only work for registered users)"
1152
 
1153
- #: config/settings.php:451
1154
  msgctxt "admin-text"
1155
  msgid ""
1156
  "One Email per line. All emails in the whitelist will be excluded from the "
@@ -1159,12 +1201,12 @@ msgstr ""
1159
  "One Email per line. All emails in the whitelist will be excluded from the "
1160
  "review submission limit."
1161
 
1162
- #: config/settings.php:452
1163
  msgctxt "admin-text"
1164
  msgid "Email Whitelist"
1165
  msgstr "Email Whitelist"
1166
 
1167
- #: config/settings.php:461
1168
  msgctxt "admin-text"
1169
  msgid ""
1170
  "One IP Address per line. All IP Addresses in the whitelist will be excluded "
@@ -1173,12 +1215,12 @@ msgstr ""
1173
  "One IP Address per line. All IP Addresses in the whitelist will be excluded "
1174
  "from the review submission limit.."
1175
 
1176
- #: config/settings.php:462
1177
  msgctxt "admin-text"
1178
  msgid "IP Address Whitelist"
1179
  msgstr "IP Address Whitelist"
1180
 
1181
- #: config/settings.php:471
1182
  msgctxt "admin-text"
1183
  msgid ""
1184
  "One Username per line. All registered users with a Username in the "
@@ -1187,12 +1229,12 @@ msgstr ""
1187
  "One Username per line. All registered users with a Username in the "
1188
  "whitelist will be excluded from the review submission limit."
1189
 
1190
- #: config/settings.php:472
1191
  msgctxt "admin-text"
1192
  msgid "Username Whitelist"
1193
  msgstr "Username Whitelist"
1194
 
1195
- #: config/settings.php:478
1196
  msgctxt "admin-text"
1197
  msgid ""
1198
  "The Invisible reCAPTCHA badge (reCAPTCHA v2) is a free anti-spam service "
@@ -1205,37 +1247,37 @@ msgstr ""
1205
  "href=\"https://www.google.com/recaptcha/admin\" target=\"_blank\">sign "
1206
  "up</a> for an API key pair for your site."
1207
 
1208
- #: config/settings.php:479
1209
  msgctxt "admin-text"
1210
  msgid "Invisible reCAPTCHA"
1211
  msgstr "Invisible reCAPTCHA"
1212
 
1213
- #: config/settings.php:481
1214
  msgctxt "admin-text"
1215
  msgid "Do not use reCAPTCHA"
1216
  msgstr "Do not use reCAPTCHA"
1217
 
1218
- #: config/settings.php:482
1219
  msgctxt "admin-text"
1220
  msgid "Use reCAPTCHA"
1221
  msgstr "Use reCAPTCHA"
1222
 
1223
- #: config/settings.php:483
1224
  msgctxt "admin-text"
1225
  msgid "Use reCAPTCHA only for guest users"
1226
  msgstr "Use reCAPTCHA only for guest users"
1227
 
1228
- #: config/settings.php:492
1229
  msgctxt "admin-text"
1230
  msgid "Site Key"
1231
  msgstr "Site Key"
1232
 
1233
- #: config/settings.php:500
1234
  msgctxt "admin-text"
1235
  msgid "Site Secret"
1236
  msgstr "Site Secret"
1237
 
1238
- #: config/settings.php:508
1239
  msgctxt "admin-text"
1240
  msgid ""
1241
  "This option may not work consistently if another plugin is loading "
@@ -1244,27 +1286,27 @@ msgstr ""
1244
  "This option may not work consistently if another plugin is loading "
1245
  "reCAPTCHA on the same page as Site Reviews."
1246
 
1247
- #: config/settings.php:509
1248
  msgctxt "admin-text"
1249
  msgid "Badge Position"
1250
  msgstr "Badge Position"
1251
 
1252
- #: config/settings.php:511
1253
  msgctxt "admin-text"
1254
  msgid "Bottom Left"
1255
  msgstr "Bottom Left"
1256
 
1257
- #: config/settings.php:512
1258
  msgctxt "admin-text"
1259
  msgid "Bottom Right"
1260
  msgstr "Bottom Right"
1261
 
1262
- #: config/settings.php:513
1263
  msgctxt "admin-text"
1264
  msgid "Inline"
1265
  msgstr "Inline"
1266
 
1267
- #: config/settings.php:519
1268
  msgctxt "admin-text"
1269
  msgid ""
1270
  "The <a href=\"https://akismet.com\" target=\"_blank\">Akismet plugin</a> "
@@ -1277,12 +1319,12 @@ msgstr ""
1277
  "setting to have any affect, you will need to first install and activate the "
1278
  "Akismet plugin and set up a WordPress.com API key."
1279
 
1280
- #: config/settings.php:520
1281
  msgctxt "admin-text"
1282
  msgid "Enable Akismet Integration"
1283
  msgstr "Enable Akismet Integration"
1284
 
1285
- #: config/settings.php:525
1286
  msgctxt "admin-text"
1287
  msgid ""
1288
  "Choose which Blacklist you would prefer to use for reviews. The %s option "
@@ -1291,27 +1333,27 @@ msgstr ""
1291
  "Choose which Blacklist you would prefer to use for reviews. The %s option "
1292
  "can be found in the WordPress Discussion Settings page."
1293
 
1294
- #: config/settings.php:526
1295
  msgctxt "admin-text"
1296
  msgid "Disallowed Comment Keys"
1297
  msgstr "Disallowed Comment Keys"
1298
 
1299
- #: config/settings.php:528
1300
  msgctxt "admin-text"
1301
  msgid "Blacklist"
1302
  msgstr "Blacklist"
1303
 
1304
- #: config/settings.php:530
1305
  msgctxt "admin-text"
1306
  msgid "Use the Site Reviews Blacklist"
1307
  msgstr "Use the Site Reviews Blacklist"
1308
 
1309
- #: config/settings.php:531
1310
  msgctxt "admin-text"
1311
  msgid "Use the WordPress Disallowed Comment Keys"
1312
  msgstr "Use the WordPress Disallowed Comment Keys"
1313
 
1314
- #: config/settings.php:540
1315
  msgctxt "admin-text"
1316
  msgid ""
1317
  "One entry or IP address per line. When a review contains any of these "
@@ -1324,36 +1366,31 @@ msgstr ""
1324
  "rejected. It is case-insensitive and will match partial words, so \"press\" "
1325
  "will match \"WordPress\"."
1326
 
1327
- #: config/settings.php:541
1328
  msgctxt "admin-text"
1329
  msgid "Review Blacklist"
1330
  msgstr "Review Blacklist"
1331
 
1332
- #: config/settings.php:547
1333
  msgctxt "admin-text"
1334
  msgid "Choose the action that should be taken when a review is blacklisted."
1335
  msgstr "Choose the action that should be taken when a review is blacklisted."
1336
 
1337
- #: config/settings.php:548
1338
  msgctxt "admin-text"
1339
  msgid "Blacklist Action"
1340
  msgstr "Blacklist Action"
1341
 
1342
- #: config/settings.php:550
1343
  msgctxt "admin-text"
1344
  msgid "Require approval"
1345
  msgstr "Require approval"
1346
 
1347
- #: config/settings.php:551
1348
  msgctxt "admin-text"
1349
  msgid "Reject submission"
1350
  msgstr "Reject submission"
1351
 
1352
- #: plugin/Application.php:224
1353
- msgctxt "admin-text"
1354
- msgid "Local Review"
1355
- msgstr "Local Review"
1356
-
1357
  #: plugin/Deprecated.php:24
1358
  msgctxt "admin-text"
1359
  msgid ""
@@ -1363,7 +1400,7 @@ msgstr ""
1363
  "The [%s] method has been deprecated and will be soon be removed, please use "
1364
  "the [%s] method instead."
1365
 
1366
- #: plugin/Review.php:264, plugin/Controllers/ListTableColumns/ColumnValueAuthorName.php:20
1367
  msgctxt "admin-text"
1368
  msgid "Unknown"
1369
  msgstr "Unknown"
@@ -1433,12 +1470,12 @@ msgctxt "admin-text"
1433
  msgid "Avatar"
1434
  msgstr "Avatar"
1435
 
1436
- #: plugin/Addons/Controller.php:70, plugin/Controllers/AdminController.php:47, plugin/Controllers/MenuController.php:50, views/pages/tools/sync.php:23
1437
  msgctxt "admin-text"
1438
  msgid "Settings"
1439
  msgstr "Settings"
1440
 
1441
- #: plugin/Addons/Controller.php:76, plugin/Controllers/AdminController.php:53, plugin/Controllers/MenuController.php:53
1442
  msgctxt "admin-text"
1443
  msgid "Help"
1444
  msgstr "Help"
@@ -1497,29 +1534,29 @@ msgctxt "admin-text"
1497
  msgid "Edit"
1498
  msgstr "Edit"
1499
 
1500
- #: plugin/Controllers/AdminController.php:84
1501
  msgctxt "admin-text"
1502
  msgid "%s Review"
1503
  msgid_plural "%s Reviews"
1504
  msgstr[0] "%s Review"
1505
  msgstr[1] "%s Reviews"
1506
 
1507
- #: plugin/Controllers/AdminController.php:148, plugin/Controllers/MainController.php:70
1508
  msgctxt "admin-text"
1509
  msgid "Recent Reviews"
1510
  msgstr "Recent Reviews"
1511
 
1512
- #: plugin/Controllers/AdminController.php:149, plugin/Controllers/MainController.php:74
1513
  msgctxt "admin-text"
1514
  msgid "Submit a Review"
1515
  msgstr "Submit a Review"
1516
 
1517
- #: plugin/Controllers/AdminController.php:150, plugin/Controllers/MainController.php:78
1518
  msgctxt "admin-text"
1519
  msgid "Summary of Reviews"
1520
  msgstr "Summary of Reviews"
1521
 
1522
- #: plugin/Controllers/AdminController.php:185, plugin/Controllers/AdminController.php:205, plugin/Controllers/AdminController.php:218
1523
  msgctxt "admin-text"
1524
  msgid "Nothing found."
1525
  msgstr "Nothing found."
@@ -1549,17 +1586,22 @@ msgctxt "admin-text"
1549
  msgid "Unapprove"
1550
  msgstr "Unapprove"
1551
 
1552
- #: plugin/Controllers/MainController.php:69
 
 
 
 
 
1553
  msgctxt "admin-text"
1554
  msgid "Site Reviews: Display your recent reviews."
1555
  msgstr "Site Reviews: Display your recent reviews."
1556
 
1557
- #: plugin/Controllers/MainController.php:73
1558
  msgctxt "admin-text"
1559
  msgid "Site Reviews: Display a form to submit reviews."
1560
  msgstr "Site Reviews: Display a form to submit reviews."
1561
 
1562
- #: plugin/Controllers/MainController.php:77
1563
  msgctxt "admin-text"
1564
  msgid "Site Reviews: Display a summary of your reviews."
1565
  msgstr "Site Reviews: Display a summary of your reviews."
@@ -1764,30 +1806,30 @@ msgstr "Console reloaded."
1764
 
1765
  #: plugin/Controllers/ToolsController.php:157
1766
  msgctxt "admin-text"
1767
- msgid "The plugin has been migrated sucessfully."
1768
- msgstr "The plugin has been migrated sucessfully."
1769
 
1770
  #: plugin/Controllers/ToolsController.php:154
1771
  msgctxt "admin-text"
1772
- msgid "All plugin migrations have been run successfully."
1773
- msgstr "All plugin migrations have been run successfully."
1774
 
1775
  #: plugin/Controllers/ToolsController.php:180
1776
  msgctxt "admin-text"
1777
  msgid "The assigned meta values have been reset."
1778
  msgstr "The assigned meta values have been reset."
1779
 
1780
- #: plugin/Controllers/ToolsController.php:202
1781
  msgctxt "admin-text"
1782
  msgid "The permissions have been reset."
1783
  msgstr "The permissions have been reset."
1784
 
1785
- #: plugin/Controllers/ToolsController.php:213
1786
  msgctxt "admin-text"
1787
  msgid "reload the page"
1788
  msgstr "reload the page"
1789
 
1790
- #: plugin/Controllers/ToolsController.php:217
1791
  msgctxt "admin-text"
1792
  msgid "The permissions have been reset, please %s for them to take effect."
1793
  msgstr "The permissions have been reset, please %s for them to take effect."
@@ -1942,6 +1984,21 @@ msgctxt "admin-text"
1942
  msgid "The link to edit/view a review"
1943
  msgstr "The link to edit/view a review"
1944
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1945
  #: plugin/Defaults/UpdatedMessageDefaults.php:15
1946
  msgctxt "admin-text"
1947
  msgid "Review has been approved and published."
@@ -2422,11 +2479,6 @@ msgctxt "admin-text"
2422
  msgid "All types"
2423
  msgstr "All types"
2424
 
2425
- #: plugin/Controllers/ListTableColumns/ColumnValueType.php:17
2426
- msgctxt "admin-text"
2427
- msgid "Unsupported Type"
2428
- msgstr "Unsupported Type"
2429
-
2430
  #: views/pages/addons/index.php:6
2431
  msgctxt "admin-text"
2432
  msgid ""
@@ -2596,22 +2648,27 @@ msgctxt "admin-text"
2596
  msgid "Reset Meta Values"
2597
  msgstr "Reset Meta Values"
2598
 
2599
- #: views/pages/tools/general.php:104
 
 
 
 
 
2600
  msgctxt "admin-text"
2601
  msgid "Resetting, please wait..."
2602
  msgstr "Resetting, please wait..."
2603
 
2604
- #: views/pages/tools/general.php:104
2605
  msgctxt "admin-text"
2606
  msgid "Reset Permissions"
2607
  msgstr "Reset Permissions"
2608
 
2609
- #: views/pages/tools/general.php:121
2610
  msgctxt "admin-text"
2611
  msgid "Testing, please wait..."
2612
  msgstr "Testing, please wait..."
2613
 
2614
- #: views/pages/tools/general.php:121
2615
  msgctxt "admin-text"
2616
  msgid "Test Detection"
2617
  msgstr "Test Detection"
@@ -2768,11 +2825,13 @@ msgstr "Add-ons for Site Reviews are now available!"
2768
  #: views/partials/notices/addons.php:23
2769
  msgctxt "admin-text"
2770
  msgid ""
2771
- "Allow people to submit captioned images with their review, and sort, "
2772
- "filter, and search reviews."
 
2773
  msgstr ""
2774
- "Allow people to submit captioned images with their review, and sort, "
2775
- "filter, and search reviews."
 
2776
 
2777
  #: views/partials/notices/addons.php:26
2778
  msgctxt "admin-text"
@@ -2905,7 +2964,7 @@ msgctxt "View Post (admin-text)"
2905
  msgid "View %s"
2906
  msgstr "View %s"
2907
 
2908
- #: plugin/Modules/Notification.php:141
2909
  msgctxt ""
2910
  "This string differs depending on whether or not the review has been "
2911
  "assigned to a post."
30
  msgid "%s is <strong>deprecated</strong> since version %s! Use %s instead."
31
  msgstr "%s is <strong>deprecated</strong> since version %s! Use %s instead."
32
 
33
+ #: config/settings.php:238, plugin/Modules/Html/ReviewsHtml.php:126
34
  msgid "There are no reviews yet. Be the first one to write one."
35
  msgstr "There are no reviews yet. Be the first one to write one."
36
 
82
  msgid "Show more"
83
  msgstr "Show more"
84
 
85
+ #: plugin/Commands/CreateReview.php:156
86
  msgid "Your review has been submitted!"
87
  msgstr "Your review has been submitted!"
88
 
89
+ #: plugin/Commands/CreateReview.php:161
90
  msgid ""
91
  "Your review could not be submitted and the error has been logged. Please "
92
  "notify the site admin."
126
  msgid "This field requires a valid e-mail address."
127
  msgstr "This field requires a valid e-mail address."
128
 
129
+ #: plugin/Defaults/ValidationStringsDefaults.php:19, plugin/Modules/Validator/DefaultValidator.php:58
130
  msgid "Please fix the submission errors."
131
  msgstr "Please fix the submission errors."
132
 
208
  msgstr[0] "%s year ago"
209
  msgstr[1] "%s years ago"
210
 
211
+ #: plugin/Modules/Notification.php:73
212
  msgid "Anonymous"
213
  msgstr "Anonymous"
214
 
256
  msgid "The reCAPTCHA verification failed, please try again."
257
  msgstr "The reCAPTCHA verification failed, please try again."
258
 
259
+ #: plugin/Modules/Validator/ReviewLimitsValidator.php:34
260
  msgid "You have already submitted a review."
261
  msgstr "You have already submitted a review."
262
 
788
  msgid "Initial with a period and a space"
789
  msgstr "Initial with a period and a space"
790
 
791
+ #: config/settings.php:178
792
+ msgctxt "admin-text"
793
+ msgid ""
794
+ "This setting determines how the assigned options work in the reviews and "
795
+ "summary shortcodes and blocks."
796
+ msgstr ""
797
+ "This setting determines how the assigned options work in the reviews and "
798
+ "summary shortcodes and blocks."
799
+
800
+ #: config/settings.php:179
801
+ msgctxt "admin-text"
802
+ msgid ""
803
+ "\"Loose Assignment\" means <code>display reviews that are assigned to this "
804
+ "OR this</code>."
805
+ msgstr ""
806
+ "\"Loose Assignment\" means <code>display reviews that are assigned to this "
807
+ "OR this</code>."
808
+
809
+ #: config/settings.php:180
810
+ msgctxt "admin-text"
811
+ msgid ""
812
+ "\"Strict Assignment\" means <code>display reviews that are assigned to this "
813
+ "AND this</code>."
814
+ msgstr ""
815
+ "\"Strict Assignment\" means <code>display reviews that are assigned to this "
816
+ "AND this</code>."
817
+
818
+ #: config/settings.php:182
819
+ msgctxt "admin-text"
820
+ msgid "Review Assignment"
821
+ msgstr "Review Assignment"
822
+
823
+ #: config/settings.php:184
824
+ msgctxt "admin-text"
825
+ msgid "Loose Assignment"
826
+ msgstr "Loose Assignment"
827
+
828
+ #: config/settings.php:185
829
+ msgctxt "admin-text"
830
+ msgid "Strict Assignment"
831
+ msgstr "Strict Assignment"
832
+
833
+ #: config/settings.php:191
834
  msgctxt "admin-text"
835
  msgid "Display a link to the assigned posts of a review."
836
  msgstr "Display a link to the assigned posts of a review."
837
 
838
+ #: config/settings.php:192
839
  msgctxt "admin-text"
840
  msgid "Enable Assigned Links"
841
  msgstr "Enable Assigned Links"
842
 
843
+ #: config/settings.php:197
844
  msgctxt "admin-text"
845
  msgid ""
846
  "Display reviewer avatars. These are generated from the email address of the "
849
  "Display reviewer avatars. These are generated from the email address of the "
850
  "reviewer using <a href=\"https://gravatar.com\">Gravatar</a>."
851
 
852
+ #: config/settings.php:198
853
  msgctxt "admin-text"
854
  msgid "Enable Avatars"
855
  msgstr "Enable Avatars"
856
 
857
+ #: config/settings.php:206
858
  msgctxt "admin-text"
859
  msgid "Regenerate the avatar whenever a local review is shown?"
860
  msgstr "Regenerate the avatar whenever a local review is shown?"
861
 
862
+ #: config/settings.php:207
863
  msgctxt "admin-text"
864
  msgid "Regenerate Avatars"
865
  msgstr "Regenerate Avatars"
866
 
867
+ #: config/settings.php:215
868
  msgctxt "admin-text"
869
  msgid "Set the avatar size in pixels."
870
  msgstr "Set the avatar size in pixels."
871
 
872
+ #: config/settings.php:216
873
  msgctxt "admin-text"
874
  msgid "Avatar Size"
875
  msgstr "Avatar Size"
876
 
877
+ #: config/settings.php:221
878
  msgctxt "admin-text"
879
  msgid "Display an excerpt instead of the full review."
880
  msgstr "Display an excerpt instead of the full review."
881
 
882
+ #: config/settings.php:222
883
  msgctxt "admin-text"
884
  msgid "Enable Excerpts"
885
  msgstr "Enable Excerpts"
886
 
887
+ #: config/settings.php:230
888
  msgctxt "admin-text"
889
  msgid "Set the excerpt word length."
890
  msgstr "Set the excerpt word length."
891
 
892
+ #: config/settings.php:231
893
  msgctxt "admin-text"
894
  msgid "Excerpt Length"
895
  msgstr "Excerpt Length"
896
 
897
+ #: config/settings.php:236
898
  msgctxt "admin-text"
899
  msgid ""
900
  "Display the fallback text when there are no reviews to display. This can be "
905
  "changed on the %s page. You may also override this by using the "
906
  "\"fallback\" option on the shortcode. The default fallback text is: %s"
907
 
908
+ #: config/settings.php:237, plugin/Controllers/MenuController.php:118
909
  msgctxt "admin-text"
910
  msgid "Translations"
911
  msgstr "Translations"
912
 
913
+ #: config/settings.php:240
914
  msgctxt "admin-text"
915
  msgid "Enable Fallback Text"
916
  msgstr "Enable Fallback Text"
917
 
918
+ #: config/settings.php:246
919
  msgctxt "admin-text"
920
  msgid ""
921
  "Paginated URLs include the %s URL parameter. If you would like to keep the "
926
  "pagination links but prevent search engines from indexing them, add the "
927
  "following lines to your %s file instead: %s"
928
 
929
+ #: config/settings.php:253
930
  msgctxt "admin-text"
931
  msgid "Enable Paginated URLs"
932
  msgstr "Enable Paginated URLs"
933
 
934
+ #: config/settings.php:258, config/settings.php:278, config/settings.php:296, config/settings.php:314, config/settings.php:332, config/settings.php:353, config/settings.php:363, config/settings.php:373, config/settings.php:383, config/settings.php:397, config/settings.php:408, config/settings.php:419, config/settings.php:429
935
  msgctxt "admin-text"
936
  msgid "Custom Field name"
937
  msgstr "Custom Field name"
938
 
939
+ #: config/settings.php:259
940
  msgctxt "admin-text"
941
  msgid "Default Schema Type"
942
  msgstr "Default Schema Type"
943
 
944
+ #: config/settings.php:261
945
  msgctxt "admin-text"
946
  msgid "Local Business"
947
  msgstr "Local Business"
948
 
949
+ #: config/settings.php:262
950
  msgctxt "admin-text"
951
  msgid "Product"
952
  msgstr "Product"
953
 
954
+ #: config/settings.php:263
955
  msgctxt "admin-text"
956
  msgid "Custom"
957
  msgstr "Custom"
958
 
959
+ #: config/settings.php:272
960
  msgctxt "admin-text"
961
  msgid "View more information on schema types here"
962
  msgstr "View more information on schema types here"
963
 
964
+ #: config/settings.php:273
965
  msgctxt "admin-text"
966
  msgid "Custom Schema Type"
967
  msgstr "Custom Schema Type"
968
 
969
+ #: config/settings.php:279
970
  msgctxt "admin-text"
971
  msgid "Default Name"
972
  msgstr "Default Name"
973
 
974
+ #: config/settings.php:281
975
  msgctxt "admin-text"
976
  msgid "Use the assigned or current page title"
977
  msgstr "Use the assigned or current page title"
978
 
979
+ #: config/settings.php:282
980
  msgctxt "admin-text"
981
  msgid "Enter a custom title"
982
  msgstr "Enter a custom title"
983
 
984
+ #: config/settings.php:291
985
  msgctxt "admin-text"
986
  msgid "Custom Name"
987
  msgstr "Custom Name"
988
 
989
+ #: config/settings.php:297
990
  msgctxt "admin-text"
991
  msgid "Default Description"
992
  msgstr "Default Description"
993
 
994
+ #: config/settings.php:299
995
  msgctxt "admin-text"
996
  msgid "Use the assigned or current page excerpt"
997
  msgstr "Use the assigned or current page excerpt"
998
 
999
+ #: config/settings.php:300
1000
  msgctxt "admin-text"
1001
  msgid "Enter a custom description"
1002
  msgstr "Enter a custom description"
1003
 
1004
+ #: config/settings.php:309
1005
  msgctxt "admin-text"
1006
  msgid "Custom Description"
1007
  msgstr "Custom Description"
1008
 
1009
+ #: config/settings.php:315
1010
  msgctxt "admin-text"
1011
  msgid "Default URL"
1012
  msgstr "Default URL"
1013
 
1014
+ #: config/settings.php:317
1015
  msgctxt "admin-text"
1016
  msgid "Use the assigned or current page URL"
1017
  msgstr "Use the assigned or current page URL"
1018
 
1019
+ #: config/settings.php:318
1020
  msgctxt "admin-text"
1021
  msgid "Enter a custom URL"
1022
  msgstr "Enter a custom URL"
1023
 
1024
+ #: config/settings.php:327
1025
  msgctxt "admin-text"
1026
  msgid "Custom URL"
1027
  msgstr "Custom URL"
1028
 
1029
+ #: config/settings.php:333
1030
  msgctxt "admin-text"
1031
  msgid "Default Image"
1032
  msgstr "Default Image"
1033
 
1034
+ #: config/settings.php:335
1035
  msgctxt "admin-text"
1036
  msgid "Use the featured image of the assigned or current page"
1037
  msgstr "Use the featured image of the assigned or current page"
1038
 
1039
+ #: config/settings.php:336
1040
  msgctxt "admin-text"
1041
  msgid "Enter a custom image URL"
1042
  msgstr "Enter a custom image URL"
1043
 
1044
+ #: config/settings.php:345
1045
  msgctxt "admin-text"
1046
  msgid "Custom Image URL"
1047
  msgstr "Custom Image URL"
1048
 
1049
+ #: config/settings.php:354
1050
  msgctxt "admin-text"
1051
  msgid "Address"
1052
  msgstr "Address"
1053
 
1054
+ #: config/settings.php:355
1055
  msgctxt "admin-text"
1056
  msgid "60 29th Street #343, San Francisco, CA 94110, US"
1057
  msgstr "60 29th Street #343, San Francisco, CA 94110, US"
1058
 
1059
+ #: config/settings.php:364
1060
  msgctxt "admin-text"
1061
  msgid "Telephone Number"
1062
  msgstr "Telephone Number"
1063
 
1064
+ #: config/settings.php:365
1065
  msgctxt "admin-text"
1066
  msgid "+1 (877) 273-3049"
1067
  msgstr "+1 (877) 273-3049"
1068
 
1069
+ #: config/settings.php:374
1070
  msgctxt "admin-text"
1071
  msgid "Price Range"
1072
  msgstr "Price Range"
1073
 
1074
+ #: config/settings.php:375
1075
  msgctxt "admin-text"
1076
  msgid "$$-$$$"
1077
  msgstr "$$-$$$"
1078
 
1079
+ #: config/settings.php:384
1080
  msgctxt "admin-text"
1081
  msgid "Offer Type"
1082
  msgstr "Offer Type"
1083
 
1084
+ #: config/settings.php:386
1085
  msgctxt "admin-text"
1086
  msgid "AggregateOffer"
1087
  msgstr "AggregateOffer"
1088
 
1089
+ #: config/settings.php:387
1090
  msgctxt "admin-text"
1091
  msgid "Offer"
1092
  msgstr "Offer"
1093
 
1094
+ #: config/settings.php:398
1095
  msgctxt "admin-text"
1096
  msgid "Price"
1097
  msgstr "Price"
1098
 
1099
+ #: config/settings.php:409
1100
  msgctxt "admin-text"
1101
  msgid "Low Price"
1102
  msgstr "Low Price"
1103
 
1104
+ #: config/settings.php:420
1105
  msgctxt "admin-text"
1106
  msgid "High Price"
1107
  msgstr "High Price"
1108
 
1109
+ #: config/settings.php:430
1110
  msgctxt "admin-text"
1111
  msgid "Price Currency"
1112
  msgstr "Price Currency"
1113
 
1114
+ #: config/settings.php:431
1115
  msgctxt "admin-text"
1116
  msgid "USD"
1117
  msgstr "USD"
1118
 
1119
+ #: config/settings.php:436
1120
  msgctxt "admin-text"
1121
  msgid "Choose which fields should be required in the review form."
1122
  msgstr "Choose which fields should be required in the review form."
1123
 
1124
+ #: config/settings.php:437
1125
  msgctxt "admin-text"
1126
  msgid "Required Fields"
1127
  msgstr "Required Fields"
1128
 
1129
+ #: config/settings.php:439, config/forms/metabox-fields.php:5, plugin/Defaults/PostTypeColumnDefaults.php:25, plugin/Defaults/RevisionFieldsDefaults.php:16, plugin/Tinymce/SiteReviewsTinymce.php:30
1130
  msgctxt "admin-text"
1131
  msgid "Rating"
1132
  msgstr "Rating"
1133
 
1134
+ #: config/settings.php:440, plugin/Tinymce/SiteReviewsFormTinymce.php:16, plugin/Tinymce/SiteReviewsSummaryTinymce.php:17, plugin/Tinymce/SiteReviewsTinymce.php:17, plugin/Widgets/SiteReviewsFormWidget.php:20, plugin/Widgets/SiteReviewsSummaryWidget.php:20, plugin/Widgets/SiteReviewsWidget.php:20
1135
  msgctxt "admin-text"
1136
  msgid "Title"
1137
  msgstr "Title"
1138
 
1139
+ #: config/settings.php:441, plugin/Defaults/PostTypeLabelDefaults.php:15
1140
  msgctxt "admin-text"
1141
  msgid "Review"
1142
  msgstr "Review"
1143
 
1144
+ #: config/settings.php:442, config/forms/metabox-fields.php:14, plugin/Controllers/PrivacyController.php:128, plugin/Defaults/PostTypeColumnDefaults.php:20, plugin/Defaults/RevisionFieldsDefaults.php:18
1145
  msgctxt "admin-text"
1146
  msgid "Name"
1147
  msgstr "Name"
1148
 
1149
+ #: config/settings.php:443, config/forms/metabox-fields.php:18, plugin/Controllers/PrivacyController.php:129, plugin/Defaults/PostTypeColumnDefaults.php:21, plugin/Defaults/RevisionFieldsDefaults.php:19
1150
  msgctxt "admin-text"
1151
  msgid "Email"
1152
  msgstr "Email"
1153
 
1154
+ #: config/settings.php:444
1155
  msgctxt "admin-text"
1156
  msgid "Terms"
1157
  msgstr "Terms"
1158
 
1159
+ #: config/settings.php:450
1160
  msgctxt "admin-text"
1161
  msgid ""
1162
  "Limits the number of reviews that can be submitted to one-per-person. If "
1163
  "you are assigning reviews, then the limit will be applied to the assigned "
1164
+ "page and/or category."
1165
  msgstr ""
1166
  "Limits the number of reviews that can be submitted to one-per-person. If "
1167
  "you are assigning reviews, then the limit will be applied to the assigned "
1168
+ "page and/or category."
1169
 
1170
+ #: config/settings.php:451
1171
  msgctxt "admin-text"
1172
  msgid "Limit Reviews"
1173
  msgstr "Limit Reviews"
1174
 
1175
+ #: config/settings.php:453
1176
  msgctxt "admin-text"
1177
  msgid "No Limit"
1178
  msgstr "No Limit"
1179
 
1180
+ #: config/settings.php:454
1181
  msgctxt "admin-text"
1182
  msgid "By Email Address"
1183
  msgstr "By Email Address"
1184
 
1185
+ #: config/settings.php:455
1186
  msgctxt "admin-text"
1187
  msgid "By IP Address"
1188
  msgstr "By IP Address"
1189
 
1190
+ #: config/settings.php:456
1191
  msgctxt "admin-text"
1192
  msgid "By Username (will only work for registered users)"
1193
  msgstr "By Username (will only work for registered users)"
1194
 
1195
+ #: config/settings.php:465
1196
  msgctxt "admin-text"
1197
  msgid ""
1198
  "One Email per line. All emails in the whitelist will be excluded from the "
1201
  "One Email per line. All emails in the whitelist will be excluded from the "
1202
  "review submission limit."
1203
 
1204
+ #: config/settings.php:466
1205
  msgctxt "admin-text"
1206
  msgid "Email Whitelist"
1207
  msgstr "Email Whitelist"
1208
 
1209
+ #: config/settings.php:475
1210
  msgctxt "admin-text"
1211
  msgid ""
1212
  "One IP Address per line. All IP Addresses in the whitelist will be excluded "
1215
  "One IP Address per line. All IP Addresses in the whitelist will be excluded "
1216
  "from the review submission limit.."
1217
 
1218
+ #: config/settings.php:476
1219
  msgctxt "admin-text"
1220
  msgid "IP Address Whitelist"
1221
  msgstr "IP Address Whitelist"
1222
 
1223
+ #: config/settings.php:485
1224
  msgctxt "admin-text"
1225
  msgid ""
1226
  "One Username per line. All registered users with a Username in the "
1229
  "One Username per line. All registered users with a Username in the "
1230
  "whitelist will be excluded from the review submission limit."
1231
 
1232
+ #: config/settings.php:486
1233
  msgctxt "admin-text"
1234
  msgid "Username Whitelist"
1235
  msgstr "Username Whitelist"
1236
 
1237
+ #: config/settings.php:492
1238
  msgctxt "admin-text"
1239
  msgid ""
1240
  "The Invisible reCAPTCHA badge (reCAPTCHA v2) is a free anti-spam service "
1247
  "href=\"https://www.google.com/recaptcha/admin\" target=\"_blank\">sign "
1248
  "up</a> for an API key pair for your site."
1249
 
1250
+ #: config/settings.php:493
1251
  msgctxt "admin-text"
1252
  msgid "Invisible reCAPTCHA"
1253
  msgstr "Invisible reCAPTCHA"
1254
 
1255
+ #: config/settings.php:495
1256
  msgctxt "admin-text"
1257
  msgid "Do not use reCAPTCHA"
1258
  msgstr "Do not use reCAPTCHA"
1259
 
1260
+ #: config/settings.php:496
1261
  msgctxt "admin-text"
1262
  msgid "Use reCAPTCHA"
1263
  msgstr "Use reCAPTCHA"
1264
 
1265
+ #: config/settings.php:497
1266
  msgctxt "admin-text"
1267
  msgid "Use reCAPTCHA only for guest users"
1268
  msgstr "Use reCAPTCHA only for guest users"
1269
 
1270
+ #: config/settings.php:506
1271
  msgctxt "admin-text"
1272
  msgid "Site Key"
1273
  msgstr "Site Key"
1274
 
1275
+ #: config/settings.php:514
1276
  msgctxt "admin-text"
1277
  msgid "Site Secret"
1278
  msgstr "Site Secret"
1279
 
1280
+ #: config/settings.php:522
1281
  msgctxt "admin-text"
1282
  msgid ""
1283
  "This option may not work consistently if another plugin is loading "
1286
  "This option may not work consistently if another plugin is loading "
1287
  "reCAPTCHA on the same page as Site Reviews."
1288
 
1289
+ #: config/settings.php:523
1290
  msgctxt "admin-text"
1291
  msgid "Badge Position"
1292
  msgstr "Badge Position"
1293
 
1294
+ #: config/settings.php:525
1295
  msgctxt "admin-text"
1296
  msgid "Bottom Left"
1297
  msgstr "Bottom Left"
1298
 
1299
+ #: config/settings.php:526
1300
  msgctxt "admin-text"
1301
  msgid "Bottom Right"
1302
  msgstr "Bottom Right"
1303
 
1304
+ #: config/settings.php:527
1305
  msgctxt "admin-text"
1306
  msgid "Inline"
1307
  msgstr "Inline"
1308
 
1309
+ #: config/settings.php:533
1310
  msgctxt "admin-text"
1311
  msgid ""
1312
  "The <a href=\"https://akismet.com\" target=\"_blank\">Akismet plugin</a> "
1319
  "setting to have any affect, you will need to first install and activate the "
1320
  "Akismet plugin and set up a WordPress.com API key."
1321
 
1322
+ #: config/settings.php:534
1323
  msgctxt "admin-text"
1324
  msgid "Enable Akismet Integration"
1325
  msgstr "Enable Akismet Integration"
1326
 
1327
+ #: config/settings.php:539
1328
  msgctxt "admin-text"
1329
  msgid ""
1330
  "Choose which Blacklist you would prefer to use for reviews. The %s option "
1333
  "Choose which Blacklist you would prefer to use for reviews. The %s option "
1334
  "can be found in the WordPress Discussion Settings page."
1335
 
1336
+ #: config/settings.php:540
1337
  msgctxt "admin-text"
1338
  msgid "Disallowed Comment Keys"
1339
  msgstr "Disallowed Comment Keys"
1340
 
1341
+ #: config/settings.php:542
1342
  msgctxt "admin-text"
1343
  msgid "Blacklist"
1344
  msgstr "Blacklist"
1345
 
1346
+ #: config/settings.php:544
1347
  msgctxt "admin-text"
1348
  msgid "Use the Site Reviews Blacklist"
1349
  msgstr "Use the Site Reviews Blacklist"
1350
 
1351
+ #: config/settings.php:545
1352
  msgctxt "admin-text"
1353
  msgid "Use the WordPress Disallowed Comment Keys"
1354
  msgstr "Use the WordPress Disallowed Comment Keys"
1355
 
1356
+ #: config/settings.php:554
1357
  msgctxt "admin-text"
1358
  msgid ""
1359
  "One entry or IP address per line. When a review contains any of these "
1366
  "rejected. It is case-insensitive and will match partial words, so \"press\" "
1367
  "will match \"WordPress\"."
1368
 
1369
+ #: config/settings.php:555
1370
  msgctxt "admin-text"
1371
  msgid "Review Blacklist"
1372
  msgstr "Review Blacklist"
1373
 
1374
+ #: config/settings.php:561
1375
  msgctxt "admin-text"
1376
  msgid "Choose the action that should be taken when a review is blacklisted."
1377
  msgstr "Choose the action that should be taken when a review is blacklisted."
1378
 
1379
+ #: config/settings.php:562
1380
  msgctxt "admin-text"
1381
  msgid "Blacklist Action"
1382
  msgstr "Blacklist Action"
1383
 
1384
+ #: config/settings.php:564
1385
  msgctxt "admin-text"
1386
  msgid "Require approval"
1387
  msgstr "Require approval"
1388
 
1389
+ #: config/settings.php:565
1390
  msgctxt "admin-text"
1391
  msgid "Reject submission"
1392
  msgstr "Reject submission"
1393
 
 
 
 
 
 
1394
  #: plugin/Deprecated.php:24
1395
  msgctxt "admin-text"
1396
  msgid ""
1400
  "The [%s] method has been deprecated and will be soon be removed, please use "
1401
  "the [%s] method instead."
1402
 
1403
+ #: plugin/Review.php:307, plugin/Controllers/ListTableColumns/ColumnValueAuthorName.php:20
1404
  msgctxt "admin-text"
1405
  msgid "Unknown"
1406
  msgstr "Unknown"
1470
  msgid "Avatar"
1471
  msgstr "Avatar"
1472
 
1473
+ #: plugin/Addons/Controller.php:70, plugin/Controllers/AdminController.php:48, plugin/Controllers/MenuController.php:50, views/pages/tools/sync.php:23
1474
  msgctxt "admin-text"
1475
  msgid "Settings"
1476
  msgstr "Settings"
1477
 
1478
+ #: plugin/Addons/Controller.php:76, plugin/Controllers/AdminController.php:54, plugin/Controllers/MenuController.php:53
1479
  msgctxt "admin-text"
1480
  msgid "Help"
1481
  msgstr "Help"
1534
  msgid "Edit"
1535
  msgstr "Edit"
1536
 
1537
+ #: plugin/Controllers/AdminController.php:85
1538
  msgctxt "admin-text"
1539
  msgid "%s Review"
1540
  msgid_plural "%s Reviews"
1541
  msgstr[0] "%s Review"
1542
  msgstr[1] "%s Reviews"
1543
 
1544
+ #: plugin/Controllers/AdminController.php:165, plugin/Controllers/MainController.php:149
1545
  msgctxt "admin-text"
1546
  msgid "Recent Reviews"
1547
  msgstr "Recent Reviews"
1548
 
1549
+ #: plugin/Controllers/AdminController.php:166, plugin/Controllers/MainController.php:153
1550
  msgctxt "admin-text"
1551
  msgid "Submit a Review"
1552
  msgstr "Submit a Review"
1553
 
1554
+ #: plugin/Controllers/AdminController.php:167, plugin/Controllers/MainController.php:157
1555
  msgctxt "admin-text"
1556
  msgid "Summary of Reviews"
1557
  msgstr "Summary of Reviews"
1558
 
1559
+ #: plugin/Controllers/AdminController.php:202, plugin/Controllers/AdminController.php:222, plugin/Controllers/AdminController.php:235
1560
  msgctxt "admin-text"
1561
  msgid "Nothing found."
1562
  msgstr "Nothing found."
1586
  msgid "Unapprove"
1587
  msgstr "Unapprove"
1588
 
1589
+ #: plugin/Controllers/MainController.php:105
1590
+ msgctxt "admin-text"
1591
+ msgid "Local Review"
1592
+ msgstr "Local Review"
1593
+
1594
+ #: plugin/Controllers/MainController.php:148
1595
  msgctxt "admin-text"
1596
  msgid "Site Reviews: Display your recent reviews."
1597
  msgstr "Site Reviews: Display your recent reviews."
1598
 
1599
+ #: plugin/Controllers/MainController.php:152
1600
  msgctxt "admin-text"
1601
  msgid "Site Reviews: Display a form to submit reviews."
1602
  msgstr "Site Reviews: Display a form to submit reviews."
1603
 
1604
+ #: plugin/Controllers/MainController.php:156
1605
  msgctxt "admin-text"
1606
  msgid "Site Reviews: Display a summary of your reviews."
1607
  msgstr "Site Reviews: Display a summary of your reviews."
1806
 
1807
  #: plugin/Controllers/ToolsController.php:157
1808
  msgctxt "admin-text"
1809
+ msgid "The plugin has been migrated sucessfully, please reload the page."
1810
+ msgstr "The plugin has been migrated sucessfully, please reload the page."
1811
 
1812
  #: plugin/Controllers/ToolsController.php:154
1813
  msgctxt "admin-text"
1814
+ msgid "All plugin migrations have been run successfully, please reload the page."
1815
+ msgstr "All plugin migrations have been run successfully, please reload the page."
1816
 
1817
  #: plugin/Controllers/ToolsController.php:180
1818
  msgctxt "admin-text"
1819
  msgid "The assigned meta values have been reset."
1820
  msgstr "The assigned meta values have been reset."
1821
 
1822
+ #: plugin/Controllers/ToolsController.php:206
1823
  msgctxt "admin-text"
1824
  msgid "The permissions have been reset."
1825
  msgstr "The permissions have been reset."
1826
 
1827
+ #: plugin/Controllers/ToolsController.php:217
1828
  msgctxt "admin-text"
1829
  msgid "reload the page"
1830
  msgstr "reload the page"
1831
 
1832
+ #: plugin/Controllers/ToolsController.php:221
1833
  msgctxt "admin-text"
1834
  msgid "The permissions have been reset, please %s for them to take effect."
1835
  msgstr "The permissions have been reset, please %s for them to take effect."
1984
  msgid "The link to edit/view a review"
1985
  msgstr "The link to edit/view a review"
1986
 
1987
+ #: plugin/Defaults/TemplateTagsDefaults.php:22
1988
+ msgctxt "admin-text"
1989
+ msgid "The review's assigned page titles"
1990
+ msgstr "The review's assigned page titles"
1991
+
1992
+ #: plugin/Defaults/TemplateTagsDefaults.php:23
1993
+ msgctxt "admin-text"
1994
+ msgid "The review's assigned user display names"
1995
+ msgstr "The review's assigned user display names"
1996
+
1997
+ #: plugin/Defaults/TemplateTagsDefaults.php:24
1998
+ msgctxt "admin-text"
1999
+ msgid "The review's assigned categories"
2000
+ msgstr "The review's assigned categories"
2001
+
2002
  #: plugin/Defaults/UpdatedMessageDefaults.php:15
2003
  msgctxt "admin-text"
2004
  msgid "Review has been approved and published."
2479
  msgid "All types"
2480
  msgstr "All types"
2481
 
 
 
 
 
 
2482
  #: views/pages/addons/index.php:6
2483
  msgctxt "admin-text"
2484
  msgid ""
2648
  msgid "Reset Meta Values"
2649
  msgstr "Reset Meta Values"
2650
 
2651
+ #: views/pages/tools/general.php:108
2652
+ msgctxt "admin-text"
2653
+ msgid "Hard Reset Permissions"
2654
+ msgstr "Hard Reset Permissions"
2655
+
2656
+ #: views/pages/tools/general.php:108
2657
  msgctxt "admin-text"
2658
  msgid "Resetting, please wait..."
2659
  msgstr "Resetting, please wait..."
2660
 
2661
+ #: views/pages/tools/general.php:108
2662
  msgctxt "admin-text"
2663
  msgid "Reset Permissions"
2664
  msgstr "Reset Permissions"
2665
 
2666
+ #: views/pages/tools/general.php:125
2667
  msgctxt "admin-text"
2668
  msgid "Testing, please wait..."
2669
  msgstr "Testing, please wait..."
2670
 
2671
+ #: views/pages/tools/general.php:125
2672
  msgctxt "admin-text"
2673
  msgid "Test Detection"
2674
  msgstr "Test Detection"
2825
  #: views/partials/notices/addons.php:23
2826
  msgctxt "admin-text"
2827
  msgid ""
2828
+ "Allow people to add captioned images to their reviews; provide sorting, "
2829
+ "filtering, and search functionality; and integrate with the Trustalyze "
2830
+ "platform."
2831
  msgstr ""
2832
+ "Allow people to add captioned images to their reviews; provide sorting, "
2833
+ "filtering, and search functionality; and integrate with the Trustalyze "
2834
+ "platform."
2835
 
2836
  #: views/partials/notices/addons.php:26
2837
  msgctxt "admin-text"
2964
  msgid "View %s"
2965
  msgstr "View %s"
2966
 
2967
+ #: plugin/Modules/Notification.php:174
2968
  msgctxt ""
2969
  "This string differs depending on whether or not the review has been "
2970
  "assigned to a post."
languages/site-reviews.pot CHANGED
@@ -443,516 +443,541 @@ msgctxt "admin-text"
443
  msgid "Initial with a period and a space"
444
  msgstr ""
445
 
446
- #: config/settings.php:177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
  msgctxt "admin-text"
448
  msgid "Display a link to the assigned posts of a review."
449
  msgstr ""
450
 
451
- #: config/settings.php:178
452
  msgctxt "admin-text"
453
  msgid "Enable Assigned Links"
454
  msgstr ""
455
 
456
- #: config/settings.php:183
457
  msgctxt "admin-text"
458
  msgid "Display reviewer avatars. These are generated from the email address of the reviewer using <a href=\"https://gravatar.com\">Gravatar</a>."
459
  msgstr ""
460
 
461
- #: config/settings.php:184
462
  msgctxt "admin-text"
463
  msgid "Enable Avatars"
464
  msgstr ""
465
 
466
- #: config/settings.php:192
467
  msgctxt "admin-text"
468
  msgid "Regenerate the avatar whenever a local review is shown?"
469
  msgstr ""
470
 
471
- #: config/settings.php:193
472
  msgctxt "admin-text"
473
  msgid "Regenerate Avatars"
474
  msgstr ""
475
 
476
- #: config/settings.php:201
477
  msgctxt "admin-text"
478
  msgid "Set the avatar size in pixels."
479
  msgstr ""
480
 
481
- #: config/settings.php:202
482
  msgctxt "admin-text"
483
  msgid "Avatar Size"
484
  msgstr ""
485
 
486
- #: config/settings.php:207
487
  msgctxt "admin-text"
488
  msgid "Display an excerpt instead of the full review."
489
  msgstr ""
490
 
491
- #: config/settings.php:208
492
  msgctxt "admin-text"
493
  msgid "Enable Excerpts"
494
  msgstr ""
495
 
496
- #: config/settings.php:216
497
  msgctxt "admin-text"
498
  msgid "Set the excerpt word length."
499
  msgstr ""
500
 
501
- #: config/settings.php:217
502
  msgctxt "admin-text"
503
  msgid "Excerpt Length"
504
  msgstr ""
505
 
506
- #: config/settings.php:222
507
  msgctxt "admin-text"
508
  msgid "Display the fallback text when there are no reviews to display. This can be changed on the %s page. You may also override this by using the \"fallback\" option on the shortcode. The default fallback text is: %s"
509
  msgstr ""
510
 
511
- #: config/settings.php:223, plugin/Controllers/MenuController.php:118
512
  msgctxt "admin-text"
513
  msgid "Translations"
514
  msgstr ""
515
 
516
- #: config/settings.php:224, plugin/Modules/Html/ReviewsHtml.php:127
517
  msgid "There are no reviews yet. Be the first one to write one."
518
  msgstr ""
519
 
520
- #: config/settings.php:226
521
  msgctxt "admin-text"
522
  msgid "Enable Fallback Text"
523
  msgstr ""
524
 
525
- #: config/settings.php:232
526
  msgctxt "admin-text"
527
  msgid "Paginated URLs include the %s URL parameter. If you would like to keep the pagination links but prevent search engines from indexing them, add the following lines to your %s file instead: %s"
528
  msgstr ""
529
 
530
- #: config/settings.php:239
531
  msgctxt "admin-text"
532
  msgid "Enable Paginated URLs"
533
  msgstr ""
534
 
535
- #: config/settings.php:244, config/settings.php:264, config/settings.php:282, config/settings.php:300, config/settings.php:318, config/settings.php:339, config/settings.php:349, config/settings.php:359, config/settings.php:369, config/settings.php:383, config/settings.php:394, config/settings.php:405, config/settings.php:415
536
  msgctxt "admin-text"
537
  msgid "Custom Field name"
538
  msgstr ""
539
 
540
- #: config/settings.php:245
541
  msgctxt "admin-text"
542
  msgid "Default Schema Type"
543
  msgstr ""
544
 
545
- #: config/settings.php:247
546
  msgctxt "admin-text"
547
  msgid "Local Business"
548
  msgstr ""
549
 
550
- #: config/settings.php:248
551
  msgctxt "admin-text"
552
  msgid "Product"
553
  msgstr ""
554
 
555
- #: config/settings.php:249
556
  msgctxt "admin-text"
557
  msgid "Custom"
558
  msgstr ""
559
 
560
- #: config/settings.php:258
561
  msgctxt "admin-text"
562
  msgid "View more information on schema types here"
563
  msgstr ""
564
 
565
- #: config/settings.php:259
566
  msgctxt "admin-text"
567
  msgid "Custom Schema Type"
568
  msgstr ""
569
 
570
- #: config/settings.php:265
571
  msgctxt "admin-text"
572
  msgid "Default Name"
573
  msgstr ""
574
 
575
- #: config/settings.php:267
576
  msgctxt "admin-text"
577
  msgid "Use the assigned or current page title"
578
  msgstr ""
579
 
580
- #: config/settings.php:268
581
  msgctxt "admin-text"
582
  msgid "Enter a custom title"
583
  msgstr ""
584
 
585
- #: config/settings.php:277
586
  msgctxt "admin-text"
587
  msgid "Custom Name"
588
  msgstr ""
589
 
590
- #: config/settings.php:283
591
  msgctxt "admin-text"
592
  msgid "Default Description"
593
  msgstr ""
594
 
595
- #: config/settings.php:285
596
  msgctxt "admin-text"
597
  msgid "Use the assigned or current page excerpt"
598
  msgstr ""
599
 
600
- #: config/settings.php:286
601
  msgctxt "admin-text"
602
  msgid "Enter a custom description"
603
  msgstr ""
604
 
605
- #: config/settings.php:295
606
  msgctxt "admin-text"
607
  msgid "Custom Description"
608
  msgstr ""
609
 
610
- #: config/settings.php:301
611
  msgctxt "admin-text"
612
  msgid "Default URL"
613
  msgstr ""
614
 
615
- #: config/settings.php:303
616
  msgctxt "admin-text"
617
  msgid "Use the assigned or current page URL"
618
  msgstr ""
619
 
620
- #: config/settings.php:304
621
  msgctxt "admin-text"
622
  msgid "Enter a custom URL"
623
  msgstr ""
624
 
625
- #: config/settings.php:313
626
  msgctxt "admin-text"
627
  msgid "Custom URL"
628
  msgstr ""
629
 
630
- #: config/settings.php:319
631
  msgctxt "admin-text"
632
  msgid "Default Image"
633
  msgstr ""
634
 
635
- #: config/settings.php:321
636
  msgctxt "admin-text"
637
  msgid "Use the featured image of the assigned or current page"
638
  msgstr ""
639
 
640
- #: config/settings.php:322
641
  msgctxt "admin-text"
642
  msgid "Enter a custom image URL"
643
  msgstr ""
644
 
645
- #: config/settings.php:331
646
  msgctxt "admin-text"
647
  msgid "Custom Image URL"
648
  msgstr ""
649
 
650
- #: config/settings.php:340
651
  msgctxt "admin-text"
652
  msgid "Address"
653
  msgstr ""
654
 
655
- #: config/settings.php:341
656
  msgctxt "admin-text"
657
  msgid "60 29th Street #343, San Francisco, CA 94110, US"
658
  msgstr ""
659
 
660
- #: config/settings.php:350
661
  msgctxt "admin-text"
662
  msgid "Telephone Number"
663
  msgstr ""
664
 
665
- #: config/settings.php:351
666
  msgctxt "admin-text"
667
  msgid "+1 (877) 273-3049"
668
  msgstr ""
669
 
670
- #: config/settings.php:360
671
  msgctxt "admin-text"
672
  msgid "Price Range"
673
  msgstr ""
674
 
675
- #: config/settings.php:361
676
  msgctxt "admin-text"
677
  msgid "$$-$$$"
678
  msgstr ""
679
 
680
- #: config/settings.php:370
681
  msgctxt "admin-text"
682
  msgid "Offer Type"
683
  msgstr ""
684
 
685
- #: config/settings.php:372
686
  msgctxt "admin-text"
687
  msgid "AggregateOffer"
688
  msgstr ""
689
 
690
- #: config/settings.php:373
691
  msgctxt "admin-text"
692
  msgid "Offer"
693
  msgstr ""
694
 
695
- #: config/settings.php:384
696
  msgctxt "admin-text"
697
  msgid "Price"
698
  msgstr ""
699
 
700
- #: config/settings.php:395
701
  msgctxt "admin-text"
702
  msgid "Low Price"
703
  msgstr ""
704
 
705
- #: config/settings.php:406
706
  msgctxt "admin-text"
707
  msgid "High Price"
708
  msgstr ""
709
 
710
- #: config/settings.php:416
711
  msgctxt "admin-text"
712
  msgid "Price Currency"
713
  msgstr ""
714
 
715
- #: config/settings.php:417
716
  msgctxt "admin-text"
717
  msgid "USD"
718
  msgstr ""
719
 
720
- #: config/settings.php:422
721
  msgctxt "admin-text"
722
  msgid "Choose which fields should be required in the review form."
723
  msgstr ""
724
 
725
- #: config/settings.php:423
726
  msgctxt "admin-text"
727
  msgid "Required Fields"
728
  msgstr ""
729
 
730
- #: config/settings.php:425, config/forms/metabox-fields.php:5, plugin/Defaults/PostTypeColumnDefaults.php:25, plugin/Defaults/RevisionFieldsDefaults.php:16, plugin/Tinymce/SiteReviewsTinymce.php:30
731
  msgctxt "admin-text"
732
  msgid "Rating"
733
  msgstr ""
734
 
735
- #: config/settings.php:426, plugin/Tinymce/SiteReviewsFormTinymce.php:16, plugin/Tinymce/SiteReviewsSummaryTinymce.php:17, plugin/Tinymce/SiteReviewsTinymce.php:17, plugin/Widgets/SiteReviewsFormWidget.php:20, plugin/Widgets/SiteReviewsSummaryWidget.php:20, plugin/Widgets/SiteReviewsWidget.php:20
736
  msgctxt "admin-text"
737
  msgid "Title"
738
  msgstr ""
739
 
740
- #: config/settings.php:427, plugin/Defaults/PostTypeLabelDefaults.php:15
741
  msgctxt "admin-text"
742
  msgid "Review"
743
  msgstr ""
744
 
745
- #: config/settings.php:428, config/forms/metabox-fields.php:14, plugin/Controllers/PrivacyController.php:128, plugin/Defaults/PostTypeColumnDefaults.php:20, plugin/Defaults/RevisionFieldsDefaults.php:18
746
  msgctxt "admin-text"
747
  msgid "Name"
748
  msgstr ""
749
 
750
- #: config/settings.php:429, config/forms/metabox-fields.php:18, plugin/Controllers/PrivacyController.php:129, plugin/Defaults/PostTypeColumnDefaults.php:21, plugin/Defaults/RevisionFieldsDefaults.php:19
751
  msgctxt "admin-text"
752
  msgid "Email"
753
  msgstr ""
754
 
755
- #: config/settings.php:430
756
  msgctxt "admin-text"
757
  msgid "Terms"
758
  msgstr ""
759
 
760
- #: config/settings.php:436
761
  msgctxt "admin-text"
762
- msgid "Limits the number of reviews that can be submitted to one-per-person. If you are assigning reviews, then the limit will be applied to the assigned page or category."
763
  msgstr ""
764
 
765
- #: config/settings.php:437
766
  msgctxt "admin-text"
767
  msgid "Limit Reviews"
768
  msgstr ""
769
 
770
- #: config/settings.php:439
771
  msgctxt "admin-text"
772
  msgid "No Limit"
773
  msgstr ""
774
 
775
- #: config/settings.php:440
776
  msgctxt "admin-text"
777
  msgid "By Email Address"
778
  msgstr ""
779
 
780
- #: config/settings.php:441
781
  msgctxt "admin-text"
782
  msgid "By IP Address"
783
  msgstr ""
784
 
785
- #: config/settings.php:442
786
  msgctxt "admin-text"
787
  msgid "By Username (will only work for registered users)"
788
  msgstr ""
789
 
790
- #: config/settings.php:451
791
  msgctxt "admin-text"
792
  msgid "One Email per line. All emails in the whitelist will be excluded from the review submission limit."
793
  msgstr ""
794
 
795
- #: config/settings.php:452
796
  msgctxt "admin-text"
797
  msgid "Email Whitelist"
798
  msgstr ""
799
 
800
- #: config/settings.php:461
801
  msgctxt "admin-text"
802
  msgid "One IP Address per line. All IP Addresses in the whitelist will be excluded from the review submission limit.."
803
  msgstr ""
804
 
805
- #: config/settings.php:462
806
  msgctxt "admin-text"
807
  msgid "IP Address Whitelist"
808
  msgstr ""
809
 
810
- #: config/settings.php:471
811
  msgctxt "admin-text"
812
  msgid "One Username per line. All registered users with a Username in the whitelist will be excluded from the review submission limit."
813
  msgstr ""
814
 
815
- #: config/settings.php:472
816
  msgctxt "admin-text"
817
  msgid "Username Whitelist"
818
  msgstr ""
819
 
820
- #: config/settings.php:478
821
  msgctxt "admin-text"
822
  msgid "The Invisible reCAPTCHA badge (reCAPTCHA v2) is a free anti-spam service from Google. To use it, you will need to <a href=\"https://www.google.com/recaptcha/admin\" target=\"_blank\">sign up</a> for an API key pair for your site."
823
  msgstr ""
824
 
825
- #: config/settings.php:479
826
  msgctxt "admin-text"
827
  msgid "Invisible reCAPTCHA"
828
  msgstr ""
829
 
830
- #: config/settings.php:481
831
  msgctxt "admin-text"
832
  msgid "Do not use reCAPTCHA"
833
  msgstr ""
834
 
835
- #: config/settings.php:482
836
  msgctxt "admin-text"
837
  msgid "Use reCAPTCHA"
838
  msgstr ""
839
 
840
- #: config/settings.php:483
841
  msgctxt "admin-text"
842
  msgid "Use reCAPTCHA only for guest users"
843
  msgstr ""
844
 
845
- #: config/settings.php:492
846
  msgctxt "admin-text"
847
  msgid "Site Key"
848
  msgstr ""
849
 
850
- #: config/settings.php:500
851
  msgctxt "admin-text"
852
  msgid "Site Secret"
853
  msgstr ""
854
 
855
- #: config/settings.php:508
856
  msgctxt "admin-text"
857
  msgid "This option may not work consistently if another plugin is loading reCAPTCHA on the same page as Site Reviews."
858
  msgstr ""
859
 
860
- #: config/settings.php:509
861
  msgctxt "admin-text"
862
  msgid "Badge Position"
863
  msgstr ""
864
 
865
- #: config/settings.php:511
866
  msgctxt "admin-text"
867
  msgid "Bottom Left"
868
  msgstr ""
869
 
870
- #: config/settings.php:512
871
  msgctxt "admin-text"
872
  msgid "Bottom Right"
873
  msgstr ""
874
 
875
- #: config/settings.php:513
876
  msgctxt "admin-text"
877
  msgid "Inline"
878
  msgstr ""
879
 
880
- #: config/settings.php:519
881
  msgctxt "admin-text"
882
  msgid "The <a href=\"https://akismet.com\" target=\"_blank\">Akismet plugin</a> integration provides spam-filtering for your reviews. In order for this setting to have any affect, you will need to first install and activate the Akismet plugin and set up a WordPress.com API key."
883
  msgstr ""
884
 
885
- #: config/settings.php:520
886
  msgctxt "admin-text"
887
  msgid "Enable Akismet Integration"
888
  msgstr ""
889
 
890
- #: config/settings.php:525
891
  msgctxt "admin-text"
892
  msgid "Choose which Blacklist you would prefer to use for reviews. The %s option can be found in the WordPress Discussion Settings page."
893
  msgstr ""
894
 
895
- #: config/settings.php:526
896
  msgctxt "admin-text"
897
  msgid "Disallowed Comment Keys"
898
  msgstr ""
899
 
900
- #: config/settings.php:528
901
  msgctxt "admin-text"
902
  msgid "Blacklist"
903
  msgstr ""
904
 
905
- #: config/settings.php:530
906
  msgctxt "admin-text"
907
  msgid "Use the Site Reviews Blacklist"
908
  msgstr ""
909
 
910
- #: config/settings.php:531
911
  msgctxt "admin-text"
912
  msgid "Use the WordPress Disallowed Comment Keys"
913
  msgstr ""
914
 
915
- #: config/settings.php:540
916
  msgctxt "admin-text"
917
  msgid "One entry or IP address per line. When a review contains any of these entries in its title, content, name, email, or IP address, it will be rejected. It is case-insensitive and will match partial words, so \"press\" will match \"WordPress\"."
918
  msgstr ""
919
 
920
- #: config/settings.php:541
921
  msgctxt "admin-text"
922
  msgid "Review Blacklist"
923
  msgstr ""
924
 
925
- #: config/settings.php:547
926
  msgctxt "admin-text"
927
  msgid "Choose the action that should be taken when a review is blacklisted."
928
  msgstr ""
929
 
930
- #: config/settings.php:548
931
  msgctxt "admin-text"
932
  msgid "Blacklist Action"
933
  msgstr ""
934
 
935
- #: config/settings.php:550
936
  msgctxt "admin-text"
937
  msgid "Require approval"
938
  msgstr ""
939
 
940
- #: config/settings.php:551
941
  msgctxt "admin-text"
942
  msgid "Reject submission"
943
  msgstr ""
944
 
945
- #: plugin/Application.php:224
946
- msgctxt "admin-text"
947
- msgid "Local Review"
948
- msgstr ""
949
-
950
  #: plugin/Deprecated.php:24
951
  msgctxt "admin-text"
952
  msgid "The [%s] method has been deprecated and will be soon be removed, please use the [%s] method instead."
953
  msgstr ""
954
 
955
- #: plugin/Review.php:264, plugin/Controllers/ListTableColumns/ColumnValueAuthorName.php:20
956
  msgctxt "admin-text"
957
  msgid "Unknown"
958
  msgstr ""
@@ -1066,12 +1091,12 @@ msgstr ""
1066
  msgid "This review is based on my own experience and is my genuine opinion."
1067
  msgstr ""
1068
 
1069
- #: plugin/Addons/Controller.php:70, plugin/Controllers/AdminController.php:47, plugin/Controllers/MenuController.php:50, views/pages/tools/sync.php:23
1070
  msgctxt "admin-text"
1071
  msgid "Settings"
1072
  msgstr ""
1073
 
1074
- #: plugin/Addons/Controller.php:76, plugin/Controllers/AdminController.php:53, plugin/Controllers/MenuController.php:53
1075
  msgctxt "admin-text"
1076
  msgid "Help"
1077
  msgstr ""
@@ -1085,11 +1110,11 @@ msgstr ""
1085
  msgid "Show more"
1086
  msgstr ""
1087
 
1088
- #: plugin/Commands/CreateReview.php:155
1089
  msgid "Your review has been submitted!"
1090
  msgstr ""
1091
 
1092
- #: plugin/Commands/CreateReview.php:160
1093
  msgid "Your review could not be submitted and the error has been logged. Please notify the site admin."
1094
  msgstr ""
1095
 
@@ -1142,29 +1167,29 @@ msgctxt "admin-text"
1142
  msgid "Edit"
1143
  msgstr ""
1144
 
1145
- #: plugin/Controllers/AdminController.php:84
1146
  msgctxt "admin-text"
1147
  msgid "%s Review"
1148
  msgid_plural "%s Reviews"
1149
  msgstr[0] ""
1150
  msgstr[1] ""
1151
 
1152
- #: plugin/Controllers/AdminController.php:148, plugin/Controllers/MainController.php:70
1153
  msgctxt "admin-text"
1154
  msgid "Recent Reviews"
1155
  msgstr ""
1156
 
1157
- #: plugin/Controllers/AdminController.php:149, plugin/Controllers/MainController.php:74
1158
  msgctxt "admin-text"
1159
  msgid "Submit a Review"
1160
  msgstr ""
1161
 
1162
- #: plugin/Controllers/AdminController.php:150, plugin/Controllers/MainController.php:78
1163
  msgctxt "admin-text"
1164
  msgid "Summary of Reviews"
1165
  msgstr ""
1166
 
1167
- #: plugin/Controllers/AdminController.php:185, plugin/Controllers/AdminController.php:205, plugin/Controllers/AdminController.php:218
1168
  msgctxt "admin-text"
1169
  msgid "Nothing found."
1170
  msgstr ""
@@ -1199,17 +1224,22 @@ msgctxt "Approve the review (admin-text)"
1199
  msgid "%s this review"
1200
  msgstr ""
1201
 
1202
- #: plugin/Controllers/MainController.php:69
 
 
 
 
 
1203
  msgctxt "admin-text"
1204
  msgid "Site Reviews: Display your recent reviews."
1205
  msgstr ""
1206
 
1207
- #: plugin/Controllers/MainController.php:73
1208
  msgctxt "admin-text"
1209
  msgid "Site Reviews: Display a form to submit reviews."
1210
  msgstr ""
1211
 
1212
- #: plugin/Controllers/MainController.php:77
1213
  msgctxt "admin-text"
1214
  msgid "Site Reviews: Display a summary of your reviews."
1215
  msgstr ""
@@ -1406,12 +1436,12 @@ msgstr ""
1406
 
1407
  #: plugin/Controllers/ToolsController.php:157
1408
  msgctxt "admin-text"
1409
- msgid "The plugin has been migrated sucessfully."
1410
  msgstr ""
1411
 
1412
  #: plugin/Controllers/ToolsController.php:154
1413
  msgctxt "admin-text"
1414
- msgid "All plugin migrations have been run successfully."
1415
  msgstr ""
1416
 
1417
  #: plugin/Controllers/ToolsController.php:180
@@ -1419,17 +1449,17 @@ msgctxt "admin-text"
1419
  msgid "The assigned meta values have been reset."
1420
  msgstr ""
1421
 
1422
- #: plugin/Controllers/ToolsController.php:202
1423
  msgctxt "admin-text"
1424
  msgid "The permissions have been reset."
1425
  msgstr ""
1426
 
1427
- #: plugin/Controllers/ToolsController.php:213
1428
  msgctxt "admin-text"
1429
  msgid "reload the page"
1430
  msgstr ""
1431
 
1432
- #: plugin/Controllers/ToolsController.php:217
1433
  msgctxt "admin-text"
1434
  msgid "The permissions have been reset, please %s for them to take effect."
1435
  msgstr ""
@@ -1660,6 +1690,21 @@ msgctxt "admin-text"
1660
  msgid "The link to edit/view a review"
1661
  msgstr ""
1662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1663
  #: plugin/Defaults/UpdatedMessageDefaults.php:15
1664
  msgctxt "admin-text"
1665
  msgid "Review has been approved and published."
@@ -1736,7 +1781,7 @@ msgstr ""
1736
  msgid "This field requires a valid e-mail address."
1737
  msgstr ""
1738
 
1739
- #: plugin/Defaults/ValidationStringsDefaults.php:19, plugin/Modules/Validator/DefaultValidator.php:52
1740
  msgid "Please fix the submission errors."
1741
  msgstr ""
1742
 
@@ -1824,11 +1869,11 @@ msgid_plural "%s years ago"
1824
  msgstr[0] ""
1825
  msgstr[1] ""
1826
 
1827
- #: plugin/Modules/Notification.php:71
1828
  msgid "Anonymous"
1829
  msgstr ""
1830
 
1831
- #: plugin/Modules/Notification.php:141
1832
  msgctxt "This string differs depending on whether or not the review has been assigned to a post."
1833
  msgid "New %s-star review"
1834
  msgid_plural "New %s-star review of %s"
@@ -2242,11 +2287,6 @@ msgctxt "admin-text"
2242
  msgid "All types"
2243
  msgstr ""
2244
 
2245
- #: plugin/Controllers/ListTableColumns/ColumnValueType.php:17
2246
- msgctxt "admin-text"
2247
- msgid "Unsupported Type"
2248
- msgstr ""
2249
-
2250
  #: plugin/Modules/Validator/AkismetValidator.php:49
2251
  msgid "This review has been flagged as possible spam and cannot be submitted."
2252
  msgstr ""
@@ -2271,7 +2311,7 @@ msgstr ""
2271
  msgid "The reCAPTCHA verification failed, please try again."
2272
  msgstr ""
2273
 
2274
- #: plugin/Modules/Validator/ReviewLimitsValidator.php:43
2275
  msgid "You have already submitted a review."
2276
  msgstr ""
2277
 
@@ -2410,22 +2450,27 @@ msgctxt "admin-text"
2410
  msgid "Reset Meta Values"
2411
  msgstr ""
2412
 
2413
- #: views/pages/tools/general.php:104
 
 
 
 
 
2414
  msgctxt "admin-text"
2415
  msgid "Resetting, please wait..."
2416
  msgstr ""
2417
 
2418
- #: views/pages/tools/general.php:104
2419
  msgctxt "admin-text"
2420
  msgid "Reset Permissions"
2421
  msgstr ""
2422
 
2423
- #: views/pages/tools/general.php:121
2424
  msgctxt "admin-text"
2425
  msgid "Testing, please wait..."
2426
  msgstr ""
2427
 
2428
- #: views/pages/tools/general.php:121
2429
  msgctxt "admin-text"
2430
  msgid "Test Detection"
2431
  msgstr ""
@@ -2577,7 +2622,7 @@ msgstr ""
2577
 
2578
  #: views/partials/notices/addons.php:23
2579
  msgctxt "admin-text"
2580
- msgid "Allow people to submit captioned images with their review, and sort, filter, and search reviews."
2581
  msgstr ""
2582
 
2583
  #: views/partials/notices/addons.php:26
443
  msgid "Initial with a period and a space"
444
  msgstr ""
445
 
446
+ #: config/settings.php:178
447
+ msgctxt "admin-text"
448
+ msgid "This setting determines how the assigned options work in the reviews and summary shortcodes and blocks."
449
+ msgstr ""
450
+
451
+ #: config/settings.php:179
452
+ msgctxt "admin-text"
453
+ msgid "\"Loose Assignment\" means <code>display reviews that are assigned to this OR this</code>."
454
+ msgstr ""
455
+
456
+ #: config/settings.php:180
457
+ msgctxt "admin-text"
458
+ msgid "\"Strict Assignment\" means <code>display reviews that are assigned to this AND this</code>."
459
+ msgstr ""
460
+
461
+ #: config/settings.php:182
462
+ msgctxt "admin-text"
463
+ msgid "Review Assignment"
464
+ msgstr ""
465
+
466
+ #: config/settings.php:184
467
+ msgctxt "admin-text"
468
+ msgid "Loose Assignment"
469
+ msgstr ""
470
+
471
+ #: config/settings.php:185
472
+ msgctxt "admin-text"
473
+ msgid "Strict Assignment"
474
+ msgstr ""
475
+
476
+ #: config/settings.php:191
477
  msgctxt "admin-text"
478
  msgid "Display a link to the assigned posts of a review."
479
  msgstr ""
480
 
481
+ #: config/settings.php:192
482
  msgctxt "admin-text"
483
  msgid "Enable Assigned Links"
484
  msgstr ""
485
 
486
+ #: config/settings.php:197
487
  msgctxt "admin-text"
488
  msgid "Display reviewer avatars. These are generated from the email address of the reviewer using <a href=\"https://gravatar.com\">Gravatar</a>."
489
  msgstr ""
490
 
491
+ #: config/settings.php:198
492
  msgctxt "admin-text"
493
  msgid "Enable Avatars"
494
  msgstr ""
495
 
496
+ #: config/settings.php:206
497
  msgctxt "admin-text"
498
  msgid "Regenerate the avatar whenever a local review is shown?"
499
  msgstr ""
500
 
501
+ #: config/settings.php:207
502
  msgctxt "admin-text"
503
  msgid "Regenerate Avatars"
504
  msgstr ""
505
 
506
+ #: config/settings.php:215
507
  msgctxt "admin-text"
508
  msgid "Set the avatar size in pixels."
509
  msgstr ""
510
 
511
+ #: config/settings.php:216
512
  msgctxt "admin-text"
513
  msgid "Avatar Size"
514
  msgstr ""
515
 
516
+ #: config/settings.php:221
517
  msgctxt "admin-text"
518
  msgid "Display an excerpt instead of the full review."
519
  msgstr ""
520
 
521
+ #: config/settings.php:222
522
  msgctxt "admin-text"
523
  msgid "Enable Excerpts"
524
  msgstr ""
525
 
526
+ #: config/settings.php:230
527
  msgctxt "admin-text"
528
  msgid "Set the excerpt word length."
529
  msgstr ""
530
 
531
+ #: config/settings.php:231
532
  msgctxt "admin-text"
533
  msgid "Excerpt Length"
534
  msgstr ""
535
 
536
+ #: config/settings.php:236
537
  msgctxt "admin-text"
538
  msgid "Display the fallback text when there are no reviews to display. This can be changed on the %s page. You may also override this by using the \"fallback\" option on the shortcode. The default fallback text is: %s"
539
  msgstr ""
540
 
541
+ #: config/settings.php:237, plugin/Controllers/MenuController.php:118
542
  msgctxt "admin-text"
543
  msgid "Translations"
544
  msgstr ""
545
 
546
+ #: config/settings.php:238, plugin/Modules/Html/ReviewsHtml.php:126
547
  msgid "There are no reviews yet. Be the first one to write one."
548
  msgstr ""
549
 
550
+ #: config/settings.php:240
551
  msgctxt "admin-text"
552
  msgid "Enable Fallback Text"
553
  msgstr ""
554
 
555
+ #: config/settings.php:246
556
  msgctxt "admin-text"
557
  msgid "Paginated URLs include the %s URL parameter. If you would like to keep the pagination links but prevent search engines from indexing them, add the following lines to your %s file instead: %s"
558
  msgstr ""
559
 
560
+ #: config/settings.php:253
561
  msgctxt "admin-text"
562
  msgid "Enable Paginated URLs"
563
  msgstr ""
564
 
565
+ #: config/settings.php:258, config/settings.php:278, config/settings.php:296, config/settings.php:314, config/settings.php:332, config/settings.php:353, config/settings.php:363, config/settings.php:373, config/settings.php:383, config/settings.php:397, config/settings.php:408, config/settings.php:419, config/settings.php:429
566
  msgctxt "admin-text"
567
  msgid "Custom Field name"
568
  msgstr ""
569
 
570
+ #: config/settings.php:259
571
  msgctxt "admin-text"
572
  msgid "Default Schema Type"
573
  msgstr ""
574
 
575
+ #: config/settings.php:261
576
  msgctxt "admin-text"
577
  msgid "Local Business"
578
  msgstr ""
579
 
580
+ #: config/settings.php:262
581
  msgctxt "admin-text"
582
  msgid "Product"
583
  msgstr ""
584
 
585
+ #: config/settings.php:263
586
  msgctxt "admin-text"
587
  msgid "Custom"
588
  msgstr ""
589
 
590
+ #: config/settings.php:272
591
  msgctxt "admin-text"
592
  msgid "View more information on schema types here"
593
  msgstr ""
594
 
595
+ #: config/settings.php:273
596
  msgctxt "admin-text"
597
  msgid "Custom Schema Type"
598
  msgstr ""
599
 
600
+ #: config/settings.php:279
601
  msgctxt "admin-text"
602
  msgid "Default Name"
603
  msgstr ""
604
 
605
+ #: config/settings.php:281
606
  msgctxt "admin-text"
607
  msgid "Use the assigned or current page title"
608
  msgstr ""
609
 
610
+ #: config/settings.php:282
611
  msgctxt "admin-text"
612
  msgid "Enter a custom title"
613
  msgstr ""
614
 
615
+ #: config/settings.php:291
616
  msgctxt "admin-text"
617
  msgid "Custom Name"
618
  msgstr ""
619
 
620
+ #: config/settings.php:297
621
  msgctxt "admin-text"
622
  msgid "Default Description"
623
  msgstr ""
624
 
625
+ #: config/settings.php:299
626
  msgctxt "admin-text"
627
  msgid "Use the assigned or current page excerpt"
628
  msgstr ""
629
 
630
+ #: config/settings.php:300
631
  msgctxt "admin-text"
632
  msgid "Enter a custom description"
633
  msgstr ""
634
 
635
+ #: config/settings.php:309
636
  msgctxt "admin-text"
637
  msgid "Custom Description"
638
  msgstr ""
639
 
640
+ #: config/settings.php:315
641
  msgctxt "admin-text"
642
  msgid "Default URL"
643
  msgstr ""
644
 
645
+ #: config/settings.php:317
646
  msgctxt "admin-text"
647
  msgid "Use the assigned or current page URL"
648
  msgstr ""
649
 
650
+ #: config/settings.php:318
651
  msgctxt "admin-text"
652
  msgid "Enter a custom URL"
653
  msgstr ""
654
 
655
+ #: config/settings.php:327
656
  msgctxt "admin-text"
657
  msgid "Custom URL"
658
  msgstr ""
659
 
660
+ #: config/settings.php:333
661
  msgctxt "admin-text"
662
  msgid "Default Image"
663
  msgstr ""
664
 
665
+ #: config/settings.php:335
666
  msgctxt "admin-text"
667
  msgid "Use the featured image of the assigned or current page"
668
  msgstr ""
669
 
670
+ #: config/settings.php:336
671
  msgctxt "admin-text"
672
  msgid "Enter a custom image URL"
673
  msgstr ""
674
 
675
+ #: config/settings.php:345
676
  msgctxt "admin-text"
677
  msgid "Custom Image URL"
678
  msgstr ""
679
 
680
+ #: config/settings.php:354
681
  msgctxt "admin-text"
682
  msgid "Address"
683
  msgstr ""
684
 
685
+ #: config/settings.php:355
686
  msgctxt "admin-text"
687
  msgid "60 29th Street #343, San Francisco, CA 94110, US"
688
  msgstr ""
689
 
690
+ #: config/settings.php:364
691
  msgctxt "admin-text"
692
  msgid "Telephone Number"
693
  msgstr ""
694
 
695
+ #: config/settings.php:365
696
  msgctxt "admin-text"
697
  msgid "+1 (877) 273-3049"
698
  msgstr ""
699
 
700
+ #: config/settings.php:374
701
  msgctxt "admin-text"
702
  msgid "Price Range"
703
  msgstr ""
704
 
705
+ #: config/settings.php:375
706
  msgctxt "admin-text"
707
  msgid "$$-$$$"
708
  msgstr ""
709
 
710
+ #: config/settings.php:384
711
  msgctxt "admin-text"
712
  msgid "Offer Type"
713
  msgstr ""
714
 
715
+ #: config/settings.php:386
716
  msgctxt "admin-text"
717
  msgid "AggregateOffer"
718
  msgstr ""
719
 
720
+ #: config/settings.php:387
721
  msgctxt "admin-text"
722
  msgid "Offer"
723
  msgstr ""
724
 
725
+ #: config/settings.php:398
726
  msgctxt "admin-text"
727
  msgid "Price"
728
  msgstr ""
729
 
730
+ #: config/settings.php:409
731
  msgctxt "admin-text"
732
  msgid "Low Price"
733
  msgstr ""
734
 
735
+ #: config/settings.php:420
736
  msgctxt "admin-text"
737
  msgid "High Price"
738
  msgstr ""
739
 
740
+ #: config/settings.php:430
741
  msgctxt "admin-text"
742
  msgid "Price Currency"
743
  msgstr ""
744
 
745
+ #: config/settings.php:431
746
  msgctxt "admin-text"
747
  msgid "USD"
748
  msgstr ""
749
 
750
+ #: config/settings.php:436
751
  msgctxt "admin-text"
752
  msgid "Choose which fields should be required in the review form."
753
  msgstr ""
754
 
755
+ #: config/settings.php:437
756
  msgctxt "admin-text"
757
  msgid "Required Fields"
758
  msgstr ""
759
 
760
+ #: config/settings.php:439, config/forms/metabox-fields.php:5, plugin/Defaults/PostTypeColumnDefaults.php:25, plugin/Defaults/RevisionFieldsDefaults.php:16, plugin/Tinymce/SiteReviewsTinymce.php:30
761
  msgctxt "admin-text"
762
  msgid "Rating"
763
  msgstr ""
764
 
765
+ #: config/settings.php:440, plugin/Tinymce/SiteReviewsFormTinymce.php:16, plugin/Tinymce/SiteReviewsSummaryTinymce.php:17, plugin/Tinymce/SiteReviewsTinymce.php:17, plugin/Widgets/SiteReviewsFormWidget.php:20, plugin/Widgets/SiteReviewsSummaryWidget.php:20, plugin/Widgets/SiteReviewsWidget.php:20
766
  msgctxt "admin-text"
767
  msgid "Title"
768
  msgstr ""
769
 
770
+ #: config/settings.php:441, plugin/Defaults/PostTypeLabelDefaults.php:15
771
  msgctxt "admin-text"
772
  msgid "Review"
773
  msgstr ""
774
 
775
+ #: config/settings.php:442, config/forms/metabox-fields.php:14, plugin/Controllers/PrivacyController.php:128, plugin/Defaults/PostTypeColumnDefaults.php:20, plugin/Defaults/RevisionFieldsDefaults.php:18
776
  msgctxt "admin-text"
777
  msgid "Name"
778
  msgstr ""
779
 
780
+ #: config/settings.php:443, config/forms/metabox-fields.php:18, plugin/Controllers/PrivacyController.php:129, plugin/Defaults/PostTypeColumnDefaults.php:21, plugin/Defaults/RevisionFieldsDefaults.php:19
781
  msgctxt "admin-text"
782
  msgid "Email"
783
  msgstr ""
784
 
785
+ #: config/settings.php:444
786
  msgctxt "admin-text"
787
  msgid "Terms"
788
  msgstr ""
789
 
790
+ #: config/settings.php:450
791
  msgctxt "admin-text"
792
+ msgid "Limits the number of reviews that can be submitted to one-per-person. If you are assigning reviews, then the limit will be applied to the assigned page and/or category."
793
  msgstr ""
794
 
795
+ #: config/settings.php:451
796
  msgctxt "admin-text"
797
  msgid "Limit Reviews"
798
  msgstr ""
799
 
800
+ #: config/settings.php:453
801
  msgctxt "admin-text"
802
  msgid "No Limit"
803
  msgstr ""
804
 
805
+ #: config/settings.php:454
806
  msgctxt "admin-text"
807
  msgid "By Email Address"
808
  msgstr ""
809
 
810
+ #: config/settings.php:455
811
  msgctxt "admin-text"
812
  msgid "By IP Address"
813
  msgstr ""
814
 
815
+ #: config/settings.php:456
816
  msgctxt "admin-text"
817
  msgid "By Username (will only work for registered users)"
818
  msgstr ""
819
 
820
+ #: config/settings.php:465
821
  msgctxt "admin-text"
822
  msgid "One Email per line. All emails in the whitelist will be excluded from the review submission limit."
823
  msgstr ""
824
 
825
+ #: config/settings.php:466
826
  msgctxt "admin-text"
827
  msgid "Email Whitelist"
828
  msgstr ""
829
 
830
+ #: config/settings.php:475
831
  msgctxt "admin-text"
832
  msgid "One IP Address per line. All IP Addresses in the whitelist will be excluded from the review submission limit.."
833
  msgstr ""
834
 
835
+ #: config/settings.php:476
836
  msgctxt "admin-text"
837
  msgid "IP Address Whitelist"
838
  msgstr ""
839
 
840
+ #: config/settings.php:485
841
  msgctxt "admin-text"
842
  msgid "One Username per line. All registered users with a Username in the whitelist will be excluded from the review submission limit."
843
  msgstr ""
844
 
845
+ #: config/settings.php:486
846
  msgctxt "admin-text"
847
  msgid "Username Whitelist"
848
  msgstr ""
849
 
850
+ #: config/settings.php:492
851
  msgctxt "admin-text"
852
  msgid "The Invisible reCAPTCHA badge (reCAPTCHA v2) is a free anti-spam service from Google. To use it, you will need to <a href=\"https://www.google.com/recaptcha/admin\" target=\"_blank\">sign up</a> for an API key pair for your site."
853
  msgstr ""
854
 
855
+ #: config/settings.php:493
856
  msgctxt "admin-text"
857
  msgid "Invisible reCAPTCHA"
858
  msgstr ""
859
 
860
+ #: config/settings.php:495
861
  msgctxt "admin-text"
862
  msgid "Do not use reCAPTCHA"
863
  msgstr ""
864
 
865
+ #: config/settings.php:496
866
  msgctxt "admin-text"
867
  msgid "Use reCAPTCHA"
868
  msgstr ""
869
 
870
+ #: config/settings.php:497
871
  msgctxt "admin-text"
872
  msgid "Use reCAPTCHA only for guest users"
873
  msgstr ""
874
 
875
+ #: config/settings.php:506
876
  msgctxt "admin-text"
877
  msgid "Site Key"
878
  msgstr ""
879
 
880
+ #: config/settings.php:514
881
  msgctxt "admin-text"
882
  msgid "Site Secret"
883
  msgstr ""
884
 
885
+ #: config/settings.php:522
886
  msgctxt "admin-text"
887
  msgid "This option may not work consistently if another plugin is loading reCAPTCHA on the same page as Site Reviews."
888
  msgstr ""
889
 
890
+ #: config/settings.php:523
891
  msgctxt "admin-text"
892
  msgid "Badge Position"
893
  msgstr ""
894
 
895
+ #: config/settings.php:525
896
  msgctxt "admin-text"
897
  msgid "Bottom Left"
898
  msgstr ""
899
 
900
+ #: config/settings.php:526
901
  msgctxt "admin-text"
902
  msgid "Bottom Right"
903
  msgstr ""
904
 
905
+ #: config/settings.php:527
906
  msgctxt "admin-text"
907
  msgid "Inline"
908
  msgstr ""
909
 
910
+ #: config/settings.php:533
911
  msgctxt "admin-text"
912
  msgid "The <a href=\"https://akismet.com\" target=\"_blank\">Akismet plugin</a> integration provides spam-filtering for your reviews. In order for this setting to have any affect, you will need to first install and activate the Akismet plugin and set up a WordPress.com API key."
913
  msgstr ""
914
 
915
+ #: config/settings.php:534
916
  msgctxt "admin-text"
917
  msgid "Enable Akismet Integration"
918
  msgstr ""
919
 
920
+ #: config/settings.php:539
921
  msgctxt "admin-text"
922
  msgid "Choose which Blacklist you would prefer to use for reviews. The %s option can be found in the WordPress Discussion Settings page."
923
  msgstr ""
924
 
925
+ #: config/settings.php:540
926
  msgctxt "admin-text"
927
  msgid "Disallowed Comment Keys"
928
  msgstr ""
929
 
930
+ #: config/settings.php:542
931
  msgctxt "admin-text"
932
  msgid "Blacklist"
933
  msgstr ""
934
 
935
+ #: config/settings.php:544
936
  msgctxt "admin-text"
937
  msgid "Use the Site Reviews Blacklist"
938
  msgstr ""
939
 
940
+ #: config/settings.php:545
941
  msgctxt "admin-text"
942
  msgid "Use the WordPress Disallowed Comment Keys"
943
  msgstr ""
944
 
945
+ #: config/settings.php:554
946
  msgctxt "admin-text"
947
  msgid "One entry or IP address per line. When a review contains any of these entries in its title, content, name, email, or IP address, it will be rejected. It is case-insensitive and will match partial words, so \"press\" will match \"WordPress\"."
948
  msgstr ""
949
 
950
+ #: config/settings.php:555
951
  msgctxt "admin-text"
952
  msgid "Review Blacklist"
953
  msgstr ""
954
 
955
+ #: config/settings.php:561
956
  msgctxt "admin-text"
957
  msgid "Choose the action that should be taken when a review is blacklisted."
958
  msgstr ""
959
 
960
+ #: config/settings.php:562
961
  msgctxt "admin-text"
962
  msgid "Blacklist Action"
963
  msgstr ""
964
 
965
+ #: config/settings.php:564
966
  msgctxt "admin-text"
967
  msgid "Require approval"
968
  msgstr ""
969
 
970
+ #: config/settings.php:565
971
  msgctxt "admin-text"
972
  msgid "Reject submission"
973
  msgstr ""
974
 
 
 
 
 
 
975
  #: plugin/Deprecated.php:24
976
  msgctxt "admin-text"
977
  msgid "The [%s] method has been deprecated and will be soon be removed, please use the [%s] method instead."
978
  msgstr ""
979
 
980
+ #: plugin/Review.php:307, plugin/Controllers/ListTableColumns/ColumnValueAuthorName.php:20
981
  msgctxt "admin-text"
982
  msgid "Unknown"
983
  msgstr ""
1091
  msgid "This review is based on my own experience and is my genuine opinion."
1092
  msgstr ""
1093
 
1094
+ #: plugin/Addons/Controller.php:70, plugin/Controllers/AdminController.php:48, plugin/Controllers/MenuController.php:50, views/pages/tools/sync.php:23
1095
  msgctxt "admin-text"
1096
  msgid "Settings"
1097
  msgstr ""
1098
 
1099
+ #: plugin/Addons/Controller.php:76, plugin/Controllers/AdminController.php:54, plugin/Controllers/MenuController.php:53
1100
  msgctxt "admin-text"
1101
  msgid "Help"
1102
  msgstr ""
1110
  msgid "Show more"
1111
  msgstr ""
1112
 
1113
+ #: plugin/Commands/CreateReview.php:156
1114
  msgid "Your review has been submitted!"
1115
  msgstr ""
1116
 
1117
+ #: plugin/Commands/CreateReview.php:161
1118
  msgid "Your review could not be submitted and the error has been logged. Please notify the site admin."
1119
  msgstr ""
1120
 
1167
  msgid "Edit"
1168
  msgstr ""
1169
 
1170
+ #: plugin/Controllers/AdminController.php:85
1171
  msgctxt "admin-text"
1172
  msgid "%s Review"
1173
  msgid_plural "%s Reviews"
1174
  msgstr[0] ""
1175
  msgstr[1] ""
1176
 
1177
+ #: plugin/Controllers/AdminController.php:165, plugin/Controllers/MainController.php:149
1178
  msgctxt "admin-text"
1179
  msgid "Recent Reviews"
1180
  msgstr ""
1181
 
1182
+ #: plugin/Controllers/AdminController.php:166, plugin/Controllers/MainController.php:153
1183
  msgctxt "admin-text"
1184
  msgid "Submit a Review"
1185
  msgstr ""
1186
 
1187
+ #: plugin/Controllers/AdminController.php:167, plugin/Controllers/MainController.php:157
1188
  msgctxt "admin-text"
1189
  msgid "Summary of Reviews"
1190
  msgstr ""
1191
 
1192
+ #: plugin/Controllers/AdminController.php:202, plugin/Controllers/AdminController.php:222, plugin/Controllers/AdminController.php:235
1193
  msgctxt "admin-text"
1194
  msgid "Nothing found."
1195
  msgstr ""
1224
  msgid "%s this review"
1225
  msgstr ""
1226
 
1227
+ #: plugin/Controllers/MainController.php:105
1228
+ msgctxt "admin-text"
1229
+ msgid "Local Review"
1230
+ msgstr ""
1231
+
1232
+ #: plugin/Controllers/MainController.php:148
1233
  msgctxt "admin-text"
1234
  msgid "Site Reviews: Display your recent reviews."
1235
  msgstr ""
1236
 
1237
+ #: plugin/Controllers/MainController.php:152
1238
  msgctxt "admin-text"
1239
  msgid "Site Reviews: Display a form to submit reviews."
1240
  msgstr ""
1241
 
1242
+ #: plugin/Controllers/MainController.php:156
1243
  msgctxt "admin-text"
1244
  msgid "Site Reviews: Display a summary of your reviews."
1245
  msgstr ""
1436
 
1437
  #: plugin/Controllers/ToolsController.php:157
1438
  msgctxt "admin-text"
1439
+ msgid "The plugin has been migrated sucessfully, please reload the page."
1440
  msgstr ""
1441
 
1442
  #: plugin/Controllers/ToolsController.php:154
1443
  msgctxt "admin-text"
1444
+ msgid "All plugin migrations have been run successfully, please reload the page."
1445
  msgstr ""
1446
 
1447
  #: plugin/Controllers/ToolsController.php:180
1449
  msgid "The assigned meta values have been reset."
1450
  msgstr ""
1451
 
1452
+ #: plugin/Controllers/ToolsController.php:206
1453
  msgctxt "admin-text"
1454
  msgid "The permissions have been reset."
1455
  msgstr ""
1456
 
1457
+ #: plugin/Controllers/ToolsController.php:217
1458
  msgctxt "admin-text"
1459
  msgid "reload the page"
1460
  msgstr ""
1461
 
1462
+ #: plugin/Controllers/ToolsController.php:221
1463
  msgctxt "admin-text"
1464
  msgid "The permissions have been reset, please %s for them to take effect."
1465
  msgstr ""
1690
  msgid "The link to edit/view a review"
1691
  msgstr ""
1692
 
1693
+ #: plugin/Defaults/TemplateTagsDefaults.php:22
1694
+ msgctxt "admin-text"
1695
+ msgid "The review's assigned page titles"
1696
+ msgstr ""
1697
+
1698
+ #: plugin/Defaults/TemplateTagsDefaults.php:23
1699
+ msgctxt "admin-text"
1700
+ msgid "The review's assigned user display names"
1701
+ msgstr ""
1702
+
1703
+ #: plugin/Defaults/TemplateTagsDefaults.php:24
1704
+ msgctxt "admin-text"
1705
+ msgid "The review's assigned categories"
1706
+ msgstr ""
1707
+
1708
  #: plugin/Defaults/UpdatedMessageDefaults.php:15
1709
  msgctxt "admin-text"
1710
  msgid "Review has been approved and published."
1781
  msgid "This field requires a valid e-mail address."
1782
  msgstr ""
1783
 
1784
+ #: plugin/Defaults/ValidationStringsDefaults.php:19, plugin/Modules/Validator/DefaultValidator.php:58
1785
  msgid "Please fix the submission errors."
1786
  msgstr ""
1787
 
1869
  msgstr[0] ""
1870
  msgstr[1] ""
1871
 
1872
+ #: plugin/Modules/Notification.php:73
1873
  msgid "Anonymous"
1874
  msgstr ""
1875
 
1876
+ #: plugin/Modules/Notification.php:174
1877
  msgctxt "This string differs depending on whether or not the review has been assigned to a post."
1878
  msgid "New %s-star review"
1879
  msgid_plural "New %s-star review of %s"
2287
  msgid "All types"
2288
  msgstr ""
2289
 
 
 
 
 
 
2290
  #: plugin/Modules/Validator/AkismetValidator.php:49
2291
  msgid "This review has been flagged as possible spam and cannot be submitted."
2292
  msgstr ""
2311
  msgid "The reCAPTCHA verification failed, please try again."
2312
  msgstr ""
2313
 
2314
+ #: plugin/Modules/Validator/ReviewLimitsValidator.php:34
2315
  msgid "You have already submitted a review."
2316
  msgstr ""
2317
 
2450
  msgid "Reset Meta Values"
2451
  msgstr ""
2452
 
2453
+ #: views/pages/tools/general.php:108
2454
+ msgctxt "admin-text"
2455
+ msgid "Hard Reset Permissions"
2456
+ msgstr ""
2457
+
2458
+ #: views/pages/tools/general.php:108
2459
  msgctxt "admin-text"
2460
  msgid "Resetting, please wait..."
2461
  msgstr ""
2462
 
2463
+ #: views/pages/tools/general.php:108
2464
  msgctxt "admin-text"
2465
  msgid "Reset Permissions"
2466
  msgstr ""
2467
 
2468
+ #: views/pages/tools/general.php:125
2469
  msgctxt "admin-text"
2470
  msgid "Testing, please wait..."
2471
  msgstr ""
2472
 
2473
+ #: views/pages/tools/general.php:125
2474
  msgctxt "admin-text"
2475
  msgid "Test Detection"
2476
  msgstr ""
2622
 
2623
  #: views/partials/notices/addons.php:23
2624
  msgctxt "admin-text"
2625
+ msgid "Allow people to add captioned images to their reviews; provide sorting, filtering, and search functionality; and integrate with the Trustalyze platform."
2626
  msgstr ""
2627
 
2628
  #: views/partials/notices/addons.php:26
plugin/Addons/Addon.php CHANGED
@@ -56,7 +56,7 @@ abstract class Addon
56
  public function update()
57
  {
58
  $this->updater = new Updater(static::UPDATE_URL, $this->file, [
59
- 'license' => glsr_get_option('settings.licenses.'.static::ID),
60
  // 'testedTo' => $this->testedTo,
61
  ]);
62
  $this->updater->init();
56
  public function update()
57
  {
58
  $this->updater = new Updater(static::UPDATE_URL, $this->file, [
59
+ 'license' => glsr_get_option('licenses.'.static::ID),
60
  // 'testedTo' => $this->testedTo,
61
  ]);
62
  $this->updater->init();
plugin/Addons/Updater.php CHANGED
@@ -4,6 +4,7 @@ namespace GeminiLabs\SiteReviews\Addons;
4
 
5
  use GeminiLabs\SiteReviews\Helper;
6
  use GeminiLabs\SiteReviews\Helpers\Arr;
 
7
 
8
  class Updater
9
  {
@@ -110,7 +111,7 @@ class Updater
110
  */
111
  public function init()
112
  {
113
- if ($this->apiUrl === trailingslashit(home_url())) {
114
  return;
115
  }
116
  add_filter('plugins_api', [$this, 'filterPluginUpdateDetails'], 10, 3);
@@ -253,7 +254,7 @@ class Updater
253
  'item_name' => Arr::get($data, 'Name'),
254
  'license' => Arr::get($data, 'license'),
255
  'slug' => Arr::get($data, 'TextDomain'),
256
- 'url' => home_url(),
257
  ],
258
  'sslverify' => glsr()->filterBool('sslverify/post', false),
259
  'timeout' => 15,
4
 
5
  use GeminiLabs\SiteReviews\Helper;
6
  use GeminiLabs\SiteReviews\Helpers\Arr;
7
+ use GeminiLabs\SiteReviews\Helpers\Url;
8
 
9
  class Updater
10
  {
111
  */
112
  public function init()
113
  {
114
+ if ($this->apiUrl === Url::home()) {
115
  return;
116
  }
117
  add_filter('plugins_api', [$this, 'filterPluginUpdateDetails'], 10, 3);
254
  'item_name' => Arr::get($data, 'Name'),
255
  'license' => Arr::get($data, 'license'),
256
  'slug' => Arr::get($data, 'TextDomain'),
257
+ 'url' => Url::home(),
258
  ],
259
  'sslverify' => glsr()->filterBool('sslverify/post', false),
260
  'timeout' => 15,
plugin/Application.php CHANGED
@@ -3,17 +3,17 @@
3
  namespace GeminiLabs\SiteReviews;
4
 
5
  use GeminiLabs\SiteReviews\Database\DefaultsManager;
 
6
  use GeminiLabs\SiteReviews\Defaults\PermissionDefaults;
7
  use GeminiLabs\SiteReviews\Helpers\Arr;
8
  use GeminiLabs\SiteReviews\Helpers\Str;
9
- use GeminiLabs\SiteReviews\Role;
10
- use ReflectionClass;
11
 
12
  /**
13
  * @property array $addons
14
  * @property string $capability
15
  * @property string $cron_event
16
- * @property string $defaults
17
  * @property string $export_key
18
  * @property string $file
19
  * @property string $id
@@ -23,7 +23,6 @@ use ReflectionClass;
23
  * @property string $paged_query_var
24
  * @property string $post_type
25
  * @property string $prefix
26
- * @property array $reviewTypes
27
  * @property array $session
28
  * @property \GeminiLabs\SiteReviews\Arguments $storage
29
  * @property string $taxonomy
@@ -36,7 +35,6 @@ final class Application extends Container
36
  use Session;
37
  use Storage;
38
 
39
- const CRON_EVENT = 'site-reviews/schedule/session/purge';
40
  const EXPORT_KEY = '_glsr_export';
41
  const ID = 'site-reviews';
42
  const PAGED_HANDLE = 'pagination_request';
@@ -45,20 +43,20 @@ final class Application extends Container
45
  const PREFIX = 'glsr_';
46
  const TAXONOMY = 'site-review-category';
47
 
 
 
 
48
  protected $addons = [];
 
 
 
 
49
  protected $defaults;
50
- protected $name;
51
- protected $reviewTypes;
52
 
53
  /**
54
- * @return void
55
  */
56
- public function activate()
57
- {
58
- $this->scheduleCronJob();
59
- add_option(static::PREFIX.'activated', true);
60
- $this->make(Role::class)->resetAll();
61
- }
62
 
63
  /**
64
  * @param string $view
@@ -92,11 +90,13 @@ final class Application extends Container
92
  }
93
 
94
  /**
 
95
  * @return void
 
96
  */
97
- public function deactivate()
98
  {
99
- $this->unscheduleCronJob();
100
  }
101
 
102
  /**
@@ -119,17 +119,6 @@ final class Application extends Container
119
  }
120
  }
121
 
122
- /**
123
- * @return array
124
- */
125
- public function getDefaultSettings()
126
- {
127
- if (empty($this->defaults)) {
128
- $this->defaults = $this->make(DefaultsManager::class)->get();
129
- }
130
- return $this->filterArray('get/defaults', $this->defaults);
131
- }
132
-
133
  /**
134
  * @param string $page
135
  * @param string $tab
@@ -164,7 +153,11 @@ final class Application extends Container
164
  */
165
  public function init()
166
  {
167
- $this->make(Database::class)->createTables();
 
 
 
 
168
  $this->make(Hooks::class)->run();
169
  }
170
 
@@ -173,7 +166,7 @@ final class Application extends Container
173
  */
174
  public function isAdmin()
175
  {
176
- return is_admin() && !wp_doing_ajax();
177
  }
178
 
179
  /**
@@ -196,35 +189,6 @@ final class Application extends Container
196
  }
197
  }
198
 
199
- /**
200
- * @return void
201
- */
202
- public function registerAddons()
203
- {
204
- $this->action('addon/register', $this);
205
- }
206
-
207
- /**
208
- * @return void
209
- */
210
- public function registerLanguages()
211
- {
212
- load_plugin_textdomain(static::ID, false,
213
- trailingslashit(plugin_basename($this->path()).'/'.$this->languages)
214
- );
215
- }
216
-
217
- /**
218
- * @return void
219
- */
220
- public function registerReviewTypes()
221
- {
222
- $types = $this->filterArray('addon/types', []);
223
- $this->reviewTypes = wp_parse_args($types, [
224
- 'local' => _x('Local Review', 'admin-text', 'site-reviews'),
225
- ]);
226
- }
227
-
228
  /**
229
  * @param string $view
230
  * @return void
@@ -245,21 +209,14 @@ final class Application extends Container
245
  /**
246
  * @return void
247
  */
248
- public function scheduleCronJob()
249
  {
250
- if (false === wp_next_scheduled(static::CRON_EVENT)) {
251
- wp_schedule_event(time(), 'twicedaily', static::CRON_EVENT);
 
252
  }
253
- }
254
-
255
- /**
256
- * @return void
257
- */
258
- public function setDefaultSettings()
259
- {
260
- if (get_option(static::PREFIX.'activated')) {
261
- $this->make(DefaultsManager::class)->set();
262
- delete_option(static::PREFIX.'activated');
263
  }
264
  }
265
 
@@ -271,12 +228,4 @@ final class Application extends Container
271
  {
272
  return get_stylesheet_directory().'/'.static::ID.'/'.ltrim(trim($file), '/');
273
  }
274
-
275
- /**
276
- * @return void
277
- */
278
- public function unscheduleCronJob()
279
- {
280
- wp_unschedule_event(intval(wp_next_scheduled(static::CRON_EVENT)), static::CRON_EVENT);
281
- }
282
  }
3
  namespace GeminiLabs\SiteReviews;
4
 
5
  use GeminiLabs\SiteReviews\Database\DefaultsManager;
6
+ use GeminiLabs\SiteReviews\Database\OptionManager;
7
  use GeminiLabs\SiteReviews\Defaults\PermissionDefaults;
8
  use GeminiLabs\SiteReviews\Helpers\Arr;
9
  use GeminiLabs\SiteReviews\Helpers\Str;
10
+ use GeminiLabs\SiteReviews\Install;
 
11
 
12
  /**
13
  * @property array $addons
14
  * @property string $capability
15
  * @property string $cron_event
16
+ * @property array $defaults
17
  * @property string $export_key
18
  * @property string $file
19
  * @property string $id
23
  * @property string $paged_query_var
24
  * @property string $post_type
25
  * @property string $prefix
 
26
  * @property array $session
27
  * @property \GeminiLabs\SiteReviews\Arguments $storage
28
  * @property string $taxonomy
35
  use Session;
36
  use Storage;
37
 
 
38
  const EXPORT_KEY = '_glsr_export';
39
  const ID = 'site-reviews';
40
  const PAGED_HANDLE = 'pagination_request';
43
  const PREFIX = 'glsr_';
44
  const TAXONOMY = 'site-review-category';
45
 
46
+ /**
47
+ * @var array
48
+ */
49
  protected $addons = [];
50
+
51
+ /**
52
+ * @var array
53
+ */
54
  protected $defaults;
 
 
55
 
56
  /**
57
+ * @var string
58
  */
59
+ protected $name;
 
 
 
 
 
60
 
61
  /**
62
  * @param string $view
90
  }
91
 
92
  /**
93
+ * @param bool $networkDeactivating
94
  * @return void
95
+ * @callback register_deactivation_hook
96
  */
97
+ public function deactivate($networkDeactivating)
98
  {
99
+ $this->make(Install::class)->deactivate($networkDeactivating);
100
  }
101
 
102
  /**
119
  }
120
  }
121
 
 
 
 
 
 
 
 
 
 
 
 
122
  /**
123
  * @param string $page
124
  * @param string $tab
153
  */
154
  public function init()
155
  {
156
+ // Ensure the custom database tables exist, this is needed in cases
157
+ // where the plugin has been updated instead of activated.
158
+ if (empty(get_option(static::PREFIX.'db_version'))) {
159
+ $this->make(Install::class)->run();
160
+ }
161
  $this->make(Hooks::class)->run();
162
  }
163
 
166
  */
167
  public function isAdmin()
168
  {
169
+ return (is_admin() || is_network_admin()) && !wp_doing_ajax();
170
  }
171
 
172
  /**
189
  }
190
  }
191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  /**
193
  * @param string $view
194
  * @return void
209
  /**
210
  * @return void
211
  */
212
+ public function storeDefaults()
213
  {
214
+ if (empty($this->defaults)) {
215
+ $defaults = $this->make(DefaultsManager::class)->get();
216
+ $this->defaults = $this->filterArray('get/defaults', $defaults);
217
  }
218
+ if (empty(get_option(OptionManager::databaseKey()))) {
219
+ update_option(OptionManager::databaseKey(), $this->defaults);
 
 
 
 
 
 
 
 
220
  }
221
  }
222
 
228
  {
229
  return get_stylesheet_directory().'/'.static::ID.'/'.ltrim(trim($file), '/');
230
  }
 
 
 
 
 
 
 
 
231
  }
plugin/Commands/CreateReview.php CHANGED
@@ -8,6 +8,7 @@ use GeminiLabs\SiteReviews\Defaults\CreateReviewDefaults;
8
  use GeminiLabs\SiteReviews\Defaults\CustomFieldsDefaults;
9
  use GeminiLabs\SiteReviews\Helper;
10
  use GeminiLabs\SiteReviews\Helpers\Cast;
 
11
  use GeminiLabs\SiteReviews\Modules\Avatar;
12
  use GeminiLabs\SiteReviews\Modules\Notification;
13
  use GeminiLabs\SiteReviews\Modules\Validator\DefaultValidator;
@@ -70,7 +71,7 @@ class CreateReview implements Contract
70
  return $referer;
71
  }
72
  glsr_log()->warning('The form referer ($_SERVER[REQUEST_URI]) was empty.')->debug($this);
73
- return home_url();
74
  }
75
 
76
  /**
@@ -202,6 +203,7 @@ class CreateReview implements Contract
202
  */
203
  protected function type()
204
  {
205
- return array_key_exists($this->type, glsr()->reviewTypes) ? $this->type : 'local';
 
206
  }
207
  }
8
  use GeminiLabs\SiteReviews\Defaults\CustomFieldsDefaults;
9
  use GeminiLabs\SiteReviews\Helper;
10
  use GeminiLabs\SiteReviews\Helpers\Cast;
11
+ use GeminiLabs\SiteReviews\Helpers\Url;
12
  use GeminiLabs\SiteReviews\Modules\Avatar;
13
  use GeminiLabs\SiteReviews\Modules\Notification;
14
  use GeminiLabs\SiteReviews\Modules\Validator\DefaultValidator;
71
  return $referer;
72
  }
73
  glsr_log()->warning('The form referer ($_SERVER[REQUEST_URI]) was empty.')->debug($this);
74
+ return Url::home();
75
  }
76
 
77
  /**
203
  */
204
  protected function type()
205
  {
206
+ $reviewTypes = glsr()->retrieveAs('array', 'review_types');
207
+ return array_key_exists($this->type, $reviewTypes) ? $this->type : 'local';
208
  }
209
  }
plugin/Commands/RegisterPostType.php CHANGED
@@ -47,7 +47,7 @@ class RegisterPostType implements Contract
47
  ['class' => 'pinned-icon']
48
  );
49
  }
50
- if (count(glsr()->reviewTypes) < 2) {
51
  unset($this->columns['type']);
52
  }
53
  $columns = wp_parse_args(glsr()->retrieve('columns', []), [
47
  ['class' => 'pinned-icon']
48
  );
49
  }
50
+ if (count(glsr()->retrieveAs('array', 'review_types')) < 2) {
51
  unset($this->columns['type']);
52
  }
53
  $columns = wp_parse_args(glsr()->retrieve('columns', []), [
plugin/Controllers/AdminController.php CHANGED
@@ -10,6 +10,7 @@ use GeminiLabs\SiteReviews\Commands\TogglePinned;
10
  use GeminiLabs\SiteReviews\Commands\ToggleStatus;
11
  use GeminiLabs\SiteReviews\Database;
12
  use GeminiLabs\SiteReviews\Helpers\Arr;
 
13
  use GeminiLabs\SiteReviews\Modules\Html\Builder;
14
  use GeminiLabs\SiteReviews\Modules\Notice;
15
  use GeminiLabs\SiteReviews\Modules\Translation;
@@ -124,6 +125,18 @@ class AdminController extends Controller
124
  return $plugins;
125
  }
126
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  /**
128
  * @return void
129
  * @action import_end
@@ -133,6 +146,10 @@ class AdminController extends Controller
133
  $this->execute(new ImportRatings());
134
  }
135
 
 
 
 
 
136
  public function printInlineStyle()
137
  {
138
  echo '<style type="text/css">a[href="edit.php?post_type=site-review&page=addons"]:not(.current):not(:hover) { color:#F6E05E!important; }</style>';
10
  use GeminiLabs\SiteReviews\Commands\ToggleStatus;
11
  use GeminiLabs\SiteReviews\Database;
12
  use GeminiLabs\SiteReviews\Helpers\Arr;
13
+ use GeminiLabs\SiteReviews\Install;
14
  use GeminiLabs\SiteReviews\Modules\Html\Builder;
15
  use GeminiLabs\SiteReviews\Modules\Notice;
16
  use GeminiLabs\SiteReviews\Modules\Translation;
125
  return $plugins;
126
  }
127
 
128
+ /**
129
+ * @return void
130
+ * @action admin_init
131
+ */
132
+ public function onActivation()
133
+ {
134
+ if (empty(get_option(glsr()->prefix.'activated'))) {
135
+ glsr(Install::class)->run();
136
+ update_option(glsr()->prefix.'activated', true);
137
+ }
138
+ }
139
+
140
  /**
141
  * @return void
142
  * @action import_end
146
  $this->execute(new ImportRatings());
147
  }
148
 
149
+ /**
150
+ * @return void
151
+ * @action admin_head
152
+ */
153
  public function printInlineStyle()
154
  {
155
  echo '<style type="text/css">a[href="edit.php?post_type=site-review&page=addons"]:not(.current):not(:hover) { color:#F6E05E!important; }</style>';
plugin/Controllers/Controller.php CHANGED
@@ -45,7 +45,7 @@ abstract class Controller
45
  protected function hasQueryPermission(WP_Query $query)
46
  {
47
  global $pagenow;
48
- return is_admin()
49
  && $query->is_main_query()
50
  && glsr()->post_type === $query->get('post_type')
51
  && 'edit.php' === $pagenow;
@@ -56,7 +56,7 @@ abstract class Controller
56
  */
57
  protected function isReviewAdminPage()
58
  {
59
- return is_admin()
60
  && in_array(glsr()->post_type, [get_post_type(), filter_input(INPUT_GET, 'post_type')]);
61
  }
62
  }
45
  protected function hasQueryPermission(WP_Query $query)
46
  {
47
  global $pagenow;
48
+ return glsr()->isAdmin()
49
  && $query->is_main_query()
50
  && glsr()->post_type === $query->get('post_type')
51
  && 'edit.php' === $pagenow;
56
  */
57
  protected function isReviewAdminPage()
58
  {
59
+ return glsr()->isAdmin()
60
  && in_array(glsr()->post_type, [get_post_type(), filter_input(INPUT_GET, 'post_type')]);
61
  }
62
  }
plugin/Controllers/ListTableColumns/ColumnFilterType.php CHANGED
@@ -13,7 +13,7 @@ class ColumnFilterType implements ColumnFilterContract
13
  */
14
  public function handle()
15
  {
16
- if (count(glsr()->reviewTypes) < 2) {
17
  return;
18
  }
19
  $label = glsr(Builder::class)->label([
@@ -23,7 +23,7 @@ class ColumnFilterType implements ColumnFilterContract
23
  ]);
24
  $filter = glsr(Builder::class)->select([
25
  'name' => 'type',
26
- 'options' => Arr::prepend(glsr()->reviewTypes, _x('All types', 'admin-text', 'site-reviews'), ''),
27
  'value' => filter_input(INPUT_GET, 'type'),
28
  ]);
29
  return $label.$filter;
13
  */
14
  public function handle()
15
  {
16
+ if (count($reviewTypes = glsr()->retrieveAs('array', 'review_types')) < 2) {
17
  return;
18
  }
19
  $label = glsr(Builder::class)->label([
23
  ]);
24
  $filter = glsr(Builder::class)->select([
25
  'name' => 'type',
26
+ 'options' => Arr::prepend($reviewTypes, _x('All types', 'admin-text', 'site-reviews'), ''),
27
  'value' => filter_input(INPUT_GET, 'type'),
28
  ]);
29
  return $label.$filter;
plugin/Controllers/ListTableColumns/ColumnValueType.php CHANGED
@@ -12,8 +12,6 @@ class ColumnValueType implements ColumnValueContract
12
  */
13
  public function handle(Review $review)
14
  {
15
- return array_key_exists($review->type, glsr()->reviewTypes)
16
- ? glsr()->reviewTypes[$review->type]
17
- : _x('Unsupported Type', 'admin-text', 'site-reviews');
18
  }
19
  }
12
  */
13
  public function handle(Review $review)
14
  {
15
+ return $review->type();
 
 
16
  }
17
  }
plugin/Controllers/MainController.php CHANGED
@@ -6,9 +6,55 @@ use GeminiLabs\SiteReviews\Commands\RegisterPostType;
6
  use GeminiLabs\SiteReviews\Commands\RegisterShortcodes;
7
  use GeminiLabs\SiteReviews\Commands\RegisterTaxonomy;
8
  use GeminiLabs\SiteReviews\Commands\RegisterWidgets;
 
 
 
9
 
10
  class MainController extends Controller
11
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * @return void
14
  * @action admin_footer
@@ -19,6 +65,26 @@ class MainController extends Controller
19
  glsr_log()->logOnce();
20
  }
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  /**
23
  * @return void
24
  * @action init
@@ -28,6 +94,19 @@ class MainController extends Controller
28
  $this->execute(new RegisterPostType());
29
  }
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  /**
32
  * @return void
33
  * @action init
6
  use GeminiLabs\SiteReviews\Commands\RegisterShortcodes;
7
  use GeminiLabs\SiteReviews\Commands\RegisterTaxonomy;
8
  use GeminiLabs\SiteReviews\Commands\RegisterWidgets;
9
+ use GeminiLabs\SiteReviews\Database\Query;
10
+ use GeminiLabs\SiteReviews\Helpers\Arr;
11
+ use GeminiLabs\SiteReviews\Install;
12
 
13
  class MainController extends Controller
14
  {
15
+ /**
16
+ * switch_to_blog() was run before this hook was triggered.
17
+ * @param array $tables
18
+ * @return array
19
+ * @see http://developer.wordpress.org/reference/functions/wp_uninitialize_site/
20
+ * @filter wpmu_drop_tables
21
+ */
22
+ public function filterDropTables($tables)
23
+ {
24
+ $customTables = [ // order is intentional
25
+ glsr()->prefix.'ratings' => glsr(Query::class)->table('ratings'),
26
+ glsr()->prefix.'assigned_posts' => glsr(Query::class)->table('assigned_posts'),
27
+ glsr()->prefix.'assigned_terms' => glsr(Query::class)->table('assigned_terms'),
28
+ glsr()->prefix.'assigned_users' => glsr(Query::class)->table('assigned_users'),
29
+ ];
30
+ foreach ($customTables as $key => $table) {
31
+ $tables = Arr::prepend($tables, $table, $key); // Custom tables have foreign indexes so they must be removed first!
32
+ }
33
+ return $tables;
34
+ }
35
+
36
+ /**
37
+ * @return void
38
+ * @action init
39
+ */
40
+ public function initDefaults()
41
+ {
42
+ // This cannot be done before plugins_loaded as it uses the gettext functions
43
+ glsr()->storeDefaults();
44
+ }
45
+
46
+ /**
47
+ * @param \WP_Site $site
48
+ * @return void
49
+ * @action wp_insert_site
50
+ */
51
+ public function installOnNewSite($site)
52
+ {
53
+ if (is_plugin_active_for_network(plugin_basename(glsr()->file))) {
54
+ glsr(Install::class)->runOnSite($site->blog_id);
55
+ }
56
+ }
57
+
58
  /**
59
  * @return void
60
  * @action admin_footer
65
  glsr_log()->logOnce();
66
  }
67
 
68
+ /**
69
+ * @return void
70
+ * @action plugins_loaded
71
+ */
72
+ public function registerAddons()
73
+ {
74
+ glsr()->action('addon/register', glsr());
75
+ }
76
+
77
+ /**
78
+ * @return void
79
+ * @action plugins_loaded
80
+ */
81
+ public function registerLanguages()
82
+ {
83
+ load_plugin_textdomain(glsr()->id, false,
84
+ trailingslashit(plugin_basename(glsr()->path()).'/'.glsr()->languages)
85
+ );
86
+ }
87
+
88
  /**
89
  * @return void
90
  * @action init
94
  $this->execute(new RegisterPostType());
95
  }
96
 
97
+ /**
98
+ * @return void
99
+ * @action plugins_loaded
100
+ */
101
+ public function registerReviewTypes()
102
+ {
103
+ $types = glsr()->filterArray('addon/types', []);
104
+ $types = wp_parse_args($types, [
105
+ 'local' => _x('Local Review', 'admin-text', 'site-reviews'),
106
+ ]);
107
+ glsr()->store('review_types', $types);
108
+ }
109
+
110
  /**
111
  * @return void
112
  * @action init
plugin/Controllers/MenuController.php CHANGED
@@ -10,7 +10,7 @@ use GeminiLabs\SiteReviews\Modules\Html\Builder;
10
  use GeminiLabs\SiteReviews\Modules\Html\Settings;
11
  use GeminiLabs\SiteReviews\Modules\Html\Template;
12
  use GeminiLabs\SiteReviews\Modules\Notice;
13
- use GeminiLabs\SiteReviews\Modules\System;
14
 
15
  class MenuController extends Controller
16
  {
@@ -153,7 +153,7 @@ class MenuController extends Controller
153
  'base_url' => admin_url('edit.php?post_type='.glsr()->post_type),
154
  'console' => glsr(Console::class)->get(),
155
  'id' => glsr()->id,
156
- 'system' => glsr(System::class)->get(),
157
  ],
158
  'services' => glsr()->filterArray('addon/sync/services', []),
159
  ],
10
  use GeminiLabs\SiteReviews\Modules\Html\Settings;
11
  use GeminiLabs\SiteReviews\Modules\Html\Template;
12
  use GeminiLabs\SiteReviews\Modules\Notice;
13
+ use GeminiLabs\SiteReviews\Modules\SystemInfo;
14
 
15
  class MenuController extends Controller
16
  {
153
  'base_url' => admin_url('edit.php?post_type='.glsr()->post_type),
154
  'console' => glsr(Console::class)->get(),
155
  'id' => glsr()->id,
156
+ 'system' => glsr(SystemInfo::class)->get(),
157
  ],
158
  'services' => glsr()->filterArray('addon/sync/services', []),
159
  ],
plugin/Controllers/MetaboxController.php CHANGED
@@ -229,7 +229,7 @@ class MetaboxController
229
  protected function normalizeDetailsMetaBox(Review $review)
230
  {
231
  $fields = glsr()->config('forms/metabox-fields');
232
- if (count(glsr()->reviewTypes) < 2) {
233
  unset($fields['type']);
234
  }
235
  foreach ($fields as $key => &$field) {
229
  protected function normalizeDetailsMetaBox(Review $review)
230
  {
231
  $fields = glsr()->config('forms/metabox-fields');
232
+ if (count(glsr()->retrieveAs('array', 'review_types')) < 2) {
233
  unset($fields['type']);
234
  }
235
  foreach ($fields as $key => &$field) {
plugin/Controllers/RestReviewController.php CHANGED
@@ -60,7 +60,7 @@ class RestReviewController extends RestController
60
  public function getReviewTypes()
61
  {
62
  $response = [];
63
- foreach (glsr()->reviewTypes as $slug => $name) {
64
  $response[] = [
65
  'name' => $name,
66
  'slug' => $slug,
60
  public function getReviewTypes()
61
  {
62
  $response = [];
63
+ foreach (glsr()->retrieveAs('array', 'review_types') as $slug => $name) {
64
  $response[] = [
65
  'name' => $name,
66
  'slug' => $slug,
plugin/Controllers/ReviewController.php CHANGED
@@ -53,6 +53,17 @@ class ReviewController extends Controller
53
  return $posts;
54
  }
55
 
 
 
 
 
 
 
 
 
 
 
 
56
  /**
57
  * Triggered when one or more categories are added or removed from a review.
58
  *
@@ -180,9 +191,9 @@ class ReviewController extends Controller
180
  'status' => 'all',
181
  ]);
182
  if (glsr(Database::class)->delete('assigned_posts', ['post_id' => $postId])) {
183
- foreach ($reviews as $review) {
184
  glsr(Cache::class)->delete($review->ID, 'reviews');
185
- }
186
  }
187
  }
188
 
@@ -213,40 +224,34 @@ class ReviewController extends Controller
213
  'status' => 'all',
214
  ]);
215
  if (glsr(Database::class)->delete('assigned_users', ['user_id' => $userId])) {
216
- foreach ($reviews as $review) {
217
  glsr(Cache::class)->delete($review->ID, 'reviews');
218
- }
219
  }
220
  }
221
 
222
  /**
223
- * Triggered when a review is edited.
224
  * It's unnecessary to trigger a term recount as this is done by the set_object_terms hook
225
  * We need to use "edit_post" to support revisions (vs "save_post").
226
  *
227
  * @param int $postId
 
 
228
  * @return void
229
- * @action edit_post_{glsr()->post_type}
230
  */
231
- public function onEditReview($postId)
232
  {
233
- $input = 'edit' === glsr_current_screen()->base ? INPUT_GET : INPUT_POST;
234
- if (!glsr()->can('edit_posts') || 'glsr_action' === filter_input($input, 'action')) {
235
- return; // abort if user does not have permission or if not a proper post update (i.e. approve/unapprove)
236
  }
237
  $review = glsr(Query::class)->review($postId);
238
- $assignedPostIds = filter_input($input, 'post_ids', FILTER_SANITIZE_NUMBER_INT, FILTER_FORCE_ARRAY);
239
- $assignedUserIds = filter_input($input, 'user_ids', FILTER_SANITIZE_NUMBER_INT, FILTER_FORCE_ARRAY);
240
- glsr()->action('review/updated/post_ids', $review, Cast::toArray($assignedPostIds)); // trigger a recount of assigned posts
241
- glsr()->action('review/updated/user_ids', $review, Cast::toArray($assignedUserIds)); // trigger a recount of assigned users
242
- glsr(MetaboxController::class)->saveResponseMetabox($review);
243
- $submittedValues = Helper::filterInputArray(glsr()->id);
244
- if (Arr::get($submittedValues, 'is_editing_review')) {
245
- $submittedValues['rating'] = Arr::get($submittedValues, 'rating');
246
- glsr(ReviewManager::class)->update($postId, $submittedValues);
247
- glsr(ReviewManager::class)->updateCustom($postId, $submittedValues);
248
  }
249
- glsr()->action('review/saved', glsr(Query::class)->review($postId), $submittedValues);
250
  }
251
 
252
  /**
@@ -263,6 +268,21 @@ class ReviewController extends Controller
263
  }
264
  }
265
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  /**
267
  * @return array
268
  */
@@ -281,4 +301,41 @@ class ReviewController extends Controller
281
  'old' => $old,
282
  ];
283
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  }
53
  return $posts;
54
  }
55
 
56
+ /**
57
+ * @param string $operator
58
+ * @return string
59
+ * @filter site-reviews/query/sql/clause/operator
60
+ */
61
+ public function filterSqlClauseOperator($operator)
62
+ {
63
+ $operators = ['loose' => 'OR', 'strict' => 'AND'];
64
+ return Arr::get($operators, glsr_get_option('reviews.assignment', 'strict', 'string'), $operator);
65
+ }
66
+
67
  /**
68
  * Triggered when one or more categories are added or removed from a review.
69
  *
191
  'status' => 'all',
192
  ]);
193
  if (glsr(Database::class)->delete('assigned_posts', ['post_id' => $postId])) {
194
+ array_walk($reviews, function ($review) {
195
  glsr(Cache::class)->delete($review->ID, 'reviews');
196
+ });
197
  }
198
  }
199
 
224
  'status' => 'all',
225
  ]);
226
  if (glsr(Database::class)->delete('assigned_users', ['user_id' => $userId])) {
227
+ array_walk($reviews, function ($review) {
228
  glsr(Cache::class)->delete($review->ID, 'reviews');
229
+ });
230
  }
231
  }
232
 
233
  /**
234
+ * Triggered when a review is edited or trashed.
235
  * It's unnecessary to trigger a term recount as this is done by the set_object_terms hook
236
  * We need to use "edit_post" to support revisions (vs "save_post").
237
  *
238
  * @param int $postId
239
+ * @param \WP_Post $post
240
+ * @param \WP_Post $oldPost
241
  * @return void
242
+ * @action post_updated
243
  */
244
+ public function onEditReview($postId, $post, $oldPost)
245
  {
246
+ if (!glsr()->can('edit_posts') || !$this->isEditedReview($post, $oldPost)) {
247
+ return;
 
248
  }
249
  $review = glsr(Query::class)->review($postId);
250
+ if ('post' === glsr_current_screen()->base) {
251
+ $this->updateReview($review);
252
+ } else {
253
+ $this->bulkUpdateReview($review);
 
 
 
 
 
 
254
  }
 
255
  }
256
 
257
  /**
268
  }
269
  }
270
 
271
+ /**
272
+ * @return void
273
+ */
274
+ protected function bulkUpdateReview(Review $review)
275
+ {
276
+ if ($assignedPostIds = filter_input(INPUT_GET, 'post_ids', FILTER_SANITIZE_NUMBER_INT, FILTER_FORCE_ARRAY)) {
277
+ glsr()->action('review/updated/post_ids', $review, Cast::toArray($assignedPostIds)); // trigger a recount of assigned posts
278
+ }
279
+ if ($assignedUserIds = filter_input(INPUT_GET, 'user_ids', FILTER_SANITIZE_NUMBER_INT, FILTER_FORCE_ARRAY)) {
280
+ glsr()->action('review/updated/user_ids', $review, Cast::toArray($assignedUserIds)); // trigger a recount of assigned users
281
+ }
282
+ $review = glsr(Query::class)->review($review->ID); // get a fresh copy of the review
283
+ glsr()->action('review/saved', $review, []); // pass an empty array since review values are unchanged
284
+ }
285
+
286
  /**
287
  * @return array
288
  */
301
  'old' => $old,
302
  ];
303
  }
304
+
305
+ /**
306
+ * @param \WP_Post $post
307
+ * @param \WP_Post $oldPost
308
+ * @return bool
309
+ */
310
+ protected function isEditedReview($post, $oldPost)
311
+ {
312
+ if (glsr()->post_type !== $post->post_type) {
313
+ return false;
314
+ }
315
+ if (in_array('trash', [$post->post_status, $oldPost->post_status])) {
316
+ return false; // trashed posts cannot be edited
317
+ }
318
+ $input = 'edit' === glsr_current_screen()->base ? INPUT_GET : INPUT_POST;
319
+ return 'glsr_action' !== filter_input($input, 'action'); // abort if not a proper post update (i.e. approve/unapprove)
320
+ }
321
+
322
+ /**
323
+ * @return void
324
+ */
325
+ protected function updateReview(Review $review)
326
+ {
327
+ $assignedPostIds = filter_input(INPUT_POST, 'post_ids', FILTER_SANITIZE_NUMBER_INT, FILTER_FORCE_ARRAY);
328
+ $assignedUserIds = filter_input(INPUT_POST, 'user_ids', FILTER_SANITIZE_NUMBER_INT, FILTER_FORCE_ARRAY);
329
+ glsr()->action('review/updated/post_ids', $review, Cast::toArray($assignedPostIds)); // trigger a recount of assigned posts
330
+ glsr()->action('review/updated/user_ids', $review, Cast::toArray($assignedUserIds)); // trigger a recount of assigned users
331
+ glsr(MetaboxController::class)->saveResponseMetabox($review);
332
+ $submittedValues = Helper::filterInputArray(glsr()->id);
333
+ if (Arr::get($submittedValues, 'is_editing_review')) {
334
+ $submittedValues['rating'] = Arr::get($submittedValues, 'rating');
335
+ glsr(ReviewManager::class)->update($review->ID, $submittedValues);
336
+ glsr(ReviewManager::class)->updateCustom($review->ID, $submittedValues);
337
+ }
338
+ $review = glsr(Query::class)->review($review->ID); // get a fresh copy of the review
339
+ glsr()->action('review/saved', $review, $submittedValues);
340
+ }
341
  }
plugin/Controllers/ToolsController.php CHANGED
@@ -11,7 +11,7 @@ use GeminiLabs\SiteReviews\Modules\Console;
11
  use GeminiLabs\SiteReviews\Modules\Html\Builder;
12
  use GeminiLabs\SiteReviews\Modules\Migrate;
13
  use GeminiLabs\SiteReviews\Modules\Notice;
14
- use GeminiLabs\SiteReviews\Modules\System;
15
  use GeminiLabs\SiteReviews\Request;
16
  use GeminiLabs\SiteReviews\Role;
17
 
@@ -91,7 +91,7 @@ class ToolsController extends Controller
91
  */
92
  public function downloadSystemInfo()
93
  {
94
- $this->download(glsr()->id.'-system-info.txt', glsr(System::class)->get());
95
  }
96
 
97
  /**
@@ -151,10 +151,10 @@ class ToolsController extends Controller
151
  {
152
  if (wp_validate_boolean($request->alt)) {
153
  glsr(Migrate::class)->runAll();
154
- glsr(Notice::class)->clear()->addSuccess(_x('All plugin migrations have been run successfully.', 'admin-text', 'site-reviews'));
155
  } else {
156
  glsr(Migrate::class)->run();
157
- glsr(Notice::class)->clear()->addSuccess(_x('The plugin has been migrated sucessfully.', 'admin-text', 'site-reviews'));
158
  }
159
  }
160
 
@@ -196,9 +196,13 @@ class ToolsController extends Controller
196
  * @return void
197
  * @action site-reviews/route/admin/reset-permissions
198
  */
199
- public function resetPermissions()
200
  {
201
- glsr(Role::class)->resetAll();
 
 
 
 
202
  glsr(Notice::class)->clear()->addSuccess(_x('The permissions have been reset.', 'admin-text', 'site-reviews'));
203
  }
204
 
@@ -206,9 +210,9 @@ class ToolsController extends Controller
206
  * @return void
207
  * @action site-reviews/route/ajax/reset-permissions
208
  */
209
- public function resetPermissionsAjax()
210
  {
211
- glsr(Role::class)->resetAll();
212
  $reloadLink = glsr(Builder::class)->a([
213
  'text' => _x('reload the page', 'admin-text', 'site-reviews'),
214
  'href' => 'javascript:window.location.reload(1)',
11
  use GeminiLabs\SiteReviews\Modules\Html\Builder;
12
  use GeminiLabs\SiteReviews\Modules\Migrate;
13
  use GeminiLabs\SiteReviews\Modules\Notice;
14
+ use GeminiLabs\SiteReviews\Modules\SystemInfo;
15
  use GeminiLabs\SiteReviews\Request;
16
  use GeminiLabs\SiteReviews\Role;
17
 
91
  */
92
  public function downloadSystemInfo()
93
  {
94
+ $this->download(glsr()->id.'-system-info.txt', glsr(SystemInfo::class)->get());
95
  }
96
 
97
  /**
151
  {
152
  if (wp_validate_boolean($request->alt)) {
153
  glsr(Migrate::class)->runAll();
154
+ glsr(Notice::class)->clear()->addSuccess(_x('All plugin migrations have been run successfully, please reload the page.', 'admin-text', 'site-reviews'));
155
  } else {
156
  glsr(Migrate::class)->run();
157
+ glsr(Notice::class)->clear()->addSuccess(_x('The plugin has been migrated sucessfully, please reload the page.', 'admin-text', 'site-reviews'));
158
  }
159
  }
160
 
196
  * @return void
197
  * @action site-reviews/route/admin/reset-permissions
198
  */
199
+ public function resetPermissions(Request $request)
200
  {
201
+ if (wp_validate_boolean($request->alt)) {
202
+ glsr(Role::class)->hardResetAll();
203
+ } else {
204
+ glsr(Role::class)->resetAll();
205
+ }
206
  glsr(Notice::class)->clear()->addSuccess(_x('The permissions have been reset.', 'admin-text', 'site-reviews'));
207
  }
208
 
210
  * @return void
211
  * @action site-reviews/route/ajax/reset-permissions
212
  */
213
+ public function resetPermissionsAjax(Request $request)
214
  {
215
+ $this->resetPermissions($request);
216
  $reloadLink = glsr(Builder::class)->a([
217
  'text' => _x('reload the page', 'admin-text', 'site-reviews'),
218
  'href' => 'javascript:window.location.reload(1)',
plugin/Database.php CHANGED
@@ -31,7 +31,7 @@ class Database
31
  }
32
 
33
  /**
34
- * Use this before bulk insert (see: $this->finishTransaction())
35
  * @param string $table
36
  * @return void
37
  */
@@ -43,15 +43,6 @@ class Database
43
  $this->dbQuery($sql);
44
  }
45
 
46
- /**
47
- * @return void
48
- */
49
- public function createTables()
50
- {
51
- glsr(SqlSchema::class)->createTables();
52
- glsr(SqlSchema::class)->addTableConstraints();
53
- }
54
-
55
  /**
56
  * @param string $sql
57
  * @return array
@@ -112,16 +103,73 @@ class Database
112
  return $this->logErrors($result);
113
  }
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  /**
116
  * @param string|string[] $keys
117
  * @param string $table
118
- * @return int|false
119
  */
120
  public function deleteMeta($keys, $table = 'postmeta')
121
  {
122
  $table = glsr(Query::class)->table($table);
123
  $metaKeys = glsr(Query::class)->escValuesForInsert(Arr::convertFromString($keys));
124
- $sql = glsr(Query::class)->sql("DELETE FROM {$table} WHERE meta_key IN {$metaKeys}");
 
 
125
  return $this->dbQuery($sql);
126
  }
127
 
@@ -151,7 +199,7 @@ class Database
151
  }
152
 
153
  /**
154
- * Use this after bulk insert (see: $this->beginTransaction())
155
  * @param string $table
156
  * @return void
157
  */
31
  }
32
 
33
  /**
34
+ * Use this before bulk insert (see: $this->finishTransaction()).
35
  * @param string $table
36
  * @return void
37
  */
43
  $this->dbQuery($sql);
44
  }
45
 
 
 
 
 
 
 
 
 
 
46
  /**
47
  * @param string $sql
48
  * @return array
103
  return $this->logErrors($result);
104
  }
105
 
106
+ /**
107
+ * @return int|bool
108
+ */
109
+ public function deleteInvalidPostAssignments()
110
+ {
111
+ return $this->dbQuery(sprintf(
112
+ glsr(Query::class)->sql("
113
+ DELETE t
114
+ FROM %s AS t
115
+ LEFT JOIN %s AS r ON t.rating_id = r.ID
116
+ LEFT JOIN {$this->db->posts} AS f ON t.post_id = f.ID
117
+ WHERE (r.ID IS NULL OR f.ID IS NULL)
118
+ "),
119
+ glsr(Query::class)->table('assigned_posts'),
120
+ glsr(Query::class)->table('ratings')
121
+ ));
122
+ }
123
+
124
+ /**
125
+ * @return int|bool
126
+ */
127
+ public function deleteInvalidTermAssignments()
128
+ {
129
+ return $this->dbQuery(sprintf(
130
+ glsr(Query::class)->sql("
131
+ DELETE t
132
+ FROM %s AS t
133
+ LEFT JOIN %s AS r ON t.rating_id = r.ID
134
+ LEFT JOIN {$this->db->term_taxonomy} AS f ON t.term_id = f.term_id
135
+ WHERE (r.ID IS NULL OR f.term_id IS NULL) OR f.taxonomy != '%s'
136
+ "),
137
+ glsr(Query::class)->table('assigned_terms'),
138
+ glsr(Query::class)->table('ratings'),
139
+ glsr()->taxonomy
140
+ ));
141
+ }
142
+
143
+ /**
144
+ * @return int|bool
145
+ */
146
+ public function deleteInvalidUserAssignments()
147
+ {
148
+ return $this->dbQuery(sprintf(
149
+ glsr(Query::class)->sql("
150
+ DELETE t
151
+ FROM %s AS t
152
+ LEFT JOIN %s AS r ON t.rating_id = r.ID
153
+ LEFT JOIN {$this->db->users} AS f ON t.user_id = f.ID
154
+ WHERE (r.ID IS NULL OR f.ID IS NULL)
155
+ "),
156
+ glsr(Query::class)->table('assigned_users'),
157
+ glsr(Query::class)->table('ratings')
158
+ ));
159
+ }
160
+
161
  /**
162
  * @param string|string[] $keys
163
  * @param string $table
164
+ * @return int|bool
165
  */
166
  public function deleteMeta($keys, $table = 'postmeta')
167
  {
168
  $table = glsr(Query::class)->table($table);
169
  $metaKeys = glsr(Query::class)->escValuesForInsert(Arr::convertFromString($keys));
170
+ $sql = glsr(Query::class)->sql("
171
+ DELETE FROM {$table} WHERE meta_key IN {$metaKeys}
172
+ ");
173
  return $this->dbQuery($sql);
174
  }
175
 
199
  }
200
 
201
  /**
202
+ * Use this after bulk insert (see: $this->beginTransaction()).
203
  * @param string $table
204
  * @return void
205
  */
plugin/Database/NormalizePaginationArgs.php CHANGED
@@ -3,11 +3,7 @@
3
  namespace GeminiLabs\SiteReviews\Database;
4
 
5
  use GeminiLabs\SiteReviews\Arguments;
6
- use GeminiLabs\SiteReviews\Defaults\ReviewsDefaults;
7
  use GeminiLabs\SiteReviews\Helper;
8
- use GeminiLabs\SiteReviews\Helpers\Arr;
9
- use GeminiLabs\SiteReviews\Helpers\Cast;
10
- use GeminiLabs\SiteReviews\Helpers\Str;
11
  use GeminiLabs\SiteReviews\Helpers\Url;
12
 
13
  /**
@@ -26,6 +22,7 @@ class NormalizePaginationArgs extends Arguments
26
  }
27
 
28
  /**
 
29
  * @return void
30
  */
31
  protected function normalizePage()
@@ -38,21 +35,23 @@ class NormalizePaginationArgs extends Arguments
38
  }
39
 
40
  /**
 
41
  * @return void
42
  */
43
  protected function normalizePageUrl()
44
  {
45
  if ($request = glsr()->retrieve(glsr()->paged_handle)) {
46
  $urlPath = Url::path($request->url);
47
- $this->pageUrl = Url::path(home_url()) === $urlPath
48
  ? Url::home()
49
  : Url::home($urlPath);
50
  } else {
51
- $this->pageUrl = filter_input(INPUT_SERVER, 'REQUEST_URI');
52
  }
53
  }
54
 
55
  /**
 
56
  * @return void
57
  */
58
  protected function normalizePageUrlParameters()
3
  namespace GeminiLabs\SiteReviews\Database;
4
 
5
  use GeminiLabs\SiteReviews\Arguments;
 
6
  use GeminiLabs\SiteReviews\Helper;
 
 
 
7
  use GeminiLabs\SiteReviews\Helpers\Url;
8
 
9
  /**
22
  }
23
 
24
  /**
25
+ * Get the page number.
26
  * @return void
27
  */
28
  protected function normalizePage()
35
  }
36
 
37
  /**
38
+ * This should return an URL with the query string removed.
39
  * @return void
40
  */
41
  protected function normalizePageUrl()
42
  {
43
  if ($request = glsr()->retrieve(glsr()->paged_handle)) {
44
  $urlPath = Url::path($request->url);
45
+ $this->pageUrl = Url::path(Url::home()) === $urlPath
46
  ? Url::home()
47
  : Url::home($urlPath);
48
  } else {
49
+ $this->pageUrl = Url::home(Url::path(filter_input(INPUT_SERVER, 'REQUEST_URI')));
50
  }
51
  }
52
 
53
  /**
54
+ * Store the query string of the URL so that we don't lose it in pagination.
55
  * @return void
56
  */
57
  protected function normalizePageUrlParameters()
plugin/Database/NormalizeQueryArgs.php CHANGED
@@ -46,7 +46,7 @@ class NormalizeQueryArgs extends Arguments
46
  */
47
  protected function normalizeOrderBy($value)
48
  {
49
- $orderBy = Str::restrictTo('author,comment_count,date,ID,menu_order,none,rand,relevance', $value, 'date');
50
  if (in_array($orderBy, ['comment_count', 'ID', 'menu_order'])) {
51
  return Str::prefix($orderBy, 'p.');
52
  }
46
  */
47
  protected function normalizeOrderBy($value)
48
  {
49
+ $orderBy = Str::restrictTo('author,comment_count,date,ID,menu_order,none,random,relevance', $value, 'date');
50
  if (in_array($orderBy, ['comment_count', 'ID', 'menu_order'])) {
51
  return Str::prefix($orderBy, 'p.');
52
  }
plugin/Database/OptionManager.php CHANGED
@@ -125,9 +125,9 @@ class OptionManager
125
  */
126
  public function reset()
127
  {
128
- $settings = Arr::consolidate(get_option(static::databaseKey()));
129
  if (empty($settings)) {
130
- glsr(Migrate::class)->reset();
131
  delete_option(static::databaseKey());
132
  $settings = Arr::consolidate(glsr()->defaults);
133
  }
125
  */
126
  public function reset()
127
  {
128
+ $settings = Arr::consolidate($this->getWP(static::databaseKey(), []));
129
  if (empty($settings)) {
130
+ glsr(Migrate::class)->reset(); // @todo why do we this here again? It should only run if this is not a fresh install.
131
  delete_option(static::databaseKey());
132
  $settings = Arr::consolidate(glsr()->defaults);
133
  }
plugin/Database/ReviewManager.php CHANGED
@@ -90,7 +90,6 @@ class ReviewManager
90
  'ping_status' => 'closed',
91
  'post_content' => $values->content,
92
  'post_date' => $values->date,
93
- 'post_date_gmt' => get_gmt_from_date($values->date),
94
  'post_name' => uniqid($values->type),
95
  'post_status' => $this->postStatus($values->type, $values->blacklisted),
96
  'post_title' => $values->title,
90
  'ping_status' => 'closed',
91
  'post_content' => $values->content,
92
  'post_date' => $values->date,
 
93
  'post_name' => uniqid($values->type),
94
  'post_status' => $this->postStatus($values->type, $values->blacklisted),
95
  'post_title' => $values->title,
plugin/Database/Sql.php CHANGED
@@ -103,7 +103,6 @@ trait Sql
103
  public function sqlOrderBy()
104
  {
105
  $values = [
106
- 'rand' => 'RAND()',
107
  'random' => 'RAND()',
108
  ];
109
  $order = $this->args['order'];
@@ -113,7 +112,7 @@ trait Sql
113
  $orderedby[] = "r.is_pinned {$order}";
114
  $orderedby[] = "{$orderby} {$order}";
115
  } elseif (array_key_exists($orderby, $values)) {
116
- $orderedby[] = $orderby;
117
  }
118
  $orderedby = glsr()->filterArrayUnique('query/sql/order-by', $orderedby, $this->sqlHandle(), $this);
119
  if (!empty($orderedby)) {
103
  public function sqlOrderBy()
104
  {
105
  $values = [
 
106
  'random' => 'RAND()',
107
  ];
108
  $order = $this->args['order'];
112
  $orderedby[] = "r.is_pinned {$order}";
113
  $orderedby[] = "{$orderby} {$order}";
114
  } elseif (array_key_exists($orderby, $values)) {
115
+ $orderedby[] = $values[$orderby];
116
  }
117
  $orderedby = glsr()->filterArrayUnique('query/sql/order-by', $orderedby, $this->sqlHandle(), $this);
118
  if (!empty($orderedby)) {
plugin/Database/SqlSchema.php CHANGED
@@ -7,8 +7,19 @@ use GeminiLabs\SiteReviews\Helpers\Str;
7
 
8
  class SqlSchema
9
  {
 
 
 
10
  protected $constraints;
 
 
 
 
11
  protected $db;
 
 
 
 
12
  protected $tables;
13
 
14
  public function __construct()
@@ -21,116 +32,114 @@ class SqlSchema
21
  /**
22
  * @return void
23
  */
24
- public function addAssignedPostsTableConstraints()
25
  {
26
- if (!$this->tableConstraintExists($ratingIdConstraint = $this->prefix('assigned_posts').'_rating_id_foreign')) {
27
- glsr(Database::class)->dbQuery(glsr(Query::class)->sql("
28
- ALTER TABLE {$this->table('assigned_posts')}
29
- ADD CONSTRAINT {$ratingIdConstraint}
30
- FOREIGN KEY (rating_id)
31
- REFERENCES {$this->table('ratings')} (ID)
32
- ON DELETE CASCADE
33
- "));
34
- }
35
- if (!$this->isInnodb('posts')) {
36
- return;
37
- }
38
- if (!$this->tableConstraintExists($postIdConstraint = $this->prefix('assigned_posts').'_post_id_foreign')) {
39
- glsr(Database::class)->dbQuery(glsr(Query::class)->sql("
40
- ALTER TABLE {$this->table('assigned_posts')}
41
- ADD CONSTRAINT {$postIdConstraint}
42
- FOREIGN KEY (post_id)
43
- REFERENCES {$this->db->posts} (ID)
44
- ON DELETE CASCADE
45
- "));
46
- }
47
  }
48
 
49
  /**
50
  * @return void
51
  */
52
- public function addAssignedTermsTableConstraints()
53
  {
54
- if (!$this->tableConstraintExists($ratingIdConstraint = $this->prefix('assigned_terms').'_rating_id_foreign')) {
55
- glsr(Database::class)->dbQuery(glsr(Query::class)->sql("
56
- ALTER TABLE {$this->table('assigned_terms')}
57
- ADD CONSTRAINT {$ratingIdConstraint}
58
- FOREIGN KEY (rating_id)
59
- REFERENCES {$this->table('ratings')} (ID)
60
- ON DELETE CASCADE
61
- "));
62
- }
63
- if (!$this->isInnodb('terms')) {
64
- return;
65
- }
66
- if (!$this->tableConstraintExists($termIdConstraint = $this->prefix('assigned_terms').'_term_id_foreign')) {
67
- glsr(Database::class)->dbQuery(glsr(Query::class)->sql("
68
- ALTER TABLE {$this->table('assigned_terms')}
69
- ADD CONSTRAINT {$termIdConstraint}
70
- FOREIGN KEY (term_id)
71
- REFERENCES {$this->db->terms} (term_id)
72
- ON DELETE CASCADE
73
- "));
74
- }
75
  }
76
 
77
  /**
78
  * @return void
79
  */
80
- public function addAssignedUsersTableConstraints()
81
  {
82
- if (!$this->tableConstraintExists($ratingIdConstraint = $this->prefix('assigned_users').'_rating_id_foreign')) {
83
- glsr(Database::class)->dbQuery(glsr(Query::class)->sql("
84
- ALTER TABLE {$this->table('assigned_users')}
85
- ADD CONSTRAINT {$ratingIdConstraint}
86
- FOREIGN KEY (rating_id)
87
- REFERENCES {$this->table('ratings')} (ID)
88
- ON DELETE CASCADE
89
- "));
90
- }
91
- if (!$this->isInnodb('users')) {
92
- return;
93
- }
94
- if (!$this->tableConstraintExists($userIdConstraint = $this->prefix('assigned_users').'_user_id_foreign')) {
95
- glsr(Database::class)->dbQuery(glsr(Query::class)->sql("
96
- ALTER TABLE {$this->table('assigned_users')}
97
- ADD CONSTRAINT {$userIdConstraint}
98
- FOREIGN KEY (user_id)
99
- REFERENCES {$this->db->users} (ID)
100
- ON DELETE CASCADE
101
- "));
102
- }
103
  }
104
 
105
  /**
106
  * @return void
107
  */
108
- public function addReviewsTableConstraints()
109
  {
110
- if (!$this->isInnodb('posts')) {
111
- return;
112
- }
113
- if (!$this->tableConstraintExists($reviewIdConstraint = $this->prefix('assigned_posts').'_review_id_foreign')) {
114
- glsr(Database::class)->dbQuery(glsr(Query::class)->sql("
115
- ALTER TABLE {$this->table('ratings')}
116
- ADD CONSTRAINT {$reviewIdConstraint}
117
- FOREIGN KEY (review_id)
118
- REFERENCES {$this->db->posts} (ID)
119
- ON DELETE CASCADE
120
- "));
 
 
 
 
 
 
 
 
 
 
 
 
121
  }
 
 
 
 
 
 
 
122
  }
123
 
124
  /**
125
  * @return void
126
  */
127
- public function addTableConstraints()
128
  {
129
  if (!defined('GLSR_UNIT_TESTS')) {
130
- $this->addAssignedPostsTableConstraints();
131
- $this->addAssignedTermsTableConstraints();
132
- $this->addAssignedUsersTableConstraints();
133
- $this->addReviewsTableConstraints();
134
  }
135
  }
136
 
@@ -140,6 +149,7 @@ class SqlSchema
140
  public function createAssignedPostsTable()
141
  {
142
  if ($this->tableExists('assigned_posts')) {
 
143
  return false;
144
  }
145
  dbDelta(glsr(Query::class)->sql("
@@ -147,8 +157,8 @@ class SqlSchema
147
  rating_id bigint(20) unsigned NOT NULL,
148
  post_id bigint(20) unsigned NOT NULL,
149
  is_published tinyint(1) NOT NULL DEFAULT '1',
150
- UNIQUE KEY {$this->prefix('assigned_posts')}_rating_id_post_id_unique (rating_id,post_id)
151
- ) {$this->db->get_charset_collate()};
152
  "));
153
  return true;
154
  }
@@ -159,14 +169,15 @@ class SqlSchema
159
  public function createAssignedTermsTable()
160
  {
161
  if ($this->tableExists('assigned_terms')) {
 
162
  return false;
163
  }
164
  dbDelta(glsr(Query::class)->sql("
165
  CREATE TABLE {$this->table('assigned_terms')} (
166
  rating_id bigint(20) unsigned NOT NULL,
167
  term_id bigint(20) unsigned NOT NULL,
168
- UNIQUE KEY {$this->prefix('assigned_terms')}_rating_id_term_id_unique (rating_id,term_id)
169
- ) {$this->db->get_charset_collate()};
170
  "));
171
  return true;
172
  }
@@ -177,24 +188,28 @@ class SqlSchema
177
  public function createAssignedUsersTable()
178
  {
179
  if ($this->tableExists('assigned_users')) {
 
180
  return false;
181
  }
182
  dbDelta(glsr(Query::class)->sql("
183
  CREATE TABLE {$this->table('assigned_users')} (
184
  rating_id bigint(20) unsigned NOT NULL,
185
  user_id bigint(20) unsigned NOT NULL,
186
- UNIQUE KEY {$this->prefix('assigned_users')}_rating_id_user_id_unique (rating_id,user_id)
187
- ) {$this->db->get_charset_collate()};
188
  "));
189
  return true;
190
  }
191
 
192
  /**
 
193
  * @return bool
 
194
  */
195
  public function createRatingTable()
196
  {
197
  if ($this->tableExists('ratings')) {
 
198
  return false;
199
  }
200
  dbDelta(glsr(Query::class)->sql("
@@ -210,10 +225,10 @@ class SqlSchema
210
  avatar varchar(200) DEFAULT NULL,
211
  ip_address varchar(100) DEFAULT NULL,
212
  url varchar(250) DEFAULT NULL,
213
- PRIMARY KEY (ID),
214
- UNIQUE KEY {$this->prefix('ratings')}_review_id_unique (review_id),
215
- KEY {$this->prefix('ratings')}_rating_type_is_pinned_index (rating,type,is_pinned)
216
- ) {$this->db->get_charset_collate()};
217
  "));
218
  return true;
219
  }
@@ -227,49 +242,122 @@ class SqlSchema
227
  $this->createAssignedTermsTable();
228
  $this->createAssignedUsersTable();
229
  $this->createRatingTable();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  }
231
 
232
  /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  * @return bool
234
  */
235
  public function isInnodb($table)
236
  {
237
- $tableStatus = $this->db->get_row("
238
- SHOW TABLE STATUS WHERE Name = '{$this->table($table)}'
 
 
239
  ");
240
- if (!isset($tableStatus->Engine)) {
241
- glsr_log()->warning(sprintf('The %s database table does not exist.', $this->table($table)));
242
  return false;
243
  }
244
- return 'innodb' === strtolower($tableStatus->Engine);
 
 
 
 
 
 
 
 
 
 
 
245
  }
246
 
247
  /**
 
248
  * @return string
249
  */
250
- public function prefix($table)
251
  {
252
- return Str::prefix($table, glsr()->prefix);
 
 
 
 
 
253
  }
254
 
255
  /**
 
256
  * @return string
257
  */
258
  public function table($table)
259
  {
 
 
 
 
260
  if (Str::endsWith(['ratings', 'assigned_posts', 'assigned_terms', 'assigned_users'], $table)) {
261
- $table = $this->prefix($table);
 
 
262
  }
263
- return $this->db->prefix.$table;
 
 
 
 
264
  }
265
 
266
  /**
 
267
  * @return bool
268
  */
269
  public function tableExists($table)
270
  {
271
- if (!isset($this->tables)) {
272
- $prefix = $this->db->prefix.glsr()->prefix;
273
  $this->tables = $this->db->get_col(
274
  $this->db->prepare("SHOW TABLES LIKE %s", $this->db->esc_like($prefix).'%')
275
  );
@@ -278,17 +366,27 @@ class SqlSchema
278
  }
279
 
280
  /**
281
- * @return bool
282
  */
283
- public function tableConstraintExists($constraint)
284
  {
285
- if (!isset($this->constraints)) {
286
- $this->constraints = $this->db->get_col("
287
- SELECT CONSTRAINT_NAME
288
- FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
289
- WHERE CONSTRAINT_SCHEMA = '{$this->db->dbname}'
290
- ");
 
 
 
 
 
 
291
  }
292
- return in_array($constraint, $this->constraints);
 
 
 
 
293
  }
294
  }
7
 
8
  class SqlSchema
9
  {
10
+ /**
11
+ * @var array|null
12
+ */
13
  protected $constraints;
14
+
15
+ /**
16
+ * @var \wpdb
17
+ */
18
  protected $db;
19
+
20
+ /**
21
+ * @var array|null
22
+ */
23
  protected $tables;
24
 
25
  public function __construct()
32
  /**
33
  * @return void
34
  */
35
+ public function addAssignedPostsForeignConstraints()
36
  {
37
+ $this->addForeignConstraint(
38
+ $table = $this->table('assigned_posts'),
39
+ $constraint = $this->foreignConstraint('assigned_posts_rating_id'),
40
+ $foreignKey = 'rating_id',
41
+ $foreignTable = $this->table('ratings'),
42
+ $foreignColumn = 'ID'
43
+ );
44
+ $this->addForeignConstraint(
45
+ $table = $this->table('assigned_posts'),
46
+ $constraint = $this->foreignConstraint('assigned_posts_post_id'),
47
+ $foreignKey = 'post_id',
48
+ $foreignTable = $this->db->posts,
49
+ $foreignColumn = 'ID'
50
+ );
 
 
 
 
 
 
 
51
  }
52
 
53
  /**
54
  * @return void
55
  */
56
+ public function addAssignedTermsForeignConstraints()
57
  {
58
+ $this->addForeignConstraint(
59
+ $table = $this->table('assigned_terms'),
60
+ $constraint = $this->foreignConstraint('assigned_terms_rating_id'),
61
+ $foreignKey = 'rating_id',
62
+ $foreignTable = $this->table('ratings'),
63
+ $foreignColumn = 'ID'
64
+ );
65
+ $this->addForeignConstraint(
66
+ $table = $this->table('assigned_terms'),
67
+ $constraint = $this->foreignConstraint('assigned_terms_term_id'),
68
+ $foreignKey = 'term_id',
69
+ $foreignTable = $this->db->terms,
70
+ $foreignColumn = 'term_id'
71
+ );
 
 
 
 
 
 
 
72
  }
73
 
74
  /**
75
  * @return void
76
  */
77
+ public function addAssignedUsersForeignConstraints()
78
  {
79
+ $this->addForeignConstraint(
80
+ $table = $this->table('assigned_users'),
81
+ $constraint = $this->foreignConstraint('assigned_users_rating_id'),
82
+ $foreignKey = 'rating_id',
83
+ $foreignTable = $this->table('ratings'),
84
+ $foreignColumn = 'ID'
85
+ );
86
+ $this->addForeignConstraint(
87
+ $table = $this->table('assigned_users'),
88
+ $constraint = $this->foreignConstraint('assigned_users_user_id'),
89
+ $foreignKey = 'user_id',
90
+ $foreignTable = $this->db->users,
91
+ $foreignColumn = 'ID'
92
+ );
 
 
 
 
 
 
 
93
  }
94
 
95
  /**
96
  * @return void
97
  */
98
+ public function addReviewsForeignConstraints()
99
  {
100
+ $this->addForeignConstraint(
101
+ $table = $this->table('ratings'),
102
+ $constraint = $this->foreignConstraint('assigned_posts_review_id'),
103
+ $foreignKey = 'review_id',
104
+ $foreignTable = $this->db->posts,
105
+ $foreignColumn = 'ID'
106
+ );
107
+ }
108
+
109
+ /**
110
+ * This method expects the fully formed foreign constraint key
111
+ * @param string $table
112
+ * @param string $constraint
113
+ * @param string $foreignKey
114
+ * @param string $foreignTable
115
+ * @param string $foreignColumn
116
+ * @return int|bool
117
+ * @see $this->foreignConstraint()
118
+ */
119
+ public function addForeignConstraint($table, $constraint, $foreignKey, $foreignTable, $foreignColumn)
120
+ {
121
+ if ($this->foreignConstraintExists($constraint, $foreignTable)) {
122
+ return false;
123
  }
124
+ return glsr(Database::class)->dbQuery(glsr(Query::class)->sql("
125
+ ALTER TABLE {$table}
126
+ ADD CONSTRAINT {$constraint}
127
+ FOREIGN KEY ({$foreignKey})
128
+ REFERENCES {$foreignTable} ({$foreignColumn})
129
+ ON DELETE CASCADE
130
+ "));
131
  }
132
 
133
  /**
134
  * @return void
135
  */
136
+ public function addForeignConstraints()
137
  {
138
  if (!defined('GLSR_UNIT_TESTS')) {
139
+ $this->addAssignedPostsForeignConstraints();
140
+ $this->addAssignedTermsForeignConstraints();
141
+ $this->addAssignedUsersForeignConstraints();
142
+ $this->addReviewsForeignConstraints();
143
  }
144
  }
145
 
149
  public function createAssignedPostsTable()
150
  {
151
  if ($this->tableExists('assigned_posts')) {
152
+ glsr_log()->debug(sprintf('Cannot create the %s table because it already exists.', $this->table('assigned_posts')));
153
  return false;
154
  }
155
  dbDelta(glsr(Query::class)->sql("
157
  rating_id bigint(20) unsigned NOT NULL,
158
  post_id bigint(20) unsigned NOT NULL,
159
  is_published tinyint(1) NOT NULL DEFAULT '1',
160
+ UNIQUE KEY {$this->prefix('assigned_posts_rating_id_post_id_unique')} (rating_id,post_id)
161
+ ) ENGINE=InnoDB {$this->db->get_charset_collate()};
162
  "));
163
  return true;
164
  }
169
  public function createAssignedTermsTable()
170
  {
171
  if ($this->tableExists('assigned_terms')) {
172
+ glsr_log()->debug(sprintf('Cannot create the %s table because it already exists.', $this->table('assigned_terms')));
173
  return false;
174
  }
175
  dbDelta(glsr(Query::class)->sql("
176
  CREATE TABLE {$this->table('assigned_terms')} (
177
  rating_id bigint(20) unsigned NOT NULL,
178
  term_id bigint(20) unsigned NOT NULL,
179
+ UNIQUE KEY {$this->prefix('assigned_terms_rating_id_term_id_unique')} (rating_id,term_id)
180
+ ) ENGINE=InnoDB {$this->db->get_charset_collate()};
181
  "));
182
  return true;
183
  }
188
  public function createAssignedUsersTable()
189
  {
190
  if ($this->tableExists('assigned_users')) {
191
+ glsr_log()->debug(sprintf('Cannot create the %s table because it already exists.', $this->table('assigned_users')));
192
  return false;
193
  }
194
  dbDelta(glsr(Query::class)->sql("
195
  CREATE TABLE {$this->table('assigned_users')} (
196
  rating_id bigint(20) unsigned NOT NULL,
197
  user_id bigint(20) unsigned NOT NULL,
198
+ UNIQUE KEY {$this->prefix('assigned_users_rating_id_user_id_unique')} (rating_id,user_id)
199
+ ) ENGINE=InnoDB {$this->db->get_charset_collate()};
200
  "));
201
  return true;
202
  }
203
 
204
  /**
205
+ * WordPress codex says there must be two spaces between PRIMARY KEY and the key definition.
206
  * @return bool
207
+ * @see https://codex.wordpress.org/Creating_Tables_with_Plugins
208
  */
209
  public function createRatingTable()
210
  {
211
  if ($this->tableExists('ratings')) {
212
+ glsr_log()->debug(sprintf('Cannot create the %s table because it already exists.', $this->table('ratings')));
213
  return false;
214
  }
215
  dbDelta(glsr(Query::class)->sql("
225
  avatar varchar(200) DEFAULT NULL,
226
  ip_address varchar(100) DEFAULT NULL,
227
  url varchar(250) DEFAULT NULL,
228
+ PRIMARY KEY (ID),
229
+ UNIQUE KEY {$this->prefix('ratings_review_id_unique')} (review_id),
230
+ KEY {$this->prefix('ratings_rating_type_is_pinned_index')} (rating,type,is_pinned)
231
+ ) ENGINE=InnoDB {$this->db->get_charset_collate()};
232
  "));
233
  return true;
234
  }
242
  $this->createAssignedTermsTable();
243
  $this->createAssignedUsersTable();
244
  $this->createRatingTable();
245
+ add_option(glsr()->prefix.'db_version', glsr()->version('minor'));
246
+ }
247
+
248
+ /**
249
+ * @param string $table
250
+ * @param string $constraint
251
+ * @return int|bool
252
+ */
253
+ public function dropForeignConstraint($table, $constraint)
254
+ {
255
+ $table = $this->table($table);
256
+ $constraint = $this->foreignConstraint($constraint);
257
+ if (!$this->foreignConstraintExists($constraint)) {
258
+ return false;
259
+ }
260
+ return glsr(Database::class)->dbQuery(glsr(Query::class)->sql("
261
+ ALTER TABLE {$table} DROP FOREIGN KEY {$constraint};
262
+ "));
263
  }
264
 
265
  /**
266
+ * This method expects the fully formed foreign constraint key
267
+ * @param string $constraint
268
+ * @param string $foreignTable
269
+ * @return bool
270
+ * @see $this->foreignConstraint()
271
+ */
272
+ public function foreignConstraintExists($constraint, $foreignTable = '')
273
+ {
274
+ if (!empty($foreignTable) && !$this->isInnodb($foreignTable)) {
275
+ glsr_log()->debug("Cannot check for a foreign constraint because {$foreignTable} does not use the InnoDB engine.");
276
+ return true; // we cannot create foreign contraints on MyISAM tables
277
+ }
278
+ if (!is_array($this->constraints)) {
279
+ $this->constraints = $this->db->get_col("
280
+ SELECT CONSTRAINT_NAME
281
+ FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
282
+ WHERE CONSTRAINT_SCHEMA = '{$this->db->dbname}'
283
+ ");
284
+ }
285
+ return in_array($constraint, $this->constraints);
286
+ }
287
+
288
+ /**
289
+ * @param string $table
290
  * @return bool
291
  */
292
  public function isInnodb($table)
293
  {
294
+ $engine = $this->db->get_var("
295
+ SELECT ENGINE
296
+ FROM INFORMATION_SCHEMA.TABLES
297
+ WHERE TABLE_SCHEMA = '{$this->db->dbname}' AND TABLE_NAME = '{$this->table($table)}'
298
  ");
299
+ if (empty($engine)) {
300
+ glsr_log()->warning(sprintf('InnoDB: The %s database table does not exist.', $this->table($table)));
301
  return false;
302
  }
303
+ return 'innodb' === strtolower($engine);
304
+ }
305
+
306
+ /**
307
+ * @param string $table
308
+ * @param string $prefix
309
+ * @return string
310
+ */
311
+ public function prefix($table, $prefix = '')
312
+ {
313
+ $table = Str::prefix($table, glsr()->prefix);
314
+ return Str::prefix($table, $prefix);
315
  }
316
 
317
  /**
318
+ * @param string $constraint
319
  * @return string
320
  */
321
+ public function foreignConstraint($constraint)
322
  {
323
+ $constraint = Str::prefix($constraint, glsr()->prefix);
324
+ $constraint = Str::suffix($constraint, '_foreign');
325
+ if (is_multisite() && $this->db->blogid > 1) {
326
+ return Str::suffix($constraint, '_'.$this->db->blogid);
327
+ }
328
+ return $constraint;
329
  }
330
 
331
  /**
332
+ * @param string $table
333
  * @return string
334
  */
335
  public function table($table)
336
  {
337
+ if (in_array($table, $this->db->tables())) {
338
+ return $table; // WordPress table is already prefixed
339
+ }
340
+ // do this next in case another plugin has created a similar table
341
  if (Str::endsWith(['ratings', 'assigned_posts', 'assigned_terms', 'assigned_users'], $table)) {
342
+ $table = Str::removePrefix($table, $this->db->get_blog_prefix());
343
+ $table = Str::removePrefix($table, glsr()->prefix);
344
+ return $this->prefix($table, $this->db->get_blog_prefix());
345
  }
346
+ if (array_key_exists($table, $this->db->tables())) {
347
+ return $this->db->{$table}; // the prefixed WordPress table
348
+ }
349
+ glsr_log()->error("The {$table} table does not exist.");
350
+ return $table; // @todo maybe throw an exception here instead...
351
  }
352
 
353
  /**
354
+ * @param string $table
355
  * @return bool
356
  */
357
  public function tableExists($table)
358
  {
359
+ if (!is_array($this->tables)) {
360
+ $prefix = $this->db->get_blog_prefix().glsr()->prefix;
361
  $this->tables = $this->db->get_col(
362
  $this->db->prepare("SHOW TABLES LIKE %s", $this->db->esc_like($prefix).'%')
363
  );
366
  }
367
 
368
  /**
369
+ * @return string[]
370
  */
371
+ public function tableEngines()
372
  {
373
+ $results = $this->db->get_results("
374
+ SELECT TABLE_NAME, ENGINE
375
+ FROM INFORMATION_SCHEMA.TABLES
376
+ WHERE TABLE_SCHEMA = '{$this->db->dbname}'
377
+ AND TABLE_NAME IN ('{$this->db->options}','{$this->db->posts}','{$this->db->terms}','{$this->db->users}')
378
+ ");
379
+ $engines = [];
380
+ foreach ($results as $result) {
381
+ if (!array_key_exists($result->ENGINE, $engines)) {
382
+ $engines[$result->ENGINE] = [];
383
+ }
384
+ $engines[$result->ENGINE][] = Str::removePrefix($result->TABLE_NAME, $this->db->get_blog_prefix());
385
  }
386
+ $tableEngines = [];
387
+ foreach ($engines as $engine => $tables) {
388
+ $tableEngines[] = sprintf('%s (%s)', $engine, implode('|', $tables));
389
+ }
390
+ return $tableEngines;
391
  }
392
  }
plugin/Defaults/CreateReviewDefaults.php CHANGED
@@ -27,11 +27,11 @@ class CreateReviewDefaults extends Defaults
27
  'content' => 'text-multiline',
28
  'custom' => 'array',
29
  'date' => 'date',
30
- 'email' => 'email',
31
  'form_id' => 'int',
32
  'ip_address' => 'text',
33
  'is_pinned' => 'bool',
34
- 'name' => 'text',
35
  'post_id' => 'int',
36
  'rating' => 'int',
37
  'referer' => 'text',
27
  'content' => 'text-multiline',
28
  'custom' => 'array',
29
  'date' => 'date',
30
+ 'email' => 'user-email',
31
  'form_id' => 'int',
32
  'ip_address' => 'text',
33
  'is_pinned' => 'bool',
34
+ 'name' => 'user-name',
35
  'post_id' => 'int',
36
  'rating' => 'int',
37
  'referer' => 'text',
plugin/Defaults/TemplateTagsDefaults.php CHANGED
@@ -19,6 +19,9 @@ class TemplateTagsDefaults extends Defaults
19
  'review_email' => _x('The email of the review author', 'admin-text', 'site-reviews'),
20
  'review_ip' => _x('The IP address of the review author', 'admin-text', 'site-reviews'),
21
  'review_link' => _x('The link to edit/view a review', 'admin-text', 'site-reviews'),
 
 
 
22
  ];
23
  }
24
  }
19
  'review_email' => _x('The email of the review author', 'admin-text', 'site-reviews'),
20
  'review_ip' => _x('The IP address of the review author', 'admin-text', 'site-reviews'),
21
  'review_link' => _x('The link to edit/view a review', 'admin-text', 'site-reviews'),
22
+ 'review_assigned_posts' => _x('The review\'s assigned page titles', 'admin-text', 'site-reviews'),
23
+ 'review_assigned_users' => _x('The review\'s assigned user display names', 'admin-text', 'site-reviews'),
24
+ 'review_categories' => _x('The review\'s assigned categories', 'admin-text', 'site-reviews'),
25
  ];
26
  }
27
  }
plugin/Helpers/Arr.php CHANGED
@@ -108,7 +108,7 @@ class Arr
108
  }
109
 
110
  /**
111
- * @param string $key
112
  * @return array
113
  */
114
  public static function insertAfter($key, array $array, array $insert)
@@ -117,7 +117,7 @@ class Arr
117
  }
118
 
119
  /**
120
- * @param string $key
121
  * @return array
122
  */
123
  public static function insertBefore($key, array $array, array $insert)
@@ -126,7 +126,7 @@ class Arr
126
  }
127
 
128
  /**
129
- * @param string $key
130
  * @param string $position
131
  * @return array
132
  */
108
  }
109
 
110
  /**
111
+ * @param string|int $key
112
  * @return array
113
  */
114
  public static function insertAfter($key, array $array, array $insert)
117
  }
118
 
119
  /**
120
+ * @param string|int $key
121
  * @return array
122
  */
123
  public static function insertBefore($key, array $array, array $insert)
126
  }
127
 
128
  /**
129
+ * @param string|int $key
130
  * @param string $position
131
  * @return array
132
  */
plugin/Helpers/Url.php CHANGED
@@ -8,9 +8,9 @@ class Url
8
  * @param string $path
9
  * @return string
10
  */
11
- public static function home($path = null)
12
  {
13
- return trailingslashit(home_url($path));
14
  }
15
 
16
  /**
8
  * @param string $path
9
  * @return string
10
  */
11
+ public static function home($path = '')
12
  {
13
+ return trailingslashit(network_home_url($path));
14
  }
15
 
16
  /**
plugin/Hooks.php CHANGED
@@ -73,11 +73,6 @@ class Hooks implements HooksContract
73
  */
74
  public function addActions()
75
  {
76
- add_action('plugins_loaded', [glsr(), 'getDefaultSettings'], 11);
77
- add_action('plugins_loaded', [glsr(), 'registerAddons']);
78
- add_action('plugins_loaded', [glsr(), 'registerLanguages']);
79
- add_action('plugins_loaded', [glsr(), 'registerReviewTypes']);
80
- add_action('admin_init', [glsr(), 'setDefaultSettings']);
81
  add_action('plugins_loaded', [$this, 'myIsamFallback']);
82
  add_action('load-edit.php', [$this, 'translateAdminEditPage']);
83
  add_action('load-post.php', [$this, 'translateAdminPostPage']);
@@ -87,6 +82,7 @@ class Hooks implements HooksContract
87
  add_action('admin_head', [$this->admin, 'printInlineStyle']);
88
  add_action('admin_init', [$this->admin, 'registerTinymcePopups']);
89
  add_action('media_buttons', [$this->admin, 'renderTinymceButton'], 11);
 
90
  add_action('import_end', [$this->admin, 'onImportEnd']);
91
  add_action('site-reviews/route/ajax/search-posts', [$this->admin, 'searchPostsAjax']);
92
  add_action('site-reviews/route/ajax/search-translations', [$this->admin, 'searchTranslationsAjax']);
@@ -103,9 +99,14 @@ class Hooks implements HooksContract
103
  add_action('pre_get_posts', [$this->listtable, 'setQueryForColumn']);
104
  add_action('restrict_manage_posts', [$this->listtable, 'renderColumnFilters']);
105
  add_action('manage_'.glsr()->post_type.'_posts_custom_column', [$this->listtable, 'renderColumnValues'], 10, 2);
 
 
106
  add_action('admin_footer', [$this->main, 'logOnce']);
107
  add_action('wp_footer', [$this->main, 'logOnce']);
 
 
108
  add_action('init', [$this->main, 'registerPostType'], 8);
 
109
  add_action('init', [$this->main, 'registerShortcodes']);
110
  add_action('init', [$this->main, 'registerTaxonomy']);
111
  add_action('widgets_init', [$this->main, 'registerWidgets']);
@@ -133,7 +134,7 @@ class Hooks implements HooksContract
133
  add_action('site-reviews/review/updated/user_ids', [$this->review, 'onChangeAssignedUsers'], 10, 2);
134
  add_action('site-reviews/review/created', [$this->review, 'onCreatedReview'], 10, 2);
135
  add_action('site-reviews/review/create', [$this->review, 'onCreateReview'], 10, 2);
136
- add_action('edit_post_'.glsr()->post_type, [$this->review, 'onEditReview']);
137
  add_action('admin_action_unapprove', [$this->review, 'unapprove']);
138
  add_action('wp_restore_post_revision', [$this->revisions, 'restoreRevision'], 10, 2);
139
  add_action('_wp_put_post_revision', [$this->revisions, 'saveRevision']);
@@ -187,12 +188,14 @@ class Hooks implements HooksContract
187
  add_filter('posts_clauses', [$this->listtable, 'filterPostClauses'], 10, 2);
188
  add_filter('post_row_actions', [$this->listtable, 'filterRowActions'], 10, 2);
189
  add_filter('manage_edit-'.glsr()->post_type.'_sortable_columns', [$this->listtable, 'filterSortableColumns']);
 
190
  add_filter('site-reviews/config/forms/metabox-fields', [$this->metabox, 'filterFieldOrder'], 11);
191
  add_filter('wp_privacy_personal_data_erasers', [$this->privacy, 'filterPersonalDataErasers']);
192
  add_filter('wp_privacy_personal_data_exporters', [$this->privacy, 'filterPersonalDataExporters']);
193
  add_filter('script_loader_tag', [$this->public, 'filterEnqueuedScriptTags'], 10, 2);
194
  add_filter('site-reviews/config/forms/review-form', [$this->public, 'filterFieldOrder'], 11);
195
  add_filter('site-reviews/render/view', [$this->public, 'filterRenderView']);
 
196
  add_filter('wp_save_post_revision_check_for_changes', [$this->revisions, 'filterCheckForChanges'], 99, 3);
197
  add_filter('wp_save_post_revision_post_has_changed', [$this->revisions, 'filterReviewHasChanged'], 10, 3);
198
  add_filter('wp_get_revision_ui_diff', [$this->revisions, 'filterRevisionUiDiff'], 10, 3);
73
  */
74
  public function addActions()
75
  {
 
 
 
 
 
76
  add_action('plugins_loaded', [$this, 'myIsamFallback']);
77
  add_action('load-edit.php', [$this, 'translateAdminEditPage']);
78
  add_action('load-post.php', [$this, 'translateAdminPostPage']);
82
  add_action('admin_head', [$this->admin, 'printInlineStyle']);
83
  add_action('admin_init', [$this->admin, 'registerTinymcePopups']);
84
  add_action('media_buttons', [$this->admin, 'renderTinymceButton'], 11);
85
+ add_action('admin_init', [$this->admin, 'onActivation']);
86
  add_action('import_end', [$this->admin, 'onImportEnd']);
87
  add_action('site-reviews/route/ajax/search-posts', [$this->admin, 'searchPostsAjax']);
88
  add_action('site-reviews/route/ajax/search-translations', [$this->admin, 'searchTranslationsAjax']);
99
  add_action('pre_get_posts', [$this->listtable, 'setQueryForColumn']);
100
  add_action('restrict_manage_posts', [$this->listtable, 'renderColumnFilters']);
101
  add_action('manage_'.glsr()->post_type.'_posts_custom_column', [$this->listtable, 'renderColumnValues'], 10, 2);
102
+ add_action('init', [$this->main, 'initDefaults'], 1);
103
+ add_action('wp_insert_site', [$this->main, 'installOnNewSite']);
104
  add_action('admin_footer', [$this->main, 'logOnce']);
105
  add_action('wp_footer', [$this->main, 'logOnce']);
106
+ add_action('plugins_loaded', [$this->main, 'registerAddons']);
107
+ add_action('plugins_loaded', [$this->main, 'registerLanguages'], 1); // do this first (may not be needed)
108
  add_action('init', [$this->main, 'registerPostType'], 8);
109
+ add_action('init', [$this->main, 'registerReviewTypes'], 7);
110
  add_action('init', [$this->main, 'registerShortcodes']);
111
  add_action('init', [$this->main, 'registerTaxonomy']);
112
  add_action('widgets_init', [$this->main, 'registerWidgets']);
134
  add_action('site-reviews/review/updated/user_ids', [$this->review, 'onChangeAssignedUsers'], 10, 2);
135
  add_action('site-reviews/review/created', [$this->review, 'onCreatedReview'], 10, 2);
136
  add_action('site-reviews/review/create', [$this->review, 'onCreateReview'], 10, 2);
137
+ add_action('post_updated', [$this->review, 'onEditReview'], 10, 3);
138
  add_action('admin_action_unapprove', [$this->review, 'unapprove']);
139
  add_action('wp_restore_post_revision', [$this->revisions, 'restoreRevision'], 10, 2);
140
  add_action('_wp_put_post_revision', [$this->revisions, 'saveRevision']);
188
  add_filter('posts_clauses', [$this->listtable, 'filterPostClauses'], 10, 2);
189
  add_filter('post_row_actions', [$this->listtable, 'filterRowActions'], 10, 2);
190
  add_filter('manage_edit-'.glsr()->post_type.'_sortable_columns', [$this->listtable, 'filterSortableColumns']);
191
+ add_filter('wpmu_drop_tables', [$this->main, 'filterDropTables'], 999); // run last
192
  add_filter('site-reviews/config/forms/metabox-fields', [$this->metabox, 'filterFieldOrder'], 11);
193
  add_filter('wp_privacy_personal_data_erasers', [$this->privacy, 'filterPersonalDataErasers']);
194
  add_filter('wp_privacy_personal_data_exporters', [$this->privacy, 'filterPersonalDataExporters']);
195
  add_filter('script_loader_tag', [$this->public, 'filterEnqueuedScriptTags'], 10, 2);
196
  add_filter('site-reviews/config/forms/review-form', [$this->public, 'filterFieldOrder'], 11);
197
  add_filter('site-reviews/render/view', [$this->public, 'filterRenderView']);
198
+ add_filter('site-reviews/query/sql/clause/operator', [$this->review, 'filterSqlClauseOperator'], 1);
199
  add_filter('wp_save_post_revision_check_for_changes', [$this->revisions, 'filterCheckForChanges'], 99, 3);
200
  add_filter('wp_save_post_revision_post_has_changed', [$this->revisions, 'filterReviewHasChanged'], 10, 3);
201
  add_filter('wp_get_revision_ui_diff', [$this->revisions, 'filterRevisionUiDiff'], 10, 3);
plugin/Install.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GeminiLabs\SiteReviews;
4
+
5
+ use GeminiLabs\SiteReviews\Database\Query;
6
+ use GeminiLabs\SiteReviews\Database\SqlSchema;
7
+
8
+ class Install
9
+ {
10
+ /**
11
+ * @param bool $isNetworkDeactivating
12
+ * @return void
13
+ */
14
+ public function deactivate($isNetworkDeactivating)
15
+ {
16
+ if (!$isNetworkDeactivating) {
17
+ $this->dropForeignConstraints();
18
+ delete_option(glsr()->prefix.'activated');
19
+ return;
20
+ }
21
+ foreach ($this->sites() as $siteId) {
22
+ switch_to_blog($siteId);
23
+ $this->dropForeignConstraints();
24
+ delete_option(glsr()->prefix.'activated');
25
+ restore_current_blog();
26
+ }
27
+ }
28
+
29
+ /**
30
+ * @return void
31
+ */
32
+ public function dropForeignConstraints()
33
+ {
34
+ glsr(SqlSchema::class)->dropForeignConstraint('assigned_posts', 'assigned_posts_post_id');
35
+ glsr(SqlSchema::class)->dropForeignConstraint('assigned_terms', 'assigned_terms_term_id');
36
+ glsr(SqlSchema::class)->dropForeignConstraint('assigned_users', 'assigned_users_user_id');
37
+ glsr(SqlSchema::class)->dropForeignConstraint('ratings', 'assigned_posts_review_id');
38
+ }
39
+
40
+ /**
41
+ * @param bool $dropAll
42
+ * @return void
43
+ */
44
+ public function dropTables($dropAll = true)
45
+ {
46
+ $tables = $this->tables();
47
+ if (is_multisite() && $dropAll) {
48
+ foreach ($this->sites() as $siteId) {
49
+ switch_to_blog($siteId);
50
+ $tables = array_unique(array_merge($tables, $this->tables()));
51
+ delete_option('glsr_db_version');
52
+ restore_current_blog();
53
+ }
54
+ }
55
+ foreach ($tables as $table) {
56
+ glsr(Database::class)->dbQuery(
57
+ glsr(Query::class)->sql("DROP TABLE IF EXISTS {$table}")
58
+ );
59
+ }
60
+ delete_option('glsr_db_version');
61
+ }
62
+
63
+ /**
64
+ * @return void
65
+ */
66
+ public function run()
67
+ {
68
+ require_once ABSPATH.'/wp-admin/includes/plugin.php';
69
+ if (is_plugin_active_for_network(plugin_basename(glsr()->file))) {
70
+ foreach ($this->sites() as $siteId) {
71
+ $this->runOnSite($siteId);
72
+ }
73
+ return;
74
+ }
75
+ $this->install();
76
+ }
77
+
78
+ /**
79
+ * @param int $siteId
80
+ * @return void
81
+ */
82
+ public function runOnSite($siteId)
83
+ {
84
+ switch_to_blog($siteId);
85
+ $this->install();
86
+ restore_current_blog();
87
+ }
88
+
89
+ /**
90
+ * @return void
91
+ */
92
+ protected function createRoleCapabilities()
93
+ {
94
+ glsr(Role::class)->resetAll();
95
+ }
96
+
97
+ /**
98
+ * @return void
99
+ */
100
+ protected function createTables()
101
+ {
102
+ glsr(SqlSchema::class)->createTables();
103
+ glsr(SqlSchema::class)->addForeignConstraints();
104
+ }
105
+
106
+ /**
107
+ * @return void
108
+ */
109
+ protected function deleteInvalidAssignments()
110
+ {
111
+ glsr(Database::class)->deleteInvalidPostAssignments();
112
+ glsr(Database::class)->deleteInvalidTermAssignments();
113
+ glsr(Database::class)->deleteInvalidUserAssignments();
114
+ }
115
+
116
+ /**
117
+ * @return void
118
+ */
119
+ protected function install()
120
+ {
121
+ $this->createRoleCapabilities();
122
+ $this->createTables();
123
+ $this->deleteInvalidAssignments();
124
+ }
125
+
126
+ /**
127
+ * @return array
128
+ */
129
+ protected function sites()
130
+ {
131
+ return get_sites([
132
+ 'fields' => 'ids',
133
+ 'network_id' => get_current_network_id(),
134
+ ]);
135
+ }
136
+
137
+ /**
138
+ * @return array
139
+ */
140
+ protected function tables()
141
+ {
142
+ return [
143
+ glsr(SqlSchema::class)->table('assigned_posts'),
144
+ glsr(SqlSchema::class)->table('assigned_terms'),
145
+ glsr(SqlSchema::class)->table('assigned_users'),
146
+ glsr(SqlSchema::class)->table('ratings'),
147
+ ];
148
+ }
149
+ }
plugin/Modules/Avatar.php CHANGED
@@ -50,7 +50,7 @@ class Avatar
50
  'style' => sprintf('width:%1$spx; height:%1$spx;', $size),
51
  'width' => $size * 2,
52
  ];
53
- if (is_admin()) {
54
  $attributes['data-fallback'] = $this->fallback($size);
55
  }
56
  return glsr(Builder::class)->img($attributes);
@@ -78,7 +78,7 @@ class Avatar
78
  if ($size = Cast::toInt($size)) {
79
  return $size;
80
  }
81
- $size = glsr_get_option('settings.reviews.avatars_size', static::FALLBACK_SIZE, 'int');
82
  return Helper::ifEmpty($size, static::FALLBACK_SIZE, $strict = true);
83
  }
84
  }
50
  'style' => sprintf('width:%1$spx; height:%1$spx;', $size),
51
  'width' => $size * 2,
52
  ];
53
+ if (glsr()->isAdmin()) {
54
  $attributes['data-fallback'] = $this->fallback($size);
55
  }
56
  return glsr(Builder::class)->img($attributes);
78
  if ($size = Cast::toInt($size)) {
79
  return $size;
80
  }
81
+ $size = glsr_get_option('reviews.avatars_size', static::FALLBACK_SIZE, 'int');
82
  return Helper::ifEmpty($size, static::FALLBACK_SIZE, $strict = true);
83
  }
84
  }
plugin/Modules/Console.php CHANGED
@@ -297,6 +297,7 @@ class Console
297
  */
298
  protected function setLogFile()
299
  {
 
300
  $uploads = wp_upload_dir();
301
  $base = trailingslashit($uploads['basedir'].'/'.glsr()->id);
302
  $this->file = $base.'logs/'.sanitize_file_name('console-'.wp_hash(glsr()->id).'.log');
297
  */
298
  protected function setLogFile()
299
  {
300
+ require_once ABSPATH.WPINC.'/pluggable.php';
301
  $uploads = wp_upload_dir();
302
  $base = trailingslashit($uploads['basedir'].'/'.glsr()->id);
303
  $this->file = $base.'logs/'.sanitize_file_name('console-'.wp_hash(glsr()->id).'.log');
plugin/Modules/Honeypot.php CHANGED
@@ -34,6 +34,7 @@ class Honeypot
34
  */
35
  public function hash($formId)
36
  {
 
37
  return substr(wp_hash($formId, 'nonce'), -12, 8);
38
  }
39
 
34
  */
35
  public function hash($formId)
36
  {
37
+ require_once ABSPATH.WPINC.'/pluggable.php';
38
  return substr(wp_hash($formId, 'nonce'), -12, 8);
39
  }
40
 
plugin/Modules/Html/ReviewsHtml.php CHANGED
@@ -4,7 +4,6 @@ namespace GeminiLabs\SiteReviews\Modules\Html;
4
 
5
  use GeminiLabs\SiteReviews\Database\OptionManager;
6
  use GeminiLabs\SiteReviews\Helper;
7
- use GeminiLabs\SiteReviews\Helpers\Url;
8
  use GeminiLabs\SiteReviews\Modules\Style;
9
  use GeminiLabs\SiteReviews\Reviews;
10
 
@@ -65,7 +64,7 @@ class ReviewsHtml extends \ArrayObject
65
  {
66
  $html = glsr(Partial::class)->build('pagination', [
67
  'add_args' => $this->args->pageUrlParameters,
68
- 'baseUrl' => Url::path($this->args->pageUrl),
69
  'current' => $this->args->page,
70
  'total' => $this->max_num_pages,
71
  ]);
4
 
5
  use GeminiLabs\SiteReviews\Database\OptionManager;
6
  use GeminiLabs\SiteReviews\Helper;
 
7
  use GeminiLabs\SiteReviews\Modules\Style;
8
  use GeminiLabs\SiteReviews\Reviews;
9
 
64
  {
65
  $html = glsr(Partial::class)->build('pagination', [
66
  'add_args' => $this->args->pageUrlParameters,
67
+ 'baseUrl' => $this->args->pageUrl,
68
  'current' => $this->args->page,
69
  'total' => $this->max_num_pages,
70
  ]);
plugin/Modules/Html/Settings.php CHANGED
@@ -117,6 +117,11 @@ class Settings
117
  protected function getTemplateDataForLicenses($id)
118
  {
119
  $fields = $this->getSettingFields($this->normalizeSettingPath($id));
 
 
 
 
 
120
  ksort($fields);
121
  return [
122
  'context' => [
117
  protected function getTemplateDataForLicenses($id)
118
  {
119
  $fields = $this->getSettingFields($this->normalizeSettingPath($id));
120
+ foreach ($fields as $key => &$field) {
121
+ if (!empty(glsr(OptionManager::class)->get($key))) {
122
+ $field['type'] = 'password'; // mask saved licenses
123
+ }
124
+ }
125
  ksort($fields);
126
  return [
127
  'context' => [
plugin/Modules/Migrations/Migrate_5_0_0/MigrateReviews.php CHANGED
@@ -6,6 +6,7 @@ use GeminiLabs\SiteReviews\Database;
6
  use GeminiLabs\SiteReviews\Database\Query;
7
  use GeminiLabs\SiteReviews\Defaults\RatingDefaults;
8
  use GeminiLabs\SiteReviews\Helpers\Arr;
 
9
 
10
  class MigrateReviews
11
  {
@@ -36,7 +37,7 @@ class MigrateReviews
36
  */
37
  protected function createDatabaseTable()
38
  {
39
- glsr(Database::class)->createTables();
40
  }
41
 
42
  /**
@@ -145,11 +146,12 @@ class MigrateReviews
145
  {
146
  glsr(Database::class)->beginTransaction('ratings');
147
  $offset = 0;
 
148
  while (true) {
149
  $sql = glsr(Query::class)->sql($this->db->prepare("
150
  SELECT p.ID, m.meta_key AS mk, m.meta_value AS mv, CAST(IF(p.post_status = 'publish', 1, 0) AS UNSIGNED) AS is_approved
151
  FROM {$this->db->posts} AS p
152
- INNER JOIN {$this->db->postmeta} AS m ON p.ID = m.post_id
153
  WHERE p.ID IN (
154
  SELECT * FROM (
155
  SELECT ID
@@ -159,7 +161,11 @@ class MigrateReviews
159
  LIMIT %d, %d
160
  ) AS post_ids
161
  )
162
- AND m.meta_key IN ('_author','_avatar','_email','_ip_address','_pinned','_rating','_review_type','_url')
 
 
 
 
163
  ", glsr()->post_type, $offset, $this->limit), 'migrate-ratings');
164
  $results = glsr(Database::class)->dbGetResults($sql, OBJECT);
165
  if (empty($results)) {
6
  use GeminiLabs\SiteReviews\Database\Query;
7
  use GeminiLabs\SiteReviews\Defaults\RatingDefaults;
8
  use GeminiLabs\SiteReviews\Helpers\Arr;
9
+ use GeminiLabs\SiteReviews\Install;
10
 
11
  class MigrateReviews
12
  {
37
  */
38
  protected function createDatabaseTable()
39
  {
40
+ glsr(Install::class)->run();
41
  }
42
 
43
  /**
146
  {
147
  glsr(Database::class)->beginTransaction('ratings');
148
  $offset = 0;
149
+ $table = glsr(Query::class)->table('ratings');
150
  while (true) {
151
  $sql = glsr(Query::class)->sql($this->db->prepare("
152
  SELECT p.ID, m.meta_key AS mk, m.meta_value AS mv, CAST(IF(p.post_status = 'publish', 1, 0) AS UNSIGNED) AS is_approved
153
  FROM {$this->db->posts} AS p
154
+ LEFT JOIN {$this->db->postmeta} AS m ON p.ID = m.post_id
155
  WHERE p.ID IN (
156
  SELECT * FROM (
157
  SELECT ID
161
  LIMIT %d, %d
162
  ) AS post_ids
163
  )
164
+ AND NOT EXISTS (
165
+ SELECT r.review_id
166
+ FROM {$table} AS r
167
+ WHERE r.review_id = p.ID
168
+ )
169
  ", glsr()->post_type, $offset, $this->limit), 'migrate-ratings');
170
  $results = glsr(Database::class)->dbGetResults($sql, OBJECT);
171
  if (empty($results)) {
plugin/Modules/Migrations/Migrate_5_2_0.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GeminiLabs\SiteReviews\Modules\Migrations;
4
+
5
+ class Migrate_5_2_0
6
+ {
7
+ /**
8
+ * @return void
9
+ */
10
+ public function run()
11
+ {
12
+ wp_clear_scheduled_hook('site-reviews/schedule/session/purge');
13
+ }
14
+ }
plugin/Modules/Notification.php CHANGED
@@ -68,7 +68,10 @@ class Notification
68
  'subject' => $args['title'],
69
  'template' => 'email-notification',
70
  'template-tags' => [
 
 
71
  'review_author' => $this->review->author ?: __('Anonymous', 'site-reviews'),
 
72
  'review_content' => $this->review->content,
73
  'review_email' => $this->review->email,
74
  'review_ip' => $this->review->ip_address,
@@ -91,6 +94,36 @@ class Notification
91
  ]);
92
  }
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  /**
95
  * @return array
96
  */
68
  'subject' => $args['title'],
69
  'template' => 'email-notification',
70
  'template-tags' => [
71
+ 'review_assigned_posts' => $this->getAssignedPostTitles(),
72
+ 'review_assigned_users' => $this->getAssignedUserTitles(),
73
  'review_author' => $this->review->author ?: __('Anonymous', 'site-reviews'),
74
+ 'review_categories' => $this->getAssignedCategories(),
75
  'review_content' => $this->review->content,
76
  'review_email' => $this->review->email,
77
  'review_ip' => $this->review->ip_address,
94
  ]);
95
  }
96
 
97
+ /**
98
+ * @return string
99
+ */
100
+ protected function getAssignedCategories()
101
+ {
102
+ $terms = $this->review->assignedTerms();
103
+ $termNames = array_filter(wp_list_pluck($terms, 'name'));
104
+ return Str::naturalJoin($termNames);
105
+ }
106
+
107
+ /**
108
+ * @return string
109
+ */
110
+ protected function getAssignedPostTitles()
111
+ {
112
+ $posts = $this->review->assignedPosts();
113
+ $postTitles = array_filter(wp_list_pluck($posts, 'post_title'));
114
+ return Str::naturalJoin($postTitles);
115
+ }
116
+
117
+ /**
118
+ * @return string
119
+ */
120
+ protected function getAssignedUserTitles()
121
+ {
122
+ $users = $this->review->assignedUsers();
123
+ $userNames = array_filter(wp_list_pluck($users, 'display_name'));
124
+ return Str::naturalJoin($userNames);
125
+ }
126
+
127
  /**
128
  * @return array
129
  */
plugin/Modules/Sanitizer.php CHANGED
@@ -90,16 +90,17 @@ class Sanitizer
90
  }
91
 
92
  /**
 
93
  * @param mixed $value
94
  * @return string
95
  */
96
  protected function sanitizeDate($value)
97
  {
98
  $date = strtotime(Cast::toString($value));
99
- if (false === $date) {
100
- $date = time();
101
  }
102
- return get_date_from_gmt(gmdate('Y-m-d H:i:s', $date));
103
  }
104
 
105
  /**
@@ -117,6 +118,7 @@ class Sanitizer
117
  */
118
  protected function sanitizeId($value)
119
  {
 
120
  $value = $this->sanitizeSlug($value);
121
  if (empty($value)) {
122
  $value = glsr()->prefix.substr(wp_hash(serialize($this->values), 'nonce'), -12, 8);
@@ -182,4 +184,32 @@ class Sanitizer
182
  $url = wp_http_validate_url($url);
183
  return esc_url_raw(Cast::toString($url));
184
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  }
90
  }
91
 
92
  /**
93
+ * If date is invalid then return an empty string.
94
  * @param mixed $value
95
  * @return string
96
  */
97
  protected function sanitizeDate($value)
98
  {
99
  $date = strtotime(Cast::toString($value));
100
+ if (false !== $date) {
101
+ return wp_date('Y-m-d H:i:s', $date);
102
  }
103
+ return '';
104
  }
105
 
106
  /**
118
  */
119
  protected function sanitizeId($value)
120
  {
121
+ require_once ABSPATH.WPINC.'/pluggable.php';
122
  $value = $this->sanitizeSlug($value);
123
  if (empty($value)) {
124
  $value = glsr()->prefix.substr(wp_hash(serialize($this->values), 'nonce'), -12, 8);
184
  $url = wp_http_validate_url($url);
185
  return esc_url_raw(Cast::toString($url));
186
  }
187
+
188
+ /**
189
+ * @param mixed $value
190
+ * @return string
191
+ */
192
+ protected function sanitizeUserEmail($value)
193
+ {
194
+ $user = wp_get_current_user();
195
+ $value = Cast::toString($value);
196
+ if ($user->exists()) {
197
+ return Helper::ifEmpty($value, $user->user_email);
198
+ }
199
+ return sanitize_email($value);
200
+ }
201
+
202
+ /**
203
+ * @param mixed $value
204
+ * @return string
205
+ */
206
+ protected function sanitizeUserName($value)
207
+ {
208
+ $user = wp_get_current_user();
209
+ $value = Cast::toString($value);
210
+ if ($user->exists()) {
211
+ return Helper::ifEmpty($value, $user->display_name);
212
+ }
213
+ return sanitize_text_field($value);
214
+ }
215
  }
plugin/Modules/Schema.php CHANGED
@@ -123,10 +123,13 @@ class Schema
123
  public function render()
124
  {
125
  if ($schemas = glsr()->retrieve('schemas', [])) {
126
- printf('<script type="application/ld+json">%s</script>', json_encode(
127
- glsr()->filterArray('schema/all', $schemas),
128
- JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
129
- ));
 
 
 
130
  }
131
  }
132
 
123
  public function render()
124
  {
125
  if ($schemas = glsr()->retrieve('schemas', [])) {
126
+ printf('<script type="application/ld+json" class="%s-schema">%s</script>',
127
+ glsr()->id,
128
+ json_encode(
129
+ glsr()->filterArray('schema/all', $schemas),
130
+ JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
131
+ )
132
+ );
133
  }
134
  }
135
 
plugin/Modules/Style.php CHANGED
@@ -168,6 +168,6 @@ class Style
168
  protected function isPublicInstance(Builder $instance)
169
  {
170
  $args = glsr()->args($instance->args)->merge(['is_raw' => false]);
171
- return !is_admin() && !Cast::toBool($args->is_raw);
172
  }
173
  }
168
  protected function isPublicInstance(Builder $instance)
169
  {
170
  $args = glsr()->args($instance->args)->merge(['is_raw' => false]);
171
+ return !glsr()->isAdmin() && !Cast::toBool($args->is_raw);
172
  }
173
  }
plugin/Modules/System.php DELETED
@@ -1,382 +0,0 @@
1
- <?php
2
-
3
- namespace GeminiLabs\SiteReviews\Modules;
4
-
5
- use GeminiLabs\Sinergi\BrowserDetector\Browser;
6
- use GeminiLabs\SiteReviews\Database\Cache;
7
- use GeminiLabs\SiteReviews\Database\OptionManager;
8
- use GeminiLabs\SiteReviews\Database\Query;
9
- use GeminiLabs\SiteReviews\Database\RatingManager;
10
- use GeminiLabs\SiteReviews\Helper;
11
- use GeminiLabs\SiteReviews\Helpers\Arr;
12
- use GeminiLabs\SiteReviews\Helpers\Str;
13
-
14
- class System
15
- {
16
- const PAD = 40;
17
-
18
- /**
19
- * @return string
20
- */
21
- public function __toString()
22
- {
23
- return $this->get();
24
- }
25
-
26
- /**
27
- * @return string
28
- */
29
- public function get()
30
- {
31
- $details = [
32
- 'plugin' => 'Plugin Details',
33
- 'addon' => 'Addon Details',
34
- 'browser' => 'Browser Details',
35
- 'server' => 'Server Details',
36
- 'php' => 'PHP Configuration',
37
- 'wordpress' => 'WordPress Configuration',
38
- 'mu-plugin' => 'Must-Use Plugins',
39
- 'multisite-plugin' => 'Network Active Plugins',
40
- 'active-plugin' => 'Active Plugins',
41
- 'inactive-plugin' => 'Inactive Plugins',
42
- 'setting' => 'Plugin Settings',
43
- 'reviews' => 'Review Counts',
44
- ];
45
- $systemInfo = array_reduce(array_keys($details), function ($carry, $key) use ($details) {
46
- $methodName = Helper::buildMethodName('get-'.$key.'-details');
47
- if (method_exists($this, $methodName) && $systemDetails = $this->$methodName()) {
48
- return $carry.$this->implode(
49
- strtoupper($details[$key]),
50
- glsr()->filterArray('system/'.$key, $systemDetails)
51
- );
52
- }
53
- return $carry;
54
- });
55
- return trim($systemInfo);
56
- }
57
-
58
- /**
59
- * @return array
60
- */
61
- public function getActivePluginDetails()
62
- {
63
- $plugins = get_plugins();
64
- $activePlugins = glsr(OptionManager::class)->getWP('active_plugins', [], 'array');
65
- $inactive = array_diff_key($plugins, array_flip($activePlugins));
66
- return $this->normalizePluginList(array_diff_key($plugins, $inactive));
67
- }
68
-
69
- /**
70
- * @return array
71
- */
72
- public function getAddonDetails()
73
- {
74
- $details = glsr()->filterArray('addon/system-info', []);
75
- ksort($details);
76
- return $details;
77
- }
78
-
79
- /**
80
- * @return array
81
- */
82
- public function getBrowserDetails()
83
- {
84
- $browser = new Browser();
85
- $name = esc_attr($browser->getName());
86
- $userAgent = esc_attr($browser->getUserAgent()->getUserAgentString());
87
- $version = esc_attr($browser->getVersion());
88
- return [
89
- 'Browser Name' => sprintf('%s %s', $name, $version),
90
- 'Browser UA' => $userAgent,
91
- ];
92
- }
93
-
94
- /**
95
- * @return array
96
- */
97
- public function getInactivePluginDetails()
98
- {
99
- $activePlugins = glsr(OptionManager::class)->getWP('active_plugins', [], 'array');
100
- $inactivePlugins = $this->normalizePluginList(
101
- array_diff_key(get_plugins(), array_flip($activePlugins))
102
- );
103
- $multisitePlugins = $this->getMultisitePluginDetails();
104
- return Helper::ifTrue(empty($multisitePlugins),
105
- $inactivePlugins,
106
- array_diff($inactivePlugins, $multisitePlugins)
107
- );
108
- }
109
-
110
- /**
111
- * @return array
112
- */
113
- public function getMuPluginDetails()
114
- {
115
- $plugins = get_mu_plugins();
116
- return Helper::ifTrue(empty($plugins), [], function () use ($plugins) {
117
- return $this->normalizePluginList($plugins);
118
- });
119
- }
120
-
121
- /**
122
- * @return array
123
- */
124
- public function getMultisitePluginDetails()
125
- {
126
- $activePlugins = (array) get_site_option('active_sitewide_plugins', []);
127
- if (!is_multisite() || empty($activePlugins)) {
128
- return [];
129
- }
130
- return $this->normalizePluginList(array_intersect_key(get_plugins(), $activePlugins));
131
- }
132
-
133
- /**
134
- * @return array
135
- */
136
- public function getPhpDetails()
137
- {
138
- $displayErrors = $this->getIni('display_errors', null);
139
- return [
140
- 'cURL' => var_export(function_exists('curl_init'), true),
141
- 'Default Charset' => $this->getIni('default_charset'),
142
- 'Display Errors' => Helper::ifTrue(empty($displayErrors), 'N/A', 'On ('.$displayErrors.')'),
143
- 'fsockopen' => var_export(function_exists('fsockopen'), true),
144
- 'Intl' => Helper::ifTrue(extension_loaded('intl'), phpversion('intl'), 'false'),
145
- 'IPv6' => var_export(defined('AF_INET6'), true),
146
- 'Max Execution Time' => $this->getIni('max_execution_time'),
147
- 'Max Input Nesting Level' => $this->getIni('max_input_nesting_level'),
148
- 'Max Input Vars' => $this->getIni('max_input_vars'),
149
- 'Memory Limit' => $this->getIni('memory_limit'),
150
- 'Post Max Size' => $this->getIni('post_max_size'),
151
- 'Sendmail Path' => $this->getIni('sendmail_path'),
152
- 'Session Cookie Path' => esc_html($this->getIni('session.cookie_path')),
153
- 'Session Name' => esc_html($this->getIni('session.name')),
154
- 'Session Save Path' => esc_html($this->getIni('session.save_path')),
155
- 'Session Use Cookies' => var_export(wp_validate_boolean($this->getIni('session.use_cookies', false)), true),
156
- 'Session Use Only Cookies' => var_export(wp_validate_boolean($this->getIni('session.use_only_cookies', false)), true),
157
- 'Upload Max Filesize' => $this->getIni('upload_max_filesize'),
158
- ];
159
- }
160
-
161
- /**
162
- * @return array
163
- */
164
- public function getReviewsDetails()
165
- {
166
- $counts = glsr(Query::class)->ratings();
167
- array_walk($counts, function (&$ratings) use ($counts) {
168
- if (is_array($ratings)) {
169
- $ratings = array_sum($ratings).' ('.implode(', ', $ratings).')';
170
- return;
171
- }
172
- glsr_log()
173
- ->error('$ratings is not an array, possibly due to incorrectly imported reviews.')
174
- ->debug($ratings)
175
- ->debug($counts);
176
- });
177
- ksort($counts);
178
- return $counts;
179
- }
180
-
181
- /**
182
- * @return array
183
- */
184
- public function getServerDetails()
185
- {
186
- global $wpdb;
187
- return [
188
- 'Host Name' => $this->getHostName(),
189
- 'MySQL Version' => $wpdb->db_version(),
190
- 'PHP Version' => PHP_VERSION,
191
- 'Server Software' => filter_input(INPUT_SERVER, 'SERVER_SOFTWARE'),
192
- ];
193
- }
194
-
195
- /**
196
- * @return array
197
- */
198
- public function getSettingDetails()
199
- {
200
- $settings = glsr(OptionManager::class)->get('settings', []);
201
- $settings = Arr::flatten($settings, true);
202
- $settings = $this->purgeSensitiveData($settings);
203
- ksort($settings);
204
- $details = [];
205
- foreach ($settings as $key => $value) {
206
- if (Str::startsWith('strings', $key) && Str::endsWith('id', $key)) {
207
- continue;
208
- }
209
- $value = htmlspecialchars(trim(preg_replace('/\s\s+/u', '\\n', $value)), ENT_QUOTES, 'UTF-8');
210
- $details[$key] = $value;
211
- }
212
- return $details;
213
- }
214
-
215
- /**
216
- * @return array
217
- */
218
- public function getPluginDetails()
219
- {
220
- return [
221
- 'Console level' => glsr(Console::class)->humanLevel(),
222
- 'Console size' => glsr(Console::class)->humanSize(),
223
- 'Last Migration Run' => glsr(Date::class)->localized(glsr(OptionManager::class)->get('last_migration_run'), 'unknown'),
224
- 'Version (current)' => glsr()->version,
225
- 'Version (previous)' => glsr(OptionManager::class)->get('version_upgraded_from'),
226
- ];
227
- }
228
-
229
- /**
230
- * @return array
231
- */
232
- public function getWordpressDetails()
233
- {
234
- global $wpdb;
235
- $theme = wp_get_theme();
236
- return [
237
- 'Active Theme' => sprintf('%s v%s', (string) $theme->name, (string) $theme->version),
238
- 'Email Domain' => substr(strrchr(glsr(OptionManager::class)->getWP('admin_email'), '@'), 1),
239
- 'Home URL' => home_url(),
240
- 'Language' => get_locale(),
241
- 'Memory Limit' => WP_MEMORY_LIMIT,
242
- 'Multisite' => var_export(is_multisite(), true),
243
- 'Page For Posts ID' => glsr(OptionManager::class)->getWP('page_for_posts'),
244
- 'Page On Front ID' => glsr(OptionManager::class)->getWP('page_on_front'),
245
- 'Permalink Structure' => glsr(OptionManager::class)->getWP('permalink_structure', 'default'),
246
- 'Post Stati' => implode(', ', get_post_stati()),
247
- 'Remote Post' => glsr(Cache::class)->getRemotePostTest(),
248
- 'Show On Front' => glsr(OptionManager::class)->getWP('show_on_front'),
249
- 'Site URL' => site_url(),
250
- 'Timezone' => glsr(OptionManager::class)->getWP('timezone_string', $this->getIni('date.timezone').' (PHP)'),
251
- 'Version' => get_bloginfo('version'),
252
- 'WP Debug' => var_export(defined('WP_DEBUG'), true),
253
- 'WP Max Upload Size' => size_format(wp_max_upload_size()),
254
- 'WP Memory Limit' => WP_MEMORY_LIMIT,
255
- ];
256
- }
257
-
258
- /**
259
- * @return string
260
- */
261
- protected function detectWebhostProvider()
262
- {
263
- $checks = [
264
- '.accountservergroup.com' => 'Site5',
265
- '.gridserver.com' => 'MediaTemple Grid',
266
- '.inmotionhosting.com' => 'InMotion Hosting',
267
- '.ovh.net' => 'OVH',
268
- '.pair.com' => 'pair Networks',
269
- '.stabletransit.com' => 'Rackspace Cloud',
270
- '.stratoserver.net' => 'STRATO',
271
- '.sysfix.eu' => 'SysFix.eu Power Hosting',
272
- 'bluehost.com' => 'Bluehost',
273
- 'DH_USER' => 'DreamHost',
274
- 'Flywheel' => 'Flywheel',
275
- 'ipagemysql.com' => 'iPage',
276
- 'ipowermysql.com' => 'IPower',
277
- 'localhost:/tmp/mysql5.sock' => 'ICDSoft',
278
- 'mysqlv5' => 'NetworkSolutions',
279
- 'PAGELYBIN' => 'Pagely',
280
- 'secureserver.net' => 'GoDaddy',
281
- 'WPE_APIKEY' => 'WP Engine',
282
- ];
283
- foreach ($checks as $key => $value) {
284
- if (!$this->isWebhostCheckValid($key)) {
285
- continue;
286
- }
287
- return $value;
288
- }
289
- return implode(',', array_filter([DB_HOST, filter_input(INPUT_SERVER, 'SERVER_NAME')]));
290
- }
291
-
292
- /**
293
- * @return string
294
- */
295
- protected function getHostName()
296
- {
297
- return sprintf('%s (%s)', $this->detectWebhostProvider(), Helper::getIpAddress());
298
- }
299
-
300
- protected function getIni($name, $disabledValue = 'ini_get() is disabled.')
301
- {
302
- return Helper::ifTrue(!function_exists('ini_get'), $disabledValue, function () use ($name) {
303
- return ini_get($name);
304
- });
305
- }
306
-
307
- /**
308
- * @return array
309
- */
310
- protected function getWordpressPlugins()
311
- {
312
- $plugins = get_plugins();
313
- $activePlugins = glsr(OptionManager::class)->getWP('active_plugins', [], 'array');
314
- $inactive = $this->normalizePluginList(array_diff_key($plugins, array_flip($activePlugins)));
315
- $active = $this->normalizePluginList(array_diff_key($plugins, $inactive));
316
- return $active + $inactive;
317
- }
318
-
319
- /**
320
- * @param string $title
321
- * @return string
322
- */
323
- protected function implode($title, array $details)
324
- {
325
- $strings = ['['.$title.']'];
326
- $padding = max(array_map('strlen', array_keys($details)));
327
- $padding = max([$padding, static::PAD]);
328
- foreach ($details as $key => $value) {
329
- $strings[] = is_string($key)
330
- ? sprintf('%s : %s', str_pad($key, $padding, '.'), $value)
331
- : ' - '.$value;
332
- }
333
- return implode(PHP_EOL, $strings).PHP_EOL.PHP_EOL;
334
- }
335
-
336
- /**
337
- * @param string $key
338
- * @return bool
339
- */
340
- protected function isWebhostCheckValid($key)
341
- {
342
- return defined($key)
343
- || filter_input(INPUT_SERVER, $key)
344
- || Str::contains($key, filter_input(INPUT_SERVER, 'SERVER_NAME'))
345
- || Str::contains($key, DB_HOST)
346
- || Str::contains($key, php_uname());
347
- }
348
-
349
- /**
350
- * @return array
351
- */
352
- protected function normalizePluginList(array $plugins)
353
- {
354
- $plugins = array_map(function ($plugin) {
355
- return sprintf('%s v%s', Arr::get($plugin, 'Name'), Arr::get($plugin, 'Version'));
356
- }, $plugins);
357
- natcasesort($plugins);
358
- return array_flip($plugins);
359
- }
360
-
361
- /**
362
- * @return array
363
- */
364
- protected function purgeSensitiveData(array $settings)
365
- {
366
- $keys = glsr()->filterArray('addon/system-info/purge', [
367
- 'licenses.',
368
- 'submissions.recaptcha.key',
369
- 'submissions.recaptcha.secret',
370
- ]);
371
- array_walk($settings, function (&$value, $setting) use ($keys) {
372
- foreach ($keys as $key) {
373
- if (!Str::startsWith($key, $setting) || empty($value)) {
374
- continue;
375
- }
376
- $value = str_repeat('•', 13);
377
- return;
378
- }
379
- });
380
- return $settings;
381
- }
382
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
plugin/Modules/SystemInfo.php ADDED
@@ -0,0 +1,458 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GeminiLabs\SiteReviews\Modules;
4
+
5
+ use GeminiLabs\Sinergi\BrowserDetector\Browser;
6
+ use GeminiLabs\SiteReviews\Database\Cache;
7
+ use GeminiLabs\SiteReviews\Database\OptionManager;
8
+ use GeminiLabs\SiteReviews\Database\Query;
9
+ use GeminiLabs\SiteReviews\Database\SqlSchema;
10
+ use GeminiLabs\SiteReviews\Helper;
11
+ use GeminiLabs\SiteReviews\Helpers\Arr;
12
+ use GeminiLabs\SiteReviews\Helpers\Cast;
13
+ use GeminiLabs\SiteReviews\Helpers\Str;
14
+ use WP_Debug_Data;
15
+
16
+ class SystemInfo
17
+ {
18
+ const PAD = 40;
19
+
20
+ /**
21
+ * @return string
22
+ */
23
+ public function __toString()
24
+ {
25
+ return $this->get();
26
+ }
27
+
28
+ /**
29
+ * @return string
30
+ */
31
+ public function get()
32
+ {
33
+ $data = $this->data();
34
+ $details = [
35
+ 'plugin' => $this->getPluginDetails(),
36
+ 'addon' => $this->getAddonDetails(),
37
+ 'reviews' => $this->getReviewCounts(),
38
+ 'setting' => $this->getPluginSettings(),
39
+ 'browser' => $this->getBrowserDetails(),
40
+ 'database' => $this->getDatabaseDetails($data),
41
+ 'server' => $this->getServerDetails($data),
42
+ 'wordpress' => $this->getWordpressDetails($data),
43
+ 'mu-plugins' => $this->getMustUsePluginDetails(),
44
+ 'network-plugins' => $this->getNetworkActivatedPluginDetails(),
45
+ 'activated-plugins' => $this->getActivePluginDetails(),
46
+ 'inactive-plugins' => $this->getInactivePluginDetails(),
47
+ ];
48
+ $systemInfo = array_reduce(array_keys($details), function ($carry, $key) use ($details) {
49
+ if (empty(Arr::get($details[$key], 'values'))) {
50
+ return $carry;
51
+ }
52
+ $hook = 'system/'.Str::dashCase($key);
53
+ $title = strtoupper(Arr::get($details[$key], 'title'));
54
+ $values = glsr()->filterArray($hook, Arr::get($details[$key], 'values'));
55
+ return $carry.$this->implode($title, $values);
56
+ });
57
+ return trim($systemInfo);
58
+ }
59
+
60
+ /**
61
+ * @return array
62
+ */
63
+ public function getActivePluginDetails()
64
+ {
65
+ $plugins = get_plugins();
66
+ $active = glsr(OptionManager::class)->getWP('active_plugins', [], 'array');
67
+ $inactive = array_diff_key($plugins, array_flip($active));
68
+ $activePlugins = $this->normalizePluginList(array_diff_key($plugins, $inactive));
69
+ return [
70
+ 'title' => 'Activated Plugins',
71
+ 'values' => $activePlugins,
72
+ ];
73
+ }
74
+
75
+ /**
76
+ * @return array
77
+ */
78
+ public function getAddonDetails()
79
+ {
80
+ $details = glsr()->filterArray('addon/system-info', []);
81
+ ksort($details);
82
+ return [
83
+ 'title' => 'Addon Details',
84
+ 'values' => $details,
85
+ ];
86
+ }
87
+
88
+ /**
89
+ * @return array
90
+ */
91
+ public function getBrowserDetails()
92
+ {
93
+ $browser = new Browser();
94
+ $name = esc_attr($browser->getName());
95
+ $userAgent = esc_attr($browser->getUserAgent()->getUserAgentString());
96
+ $version = esc_attr($browser->getVersion());
97
+ return [
98
+ 'title' => 'Browser Details',
99
+ 'values' => [
100
+ 'Browser Name' => sprintf('%s %s', $name, $version),
101
+ 'Browser UA' => $userAgent,
102
+ ],
103
+ ];
104
+ }
105
+
106
+ /**
107
+ * @param array $data
108
+ * @return array
109
+ */
110
+ public function getDatabaseDetails($data)
111
+ {
112
+ $database = Arr::get($data, 'wp-database');
113
+ return [
114
+ 'title' => 'Database Details',
115
+ 'values' => [
116
+ 'Charset' => Arr::get($database, 'database_charset'),
117
+ 'Collation' => Arr::get($database, 'database_collate'),
118
+ 'Extension' => Arr::get($database, 'extension'),
119
+ 'Table Engines' => implode(', ', glsr(SqlSchema::class)->tableEngines()),
120
+ 'Version (client)' => Arr::get($database, 'client_version'),
121
+ 'Version (server)' => Arr::get($database, 'server_version'),
122
+ ],
123
+ ];
124
+ }
125
+
126
+ /**
127
+ * @return array
128
+ */
129
+ public function getInactivePluginDetails()
130
+ {
131
+ $active = glsr(OptionManager::class)->getWP('active_plugins', [], 'array');
132
+ $inactive = $this->normalizePluginList(array_diff_key(get_plugins(), array_flip($active)));
133
+ $networkActivated = $this->getNetworkActivatedPluginDetails();
134
+ $networkActivated = Arr::consolidate(Arr::get($networkActivated, 'values'));
135
+ $inactivePlugins = Helper::ifTrue(empty($networkActivated), $inactive, array_diff($inactive, $networkActivated));
136
+ return [
137
+ 'title' => 'Inactive Plugins',
138
+ 'values' => $inactivePlugins,
139
+ ];
140
+ }
141
+
142
+ /**
143
+ * @return array
144
+ */
145
+ public function getMustUsePluginDetails()
146
+ {
147
+ $plugins = get_mu_plugins();
148
+ $muplugins = Helper::ifTrue(empty($plugins), [], function () use ($plugins) {
149
+ return $this->normalizePluginList($plugins);
150
+ });
151
+ return [
152
+ 'title' => 'Must-Use Plugins',
153
+ 'values' => $muplugins,
154
+ ];
155
+ }
156
+
157
+ /**
158
+ * @return array
159
+ */
160
+ public function getNetworkActivatedPluginDetails()
161
+ {
162
+ $plugins = Arr::consolidate(get_site_option('active_sitewide_plugins', []));
163
+ if (!is_multisite() || empty($plugins)) {
164
+ return [];
165
+ }
166
+ $networkPlugins = $this->normalizePluginList(array_intersect_key(get_plugins(), $plugins));
167
+ return [
168
+ 'title' => 'Network Activated Plugins',
169
+ 'values' => $networkPlugins,
170
+ ];
171
+ }
172
+
173
+ /**
174
+ * @return array
175
+ */
176
+ public function getPluginDetails()
177
+ {
178
+ require_once ABSPATH.'/wp-admin/includes/plugin.php';
179
+ return [
180
+ 'title' => 'Plugin Details',
181
+ 'values' => [
182
+ 'Console Level' => glsr(Console::class)->humanLevel(),
183
+ 'Console Size' => glsr(Console::class)->humanSize(),
184
+ 'Database Version' => glsr(OptionManager::class)->getWP(glsr()->prefix.'db_version'),
185
+ 'Last Migration Run' => glsr(Date::class)->localized(glsr(OptionManager::class)->get('last_migration_run'), 'unknown'),
186
+ 'Network Activated' => Helper::ifTrue(is_plugin_active_for_network(plugin_basename(glsr()->file)), 'Yes', 'No'),
187
+ 'Version' => sprintf('%s (%s)', glsr()->version, glsr(OptionManager::class)->get('version_upgraded_from')),
188
+ ],
189
+ ];
190
+ }
191
+
192
+ /**
193
+ * @return array
194
+ */
195
+ public function getPluginSettings()
196
+ {
197
+ $settings = glsr(OptionManager::class)->get('settings', []);
198
+ $settings = Arr::flatten($settings, true);
199
+ $settings = $this->purgeSensitiveData($settings);
200
+ ksort($settings);
201
+ $details = [];
202
+ foreach ($settings as $key => $value) {
203
+ if (Str::startsWith('strings', $key) && Str::endsWith('id', $key)) {
204
+ continue;
205
+ }
206
+ $value = htmlspecialchars(trim(preg_replace('/\s\s+/u', '\\n', $value)), ENT_QUOTES, 'UTF-8');
207
+ $details[$key] = $value;
208
+ }
209
+ return [
210
+ 'title' => 'Plugin Settings',
211
+ 'values' => $details,
212
+ ];
213
+ }
214
+
215
+ /**
216
+ * @return array
217
+ */
218
+ public function getReviewCounts()
219
+ {
220
+ $counts = glsr(Query::class)->ratings();
221
+ array_walk($counts, function (&$ratings) use ($counts) {
222
+ if (is_array($ratings)) {
223
+ $ratings = array_sum($ratings).' ('.implode(', ', $ratings).')';
224
+ return;
225
+ }
226
+ glsr_log()
227
+ ->error('$ratings is not an array, possibly due to incorrectly imported reviews.')
228
+ ->debug($ratings)
229
+ ->debug($counts);
230
+ });
231
+ ksort($counts);
232
+ return [
233
+ 'title' => 'Review Counts',
234
+ 'values' => wp_parse_args($counts, ['local' => 'No reviews']),
235
+ ];
236
+ }
237
+
238
+ /**
239
+ * @param array $data
240
+ * @return array
241
+ */
242
+ public function getServerDetails($data)
243
+ {
244
+ $media = Arr::get($data, 'wp-media');
245
+ $server = Arr::get($data, 'wp-server');
246
+ return [
247
+ 'title' => 'Server Details',
248
+ 'values' => [
249
+ 'cURL Version' => Arr::get($server, 'curl_version'),
250
+ 'Display Errors' => Helper::ifEmpty($this->getIni('display_errors'), 'No'),
251
+ 'File Uploads' => Arr::get($media, 'file_uploads'),
252
+ 'GD version' => Arr::get($media, 'gd_version'),
253
+ 'Ghostscript version' => Arr::get($media, 'ghostscript_version'),
254
+ 'Host Name' => $this->getHostName(),
255
+ 'ImageMagick version' => Arr::get($media, 'imagemagick_version'),
256
+ 'Intl' => Helper::ifEmpty(phpversion('intl'), 'No'),
257
+ 'IPv6' => var_export(defined('AF_INET6'), true),
258
+ 'Max Effective File Size' => Arr::get($media, 'max_effective_size'),
259
+ 'Max Execution Time' => Arr::get($server, 'time_limit'),
260
+ 'Max File Uploads' => Arr::get($media, 'max_file_uploads'),
261
+ 'Max Input Time' => Arr::get($server, 'max_input_time'),
262
+ 'Max Input Variables' => Arr::get($server, 'max_input_variables'),
263
+ 'Memory Limit' => Arr::get($server, 'memory_limit'),
264
+ 'Multibyte' => Helper::ifEmpty(phpversion('mbstring'), 'No'),
265
+ 'Permalinks Supported' => Arr::get($server, 'pretty_permalinks'),
266
+ 'PHP Version' => Arr::get($server, 'php_version'),
267
+ 'Post Max Size' => Arr::get($server, 'php_post_max_size'),
268
+ 'SAPI' => Arr::get($server, 'php_sapi'),
269
+ 'Sendmail' => $this->getIni('sendmail_path'),
270
+ 'Server Architecture' => Arr::get($server, 'server_architecture'),
271
+ 'Server Software' => Arr::get($server, 'httpd_software'),
272
+ 'SUHOSIN Installed' => Arr::get($server, 'suhosin'),
273
+ 'Upload Max Filesize' => Arr::get($server, 'upload_max_filesize'),
274
+ ],
275
+ ];
276
+ }
277
+
278
+ /**
279
+ * @param array $data
280
+ * @return array
281
+ */
282
+ public function getWordpressDetails($data)
283
+ {
284
+ $constants = Arr::get($data, 'wp-constants');
285
+ $wordpress = Arr::get($data, 'wp-core');
286
+ return [
287
+ 'title' => 'WordPress Configuration',
288
+ 'values' => [
289
+ 'Email Domain' => substr(strrchr(glsr(OptionManager::class)->getWP('admin_email'), '@'), 1),
290
+ 'Environment' => Arr::get($wordpress, 'environment_type'),
291
+ 'Hidden From Search Engines' => Arr::get($wordpress, 'blog_public'),
292
+ 'Home URL' => Arr::get($wordpress, 'home_url'),
293
+ 'HTTPS' => Arr::get($wordpress, 'https_status'),
294
+ 'Language (site)' => Arr::get($wordpress, 'site_language'),
295
+ 'Language (user)' => Arr::get($wordpress, 'user_language'),
296
+ 'Multisite' => Arr::get($wordpress, 'multisite'),
297
+ 'Page For Posts ID' => glsr(OptionManager::class)->getWP('page_for_posts'),
298
+ 'Page On Front ID' => glsr(OptionManager::class)->getWP('page_on_front'),
299
+ 'Permalink Structure' => Arr::get($wordpress, 'permalink'),
300
+ 'Post Stati' => implode(', ', get_post_stati()),
301
+ 'Remote Post' => glsr(Cache::class)->getRemotePostTest(),
302
+ 'SCRIPT_DEBUG' => Arr::get($constants, 'SCRIPT_DEBUG'),
303
+ 'Show On Front' => glsr(OptionManager::class)->getWP('show_on_front'),
304
+ 'Site URL' => Arr::get($wordpress, 'site_url'),
305
+ 'Theme (active)' => sprintf('%s v%s', Arr::get($data, 'wp-active-theme.name'), Arr::get($data, 'wp-active-theme.version')),
306
+ 'Theme (parent)' => Arr::get($data, 'wp-parent-theme.name', 'No'),
307
+ 'Timezone' => Arr::get($wordpress, 'timezone'),
308
+ 'User Count' => Arr::get($wordpress, 'user_count'),
309
+ 'Version' => Arr::get($wordpress, 'version'),
310
+ 'WP_CACHE' => Arr::get($constants, 'WP_CACHE'),
311
+ 'WP_DEBUG' => Arr::get($constants, 'WP_DEBUG'),
312
+ 'WP_DEBUG_DISPLAY' => Arr::get($constants, 'WP_DEBUG_DISPLAY'),
313
+ 'WP_DEBUG_LOG' => Arr::get($constants, 'WP_DEBUG_LOG'),
314
+ 'WP_MAX_MEMORY_LIMIT' => Arr::get($constants, 'WP_MAX_MEMORY_LIMIT'),
315
+ ],
316
+ ];
317
+ }
318
+
319
+ /**
320
+ * @return array
321
+ */
322
+ public function data()
323
+ {
324
+ $data = WP_Debug_Data::debug_data();
325
+ array_walk($data, function (&$section) {
326
+ $fields = Arr::consolidate(Arr::get($section, 'fields'));
327
+ array_walk($fields, function (&$values) {
328
+ $values = Arr::get($values, 'value');
329
+ });
330
+ $section = $fields;
331
+ });
332
+ return $data;
333
+ }
334
+
335
+ /**
336
+ * @return string
337
+ */
338
+ protected function getHostName()
339
+ {
340
+ return sprintf('%s (%s)', $this->detectWebhostProvider(), Helper::getIpAddress());
341
+ }
342
+
343
+ /**
344
+ * @param string $name
345
+ * @param string $disabledValue
346
+ * @return string
347
+ */
348
+ protected function getIni($name, $disabledValue = 'ini_get() is disabled.')
349
+ {
350
+ return Helper::ifTrue(!function_exists('ini_get'), $disabledValue, function () use ($name) {
351
+ return ini_get($name);
352
+ });
353
+ }
354
+
355
+ /**
356
+ * @param string $title
357
+ * @return string
358
+ */
359
+ protected function implode($title, array $details)
360
+ {
361
+ $strings = ['['.$title.']'];
362
+ $padding = max(array_map('strlen', array_keys($details)));
363
+ $padding = max([$padding, static::PAD]);
364
+ foreach ($details as $key => $value) {
365
+ $pad = $padding - (mb_strlen($key, 'UTF-8') - strlen($key)); // handle unicode characters
366
+ $strings[] = is_string($key)
367
+ ? sprintf('%s : %s', str_pad($key, $pad, '.'), $value)
368
+ : ' - '.$value;
369
+ }
370
+ return implode(PHP_EOL, $strings).PHP_EOL.PHP_EOL;
371
+ }
372
+
373
+ /**
374
+ * @return string
375
+ */
376
+ protected function detectWebhostProvider()
377
+ {
378
+ $checks = [
379
+ '.accountservergroup.com' => 'Site5',
380
+ '.gridserver.com' => 'MediaTemple Grid',
381
+ '.inmotionhosting.com' => 'InMotion Hosting',
382
+ '.ovh.net' => 'OVH',
383
+ '.pair.com' => 'pair Networks',
384
+ '.stabletransit.com' => 'Rackspace Cloud',
385
+ '.stratoserver.net' => 'STRATO',
386
+ '.sysfix.eu' => 'SysFix.eu Power Hosting',
387
+ 'bluehost.com' => 'Bluehost',
388
+ 'DH_USER' => 'DreamHost',
389
+ 'Flywheel' => 'Flywheel',
390
+ 'ipagemysql.com' => 'iPage',
391
+ 'ipowermysql.com' => 'IPower',
392
+ 'localhost:/tmp/mysql5.sock' => 'ICDSoft',
393
+ 'mysqlv5' => 'NetworkSolutions',
394
+ 'PAGELYBIN' => 'Pagely',
395
+ 'secureserver.net' => 'GoDaddy',
396
+ 'WPE_APIKEY' => 'WP Engine',
397
+ ];
398
+ foreach ($checks as $key => $value) {
399
+ if (!$this->isWebhostCheckValid($key)) {
400
+ continue;
401
+ }
402
+ return $value;
403
+ }
404
+ return implode(',', array_filter([DB_HOST, filter_input(INPUT_SERVER, 'SERVER_NAME')]));
405
+ }
406
+
407
+ /**
408
+ * @param string $key
409
+ * @return bool
410
+ */
411
+ protected function isWebhostCheckValid($key)
412
+ {
413
+ return defined($key)
414
+ || filter_input(INPUT_SERVER, $key)
415
+ || Str::contains($key, filter_input(INPUT_SERVER, 'SERVER_NAME'))
416
+ || Str::contains($key, DB_HOST)
417
+ || Str::contains($key, php_uname());
418
+ }
419
+
420
+ /**
421
+ * @return array
422
+ */
423
+ protected function normalizePluginList(array $plugins)
424
+ {
425
+ $plugins = array_map(function ($plugin) {
426
+ return sprintf('%s v%s', Arr::get($plugin, 'Name'), Arr::get($plugin, 'Version'));
427
+ }, $plugins);
428
+ natcasesort($plugins);
429
+ return array_flip($plugins);
430
+ }
431
+
432
+ /**
433
+ * @return array
434
+ */
435
+ protected function purgeSensitiveData(array $settings)
436
+ {
437
+ $keys = glsr()->filterArray('addon/system-info/purge', [
438
+ 'licenses.' => 8,
439
+ 'submissions.recaptcha.key' => 0,
440
+ 'submissions.recaptcha.secret' => 0,
441
+ ]);
442
+ array_walk($settings, function (&$value, $setting) use ($keys) {
443
+ foreach ($keys as $key => $preserve) {
444
+ if (!is_string($key)) { // @compat for older addons
445
+ $key = $preserve;
446
+ $preserve = 0;
447
+ }
448
+ if (Str::startsWith($key, $setting) && !empty($value)) {
449
+ $preserve = Cast::toInt($preserve);
450
+ $value = substr($value, -$preserve, $preserve);
451
+ $value = str_pad($value, 13, '*', STR_PAD_LEFT);
452
+ break;
453
+ }
454
+ }
455
+ });
456
+ return $settings;
457
+ }
458
+ }
plugin/Modules/Validator/AkismetValidator.php CHANGED
@@ -79,7 +79,7 @@ class AkismetValidator extends ValidatorAbstract
79
  */
80
  protected function isActive()
81
  {
82
- $check = !glsr_get_option('settings.submissions.akismet', false, 'bool')
83
  || !is_callable(['Akismet', 'get_api_key'])
84
  || !is_callable(['Akismet', 'http_post'])
85
  ? false
79
  */
80
  protected function isActive()
81
  {
82
+ $check = !glsr_get_option('submissions.akismet', false, 'bool')
83
  || !is_callable(['Akismet', 'get_api_key'])
84
  || !is_callable(['Akismet', 'http_post'])
85
  ? false
plugin/Modules/Validator/DefaultValidator.php CHANGED
@@ -5,6 +5,8 @@ namespace GeminiLabs\SiteReviews\Modules\Validator;
5
  use GeminiLabs\SiteReviews\Database\DefaultsManager;
6
  use GeminiLabs\SiteReviews\Defaults\ValidateReviewDefaults;
7
  use GeminiLabs\SiteReviews\Helpers\Arr;
 
 
8
  use GeminiLabs\SiteReviews\Modules\Validator;
9
  use GeminiLabs\SiteReviews\Request;
10
 
@@ -40,7 +42,11 @@ class DefaultValidator extends ValidatorAbstract
40
  $options = glsr(DefaultsManager::class)->pluck('settings.submissions.required.options');
41
  $excludedKeys = array_keys(array_diff_key($options, $this->request->toArray()));
42
  $this->request->excluded = $excludedKeys;
43
- return $this->isValid();
 
 
 
 
44
  }
45
 
46
  /**
@@ -56,12 +62,23 @@ class DefaultValidator extends ValidatorAbstract
56
  $this->request = new Request($values);
57
  }
58
 
 
 
 
 
 
 
 
 
 
 
 
59
  /**
60
  * @return array
61
  */
62
  protected function rules()
63
  {
64
- $rules = glsr()->filterArray('validation/rules', static::VALIDATION_RULES, $this->request);
65
  $customRules = array_diff_key($rules,
66
  glsr(DefaultsManager::class)->pluck('settings.submissions.required.options')
67
  );
5
  use GeminiLabs\SiteReviews\Database\DefaultsManager;
6
  use GeminiLabs\SiteReviews\Defaults\ValidateReviewDefaults;
7
  use GeminiLabs\SiteReviews\Helpers\Arr;
8
+ use GeminiLabs\SiteReviews\Helpers\Cast;
9
+ use GeminiLabs\SiteReviews\Modules\Rating;
10
  use GeminiLabs\SiteReviews\Modules\Validator;
11
  use GeminiLabs\SiteReviews\Request;
12
 
42
  $options = glsr(DefaultsManager::class)->pluck('settings.submissions.required.options');
43
  $excludedKeys = array_keys(array_diff_key($options, $this->request->toArray()));
44
  $this->request->excluded = $excludedKeys;
45
+ if ($this->isValid()) {
46
+ return true;
47
+ }
48
+ glsr_log()->warning($this->errors);
49
+ return false;
50
  }
51
 
52
  /**
62
  $this->request = new Request($values);
63
  }
64
 
65
+ /**
66
+ * @return array
67
+ */
68
+ protected function normalizedRules()
69
+ {
70
+ $rules = static::VALIDATION_RULES;
71
+ $maxRating = max(1, Cast::toInt(glsr()->constant('MAX_RATING', Rating::class)));
72
+ $rules['rating'] = str_replace('between:1,5', 'between:1,'.$maxRating, $rules['rating']);
73
+ return glsr()->filterArray('validation/rules', $rules, $this->request);
74
+ }
75
+
76
  /**
77
  * @return array
78
  */
79
  protected function rules()
80
  {
81
+ $rules = $this->normalizedRules();
82
  $customRules = array_diff_key($rules,
83
  glsr(DefaultsManager::class)->pluck('settings.submissions.required.options')
84
  );
plugin/Modules/Validator/ReviewLimitsValidator.php CHANGED
@@ -14,15 +14,6 @@ class ReviewLimitsValidator extends ValidatorAbstract
14
  return 'AND';
15
  }
16
 
17
- /**
18
- * This method can be used outside of validation
19
- * @return bool
20
- */
21
- public function hasReachedLimit()
22
- {
23
- return !$this->isValid();
24
- }
25
-
26
  /**
27
  * @return bool
28
  */
@@ -106,7 +97,7 @@ class ReviewLimitsValidator extends ValidatorAbstract
106
  || $this->isWhitelisted($value, glsr_get_option('submissions.limit_whitelist.'.$key))) {
107
  return true;
108
  }
109
- $queryArgs['assigned_posts'] = $this->request->assign_to;
110
  add_filter('query/sql/clause/operator', [$this, 'filterSqlClauseOperator']);
111
  $reviews = glsr_get_reviews($queryArgs);
112
  remove_filter('query/sql/clause/operator', [$this, 'filterSqlClauseOperator']);
14
  return 'AND';
15
  }
16
 
 
 
 
 
 
 
 
 
 
17
  /**
18
  * @return bool
19
  */
97
  || $this->isWhitelisted($value, glsr_get_option('submissions.limit_whitelist.'.$key))) {
98
  return true;
99
  }
100
+ $queryArgs['assigned_posts'] = $this->request->assigned_posts;
101
  add_filter('query/sql/clause/operator', [$this, 'filterSqlClauseOperator']);
102
  $reviews = glsr_get_reviews($queryArgs);
103
  remove_filter('query/sql/clause/operator', [$this, 'filterSqlClauseOperator']);
plugin/Review.php CHANGED
@@ -84,6 +84,50 @@ class Review extends Arguments
84
  return (string) $this->build();
85
  }
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  /**
88
  * @param int $size
89
  * @return string
@@ -259,9 +303,8 @@ class Review extends Arguments
259
  public function type()
260
  {
261
  $type = $this->get('type');
262
- return array_key_exists($type, glsr()->reviewTypes)
263
- ? glsr()->reviewTypes[$type]
264
- : _x('Unknown', 'admin-text', 'site-reviews');
265
  }
266
 
267
  /**
84
  return (string) $this->build();
85
  }
86
 
87
+ /**
88
+ * @return array
89
+ */
90
+ public function assignedPosts()
91
+ {
92
+ if (empty($this->assigned_posts)) {
93
+ return $this->assigned_posts;
94
+ }
95
+ return get_posts([
96
+ 'post__in' => $this->assigned_posts,
97
+ 'post_type' => 'any',
98
+ 'posts_per_page' => -1,
99
+ ]);
100
+ }
101
+
102
+ /**
103
+ * @return array
104
+ */
105
+ public function assignedTerms()
106
+ {
107
+ if (empty($this->assigned_terms)) {
108
+ return $this->assigned_terms;
109
+ }
110
+ $terms = get_terms(glsr()->taxonomy, ['include' => $this->assigned_terms]);
111
+ if (is_wp_error($terms)) {
112
+ return $this->assigned_terms;
113
+ }
114
+ return $terms;
115
+ }
116
+
117
+ /**
118
+ * @return array
119
+ */
120
+ public function assignedUsers()
121
+ {
122
+ if (empty($this->assigned_users)) {
123
+ return $this->assigned_users;
124
+ }
125
+ return get_users([
126
+ 'fields' => ['display_name', 'ID', 'user_email', 'user_nicename', 'user_url'],
127
+ 'include' => $this->assigned_users,
128
+ ]);
129
+ }
130
+
131
  /**
132
  * @param int $size
133
  * @return string
303
  public function type()
304
  {
305
  $type = $this->get('type');
306
+ $reviewTypes = glsr()->retrieveAs('array', 'review_types');
307
+ return Arr::get($reviewTypes, $type, _x('Unknown', 'admin-text', 'site-reviews'));
 
308
  }
309
 
310
  /**
plugin/Role.php CHANGED
@@ -31,6 +31,16 @@ class Role
31
  : current_user_can($capability);
32
  }
33
 
 
 
 
 
 
 
 
 
 
 
34
  /**
35
  * @param string $role
36
  * @return void
@@ -51,8 +61,6 @@ class Role
51
  */
52
  public function resetAll()
53
  {
54
- $roles = array_keys(wp_roles()->roles);
55
- array_walk($roles, [$this, 'removeCapabilities']);
56
  $roles = array_keys($this->roleCapabilities());
57
  array_walk($roles, [$this, 'addCapabilities']);
58
  }
@@ -62,7 +70,7 @@ class Role
62
  */
63
  protected function capabilities()
64
  {
65
- $capabilities = [
66
  'delete_others_posts',
67
  'delete_post',
68
  'delete_posts',
@@ -77,7 +85,6 @@ class Role
77
  'read_post',
78
  'read_private_posts',
79
  ];
80
- return glsr()->filterArray('capabilities', $capabilities);
81
  }
82
 
83
  /**
@@ -94,7 +101,7 @@ class Role
94
  */
95
  protected function roleCapabilities()
96
  {
97
- $capabilities = [
98
  'administrator' => [
99
  'delete_others_posts',
100
  'delete_posts',
@@ -131,6 +138,5 @@ class Role
131
  'edit_posts',
132
  ],
133
  ];
134
- return glsr()->filterArray('capabilities/for-roles', $capabilities);
135
  }
136
  }
31
  : current_user_can($capability);
32
  }
33
 
34
+ /**
35
+ * @return void
36
+ */
37
+ public function hardResetAll()
38
+ {
39
+ $roles = array_keys($this->roleCapabilities());
40
+ array_walk($roles, [$this, 'removeCapabilities']);
41
+ array_walk($roles, [$this, 'addCapabilities']);
42
+ }
43
+
44
  /**
45
  * @param string $role
46
  * @return void
61
  */
62
  public function resetAll()
63
  {
 
 
64
  $roles = array_keys($this->roleCapabilities());
65
  array_walk($roles, [$this, 'addCapabilities']);
66
  }
70
  */
71
  protected function capabilities()
72
  {
73
+ return [
74
  'delete_others_posts',
75
  'delete_post',
76
  'delete_posts',
85
  'read_post',
86
  'read_private_posts',
87
  ];
 
88
  }
89
 
90
  /**
101
  */
102
  protected function roleCapabilities()
103
  {
104
+ return [
105
  'administrator' => [
106
  'delete_others_posts',
107
  'delete_posts',
138
  'edit_posts',
139
  ],
140
  ];
 
141
  }
142
  }
plugin/Router.php CHANGED
@@ -52,7 +52,7 @@ class Router
52
  */
53
  public function routePublicPostRequest()
54
  {
55
- if (is_admin()) {
56
  return;
57
  }
58
  $request = $this->getRequest();
52
  */
53
  public function routePublicPostRequest()
54
  {
55
+ if (glsr()->isAdmin()) {
56
  return;
57
  }
58
  $request = $this->getRequest();
plugin/Storage.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace GeminiLabs\SiteReviews;
4
 
5
  use GeminiLabs\SiteReviews\Helpers\Arr;
 
6
 
7
  trait Storage
8
  {
@@ -51,6 +52,17 @@ trait Storage
51
  return $this->storage()->get($property, $fallback);
52
  }
53
 
 
 
 
 
 
 
 
 
 
 
 
54
  /**
55
  * @return Arguments
56
  */
3
  namespace GeminiLabs\SiteReviews;
4
 
5
  use GeminiLabs\SiteReviews\Helpers\Arr;
6
+ use GeminiLabs\SiteReviews\Helpers\Cast;
7
 
8
  trait Storage
9
  {
52
  return $this->storage()->get($property, $fallback);
53
  }
54
 
55
+ /**
56
+ * @param string $cast
57
+ * @param string $property
58
+ * @param mixed $fallback
59
+ * @return mixed
60
+ */
61
+ public function retrieveAs($cast, $property, $fallback = null)
62
+ {
63
+ return Cast::to($cast, $this->storage()->get($property, $fallback));
64
+ }
65
+
66
  /**
67
  * @return Arguments
68
  */
plugin/Tinymce/TinymceGenerator.php CHANGED
@@ -136,13 +136,13 @@ abstract class TinymceGenerator
136
  */
137
  protected function getTypes($tooltip = '')
138
  {
139
- if (count(glsr()->reviewTypes) < 2) {
140
  return [];
141
  }
142
  return [
143
  'label' => _x('Type', 'admin-text', 'site-reviews'),
144
  'name' => 'type',
145
- 'options' => glsr()->reviewTypes,
146
  'tooltip' => $tooltip,
147
  'type' => 'listbox',
148
  ];
136
  */
137
  protected function getTypes($tooltip = '')
138
  {
139
+ if (count($reviewTypes = glsr()->retrieveAs('array', 'review_types')) < 2) {
140
  return [];
141
  }
142
  return [
143
  'label' => _x('Type', 'admin-text', 'site-reviews'),
144
  'name' => 'type',
145
+ 'options' => $reviewTypes,
146
  'tooltip' => $tooltip,
147
  'type' => 'listbox',
148
  ];
plugin/Widgets/SiteReviewsSummaryWidget.php CHANGED
@@ -20,11 +20,11 @@ class SiteReviewsSummaryWidget extends Widget
20
  'label' => _x('Title', 'admin-text', 'site-reviews'),
21
  'name' => 'title',
22
  ]);
23
- if (count(glsr()->reviewTypes) > 1) {
24
  $this->renderField('select', [
25
  'label' => _x('Which type of review would you like to use?', 'admin-text', 'site-reviews'),
26
  'name' => 'type',
27
- 'options' => Arr::prepend(glsr()->reviewTypes, _x('All review types', 'admin-text', 'site-reviews'), ''),
28
  ]);
29
  }
30
  if (!empty($terms)) {
20
  'label' => _x('Title', 'admin-text', 'site-reviews'),
21
  'name' => 'title',
22
  ]);
23
+ if (count($reviewTypes = glsr()->retrieveAs('array', 'review_types')) > 1) {
24
  $this->renderField('select', [
25
  'label' => _x('Which type of review would you like to use?', 'admin-text', 'site-reviews'),
26
  'name' => 'type',
27
+ 'options' => Arr::prepend($reviewTypes, _x('All review types', 'admin-text', 'site-reviews'), ''),
28
  ]);
29
  }
30
  if (!empty($terms)) {
plugin/Widgets/SiteReviewsWidget.php CHANGED
@@ -38,11 +38,11 @@ class SiteReviewsWidget extends Widget
38
  '5' => esc_attr(sprintf(_nx('%s star', '%s stars', 5, 'admin-text', 'site-reviews'), 5)),
39
  ],
40
  ]);
41
- if (count(glsr()->reviewTypes) > 1) {
42
  $this->renderField('select', [
43
  'label' => _x('Which type of review would you like to display?', 'admin-text', 'site-reviews'),
44
  'name' => 'type',
45
- 'options' => Arr::prepend(glsr()->reviewTypes, _x('All Reviews', 'admin-text', 'site-reviews'), ''),
46
  ]);
47
  }
48
  if (!empty($terms)) {
38
  '5' => esc_attr(sprintf(_nx('%s star', '%s stars', 5, 'admin-text', 'site-reviews'), 5)),
39
  ],
40
  ]);
41
+ if (count($reviewTypes = glsr()->retrieveAs('array', 'review_types')) > 1) {
42
  $this->renderField('select', [
43
  'label' => _x('Which type of review would you like to display?', 'admin-text', 'site-reviews'),
44
  'name' => 'type',
45
+ 'options' => Arr::prepend($reviewTypes, _x('All Reviews', 'admin-text', 'site-reviews'), ''),
46
  ]);
47
  }
48
  if (!empty($terms)) {
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: reviews, ratings, testimonials, business reviews, product reviews, stars,
5
  Tested up to: 5.5
6
  Requires at least: 5.5
7
  Requires PHP: 5.6
8
- Stable tag: 5.1.6
9
  License: GPLv3
10
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -113,17 +113,32 @@ All documentation can be found in the "Help" page of the plugin. If your questio
113
 
114
  == Changelog ==
115
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  = 5.1.6 (2020-10-25) =
117
 
118
  - Fixed compatibility issue with the Elementor Pro Popups
119
- - Fixed validation in the glsr_create_review helper function
120
 
121
  = 5.1.4 (2020-10-25) =
122
 
123
- - Added "ORDER BY" to migration SQL queries; this will make migrations run a little slower but fix a potential problem where database migrations may not complete successfully
124
  - Fixed addons notice styling and placement
125
  - Fixed plugin file paths on IIS Windows servers
126
- - Fixed plugin migrations to work better with caching plugins
127
  - Fixed strict standard notices in PHP 5.6
128
 
129
  = 5.1.0 (2020-10-24) =
5
  Tested up to: 5.5
6
  Requires at least: 5.5
7
  Requires PHP: 5.6
8
+ Stable tag: 5.2.0
9
  License: GPLv3
10
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
 
113
 
114
  == Changelog ==
115
 
116
+ = 5.2.0 (2020-11-06) =
117
+
118
+ - Added Notification Template tags for assigned categories, posts, and users
119
+ - Added Review Assignment setting
120
+ - Changed review assignment in SQL queries to use strict assignments by default (it was previously using loose assignments, use the new "Review Assignment" setting to change this back)
121
+ - Changed the glsr_create_review function to log validation errors to the plugin console
122
+ - Fixed Bulk Editing of reviews that are assigned to post types or users
123
+ - Fixed Multibyte String support
124
+ - Fixed Multisite compatibility
125
+ - Fixed pagination URLs when used on the homepage
126
+ - Fixed rating validation when using a custom maximum rating value
127
+ - Fixed review limits validation for assigned reviews
128
+ - Fixed review migration of invalid 3rd-party reviews (reviews that were previously imported incorrectly)
129
+ - Fixed review name and email fallback values to use those of the logged-in user
130
+ - Fixed the submission date of reviews, it now uses the timezone offset in the WordPress settings
131
+
132
  = 5.1.6 (2020-10-25) =
133
 
134
  - Fixed compatibility issue with the Elementor Pro Popups
135
+ - Fixed the glsr_create_review helper function validation
136
 
137
  = 5.1.4 (2020-10-25) =
138
 
 
139
  - Fixed addons notice styling and placement
140
  - Fixed plugin file paths on IIS Windows servers
141
+ - Fixed plugin migrations to work better with the W3 Total Cache plugin
142
  - Fixed strict standard notices in PHP 5.6
143
 
144
  = 5.1.0 (2020-10-24) =
site-reviews.php CHANGED
@@ -7,7 +7,7 @@
7
  * Plugin Name: Site Reviews
8
  * Plugin URI: https://wordpress.org/plugins/site-reviews
9
  * Description: Receive and display reviews on your website
10
- * Version: 5.1.6
11
  * Author: Paul Ryley
12
  * Author URI: https://geminilabs.io
13
  * License: GPL2
@@ -29,7 +29,6 @@ if ((new GL_Plugin_Check_v5(__FILE__))->canProceed()) {
29
  require_once __DIR__.'/helpers.php';
30
  $app = GeminiLabs\SiteReviews\Application::load();
31
  $app->make('Provider')->register($app);
32
- register_activation_hook(__FILE__, array($app, 'activate'));
33
  register_deactivation_hook(__FILE__, array($app, 'deactivate'));
34
  register_shutdown_function(array($app, 'catchFatalError'));
35
  $app->init();
7
  * Plugin Name: Site Reviews
8
  * Plugin URI: https://wordpress.org/plugins/site-reviews
9
  * Description: Receive and display reviews on your website
10
+ * Version: 5.2.0
11
  * Author: Paul Ryley
12
  * Author URI: https://geminilabs.io
13
  * License: GPL2
29
  require_once __DIR__.'/helpers.php';
30
  $app = GeminiLabs\SiteReviews\Application::load();
31
  $app->make('Provider')->register($app);
 
32
  register_deactivation_hook(__FILE__, array($app, 'deactivate'));
33
  register_shutdown_function(array($app, 'catchFatalError'));
34
  $app->init();
uninstall.php CHANGED
@@ -2,71 +2,152 @@
2
 
3
  defined('WP_UNINSTALL_PLUGIN') || die;
4
 
5
- $file = __DIR__.'/site-reviews.php';
6
- require_once $file;
7
-
8
- if (!(new GL_Plugin_Check_v5($file))->isValid()) {
9
- return;
 
 
 
 
 
 
 
 
10
  }
11
 
12
- global $wpdb;
 
 
 
 
 
 
13
 
14
- $uninstallOption = glsr_get_option('general.delete_data_on_uninstall');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
- if (in_array($uninstallOption, ['all', 'minimal'])) {
17
- foreach (range(1, glsr()->version('major')) as $version) {
18
- delete_option(GeminiLabs\SiteReviews\Database\OptionManager::databaseKey($version));
 
 
 
 
 
19
  }
20
- delete_option('theme_mods_'.glsr()->id);
21
- delete_option('widget_'.glsr()->prefix.'site-reviews');
22
- delete_option('widget_'.glsr()->prefix.'site-reviews-form');
23
- delete_option('widget_'.glsr()->prefix.'site-reviews-summary');
24
- delete_option(glsr()->prefix.'activated');
25
- delete_transient(glsr()->prefix.'cloudflare_ips');
26
- delete_transient(glsr()->prefix.'migrations');
27
- delete_transient(glsr()->prefix.'remote_post_test');
28
- $wpdb->query("DELETE FROM {$wpdb->usermeta} WHERE meta_key = '_glsr_notices'");
29
  }
30
- if ('all' === $uninstallOption) {
31
- $likePrefix = '%'.$wpdb->esc_like(glsr()->prefix).'%';
32
- $likeTaxonomy = '%'.$wpdb->esc_like(glsr()->taxonomy).'%';
33
  // delete all reviews and revisions
34
- $wpdb->query($wpdb->prepare("
35
  DELETE p, pr, tr, pm
36
  FROM {$wpdb->posts} p
37
  LEFT JOIN {$wpdb->posts} pr ON (p.ID = pr.post_parent AND pr.post_type = 'revision')
38
  LEFT JOIN {$wpdb->term_relationships} tr ON (p.ID = tr.object_id)
39
  LEFT JOIN {$wpdb->postmeta} pm ON (p.ID = pm.post_id)
40
- WHERE p.post_type = %s", glsr()->post_type
41
- ));
42
  // delete all review categories
43
- $wpdb->query($wpdb->prepare("
44
  DELETE tt, t, tm
45
  FROM {$wpdb->term_taxonomy} tt
46
  LEFT JOIN {$wpdb->terms} t ON (tt.term_id = t.term_id)
47
  LEFT JOIN {$wpdb->termmeta} tm ON (tt.term_id = tm.term_id)
48
- WHERE tt.taxonomy = %s", glsr()->taxonomy
49
- ));
50
  // delete all assigned_posts meta
51
- $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE %s", $likePrefix));
52
  // delete all assigned_users meta
53
- $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE %s", $likePrefix));
54
- // delete any remaining options
55
- $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $likePrefix));
56
- $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $likeTaxonomy));
57
- // drop all custom tables
58
- $prefix = $wpdb->prefix.glsr()->prefix;
59
- $wpdb->query("DROP TABLE {$prefix}assigned_posts");
60
- $wpdb->query("DROP TABLE {$prefix}assigned_terms");
61
- $wpdb->query("DROP TABLE {$prefix}assigned_users");
62
- $wpdb->query("DROP TABLE {$prefix}ratings");
63
- // optimise affected database tables
64
- $wpdb->query("OPTIMIZE TABLE {$wpdb->options}");
65
- $wpdb->query("OPTIMIZE TABLE {$wpdb->postmeta}");
66
- $wpdb->query("OPTIMIZE TABLE {$wpdb->posts}");
67
- $wpdb->query("OPTIMIZE TABLE {$wpdb->termmeta}");
68
- $wpdb->query("OPTIMIZE TABLE {$wpdb->terms}");
69
- $wpdb->query("OPTIMIZE TABLE {$wpdb->usermeta}");
70
- // finally, flush the entire cache
71
- wp_cache_flush();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  }
2
 
3
  defined('WP_UNINSTALL_PLUGIN') || die;
4
 
5
+ function glsr_uninstall() {
6
+ $settings = get_option('site_reviews_v5');
7
+ $uninstall = isset($settings['settings']['general']['delete_data_on_uninstall'])
8
+ ? $settings['settings']['general']['delete_data_on_uninstall']
9
+ : '';
10
+ if ('all' === $uninstall) {
11
+ glsr_uninstall_all();
12
+ }
13
+ if ('minimal' === $uninstall) {
14
+ glsr_uninstall_minimal();
15
+ glsr_uninstall_minimal_drop_foreign_keys();
16
+ }
17
+ delete_option('glsr_activated');
18
  }
19
 
20
+ function glsr_uninstall_all() {
21
+ glsr_uninstall_minimal();
22
+ glsr_uninstall_all_delete_reviews();
23
+ glsr_uninstall_all_delete_tables();
24
+ glsr_uninstall_all_delete_logs();
25
+ glsr_uninstall_all_cleanup();
26
+ }
27
 
28
+ function glsr_uninstall_all_cleanup() {
29
+ global $wpdb;
30
+ // delete any remaining options
31
+ $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '%glsr_%'");
32
+ $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE 'site-review-category%'");
33
+ // optimise affected database tables
34
+ $wpdb->query("OPTIMIZE TABLE {$wpdb->options}");
35
+ $wpdb->query("OPTIMIZE TABLE {$wpdb->postmeta}");
36
+ $wpdb->query("OPTIMIZE TABLE {$wpdb->posts}");
37
+ $wpdb->query("OPTIMIZE TABLE {$wpdb->termmeta}");
38
+ $wpdb->query("OPTIMIZE TABLE {$wpdb->terms}");
39
+ $wpdb->query("OPTIMIZE TABLE {$wpdb->usermeta}");
40
+ // finally, flush the entire cache
41
+ wp_cache_flush();
42
+ }
43
 
44
+ function glsr_uninstall_all_delete_logs() {
45
+ require_once ABSPATH.'/wp-admin/includes/file.php';
46
+ global $wp_filesystem;
47
+ // delete the Site Reviews logs directory
48
+ if (WP_Filesystem()) {
49
+ $uploads = wp_upload_dir();
50
+ $dirname = trailingslashit($uploads['basedir'].'/site-reviews/logs');
51
+ $wp_filesystem->rmdir(wp_normalize_path($dirname), true);
52
  }
 
 
 
 
 
 
 
 
 
53
  }
54
+
55
+ function glsr_uninstall_all_delete_reviews() {
56
+ global $wpdb;
57
  // delete all reviews and revisions
58
+ $wpdb->query("
59
  DELETE p, pr, tr, pm
60
  FROM {$wpdb->posts} p
61
  LEFT JOIN {$wpdb->posts} pr ON (p.ID = pr.post_parent AND pr.post_type = 'revision')
62
  LEFT JOIN {$wpdb->term_relationships} tr ON (p.ID = tr.object_id)
63
  LEFT JOIN {$wpdb->postmeta} pm ON (p.ID = pm.post_id)
64
+ WHERE p.post_type = 'site-review'
65
+ ");
66
  // delete all review categories
67
+ $wpdb->query("
68
  DELETE tt, t, tm
69
  FROM {$wpdb->term_taxonomy} tt
70
  LEFT JOIN {$wpdb->terms} t ON (tt.term_id = t.term_id)
71
  LEFT JOIN {$wpdb->termmeta} tm ON (tt.term_id = tm.term_id)
72
+ WHERE tt.taxonomy = 'site-review-category'
73
+ ");
74
  // delete all assigned_posts meta
75
+ $wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE '%glsr_%'");
76
  // delete all assigned_users meta
77
+ $wpdb->query("DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE '%glsr_%'");
78
+ }
79
+
80
+ function glsr_uninstall_all_delete_tables() {
81
+ global $wpdb;
82
+ // order is intentional
83
+ $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}glsr_assigned_users");
84
+ $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}glsr_assigned_terms");
85
+ $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}glsr_assigned_posts");
86
+ $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}glsr_ratings");
87
+ }
88
+
89
+ function glsr_uninstall_minimal() {
90
+ global $wpdb;
91
+ $options = array(
92
+ 'geminilabs_site_reviews-v2', // v2 settings
93
+ 'geminilabs_site_reviews_settings', // v1 settings
94
+ 'site_reviews_v3', // v3 settings
95
+ 'site_reviews_v4', // v4 settings
96
+ 'site_reviews_v5', // v5 settings
97
+ 'theme_mods_site-reviews',
98
+ 'widget_glsr_site-reviews',
99
+ 'widget_glsr_site-reviews-form',
100
+ 'widget_glsr_site-reviews-summary',
101
+ );
102
+ foreach ($options as $option) {
103
+ delete_option($option);
104
+ }
105
+ delete_transient('glsr_cloudflare_ips');
106
+ delete_transient('glsr_migrations');
107
+ delete_transient('glsr_remote_post_test');
108
+ $wpdb->query("DELETE FROM {$wpdb->usermeta} WHERE meta_key = '_glsr_notices'");
109
+ }
110
+
111
+ function glsr_uninstall_minimal_drop_foreign_keys() {
112
+ global $wpdb;
113
+ $siteId = '';
114
+ if (get_current_blog_id() > 1) {
115
+ $siteId = '_'.get_current_blog_id();
116
+ }
117
+ $constraints = [ // order is intentional
118
+ "{$wpdb->prefix}glsr_assigned_users" => "glsr_assigned_users_user_id_foreign{$siteId}",
119
+ "{$wpdb->prefix}glsr_assigned_terms" => "glsr_assigned_terms_term_id_foreign{$siteId}",
120
+ "{$wpdb->prefix}glsr_assigned_posts" => "glsr_assigned_posts_post_id_foreign{$siteId}",
121
+ "{$wpdb->prefix}glsr_ratings" => "glsr_assigned_posts_review_id_foreign{$siteId}",
122
+ ];
123
+ foreach ($constraints as $table => $constraint) { // This should work for both MyISAM and InnoDB engines
124
+ $foreignKey = $wpdb->get_var("
125
+ SELECT INDEX_NAME
126
+ FROM INFORMATION_SCHEMA.STATISTICS
127
+ WHERE INDEX_SCHEMA = '{$wpdb->dbname}' AND TABLE_NAME = '{$table}' AND INDEX_NAME = '{$constraint}'
128
+ ");
129
+ if (!empty($foreignKey)) {
130
+ $wpdb->query("
131
+ ALTER TABLE {$table} DROP FOREIGN KEY {$constraint};
132
+ ");
133
+ }
134
+ }
135
+ // delete the saved database version
136
+ delete_option('glsr_db_version');
137
+ }
138
+
139
+ if (!is_multisite()) {
140
+ glsr_uninstall();
141
+ return;
142
+ }
143
+ if (!function_exists('get_sites')) {
144
+ global $wpdb;
145
+ $siteIds = $wpdb->get_col("SELECT blog_id FROM {$wpdb->blogs}");
146
+ } else {
147
+ $siteIds = get_sites(array('fields' => 'ids'));
148
+ }
149
+ foreach ($siteIds as $siteId) {
150
+ switch_to_blog($siteId);
151
+ glsr_uninstall();
152
+ restore_current_blog();
153
  }
views/pages/documentation/faq/hide-form-after-submission.php CHANGED
@@ -32,9 +32,9 @@ add_filter('site-reviews/enqueue/public/inline-script', function ($script) {
32
  * @return string
33
  */
34
  add_filter('site-reviews/rendered/template/reviews-form', function ($template) {
35
- return glsr('Modules\Validator\ReviewLimitsValidator')->hasReachedLimit()
36
- ? sprintf('&lt;p&gt;%s&lt;/p&gt;', __('Thank you for your review!'))
37
- : $template;
38
  });</code></pre>
39
  </div>
40
  </div>
32
  * @return string
33
  */
34
  add_filter('site-reviews/rendered/template/reviews-form', function ($template) {
35
+ return glsr('Modules\Validator\ReviewLimitsValidator')->isValid()
36
+ ? $template
37
+ : sprintf('&lt;p&gt;%s&lt;/p&gt;', __('Thank you for your review!'));
38
  });</code></pre>
39
  </div>
40
  </div>
views/pages/documentation/functions/glsr_create_review.php CHANGED
@@ -7,6 +7,11 @@
7
  </button>
8
  </h3>
9
  <div id="fn-glsr_create_review" class="inside">
 
 
 
 
 
10
  <pre><code class="language-php">/**
11
  * Default values in the $reviewValues array:
12
  * - 'assigned_posts' => '',
7
  </button>
8
  </h3>
9
  <div id="fn-glsr_create_review" class="inside">
10
+ <div class="components-notice is-warning">
11
+ <p class="components-notice__content">This function uses basic validation on the provided values. If validation fails, the function will return false and the validation errors will be logged to the <a href="<?= admin_url('edit.php?post_type='.glsr()->post_type.'&page=tools#tab-console'); ?>">Plugin Console</a>.</p>
12
+
13
+ </div>
14
+ <br>
15
  <pre><code class="language-php">/**
16
  * Default values in the $reviewValues array:
17
  * - 'assigned_posts' => '',
views/pages/documentation/functions/glsr_get_reviews.php CHANGED
@@ -22,15 +22,15 @@ glsr_get_reviews(array $args = []);</code></pre>
22
  'email' => '',
23
  'ip_address' => '',
24
  'offset' => '',
25
- 'order' => 'DESC',
26
- 'orderby' => 'date',
27
  'page' => 1,
28
  'pagination' => false,
29
  'per_page' => 10,
30
  'post__in' => [],
31
  'post__not_in' => [],
32
  'rating' => '',
33
- 'status' => 'approved',
34
  'type' => '',
35
  ];</code></pre>
36
  <p><strong>Example Usage:</strong></p>
22
  'email' => '',
23
  'ip_address' => '',
24
  'offset' => '',
25
+ 'order' => 'DESC', // value can be "ASC" or "DESC"
26
+ 'orderby' => 'date', // value can be "author", "date", "ID", or "random"
27
  'page' => 1,
28
  'pagination' => false,
29
  'per_page' => 10,
30
  'post__in' => [],
31
  'post__not_in' => [],
32
  'rating' => '',
33
+ 'status' => 'approved', // value can be "all", "approved", or "unapproved"
34
  'type' => '',
35
  ];</code></pre>
36
  <p><strong>Example Usage:</strong></p>
views/pages/tools/general.php CHANGED
@@ -94,14 +94,18 @@
94
 
95
  <div class="glsr-card card">
96
  <h3>Reset Permissions</h3>
 
 
 
97
  <p>Site Reviews provides custom post_type capabilities that mirror the capabilities of your posts by default. For example, if a user role has permission to edit others posts, then that role will also have permission to edit other users reviews.</p>
98
- <p>If you have changed the capabilities of your user roles and you suspect that Site Reviews is not working correctly due to your changes, you may use this tool to reset the Site Reviews capabilities for your user roles.</p>
99
  <form method="post">
100
  <input type="hidden" name="{{ id }}[_action]" value="reset-permissions">
 
101
  <?php wp_nonce_field('reset-permissions'); ?>
102
  <p class="submit">
103
  <button type="submit" class="glsr-button button" name="reset-permissions" id="reset-permissions" data-ajax-click>
104
- <span data-loading="<?= esc_attr_x('Resetting, please wait...', 'admin-text', 'site-reviews'); ?>"><?= _x('Reset Permissions', 'admin-text', 'site-reviews'); ?></span>
105
  </button>
106
  </p>
107
  </form>
94
 
95
  <div class="glsr-card card">
96
  <h3>Reset Permissions</h3>
97
+ <div class="components-notice is-info">
98
+ <p class="components-notice__content">Hold down the ALT/Option key to perform a "Hard Reset"; this removes all Site Reviews capabilites from your Editor, Author, and Contributor roles before re-adding them.</p>
99
+ </div>
100
  <p>Site Reviews provides custom post_type capabilities that mirror the capabilities of your posts by default. For example, if a user role has permission to edit others posts, then that role will also have permission to edit other users reviews.</p>
101
+ <p>If you have changed the capabilities of your user roles (Administrator, Editor, Author, and Contributor) and you suspect that Site Reviews is not working correctly due to your changes, you may use this tool to reset the Site Reviews capabilities for your user roles.</p>
102
  <form method="post">
103
  <input type="hidden" name="{{ id }}[_action]" value="reset-permissions">
104
+ <input type="hidden" name="{{ id }}[alt]" value="0" data-alt>
105
  <?php wp_nonce_field('reset-permissions'); ?>
106
  <p class="submit">
107
  <button type="submit" class="glsr-button button" name="reset-permissions" id="reset-permissions" data-ajax-click>
108
+ <span data-alt-text="<?= esc_attr_x('Hard Reset Permissions', 'admin-text', 'site-reviews'); ?>" data-loading="<?= esc_attr_x('Resetting, please wait...', 'admin-text', 'site-reviews'); ?>"><?= _x('Reset Permissions', 'admin-text', 'site-reviews'); ?></span>
109
  </button>
110
  </p>
111
  </form>
views/pages/welcome/whatsnew.php CHANGED
@@ -4,6 +4,7 @@
4
  <div class="is-fullwidth">
5
  <div class="glsr-flex-row">
6
  <div class="glsr-column">
 
7
  <?php include trailingslashit(__DIR__).'whatsnew/v51.php'; ?>
8
  <?php include trailingslashit(__DIR__).'whatsnew/v50.php'; ?>
9
  <?php include trailingslashit(__DIR__).'whatsnew/v46.php'; ?>
4
  <div class="is-fullwidth">
5
  <div class="glsr-flex-row">
6
  <div class="glsr-column">
7
+ <?php include trailingslashit(__DIR__).'whatsnew/v52.php'; ?>
8
  <?php include trailingslashit(__DIR__).'whatsnew/v51.php'; ?>
9
  <?php include trailingslashit(__DIR__).'whatsnew/v50.php'; ?>
10
  <?php include trailingslashit(__DIR__).'whatsnew/v46.php'; ?>
views/pages/welcome/whatsnew/v40.php CHANGED
@@ -7,7 +7,7 @@
7
  </h3>
8
  <div id="welcome-v400" class="inside">
9
  <p><em>Initial Release Date &mdash; October 6th, 2019</em></p>
10
- <h4>New Features</h4>
11
  <ul>
12
  <li>Added Multisite support</li>
13
  <li>Added product schema price options</li>
@@ -19,12 +19,12 @@
19
  <li>Added widget icons in the WordPress customizer</li>
20
  <li>Added WPML integration for summary counts</li>
21
  </ul>
22
- <h4>Changes</h4>
23
  <ul>
24
  <li>Changed category assignment to one-per-review</li>
25
  <li>Removed $_SESSION usage</li>
26
  </ul>
27
- <h4>Tweaks</h4>
28
  <ul>
29
  <li>Improved AJAX pagination</li>
30
  <li>Improved documentation</li>
@@ -35,7 +35,7 @@
35
  <li>Updated plugin hooks</li>
36
  <li>Updated templates</li>
37
  </ul>
38
- <h4>Bugs Fixed</h4>
39
  <ul>
40
  <li>Fixed badge counter in menu when reviews are approved/unapproved</li>
41
  <li>Fixed overriding star styles on the "Add plugin" page</li>
7
  </h3>
8
  <div id="welcome-v400" class="inside">
9
  <p><em>Initial Release Date &mdash; October 6th, 2019</em></p>
10
+ <h4>✨ New Features</h4>
11
  <ul>
12
  <li>Added Multisite support</li>
13
  <li>Added product schema price options</li>
19
  <li>Added widget icons in the WordPress customizer</li>
20
  <li>Added WPML integration for summary counts</li>
21
  </ul>
22
+ <h4>📢 Changes</h4>
23
  <ul>
24
  <li>Changed category assignment to one-per-review</li>
25
  <li>Removed $_SESSION usage</li>
26
  </ul>
27
+ <h4>🛠 Tweaks</h4>
28
  <ul>
29
  <li>Improved AJAX pagination</li>
30
  <li>Improved documentation</li>
35
  <li>Updated plugin hooks</li>
36
  <li>Updated templates</li>
37
  </ul>
38
+ <h4>🐞 Bugs Fixed</h4>
39
  <ul>
40
  <li>Fixed badge counter in menu when reviews are approved/unapproved</li>
41
  <li>Fixed overriding star styles on the "Add plugin" page</li>
views/pages/welcome/whatsnew/v41.php CHANGED
@@ -7,21 +7,21 @@
7
  </h3>
8
  <div id="welcome-v410" class="inside">
9
  <p><em>Initial Release Date &mdash; October 16th, 2019</em></p>
10
- <h4>New Features</h4>
11
  <ul>
12
  <li>Added optional "Email", "IP Address", and "Response" columns to the reviews table</li>
13
  </ul>
14
- <h4>Changes</h4>
15
  <ul>
16
  <li>Changed <code>[site_reviews]</code> "count" option name to "display" (i.e. [site_reviews display=10])</li>
17
  <li>Changed <code>glsr_get_reviews()</code> "count" option name to "per_page" (i.e. glsr_get_reviews(['per_page' => 10]))</li>
18
  <li>Renamed "Documentation" page to "Help"</li>
19
  </ul>
20
- <h4>Tweaks</h4>
21
  <ul>
22
  <li>Updated the "Common Problems and Solutions" help section</li>
23
  </ul>
24
- <h4>Bugs Fixed</h4>
25
  <ul>
26
  <li>Fixed a HTML5 validation issue in the plugin settings</li>
27
  <li>Fixed column sorting on the reviews table</li>
7
  </h3>
8
  <div id="welcome-v410" class="inside">
9
  <p><em>Initial Release Date &mdash; October 16th, 2019</em></p>
10
+ <h4>✨ New Features</h4>
11
  <ul>
12
  <li>Added optional "Email", "IP Address", and "Response" columns to the reviews table</li>
13
  </ul>
14
+ <h4>📢 Changes</h4>
15
  <ul>
16
  <li>Changed <code>[site_reviews]</code> "count" option name to "display" (i.e. [site_reviews display=10])</li>
17
  <li>Changed <code>glsr_get_reviews()</code> "count" option name to "per_page" (i.e. glsr_get_reviews(['per_page' => 10]))</li>
18
  <li>Renamed "Documentation" page to "Help"</li>
19
  </ul>
20
+ <h4>🛠 Tweaks</h4>
21
  <ul>
22
  <li>Updated the "Common Problems and Solutions" help section</li>
23
  </ul>
24
+ <h4>🐞 Bugs Fixed</h4>
25
  <ul>
26
  <li>Fixed a HTML5 validation issue in the plugin settings</li>
27
  <li>Fixed column sorting on the reviews table</li>
views/pages/welcome/whatsnew/v42.php CHANGED
@@ -7,17 +7,17 @@
7
  </h3>
8
  <div id="welcome-v420" class="inside">
9
  <p><em>Initial Release Date &mdash; October 29th, 2019</em></p>
10
- <h4>New Features</h4>
11
  <ul>
12
  <li>Added the <code>site-reviews/support/deprecated/v4</code> filter hook. If this hook returns <code>false</code> then the plugin will skip deprecated checks. If the plugin console does not show any deprecated notices, then it should be safe to use this hook for increased performance.</li>
13
  <li>Added WordPress v5.3 compatibility</li>
14
  </ul>
15
- <h4>Tweaks</h4>
16
  <ul>
17
  <li>Optimised translation performance</li>
18
  <li>Rebuilt the WordPress Editor Blocks</li>
19
  </ul>
20
- <h4>Bugs Fixed</h4>
21
  <ul>
22
  <li>Fixed pagination of reviews on static front page</li>
23
  <li>Fixed performance issues related to IP Address detection</li>
7
  </h3>
8
  <div id="welcome-v420" class="inside">
9
  <p><em>Initial Release Date &mdash; October 29th, 2019</em></p>
10
+ <h4>✨ New Features</h4>
11
  <ul>
12
  <li>Added the <code>site-reviews/support/deprecated/v4</code> filter hook. If this hook returns <code>false</code> then the plugin will skip deprecated checks. If the plugin console does not show any deprecated notices, then it should be safe to use this hook for increased performance.</li>
13
  <li>Added WordPress v5.3 compatibility</li>
14
  </ul>
15
+ <h4>🛠 Tweaks</h4>
16
  <ul>
17
  <li>Optimised translation performance</li>
18
  <li>Rebuilt the WordPress Editor Blocks</li>
19
  </ul>
20
+ <h4>🐞 Bugs Fixed</h4>
21
  <ul>
22
  <li>Fixed pagination of reviews on static front page</li>
23
  <li>Fixed performance issues related to IP Address detection</li>
views/pages/welcome/whatsnew/v43.php CHANGED
@@ -7,18 +7,18 @@
7
  </h3>
8
  <div id="welcome-v430" class="inside">
9
  <p><em>Initial Release Date &mdash; January 12th, 2020</em></p>
10
- <h4>New Features</h4>
11
  <ul>
12
  <li>Added migration tool for cases when auto-migration is not triggered when upgrading to version 4</li>
13
  <li>Added permission validation to the review form</li>
14
  <li>Added update functionality for add-ons</li>
15
  </ul>
16
- <h4>Tweaks</h4>
17
  <ul>
18
  <li>Rebuilt the star rating to account for a MAX_RATING greater than 5</li>
19
  <li>Updated the version requirement checks</li>
20
  </ul>
21
- <h4>Bugs Fixed</h4>
22
  <ul>
23
  <li>Fixed assigned_to links</li>
24
  <li>Fixed avatar regeneration</li>
7
  </h3>
8
  <div id="welcome-v430" class="inside">
9
  <p><em>Initial Release Date &mdash; January 12th, 2020</em></p>
10
+ <h4>✨ New Features</h4>
11
  <ul>
12
  <li>Added migration tool for cases when auto-migration is not triggered when upgrading to version 4</li>
13
  <li>Added permission validation to the review form</li>
14
  <li>Added update functionality for add-ons</li>
15
  </ul>
16
+ <h4>🛠 Tweaks</h4>
17
  <ul>
18
  <li>Rebuilt the star rating to account for a MAX_RATING greater than 5</li>
19
  <li>Updated the version requirement checks</li>
20
  </ul>
21
+ <h4>🐞 Bugs Fixed</h4>
22
  <ul>
23
  <li>Fixed assigned_to links</li>
24
  <li>Fixed avatar regeneration</li>
views/pages/welcome/whatsnew/v44.php CHANGED
@@ -7,17 +7,17 @@
7
  </h3>
8
  <div id="welcome-v440" class="inside">
9
  <p><em>Initial Release Date &mdash; February 12th, 2020</em></p>
10
- <h4>New Features</h4>
11
  <ul>
12
  <li>Added an invitation to try the unreleased beta version of the Images add-on</li>
13
  <li>Added custom review capabilities which can be added to your user roles. By default, these capabilities will mirror the capabilities of your posts. For example, if a user role has permission to edit others posts, then that role will also have permission to edit other users reviews.</li>
14
  </ul>
15
- <h4>Tweaks</h4>
16
  <ul>
17
  <li>Updated the Common Problems and Solutions section on the Help page</li>
18
  <li>Updated the FAQ page</li>
19
  </ul>
20
- <h4>Bugs Fixed</h4>
21
  <ul>
22
  <li>Fixed compatibility with Fusion Builder</li>
23
  <li>Fixed plugin migrations</li>
7
  </h3>
8
  <div id="welcome-v440" class="inside">
9
  <p><em>Initial Release Date &mdash; February 12th, 2020</em></p>
10
+ <h4>✨ New Features</h4>
11
  <ul>
12
  <li>Added an invitation to try the unreleased beta version of the Images add-on</li>
13
  <li>Added custom review capabilities which can be added to your user roles. By default, these capabilities will mirror the capabilities of your posts. For example, if a user role has permission to edit others posts, then that role will also have permission to edit other users reviews.</li>
14
  </ul>
15
+ <h4>🛠 Tweaks</h4>
16
  <ul>
17
  <li>Updated the Common Problems and Solutions section on the Help page</li>
18
  <li>Updated the FAQ page</li>
19
  </ul>
20
+ <h4>🐞 Bugs Fixed</h4>
21
  <ul>
22
  <li>Fixed compatibility with Fusion Builder</li>
23
  <li>Fixed plugin migrations</li>
views/pages/welcome/whatsnew/v45.php CHANGED
@@ -7,13 +7,13 @@
7
  </h3>
8
  <div id="welcome-v450" class="inside">
9
  <p><em>Initial Release Date &mdash; February 24th, 2020</em></p>
10
- <h4>Changes</h4>
11
  <ul>
12
  <li>Updated the author column on the "All Reviews" page to link to the author if they exist</li>
13
  <li>Updated the Rebusify integration as they have rebranded to <a href="https://trustalyze.com?ref=105">Trustalyze</a></li>
14
  <li>Updated Trustalyze integration notice</li>
15
  </ul>
16
- <h4>Bugs Fixed</h4>
17
  <ul>
18
  <li>Fixed addon license setting</li>
19
  <li>Fixed compatibility with misbehaving plugins that break the Settings tabs</li>
7
  </h3>
8
  <div id="welcome-v450" class="inside">
9
  <p><em>Initial Release Date &mdash; February 24th, 2020</em></p>
10
+ <h4>📢 Changes</h4>
11
  <ul>
12
  <li>Updated the author column on the "All Reviews" page to link to the author if they exist</li>
13
  <li>Updated the Rebusify integration as they have rebranded to <a href="https://trustalyze.com?ref=105">Trustalyze</a></li>
14
  <li>Updated Trustalyze integration notice</li>
15
  </ul>
16
+ <h4>🐞 Bugs Fixed</h4>
17
  <ul>
18
  <li>Fixed addon license setting</li>
19
  <li>Fixed compatibility with misbehaving plugins that break the Settings tabs</li>
views/pages/welcome/whatsnew/v46.php CHANGED
@@ -7,16 +7,16 @@
7
  </h3>
8
  <div id="welcome-v450" class="inside">
9
  <p><em>Initial Release Date &mdash; April 22nd, 2020</em></p>
10
- <h4>New Features</h4>
11
  <ul>
12
  <li>Added an option to disable paginated URLs (see Settings > Reviews page)</li>
13
  <li>Added the <code>glsr_get_rating()</code> helper function (see Help > Functions page)</li>
14
  </ul>
15
- <h4>Changes</h4>
16
  <ul>
17
  <li>Updated Trustalyze integration</li>
18
  </ul>
19
- <h4>Bugs Fixed</h4>
20
  <ul>
21
  <li>Fixed PHP Notice introduced in WP 5.5</li>
22
  <li>Fixed PHPMailer issue introduced in WP v5.5</li>
7
  </h3>
8
  <div id="welcome-v450" class="inside">
9
  <p><em>Initial Release Date &mdash; April 22nd, 2020</em></p>
10
+ <h4>✨ New Features</h4>
11
  <ul>
12
  <li>Added an option to disable paginated URLs (see Settings > Reviews page)</li>
13
  <li>Added the <code>glsr_get_rating()</code> helper function (see Help > Functions page)</li>
14
  </ul>
15
+ <h4>📢 Changes</h4>
16
  <ul>
17
  <li>Updated Trustalyze integration</li>
18
  </ul>
19
+ <h4>🐞 Bugs Fixed</h4>
20
  <ul>
21
  <li>Fixed PHP Notice introduced in WP 5.5</li>
22
  <li>Fixed PHPMailer issue introduced in WP v5.5</li>
views/pages/welcome/whatsnew/v50.php CHANGED
@@ -24,7 +24,7 @@
24
  <li>The Review Details metabox now allows you to modify any value</li>
25
  <li>The <code>site-reviews/after/submission</code> javascript event now contains the submitted review</li>
26
  </ul>
27
- <h4>♻️ Changes</h4>
28
  <ul>
29
  <li>Changed the settings to use the WordPress "Disallowed Comment Keys" by default</li>
30
  <li>Increased the minimum PHP version to 5.6.20</li>
24
  <li>The Review Details metabox now allows you to modify any value</li>
25
  <li>The <code>site-reviews/after/submission</code> javascript event now contains the submitted review</li>
26
  </ul>
27
+ <h4>📢 Changes</h4>
28
  <ul>
29
  <li>Changed the settings to use the WordPress "Disallowed Comment Keys" by default</li>
30
  <li>Increased the minimum PHP version to 5.6.20</li>
views/pages/welcome/whatsnew/v51.php CHANGED
@@ -1,6 +1,6 @@
1
- <div class="glsr-card postbox is-fullwidth open">
2
  <h3 class="glsr-card-heading">
3
- <button type="button" class="glsr-accordion-trigger" aria-expanded="true" aria-controls="welcome-v510">
4
  <span class="title">Version 5.1</span>
5
  <span class="icon"></span>
6
  </button>
1
+ <div class="glsr-card postbox is-fullwidth">
2
  <h3 class="glsr-card-heading">
3
+ <button type="button" class="glsr-accordion-trigger" aria-expanded="false" aria-controls="welcome-v510">
4
  <span class="title">Version 5.1</span>
5
  <span class="icon"></span>
6
  </button>
views/pages/welcome/whatsnew/v52.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="glsr-card postbox is-fullwidth open">
2
+ <h3 class="glsr-card-heading">
3
+ <button type="button" class="glsr-accordion-trigger" aria-expanded="true" aria-controls="welcome-v520">
4
+ <span class="title">Version 5.2</span>
5
+ <span class="icon"></span>
6
+ </button>
7
+ </h3>
8
+ <div id="welcome-v520" class="inside">
9
+ <p><em>Initial Release Date &mdash; November 6th, 2020</em></p>
10
+ <h4>✨ New Features</h4>
11
+ <ul>
12
+ <li>Added Notification Template tags for assigned categories, posts, and users</li>
13
+ <li>Added Review Assignment setting</li>
14
+ </ul>
15
+ <h4>📢 Changes</h4>
16
+ <ul>
17
+ <li>Changed review assignment in SQL queries to use strict assignments by default (it was previously using loose assignments, use the new "Review Assignment" setting to change this back)</li>
18
+ </ul>
19
+ <h4>🐞 Bugs Fixed</h4>
20
+ <ul>
21
+ <li>Fixed addons notice styling and placement</li>
22
+ <li>Fixed Bulk Editing of reviews that are assigned to post types or users</li>
23
+ <li>Fixed compatibility issue with the Elementor Pro Popups</li>
24
+ <li>Fixed Multibyte String support</li>
25
+ <li>Fixed Multisite compatibility</li>
26
+ <li>Fixed pagination URLs when used on the homepage</li>
27
+ <li>Fixed plugin file paths on IIS Windows servers</li>
28
+ <li>Fixed plugin migrations to work better with the W3 Total Cache plugin</li>
29
+ <li>Fixed rating validation when using a custom maximum rating value</li>
30
+ <li>Fixed review limits validation for assigned reviews</li>
31
+ <li>Fixed review migration of invalid 3rd-party reviews (reviews that were previously imported incorrectly)</li>
32
+ <li>Fixed review name and email fallback values to use those of the logged-in user</li>
33
+ <li>Fixed strict standard notices in PHP 5.6</li>
34
+ <li>Fixed the glsr_create_review helper function validation</li>
35
+ <li>Fixed the submission date of reviews, it now uses the timezone offset in the WordPress settings</li>
36
+ </ul>
37
+ </div>
38
+ </div>
views/partials/notices/addons.php CHANGED
@@ -20,7 +20,7 @@
20
  </div>
21
  <p>
22
  <strong><?= _x('Add-ons for Site Reviews are now available!', 'admin-text', 'site-reviews'); ?></strong>
23
- <br><?= _x('Allow people to submit captioned images with their review, and sort, filter, and search reviews.', 'admin-text', 'site-reviews'); ?>
24
  </p>
25
  <p>
26
  <a class="components-button is-secondary is-small" href="<?= admin_url('edit.php?post_type='.glsr()->post_type.'&page=addons'); ?>"><?= _x('Check Them Out', 'admin-text', 'site-reviews'); ?> →</a>
20
  </div>
21
  <p>
22
  <strong><?= _x('Add-ons for Site Reviews are now available!', 'admin-text', 'site-reviews'); ?></strong>
23
+ <br><?= _x('Allow people to add captioned images to their reviews; provide sorting, filtering, and search functionality; and integrate with the Trustalyze platform.', 'admin-text', 'site-reviews'); ?>
24
  </p>
25
  <p>
26
  <a class="components-button is-secondary is-small" href="<?= admin_url('edit.php?post_type='.glsr()->post_type.'&page=addons'); ?>"><?= _x('Check Them Out', 'admin-text', 'site-reviews'); ?> →</a>