Plugin Directory

Changeset 3095958


Ignore:
Timestamp:
06/01/2024 07:01:42 AM (22 months ago)
Author:
hcaptcha
Message:

Update to version 4.2.0 from GitHub

Location:
hcaptcha-for-forms-and-more
Files:
20 added
4 deleted
72 edited
1 copied

Legend:

Unmodified
Added
Removed
  • hcaptcha-for-forms-and-more/tags/4.2.0/assets/css/settings-base.css

    r3086102 r3095958  
    4545}
    4646
     47.hcaptcha-header-bar {
     48    display: flex;
     49    justify-content: space-between;
     50    align-items: center;
     51    margin: 0;
     52}
     53
    4754#hcaptcha-options h2 {
    4855    font-size: 1.5em;
     
    269276        z-index: 1;
    270277    }
    271 }
     278
     279    .hcaptcha-settings-tab {
     280        margin-right: 15px;
     281    }
     282}
  • hcaptcha-for-forms-and-more/tags/4.2.0/assets/css/settings-base.min.css

    r3086102 r3095958  
    1 body.settings_page_hcaptcha{background:#f0f2f5;color:#5c6f8a}.wrap h1.hcaptcha-settings-header{align-items:center;display:flex;font-size:34px;font-weight:700}.hcaptcha-logo{height:64px;margin:10px 5px 10px 0}.hcaptcha-settings-tabs{background:#fff;display:flex;flex-wrap:wrap;justify-content:space-between;line-height:4.5em;margin:10px -20px 0;padding:0 20px}.hcaptcha-settings-tab{border-bottom:2px solid transparent;color:#646970;display:inline-block;font-size:1.1em;margin-right:30px;text-decoration:none}.hcaptcha-settings-tab:hover{border-bottom-color:#025176!important;border-bottom:2px solid;color:#666}.hcaptcha-settings-tab.active{border-bottom:2px solid #0075ab}#hcaptcha-options h2{color:#5c6f8a;font-size:1.5em}#hcaptcha-options h3{color:#5c6f8a;margin:1.5em 0 1em}#hcaptcha-options .notice-dismiss:before{color:#5c6f8a}#hcaptcha-options table tbody tr td{margin:0;padding:0;position:relative}#hcaptcha-options table tr td input[type=checkbox]{border:none;box-shadow:none;display:inline;height:1.25rem;margin:-.125rem .5rem 0 0;width:2.3611rem}#hcaptcha-options table tr td input[type=checkbox]:before{background:url(../images/checkbox-off.svg);background-size:cover;content:"";display:inline-block;height:1.25rem;margin:0;width:2.3611rem}#hcaptcha-options table tr td input[type=checkbox]:checked:before{background:no-repeat url(../images/checkbox-on.svg);background-size:cover}#hcaptcha-options fieldset:disabled{color:#dadada}#hcaptcha-options .button-primary{background-color:#026593;border-color:#026593;color:#fff}#hcaptcha-options .button-primary:hover{background-color:#025176}#hcaptcha-options .button-secondary{background-color:#fff;border-color:#026593;color:#026593}#hcaptcha-options .button-secondary:hover{background-color:#ccc}#hcaptcha-options a{color:#0075ab}#hcaptcha-navigation a{border-color:#0075ab}#hcaptcha-options a.hcaptcha-settings-tab{color:#5c6f8a}#hcaptcha-options .helper:before{background:#5c6f8a;border-radius:1.2em;color:#fff;content:"?";height:1.2em;position:absolute;right:0;text-align:center;top:0;transform:translateY(-26px);width:1.2em}#hcaptcha-options fieldset+.helper:before{top:50%;transform:translate(25px,-.8em)}#hcaptcha-options .helper .helper-content{background:#5c6f8a;box-sizing:border-box;color:#f0f2f5;display:none;padding:.5em 1em;position:absolute;right:0;top:0;transform:translate(1px,10px);width:100%}#hcaptcha-options fieldset+.helper .helper-content{top:50%;transform:translate(25px,25px);width:calc(100% + 25px)}#hcaptcha-options .helper:hover{cursor:help}#hcaptcha-options .helper:hover .helper-content{display:block;z-index:1}#hcaptcha-options .helper .helper-content:after{border:10px solid transparent;border-bottom-color:#5c6f8a;content:"";position:absolute;right:0;top:0;transform:translateY(-100%)}#hcaptcha-options .helper .helper-content a{color:#fff}#hcaptcha-message{box-sizing:border-box}#hcaptcha-message p{font-size:13px;font-weight:600;line-height:1.5;margin:.5em 0}@keyframes blink{0%{opacity:1}16.7%{opacity:0}33.3%{opacity:1}50%{opacity:0}66.7%{opacity:1}83.3%{opacity:0}to{opacity:1}}.blink{animation:blink 3s linear}.hcaptcha-hide{display:none}.hcaptcha-excerpt{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hcaptcha-excerpt:hover .hcaptcha-hide{background:#5c6f8a;border:1px solid #c3c4c7;border-radius:6px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.1);color:#f0f2f5;display:block;left:0;max-width:300px;padding:8px 10px;position:absolute;text-align:center;top:0;white-space:normal;width:max-content;z-index:1}@media (max-width:782px){.hcaptcha-settings-tabs{margin:10px -12px 0 -10px;padding:0 12px 0 10px}}@media (max-width:600px){#hcaptcha-options table tbody{grid-template-columns:1fr}#hcaptcha-options table tbody tr{position:relative}#hcaptcha-options fieldset+.helper:before{transform:translateY(-.7em)}#hcaptcha-options fieldset+.helper .helper-content{transform:translateY(25px);width:100%}#hcaptcha-options .helper{z-index:1}}
     1body.settings_page_hcaptcha{background:#f0f2f5;color:#5c6f8a}.wrap h1.hcaptcha-settings-header{align-items:center;display:flex;font-size:34px;font-weight:700}.hcaptcha-logo{height:64px;margin:10px 5px 10px 0}.hcaptcha-settings-tabs{background:#fff;display:flex;flex-wrap:wrap;justify-content:space-between;line-height:4.5em;margin:10px -20px 0;padding:0 20px}.hcaptcha-settings-tab{border-bottom:2px solid transparent;color:#646970;display:inline-block;font-size:1.1em;margin-right:30px;text-decoration:none}.hcaptcha-settings-tab:hover{border-bottom-color:#025176!important;border-bottom:2px solid;color:#666}.hcaptcha-settings-tab.active{border-bottom:2px solid #0075ab}.hcaptcha-header-bar{align-items:center;display:flex;justify-content:space-between;margin:0}#hcaptcha-options h2{color:#5c6f8a;font-size:1.5em}#hcaptcha-options h3{color:#5c6f8a;margin:1.5em 0 1em}#hcaptcha-options .notice-dismiss:before{color:#5c6f8a}#hcaptcha-options table tbody tr td{margin:0;padding:0;position:relative}#hcaptcha-options table tr td input[type=checkbox]{border:none;box-shadow:none;display:inline;height:1.25rem;margin:-.125rem .5rem 0 0;width:2.3611rem}#hcaptcha-options table tr td input[type=checkbox]:before{background:url(../images/checkbox-off.svg);background-size:cover;content:"";display:inline-block;height:1.25rem;margin:0;width:2.3611rem}#hcaptcha-options table tr td input[type=checkbox]:checked:before{background:no-repeat url(../images/checkbox-on.svg);background-size:cover}#hcaptcha-options fieldset:disabled{color:#dadada}#hcaptcha-options .button-primary{background-color:#026593;border-color:#026593;color:#fff}#hcaptcha-options .button-primary:hover{background-color:#025176}#hcaptcha-options .button-secondary{background-color:#fff;border-color:#026593;color:#026593}#hcaptcha-options .button-secondary:hover{background-color:#ccc}#hcaptcha-options a{color:#0075ab}#hcaptcha-navigation a{border-color:#0075ab}#hcaptcha-options a.hcaptcha-settings-tab{color:#5c6f8a}#hcaptcha-options .helper:before{background:#5c6f8a;border-radius:1.2em;color:#fff;content:"?";height:1.2em;position:absolute;right:0;text-align:center;top:0;transform:translateY(-26px);width:1.2em}#hcaptcha-options fieldset+.helper:before{top:50%;transform:translate(25px,-.8em)}#hcaptcha-options .helper .helper-content{background:#5c6f8a;box-sizing:border-box;color:#f0f2f5;display:none;padding:.5em 1em;position:absolute;right:0;top:0;transform:translate(1px,10px);width:100%}#hcaptcha-options fieldset+.helper .helper-content{top:50%;transform:translate(25px,25px);width:calc(100% + 25px)}#hcaptcha-options .helper:hover{cursor:help}#hcaptcha-options .helper:hover .helper-content{display:block;z-index:1}#hcaptcha-options .helper .helper-content:after{border:10px solid transparent;border-bottom-color:#5c6f8a;content:"";position:absolute;right:0;top:0;transform:translateY(-100%)}#hcaptcha-options .helper .helper-content a{color:#fff}#hcaptcha-message{box-sizing:border-box}#hcaptcha-message p{font-size:13px;font-weight:600;line-height:1.5;margin:.5em 0}@keyframes blink{0%{opacity:1}16.7%{opacity:0}33.3%{opacity:1}50%{opacity:0}66.7%{opacity:1}83.3%{opacity:0}to{opacity:1}}.blink{animation:blink 3s linear}.hcaptcha-hide{display:none}.hcaptcha-excerpt{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hcaptcha-excerpt:hover .hcaptcha-hide{background:#5c6f8a;border:1px solid #c3c4c7;border-radius:6px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.1);color:#f0f2f5;display:block;left:0;max-width:300px;padding:8px 10px;position:absolute;text-align:center;top:0;white-space:normal;width:max-content;z-index:1}@media (max-width:782px){.hcaptcha-settings-tabs{margin:10px -12px 0 -10px;padding:0 12px 0 10px}}@media (max-width:600px){#hcaptcha-options table tbody{grid-template-columns:1fr}#hcaptcha-options table tbody tr{position:relative}#hcaptcha-options fieldset+.helper:before{transform:translateY(-.7em)}#hcaptcha-options fieldset+.helper .helper-content{transform:translateY(25px);width:100%}#hcaptcha-options .helper{z-index:1}.hcaptcha-settings-tab{margin-right:15px}}
  • hcaptcha-for-forms-and-more/tags/4.2.0/assets/js/events.js

    r3086102 r3095958  
    22
    33/**
     4 * @param HCaptchaEventsObject.failed
     5 * @param HCaptchaEventsObject.failedLabel
    46 * @param HCaptchaEventsObject.succeed
    5  * @param HCaptchaEventsObject.failed
    67 * @param HCaptchaEventsObject.succeedLabel
    7  * @param HCaptchaEventsObject.failedLabel
     8 * @param HCaptchaEventsObject.unit
    89 */
    910document.addEventListener( 'DOMContentLoaded', function() {
     
    4748                        },
    4849                        tooltipFormat: 'dd.MM.yyyy HH:mm',
     50                        unit: HCaptchaEventsObject.unit,
    4951                    },
    5052                },
  • hcaptcha-for-forms-and-more/tags/4.2.0/assets/js/events.min.js

    r3086102 r3095958  
    1 document.addEventListener("DOMContentLoaded",(function(){var e=document.getElementById("eventsChart"),t=window.innerWidth>600?3:2;new Chart(e,{type:"bar",data:{datasets:[{label:HCaptchaEventsObject.succeedLabel,data:HCaptchaEventsObject.succeed,borderWidth:1},{label:HCaptchaEventsObject.failedLabel,data:HCaptchaEventsObject.failed,borderWidth:1}]},options:{responsive:!0,maintainAspectRatio:!0,aspectRatio:t,scales:{x:{type:"time",time:{displayFormats:{millisecond:"HH:mm:ss",second:"HH:mm:ss",minute:"HH:mm",hour:"HH:mm",day:"dd.MM.yyyy",week:"dd.MM.yyyy",month:"dd.MM.yyyy",quarter:"dd.MM.yyyy",year:"dd.MM.yyyy"},tooltipFormat:"dd.MM.yyyy HH:mm"}},y:{beginAtZero:!0,ticks:{precision:0}}}}})}));
     1document.addEventListener("DOMContentLoaded",(function(){var e=document.getElementById("eventsChart"),t=window.innerWidth>600?3:2;new Chart(e,{type:"bar",data:{datasets:[{label:HCaptchaEventsObject.succeedLabel,data:HCaptchaEventsObject.succeed,borderWidth:1},{label:HCaptchaEventsObject.failedLabel,data:HCaptchaEventsObject.failed,borderWidth:1}]},options:{responsive:!0,maintainAspectRatio:!0,aspectRatio:t,scales:{x:{type:"time",time:{displayFormats:{millisecond:"HH:mm:ss",second:"HH:mm:ss",minute:"HH:mm",hour:"HH:mm",day:"dd.MM.yyyy",week:"dd.MM.yyyy",month:"dd.MM.yyyy",quarter:"dd.MM.yyyy",year:"dd.MM.yyyy"},tooltipFormat:"dd.MM.yyyy HH:mm",unit:HCaptchaEventsObject.unit}},y:{beginAtZero:!0,ticks:{precision:0}}}}})}));
  • hcaptcha-for-forms-and-more/tags/4.2.0/assets/js/forms.js

    r3086102 r3095958  
    44 * @param HCaptchaFormsObject.served
    55 * @param HCaptchaFormsObject.servedLabel
     6 * @param HCaptchaFormsObject.unit
    67 */
    78document.addEventListener( 'DOMContentLoaded', function() {
     
    4142                        },
    4243                        tooltipFormat: 'dd.MM.yyyy HH:mm',
     44                        unit: HCaptchaFormsObject.unit,
    4345                    },
    4446                },
  • hcaptcha-for-forms-and-more/tags/4.2.0/assets/js/forms.min.js

    r3086102 r3095958  
    1 document.addEventListener("DOMContentLoaded",(function(){var e=document.getElementById("formsChart"),t=window.innerWidth>600?3:2;new Chart(e,{type:"bar",data:{datasets:[{label:HCaptchaFormsObject.servedLabel,backgroundColor:"rgba(2,101,147,0.5)",data:HCaptchaFormsObject.served,borderWidth:1}]},options:{responsive:!0,maintainAspectRatio:!0,aspectRatio:t,scales:{x:{type:"time",time:{displayFormats:{millisecond:"HH:mm:ss",second:"HH:mm:ss",minute:"HH:mm",hour:"HH:mm",day:"dd.MM.yyyy",week:"dd.MM.yyyy",month:"dd.MM.yyyy",quarter:"dd.MM.yyyy",year:"dd.MM.yyyy"},tooltipFormat:"dd.MM.yyyy HH:mm"}},y:{beginAtZero:!0,ticks:{precision:0}}}}})}));
     1document.addEventListener("DOMContentLoaded",(function(){var t=document.getElementById("formsChart"),e=window.innerWidth>600?3:2;new Chart(t,{type:"bar",data:{datasets:[{label:HCaptchaFormsObject.servedLabel,backgroundColor:"rgba(2,101,147,0.5)",data:HCaptchaFormsObject.served,borderWidth:1}]},options:{responsive:!0,maintainAspectRatio:!0,aspectRatio:e,scales:{x:{type:"time",time:{displayFormats:{millisecond:"HH:mm:ss",second:"HH:mm:ss",minute:"HH:mm",hour:"HH:mm",day:"dd.MM.yyyy",week:"dd.MM.yyyy",month:"dd.MM.yyyy",quarter:"dd.MM.yyyy",year:"dd.MM.yyyy"},tooltipFormat:"dd.MM.yyyy HH:mm",unit:HCaptchaFormsObject.unit}},y:{beginAtZero:!0,ticks:{precision:0}}}}})}));
  • hcaptcha-for-forms-and-more/tags/4.2.0/assets/js/general.js

    r3081325 r3095958  
    104104
    105105    function getCleanConsoleLogs() {
    106         const ignore = [ 'recaptchacompat disabled' ];
     106        const ignore = [
     107            'recaptchacompat disabled',
     108            'Missing sitekey - https://hcaptcha.com/docs/configuration#jsapi',
     109        ];
    107110        const logs = [];
    108111
     
    200203        const sampleHCaptcha = document.querySelector( '#hcaptcha-options .h-captcha' );
    201204        sampleHCaptcha.innerHTML = '';
     205
     206        // Map the theme to the palette mode.
     207        params.theme = params?.theme?.palette?.mode;
     208
     209        if ( ! params.theme ) {
     210            // Remove the theme if it's not set.
     211            delete params.theme;
     212        }
    202213
    203214        for ( const key in params ) {
  • hcaptcha-for-forms-and-more/tags/4.2.0/assets/js/general.min.js

    r3081325 r3095958  
    1 (()=>{var t={};function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},e(t)}t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}();var a=function(a){var n="#hcaptcha-message",c=a(n),o=a("form.hcaptcha-general"),r=a('[name="hcaptcha_settings[site_key]"]'),i=a('[name="hcaptcha_settings[secret_key]"]'),s=a("#check_config"),l=a("#reset_notifications"),h=a('[name="hcaptcha_settings[theme]"]'),p=a('[name="hcaptcha_settings[size]"]'),u=a('[name="hcaptcha_settings[language]"]'),d=a('[name="hcaptcha_settings[mode]"]'),f=a('[name="hcaptcha_settings[custom_themes][]"]'),v=a(".hcaptcha-general-custom-prop select"),m=a(".hcaptcha-general-custom-value input"),g=a('[name="hcaptcha_settings[config_params]"]'),b=a(".hcaptcha-section-enterprise + table input"),y=a('[name="hcaptcha_settings[recaptcha_compat_off][]"]'),C=o.find("#submit"),j={},O=r.val(),H=i.val(),k=T();j[HCaptchaGeneralObject.modeLive]=HCaptchaGeneralObject.siteKey,j[HCaptchaGeneralObject.modeTestPublisher]=HCaptchaGeneralObject.modeTestPublisherSiteKey,j[HCaptchaGeneralObject.modeTestEnterpriseSafeEndUser]=HCaptchaGeneralObject.modeTestEnterpriseSafeEndUserSiteKey,j[HCaptchaGeneralObject.modeTestEnterpriseBotDetected]=HCaptchaGeneralObject.modeTestEnterpriseBotDetectedSiteKey;var G=!1,S=!1,_=[];function w(t){var e={};return t.each((function(){var t=a(this),n=t.attr("name").replace(/hcaptcha_settings\[(.+)]/,"$1");e[n]=t.val()})),e}function T(){return w(b)}function A(){c.remove(),a('<div id="hcaptcha-message"></div>').insertAfter("#hcaptcha-options h2"),c=a(n)}function E(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(t=void 0===t?"":String(t),t=(t+="\n"+function(){for(var t=["recaptchacompat disabled"],e=[],a=0;a<_.length;a++){for(var n=_[a],c=n[0],o=n[1],r=Object.keys(o),i=[],s=0;s<r.length;s++){var l=o[s];"string"==typeof l&&-1===t.indexOf(l)&&i.push([c,l].join(" "))}e.push(i.join("\n"))}return _=[],e.join("\n")}()).trim()){c.removeClass(),c.addClass(e+" notice is-dismissible");var n=t.split("\n").map((function(t){return"<p>".concat(t,"</p>")}));c.html(n.join("")),a(document).trigger("wp-updates-notice-added");var o=a("#wpwrap").position().top;a("html, body").animate({scrollTop:c.offset().top-o-parseInt(c.css("margin-bottom"))},1e3)}}function x(){E(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"","notice-success")}function N(){E(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"","notice-error")}function L(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=Object.assign(hCaptcha.getParams(),t);hCaptcha.setParams(e);var a=document.querySelector("#hcaptcha-options .h-captcha");for(var n in a.innerHTML="",t)a.setAttribute("data-".concat(n),"".concat(t[n]));hCaptcha.bindEvents()}function K(t,a){var n=function(t){return t&&"object"===e(t)};return n(t)&&n(a)?(Object.keys(a).forEach((function(e){var c=t[e],o=a[e];Array.isArray(c)&&Array.isArray(o)?t[e]=c.concat(o):n(c)&&n(o)?t[e]=K(Object.assign({},c),o):t[e]=o})),t):a}function U(t){var a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";for(var n in t){var c=a?"".concat(a,"--").concat(n):n;if("object"===e(t[n])&&null!==t[n])U(t[n],c);else{var o=t[n],r=c.replace(/theme--/g,""),i="".concat(r,"=").concat(o),s=v.find('option[value*="'.concat(r,'="]'));1===s.length&&(s.attr("value",i),s.is(":selected")&&m.val(o))}}}function B(){var t,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},a=g.val().trim();a=a||null;try{t=JSON.parse(a)}catch(t){return g.css("background-color","#ffabaf"),C.attr("disabled",!0),void N("Bad JSON!")}t=K(t,e),g.val(JSON.stringify(t,null,2)),U(t),f.prop("checked")||(t={sitekey:r.val(),theme:h.val(),size:p.val(),hl:u.val()}),L(t)}function P(){r.val()===O&&i.val()===H?(G=!1,A(),C.attr("disabled",!1)):G||(G=!0,N(HCaptchaGeneralObject.checkConfigNotice),C.attr("disabled",!0))}function J(t){return t=t.replace(/(http|https):\/\//,""),"https://"+new URL("https://"+t).host}!function(){_=[];var t=console.log,e=console.warn,a=console.info,n=console.error,c=console.clear;console.log=function(e){_.push(["Console log:",arguments]),t.apply(console,arguments)},console.warn=function(t){_.push(["Console warn:",arguments]),e.apply(console,arguments)},console.info=function(t){_.push(["Console info:",arguments]),a.apply(console,arguments)},console.error=function(t){_.push(["Console error:",arguments]),n.apply(console,arguments)},console.clear=function(){_=[],c()}}(),document.addEventListener("hCaptchaLoaded",(function(){N()})),s.on("click",(function(t){t.preventDefault(),""!==a(".hcaptcha-general-sample-hcaptcha iframe").attr("data-hcaptcha-response")?function(){A(),C.attr("disabled",!0);var t={action:HCaptchaGeneralObject.checkConfigAction,nonce:HCaptchaGeneralObject.checkConfigNonce,mode:d.val(),siteKey:r.val(),secretKey:i.val(),"h-captcha-response":a('textarea[name="h-captcha-response"]').val()};a.post({url:HCaptchaGeneralObject.ajaxUrl,data:t,beforeSend:function(){return x(HCaptchaGeneralObject.checkingConfigMsg)}}).done((function(t){t.success?(O=r.val(),H=i.val(),k=w(b),S=!1,x(t.data),C.attr("disabled",!1)):N(t.data)})).fail((function(t){N(t.statusText)})).always((function(){L()}))}():kaggDialog.confirm({title:HCaptchaGeneralObject.completeHCaptchaTitle,content:HCaptchaGeneralObject.completeHCaptchaContent,type:"info",buttons:{ok:{text:HCaptchaGeneralObject.OKBtnText}},onAction:function(){return window.hCaptchaReset(document.querySelector(".hcaptcha-general-sample-hcaptcha"))}})})),r.on("change",(function(t){L({sitekey:a(t.target).val()}),P()})),i.on("change",(function(){P()})),h.on("change",(function(t){L({theme:a(t.target).val()})})),p.on("change",(function(t){var e=a("#hcaptcha-invisible-notice"),n=a(t.target).val();"invisible"===n?e.show():e.hide(),L({size:n})})),u.on("change",(function(t){L({hl:a(t.target).val()})})),d.on("change",(function(t){var e=a(t.target).val();j.hasOwnProperty(e)&&(e===HCaptchaGeneralObject.modeLive?(r.attr("disabled",!1),i.attr("disabled",!1)):(r.attr("disabled",!0),i.attr("disabled",!0)),L({sitekey:j[e]}))})),f.on("change",(function(){B()})),g.on("blur",(function(){B()})),g.on("focus",(function(){g.css("background-color","unset"),C.attr("disabled",!1)})),b.on("change",(function(){!function(){var e={onload:"hCaptchaOnLoad",render:"explicit"};y.prop("checked")&&(e.recaptchacompat="off"),f.prop("checked")&&(e.custom="true");var a={asset_host:"assethost",endpoint:"endpoint",host:"host",image_host:"imghost",report_api:"reportapi",sentry:"sentry"},n=T();for(var c in a){var o=n[c].trim();o&&(e[a[c]]=encodeURIComponent(J(o)))}var r=n.api_host.trim();r=J(r=r||"js.hcaptcha.com")+"/1/api.js";var i=new URL(r);for(var s in e)i.searchParams.append(s,e[s]);document.getElementById("hcaptcha-api").remove(),delete t.g.hcaptcha,document.querySelector("#hcaptcha-options .h-captcha").innerHTML="";var l=document.getElementsByTagName("head")[0],h=document.createElement("script");h.type="text/javascript",h.id="hcaptcha-api",h.src=i.href,l.appendChild(h)}(),JSON.stringify(T())===JSON.stringify(k)?(S=!1,A(),C.attr("disabled",!1)):S||(S=!0,N(HCaptchaGeneralObject.checkConfigNotice),C.attr("disabled",!0))})),a(".hcaptcha-general h3").on("click",(function(t){var e=a(t.currentTarget);e.toggleClass("closed");var n={action:HCaptchaGeneralObject.toggleSectionAction,nonce:HCaptchaGeneralObject.toggleSectionNonce,section:e.attr("class").replaceAll(/(hcaptcha-section-|closed)/g,"").trim(),status:!e.hasClass("closed")};a.post({url:HCaptchaGeneralObject.ajaxUrl,data:n}).done((function(t){t.success||N(t.data)})).fail((function(t){N(t.statusText)}))})),s.removeAttr("name"),l.removeAttr("name"),v.removeAttr("name"),m.removeAttr("name"),v.find("option").each((function(){var t=a(this);t.val().split("=")[1]||t.attr("disabled",!0)})),m.val(""),v.on("change",(function(){var t=a(this).find("option:selected").val().split("="),e=t[0],n=t[1];"palette--mode"===e?(m.attr("type","text"),m.val(n)):(m.val(n),m.attr("type","color"))})),m.on("change",(function(t){var e=a(t.target).val(),n=v.find("option:selected"),c=n.val().split("="),o=c[0],r=e;n.val(o+"="+e),B(r=(o="theme--"+c[0]).split("--").reverse().reduce((function(t,e){var a={};return a[e]=t,a}),r))}))};window.hCaptchaGeneral=a,jQuery(document).ready(a)})();
     1(()=>{var e={};function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t(e)}e.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}();var a=function(a){var n="#hcaptcha-message",c=a(n),o=a("form.hcaptcha-general"),r=a('[name="hcaptcha_settings[site_key]"]'),i=a('[name="hcaptcha_settings[secret_key]"]'),s=a("#check_config"),l=a("#reset_notifications"),h=a('[name="hcaptcha_settings[theme]"]'),p=a('[name="hcaptcha_settings[size]"]'),u=a('[name="hcaptcha_settings[language]"]'),d=a('[name="hcaptcha_settings[mode]"]'),f=a('[name="hcaptcha_settings[custom_themes][]"]'),v=a(".hcaptcha-general-custom-prop select"),m=a(".hcaptcha-general-custom-value input"),g=a('[name="hcaptcha_settings[config_params]"]'),b=a(".hcaptcha-section-enterprise + table input"),y=a('[name="hcaptcha_settings[recaptcha_compat_off][]"]'),C=o.find("#submit"),j={},O=r.val(),H=i.val(),k=T();j[HCaptchaGeneralObject.modeLive]=HCaptchaGeneralObject.siteKey,j[HCaptchaGeneralObject.modeTestPublisher]=HCaptchaGeneralObject.modeTestPublisherSiteKey,j[HCaptchaGeneralObject.modeTestEnterpriseSafeEndUser]=HCaptchaGeneralObject.modeTestEnterpriseSafeEndUserSiteKey,j[HCaptchaGeneralObject.modeTestEnterpriseBotDetected]=HCaptchaGeneralObject.modeTestEnterpriseBotDetectedSiteKey;var G=!1,S=!1,_=[];function w(e){var t={};return e.each((function(){var e=a(this),n=e.attr("name").replace(/hcaptcha_settings\[(.+)]/,"$1");t[n]=e.val()})),t}function T(){return w(b)}function A(){c.remove(),a('<div id="hcaptcha-message"></div>').insertAfter("#hcaptcha-options h2"),c=a(n)}function E(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(e=void 0===e?"":String(e),e=(e+="\n"+function(){for(var e=["recaptchacompat disabled","Missing sitekey - https://hcaptcha.com/docs/configuration#jsapi"],t=[],a=0;a<_.length;a++){for(var n=_[a],c=n[0],o=n[1],r=Object.keys(o),i=[],s=0;s<r.length;s++){var l=o[s];"string"==typeof l&&-1===e.indexOf(l)&&i.push([c,l].join(" "))}t.push(i.join("\n"))}return _=[],t.join("\n")}()).trim()){c.removeClass(),c.addClass(t+" notice is-dismissible");var n=e.split("\n").map((function(e){return"<p>".concat(e,"</p>")}));c.html(n.join("")),a(document).trigger("wp-updates-notice-added");var o=a("#wpwrap").position().top;a("html, body").animate({scrollTop:c.offset().top-o-parseInt(c.css("margin-bottom"))},1e3)}}function x(){E(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"","notice-success")}function N(){E(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"","notice-error")}function L(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},a=Object.assign(hCaptcha.getParams(),t);hCaptcha.setParams(a);var n=document.querySelector("#hcaptcha-options .h-captcha");for(var c in n.innerHTML="",t.theme=null==t||null===(e=t.theme)||void 0===e||null===(e=e.palette)||void 0===e?void 0:e.mode,t.theme||delete t.theme,t)n.setAttribute("data-".concat(c),"".concat(t[c]));hCaptcha.bindEvents()}function K(e,a){var n=function(e){return e&&"object"===t(e)};return n(e)&&n(a)?(Object.keys(a).forEach((function(t){var c=e[t],o=a[t];Array.isArray(c)&&Array.isArray(o)?e[t]=c.concat(o):n(c)&&n(o)?e[t]=K(Object.assign({},c),o):e[t]=o})),e):a}function U(e){var a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";for(var n in e){var c=a?"".concat(a,"--").concat(n):n;if("object"===t(e[n])&&null!==e[n])U(e[n],c);else{var o=e[n],r=c.replace(/theme--/g,""),i="".concat(r,"=").concat(o),s=v.find('option[value*="'.concat(r,'="]'));1===s.length&&(s.attr("value",i),s.is(":selected")&&m.val(o))}}}function B(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},a=g.val().trim();a=a||null;try{e=JSON.parse(a)}catch(e){return g.css("background-color","#ffabaf"),C.attr("disabled",!0),void N("Bad JSON!")}e=K(e,t),g.val(JSON.stringify(e,null,2)),U(e),f.prop("checked")||(e={sitekey:r.val(),theme:h.val(),size:p.val(),hl:u.val()}),L(e)}function P(){r.val()===O&&i.val()===H?(G=!1,A(),C.attr("disabled",!1)):G||(G=!0,N(HCaptchaGeneralObject.checkConfigNotice),C.attr("disabled",!0))}function J(e){return e=e.replace(/(http|https):\/\//,""),"https://"+new URL("https://"+e).host}!function(){_=[];var e=console.log,t=console.warn,a=console.info,n=console.error,c=console.clear;console.log=function(t){_.push(["Console log:",arguments]),e.apply(console,arguments)},console.warn=function(e){_.push(["Console warn:",arguments]),t.apply(console,arguments)},console.info=function(e){_.push(["Console info:",arguments]),a.apply(console,arguments)},console.error=function(e){_.push(["Console error:",arguments]),n.apply(console,arguments)},console.clear=function(){_=[],c()}}(),document.addEventListener("hCaptchaLoaded",(function(){N()})),s.on("click",(function(e){e.preventDefault(),""!==a(".hcaptcha-general-sample-hcaptcha iframe").attr("data-hcaptcha-response")?function(){A(),C.attr("disabled",!0);var e={action:HCaptchaGeneralObject.checkConfigAction,nonce:HCaptchaGeneralObject.checkConfigNonce,mode:d.val(),siteKey:r.val(),secretKey:i.val(),"h-captcha-response":a('textarea[name="h-captcha-response"]').val()};a.post({url:HCaptchaGeneralObject.ajaxUrl,data:e,beforeSend:function(){return x(HCaptchaGeneralObject.checkingConfigMsg)}}).done((function(e){e.success?(O=r.val(),H=i.val(),k=w(b),S=!1,x(e.data),C.attr("disabled",!1)):N(e.data)})).fail((function(e){N(e.statusText)})).always((function(){L()}))}():kaggDialog.confirm({title:HCaptchaGeneralObject.completeHCaptchaTitle,content:HCaptchaGeneralObject.completeHCaptchaContent,type:"info",buttons:{ok:{text:HCaptchaGeneralObject.OKBtnText}},onAction:function(){return window.hCaptchaReset(document.querySelector(".hcaptcha-general-sample-hcaptcha"))}})})),r.on("change",(function(e){L({sitekey:a(e.target).val()}),P()})),i.on("change",(function(){P()})),h.on("change",(function(e){L({theme:a(e.target).val()})})),p.on("change",(function(e){var t=a("#hcaptcha-invisible-notice"),n=a(e.target).val();"invisible"===n?t.show():t.hide(),L({size:n})})),u.on("change",(function(e){L({hl:a(e.target).val()})})),d.on("change",(function(e){var t=a(e.target).val();j.hasOwnProperty(t)&&(t===HCaptchaGeneralObject.modeLive?(r.attr("disabled",!1),i.attr("disabled",!1)):(r.attr("disabled",!0),i.attr("disabled",!0)),L({sitekey:j[t]}))})),f.on("change",(function(){B()})),g.on("blur",(function(){B()})),g.on("focus",(function(){g.css("background-color","unset"),C.attr("disabled",!1)})),b.on("change",(function(){!function(){var t={onload:"hCaptchaOnLoad",render:"explicit"};y.prop("checked")&&(t.recaptchacompat="off"),f.prop("checked")&&(t.custom="true");var a={asset_host:"assethost",endpoint:"endpoint",host:"host",image_host:"imghost",report_api:"reportapi",sentry:"sentry"},n=T();for(var c in a){var o=n[c].trim();o&&(t[a[c]]=encodeURIComponent(J(o)))}var r=n.api_host.trim();r=J(r=r||"js.hcaptcha.com")+"/1/api.js";var i=new URL(r);for(var s in t)i.searchParams.append(s,t[s]);document.getElementById("hcaptcha-api").remove(),delete e.g.hcaptcha,document.querySelector("#hcaptcha-options .h-captcha").innerHTML="";var l=document.getElementsByTagName("head")[0],h=document.createElement("script");h.type="text/javascript",h.id="hcaptcha-api",h.src=i.href,l.appendChild(h)}(),JSON.stringify(T())===JSON.stringify(k)?(S=!1,A(),C.attr("disabled",!1)):S||(S=!0,N(HCaptchaGeneralObject.checkConfigNotice),C.attr("disabled",!0))})),a(".hcaptcha-general h3").on("click",(function(e){var t=a(e.currentTarget);t.toggleClass("closed");var n={action:HCaptchaGeneralObject.toggleSectionAction,nonce:HCaptchaGeneralObject.toggleSectionNonce,section:t.attr("class").replaceAll(/(hcaptcha-section-|closed)/g,"").trim(),status:!t.hasClass("closed")};a.post({url:HCaptchaGeneralObject.ajaxUrl,data:n}).done((function(e){e.success||N(e.data)})).fail((function(e){N(e.statusText)}))})),s.removeAttr("name"),l.removeAttr("name"),v.removeAttr("name"),m.removeAttr("name"),v.find("option").each((function(){var e=a(this);e.val().split("=")[1]||e.attr("disabled",!0)})),m.val(""),v.on("change",(function(){var e=a(this).find("option:selected").val().split("="),t=e[0],n=e[1];"palette--mode"===t?(m.attr("type","text"),m.val(n)):(m.val(n),m.attr("type","color"))})),m.on("change",(function(e){var t=a(e.target).val(),n=v.find("option:selected"),c=n.val().split("="),o=c[0],r=t;n.val(o+"="+t),B(r=(o="theme--"+c[0]).split("--").reverse().reduce((function(e,t){var a={};return a[t]=e,a}),r))}))};window.hCaptchaGeneral=a,jQuery(document).ready(a)})();
  • hcaptcha-for-forms-and-more/tags/4.2.0/assets/js/integrations.js

    r3064004 r3095958  
    156156        }
    157157
     158        function updateActivationStati( stati ) {
     159            const $tables = $( '.form-table' );
     160
     161            for ( const [ key, status ] of Object.entries( stati ) ) {
     162                const statusClass = 'hcaptcha-integrations-' + key.replace( /_/g, '-' );
     163
     164                const $tr = $( `tr.${ statusClass }` );
     165                const currStatus = isActiveTable( $tr.closest( '.form-table' ) );
     166
     167                if ( currStatus !== status ) {
     168                    const $toTable = $tables.eq( status ? 0 : 1 );
     169                    const alt = $tr.find( '.hcaptcha-integrations-logo img' ).attr( 'alt' );
     170
     171                    insertIntoTable( $toTable, alt, $tr );
     172                }
     173            }
     174        }
     175
    158176        function toggleActivation() {
    159177            const activateClass = activate ? 'on' : 'off';
     
    175193                data,
    176194            } )
     195                /**
     196                 * @param {Object} response.data
     197                 * @param {Object} response.data.defaultTheme
     198                 * @param {Object} response.data.message
     199                 * @param {Object} response.data.stati
     200                 * @param {Object} response.data.themes
     201                 * @param {Object} response.success
     202                 */
    177203                .done( function( response ) {
    178204                    if ( response.success === undefined ) {
     
    201227                    insertIntoTable( $table, alt, $tr );
    202228                    showSuccessMessage( response.data.message );
     229                    updateActivationStati( response.data.stati );
    203230
    204231                    $( 'html, body' ).animate(
     
    330357            const search = $search.val().trim().toLowerCase();
    331358            const $logo = $( '.hcaptcha-integrations-logo img' );
     359            let $trFirst = null;
    332360
    333361            $logo.each( function( i, el ) {
     
    342370                if ( $el.data( 'label' ).toLowerCase().includes( search ) ) {
    343371                    $tr.show();
     372                    $trFirst = $trFirst ?? $tr;
    344373                } else {
    345374                    $tr.hide();
    346375                }
    347376            } );
     377
     378            if ( ! $trFirst ) {
     379                return;
     380            }
     381
     382            const scrollTop = $trFirst.offset().top + $trFirst.outerHeight() - $( window ).height() + 5;
     383
     384            $( 'html' ).stop().animate(
     385                { scrollTop },
     386                1000
     387            );
    348388        },
    349389        100
  • hcaptcha-for-forms-and-more/tags/4.2.0/assets/js/integrations.min.js

    r3064004 r3095958  
    1 (()=>{var t=function(t){var e="#hcaptcha-message",a=t(e),n=t("#wpwrap"),i=t("#adminmenuwrap"),o=t("#hcaptcha-integrations-search");function c(e,o){a.removeClass(),a.addClass(o+" notice settings-error is-dismissible"),a.html("<p>".concat(e,"</p>")),t(document).trigger("wp-updates-notice-added");var c=a.clone();a.css("visibility","hidden"),c.css("margin","0px"),c.css("top",n.position().top),c.css("z-index","999999");var s="block"===i.css("display")?i.width():0;c.css("left",s),c.width(t(window).width()-s),c.css("position","fixed"),t("body").append(c),setTimeout((function(){a.css("visibility","unset"),c.remove()}),3e3)}function s(t){c(t,"notice-error")}function r(e,a,n){var i=!1,o=a.toLowerCase(),c=!function(t){return t.is(jQuery(".form-table").eq(0))}(e),s=n.find("fieldset");s.attr("disabled",c),s.find("input").attr("disabled",c),e.find("tbody").children().each((function(e,a){var c=t(a).find(".hcaptcha-integrations-logo img").attr("alt");if((c=(c=c||"").replace(" Logo","")).toLowerCase()>o)return n.insertBefore(t(a)),i=!0,!1})),i||e.find("tbody").append(n)}t(".form-table img").on("click",(function(i){function o(){var e,i,o=u?"on":"off",l=(i=document.querySelector(".kagg-dialog select"))&&null!==(e=i.value)&&void 0!==e?e:"",f={action:HCaptchaIntegrationsObject.action,nonce:HCaptchaIntegrationsObject.nonce,activate:u,entity:d,status:g,newTheme:l};p.addClass(o),t.post({url:HCaptchaIntegrationsObject.ajaxUrl,data:f}).done((function(e){if(void 0!==e.success)if(void 0!==e.data.themes&&(window.HCaptchaIntegrationsObject.themes=e.data.themes,window.HCaptchaIntegrationsObject.defaultTheme=e.data.defaultTheme),e.success){var i=t(".form-table").eq(u?0:1),o=n.position().top;!function(e,a,n){if("theme"===a){var i=t(".form-table"),o=e?"":'[data-label="'+n+'"]',c=i.eq(e?0:1).find('.hcaptcha-integrations-logo img[data-entity="theme"]'+o);if(c.length){var s=i.eq(e?1:0),l=c.closest("tr");r(s,c.attr("data-label"),l)}}}(u,d,l),r(i,h,p),function(t){c(t,"notice-success")}(e.data.message),t("html, body").animate({scrollTop:p.offset().top-o-a.outerHeight()},1e3)}else{var g,f;s(null!==(g=null===(f=e.data)||void 0===f?void 0:f.message)&&void 0!==g?g:e.data)}else c(HCaptchaIntegrationsObject.unexpectedErrorMsg,"notice-error")})).fail((function(t){s(t.statusText)})).always((function(){p.removeClass("on off")}))}i.preventDefault(),a.remove(),t('<div id="hcaptcha-message"></div>').insertAfter("#hcaptcha-options h2"),a=t(e);var l=t(i.target),d=l.data("entity");if(d=d||"",-1!==t.inArray(d,["core","theme","plugin"])&&-1===t.inArray(d,["core"])){var h=l.attr("alt");h=(h=h||"").replace(" Logo","");var p=l.closest("tr"),g=p.attr("class");g=g.replace("hcaptcha-integrations-","");var f,u,m="";if(p.find("fieldset").attr("disabled"))f="plugin"===d?HCaptchaIntegrationsObject.activateMsg:HCaptchaIntegrationsObject.activateThemeMsg,u=!0;else{if("plugin"===d)f=HCaptchaIntegrationsObject.deactivateMsg;else{for(var v in f=HCaptchaIntegrationsObject.deactivateThemeMsg,m="<p>"+HCaptchaIntegrationsObject.selectThemeMsg+"</p>",m+="<select>",HCaptchaIntegrationsObject.themes){var b=v===HCaptchaIntegrationsObject.defaultTheme?' selected="selected"':"";m+='<option value="'.concat(v,'"').concat(b,">").concat(HCaptchaIntegrationsObject.themes[v],"</option>")}m+="</select>"}u=!1}-1===t.inArray(d,["theme"])||u||0!==Object.keys(HCaptchaIntegrationsObject.themes).length?(f=f.replace("%s",h),i.ctrlKey?o():kaggDialog.confirm({title:f,content:m,type:u?"activate":"deactivate",buttons:{ok:{text:HCaptchaIntegrationsObject.OKBtnText},cancel:{text:HCaptchaIntegrationsObject.CancelBtnText}},onAction:function(t){t&&o()}})):kaggDialog.confirm({title:HCaptchaIntegrationsObject.onlyOneThemeMsg,content:"",type:"info",buttons:{ok:{text:HCaptchaIntegrationsObject.OKBtnText}}})}}));var l,d,h;o.on("input",(l=function(){var e=o.val().trim().toLowerCase();t(".hcaptcha-integrations-logo img").each((function(a,n){var i=t(n);if("core"!==i.data("entity")){var o=i.closest("tr");i.data("label").toLowerCase().includes(e)?o.show():o.hide()}}))},d=100,function(){var t=this,e=arguments;clearTimeout(h),h=setTimeout((function(){return l.apply(t,e)}),d)})),t("#hcaptcha-options").keydown((function(e){t(e.target).is(o)&&13===e.which&&e.preventDefault()}))};window.hCaptchaIntegrations=t,jQuery(document).ready(t)})();
     1(()=>{function t(t,a){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var a=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=a){var n,i,o,r,c=[],s=!0,l=!1;try{if(o=(a=a.call(t)).next,0===e){if(Object(a)!==a)return;s=!1}else for(;!(s=(n=o.call(a)).done)&&(c.push(n.value),c.length!==e);s=!0);}catch(t){l=!0,i=t}finally{try{if(!s&&null!=a.return&&(r=a.return(),Object(r)!==r))return}finally{if(l)throw i}}return c}}(t,a)||function(t,a){if(!t)return;if("string"==typeof t)return e(t,a);var n=Object.prototype.toString.call(t).slice(8,-1);"Object"===n&&t.constructor&&(n=t.constructor.name);if("Map"===n||"Set"===n)return Array.from(t);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return e(t,a)}(t,a)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function e(t,e){(null==e||e>t.length)&&(e=t.length);for(var a=0,n=new Array(e);a<e;a++)n[a]=t[a];return n}var a=function(e){var a="#hcaptcha-message",n=e(a),i=e("#wpwrap"),o=e("#adminmenuwrap"),r=e("#hcaptcha-integrations-search");function c(t,a){n.removeClass(),n.addClass(a+" notice settings-error is-dismissible"),n.html("<p>".concat(t,"</p>")),e(document).trigger("wp-updates-notice-added");var r=n.clone();n.css("visibility","hidden"),r.css("margin","0px"),r.css("top",i.position().top),r.css("z-index","999999");var c="block"===o.css("display")?o.width():0;r.css("left",c),r.width(e(window).width()-c),r.css("position","fixed"),e("body").append(r),setTimeout((function(){n.css("visibility","unset"),r.remove()}),3e3)}function s(t){c(t,"notice-error")}function l(t){return t.is(jQuery(".form-table").eq(0))}function u(t,a,n){var i=!1,o=a.toLowerCase(),r=!l(t),c=n.find("fieldset");c.attr("disabled",r),c.find("input").attr("disabled",r),t.find("tbody").children().each((function(t,a){var r=e(a).find(".hcaptcha-integrations-logo img").attr("alt");if((r=(r=r||"").replace(" Logo","")).toLowerCase()>o)return n.insertBefore(e(a)),i=!0,!1})),i||t.find("tbody").append(n)}e(".form-table img").on("click",(function(o){function r(){var a,o,r=v?"on":"off",d=(o=document.querySelector(".kagg-dialog select"))&&null!==(a=o.value)&&void 0!==a?a:"",m={action:HCaptchaIntegrationsObject.action,nonce:HCaptchaIntegrationsObject.nonce,activate:v,entity:f,status:g,newTheme:d};p.addClass(r),e.post({url:HCaptchaIntegrationsObject.ajaxUrl,data:m}).done((function(a){if(void 0!==a.success)if(void 0!==a.data.themes&&(window.HCaptchaIntegrationsObject.themes=a.data.themes,window.HCaptchaIntegrationsObject.defaultTheme=a.data.defaultTheme),a.success){var o=e(".form-table").eq(v?0:1),r=i.position().top;!function(t,a,n){if("theme"===a){var i=e(".form-table"),o=t?"":'[data-label="'+n+'"]',r=i.eq(t?0:1).find('.hcaptcha-integrations-logo img[data-entity="theme"]'+o);if(r.length){var c=i.eq(t?1:0),s=r.closest("tr");u(c,r.attr("data-label"),s)}}}(v,f,d),u(o,h,p),function(t){c(t,"notice-success")}(a.data.message),function(a){for(var n=e(".form-table"),i=0,o=Object.entries(a);i<o.length;i++){var r=t(o[i],2),c=r[0],s=r[1],d="hcaptcha-integrations-"+c.replace(/_/g,"-"),f=e("tr.".concat(d));l(f.closest(".form-table"))!==s&&u(n.eq(s?0:1),f.find(".hcaptcha-integrations-logo img").attr("alt"),f)}}(a.data.stati),e("html, body").animate({scrollTop:p.offset().top-r-n.outerHeight()},1e3)}else{var g,m;s(null!==(g=null===(m=a.data)||void 0===m?void 0:m.message)&&void 0!==g?g:a.data)}else c(HCaptchaIntegrationsObject.unexpectedErrorMsg,"notice-error")})).fail((function(t){s(t.statusText)})).always((function(){p.removeClass("on off")}))}o.preventDefault(),n.remove(),e('<div id="hcaptcha-message"></div>').insertAfter("#hcaptcha-options h2"),n=e(a);var d=e(o.target),f=d.data("entity");if(f=f||"",-1!==e.inArray(f,["core","theme","plugin"])&&-1===e.inArray(f,["core"])){var h=d.attr("alt");h=(h=h||"").replace(" Logo","");var p=d.closest("tr"),g=p.attr("class");g=g.replace("hcaptcha-integrations-","");var m,v,b="";if(p.find("fieldset").attr("disabled"))m="plugin"===f?HCaptchaIntegrationsObject.activateMsg:HCaptchaIntegrationsObject.activateThemeMsg,v=!0;else{if("plugin"===f)m=HCaptchaIntegrationsObject.deactivateMsg;else{for(var y in m=HCaptchaIntegrationsObject.deactivateThemeMsg,b="<p>"+HCaptchaIntegrationsObject.selectThemeMsg+"</p>",b+="<select>",HCaptchaIntegrationsObject.themes){var w=y===HCaptchaIntegrationsObject.defaultTheme?' selected="selected"':"";b+='<option value="'.concat(y,'"').concat(w,">").concat(HCaptchaIntegrationsObject.themes[y],"</option>")}b+="</select>"}v=!1}-1===e.inArray(f,["theme"])||v||0!==Object.keys(HCaptchaIntegrationsObject.themes).length?(m=m.replace("%s",h),o.ctrlKey?r():kaggDialog.confirm({title:m,content:b,type:v?"activate":"deactivate",buttons:{ok:{text:HCaptchaIntegrationsObject.OKBtnText},cancel:{text:HCaptchaIntegrationsObject.CancelBtnText}},onAction:function(t){t&&r()}})):kaggDialog.confirm({title:HCaptchaIntegrationsObject.onlyOneThemeMsg,content:"",type:"info",buttons:{ok:{text:HCaptchaIntegrationsObject.OKBtnText}}})}}));var d,f,h;r.on("input",(d=function(){var t=r.val().trim().toLowerCase(),a=e(".hcaptcha-integrations-logo img"),n=null;if(a.each((function(a,i){var o=e(i);if("core"!==o.data("entity")){var r,c=o.closest("tr");o.data("label").toLowerCase().includes(t)?(c.show(),n=null!==(r=n)&&void 0!==r?r:c):c.hide()}})),n){var i=n.offset().top+n.outerHeight()-e(window).height()+5;e("html").stop().animate({scrollTop:i},1e3)}},f=100,function(){var t=this,e=arguments;clearTimeout(h),h=setTimeout((function(){return d.apply(t,e)}),f)})),e("#hcaptcha-options").keydown((function(t){e(t.target).is(r)&&13===t.which&&t.preventDefault()}))};window.hCaptchaIntegrations=a,jQuery(document).ready(a)})();
  • hcaptcha-for-forms-and-more/tags/4.2.0/changelog.txt

    r3086102 r3095958  
     1= 4.2.0 =
     2* The minimum required WordPress version is now 5.3.
     3* Added support for Multisite Network Admin synced with network-wide plugin options.
     4* Added selection by date range on Forms and Events pages.
     5* Added automatic activation of dependent plugins on the Integrations page.
     6* Added scrolling on the Integrations page during the search.
     7* Fixed color flickering of hCaptcha placeholder with custom themes.
     8* Fixed JS error on the Lost Password page.
     9* Fixed missing site key notification on the General page.
     10* Fixed fatal error on some sites during migration to 4.0.0.
     11
    112= 4.1.2 =
    213* Added option to have the hCaptcha admin menu under Settings.
  • hcaptcha-for-forms-and-more/tags/4.2.0/hcaptcha.php

    r3086102 r3095958  
    1111 * Plugin URI:           https://www.hcaptcha.com/
    1212 * Description:          hCaptcha keeps out bots and spam while putting privacy first. It is a drop-in replacement for reCAPTCHA.
    13  * Version:              4.1.2
     13 * Version:              4.2.0
    1414 * Requires at least:    5.1
    1515 * Requires PHP:         7.0
     
    2222 *
    2323 * WC requires at least: 3.0
    24  * WC tested up to:      8.8
     24 * WC tested up to:      8.9
    2525 */
    2626
     
    4040 * Plugin version.
    4141 */
    42 const HCAPTCHA_VERSION = '4.1.2';
     42const HCAPTCHA_VERSION = '4.2.0';
    4343
    4444/**
  • hcaptcha-for-forms-and-more/tags/4.2.0/readme.txt

    r3086102 r3095958  
    22Contributors: hcaptcha, kaggdesign
    33Tags: captcha, hcaptcha, antispam, abuse, protect form
    4 Requires at least: 5.1
     4Requires at least: 5.3
    55Tested up to: 6.5
    66Requires PHP: 7.0.0
    7 Stable tag: 4.1.2
     7Stable tag: 4.2.0
    88License: GPLv2 or later
    99License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    354354* Filters delay time for hCaptcha API script.
    355355*
    356 * Any negative value will prevent API script from loading at all,
     356* Any negative value will prevent the API script from loading at all,
    357357* until user interaction: mouseenter, click, scroll or touch.
    358358* This significantly improves Google Pagespeed Insights score.
     
    448448`parent`: a string — the parent menu item. Default '' for 'pages' mode and 'options-general.php' for 'tabs' mode;
    449449`position`: a number — the position of the menu item. Default 58.990225 for 'pages' mode. It Has no effect on 'tabs' mode;
    450 
    451 = Why isn't my WPForms Lite installation working? =
    452 
    453 Please make sure you have removed the reCAPTCHA keys under WPForms > Settings > reCAPTCHA to avoid a conflict.
    454450
    455451= Where can I get more information about hCaptcha? =
     
    555551We also suggest emailing the authors of plugins you'd like to support hCaptcha: it will usually take them only an hour or two to add native support. This will simplify your use of hCaptcha, and is the best solution in the long run.
    556552
    557 Some plugins listed have been superseded by native support, and are included only for legacy purposes.
    558 
    559 You should always use native hCaptcha support if available for your plugin.
    560 Please check with your plugin author if native support is not yet available.
     553You may use native hCaptcha support if available for your plugin. Please check with your plugin author if native support is not yet available.
     554
     555However, the hCaptcha plugin provides a broader set of options and features so that you can use it with any form on your site.
    561556
    562557Instructions for popular native integrations are below:
     
    565560
    566561== Changelog ==
     562
     563= 4.2.0 =
     564* The minimum required WordPress version is now 5.3.
     565* Added support for Multisite Network Admin synced with network-wide plugin options.
     566* Added selection by date range on Forms and Events pages.
     567* Added automatic activation of dependent plugins on the Integrations page.
     568* Added scrolling on the Integrations page during the search.
     569* Fixed color flickering of hCaptcha placeholder with custom themes.
     570* Fixed JS error on the Lost Password page.
     571* Fixed missing site key notification on the General page.
     572* Fixed fatal error on some sites during migration to 4.0.0.
    567573
    568574= 4.1.2 =
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Admin/Events/Events.php

    r3072795 r3095958  
    3939        }
    4040
    41         add_action( 'hcap_verify_request', [ $this, 'save_event' ], - PHP_INT_MAX, 2 );
     41        add_action( 'hcap_verify_request', [ $this, 'save_event' ], -PHP_INT_MAX, 2 );
    4242    }
    4343
     
    4848     * @param array             $error_codes Error codes.
    4949     *
    50      * @return string|null|mixed
     50     * @return void
    5151     */
    5252    public function save_event( $result, array $error_codes ) {
     
    5454
    5555        if ( ! ( is_string( $result ) || is_null( $result ) ) ) {
    56             return $result;
     56            return;
    5757        }
    5858
     
    8686            ]
    8787        );
    88 
    89         return $result;
    9088    }
    9189
     
    10098        global $wpdb;
    10199
    102         $args    = wp_parse_args(
     100        $args          = wp_parse_args(
    103101            $args,
    104102            [
     
    108106                'order'   => 'ASC',
    109107                'orderby' => '',
     108                'dates'   => [],
    110109            ]
    111110        );
    112         $columns = implode( ',', $args['columns'] );
    113         $columns = $columns ?: '*';
    114         $order   = strtoupper( $args['order'] );
    115         $order   = 'ASC' === $order ? '' : $order;
    116         $orderby = $args['orderby'] ? 'ORDER BY ' . $args['orderby'] . ' ' . $order : '';
    117         $offset  = absint( $args['offset'] );
    118         $limit   = absint( $args['limit'] );
    119 
     111        $args['dates'] = $args['dates'] ?: self::get_default_dates();
     112
     113        $columns    = implode( ',', $args['columns'] );
     114        $columns    = $columns ?: '*';
    120115        $table_name = $wpdb->prefix . self::TABLE_NAME;
     116        $where_date = self::get_where_date_gmt( $args );
     117        $orderby    = self::get_order_by( $args );
     118        $offset     = absint( $args['offset'] );
     119        $limit      = absint( $args['limit'] );
    121120
    122121        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    123122        $results = (array) $wpdb->get_results(
    124123            $wpdb->prepare(
    125             // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    126                 "SELECT SQL_CALC_FOUND_ROWS $columns FROM $table_name $orderby LIMIT %d, %d",
     124            // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     125                "SELECT
     126                        SQL_CALC_FOUND_ROWS
     127                        $columns
     128                        FROM $table_name
     129                        WHERE $where_date
     130                        $orderby
     131                        LIMIT %d, %d",
    127132                $offset,
    128133                $limit
     134            // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    129135            )
    130136        );
    131137
    132138        $total = (int) $wpdb->get_var( 'SELECT FOUND_ROWS()' );
     139
    133140        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    134141
     
    149156        global $wpdb;
    150157
    151         $args    = wp_parse_args(
     158        $args          = wp_parse_args(
    152159            $args,
    153160            [
     
    156163                'order'   => 'ASC',
    157164                'orderby' => '',
     165                'dates'   => [],
    158166            ]
    159167        );
    160         $order   = strtoupper( $args['order'] );
    161         $order   = 'ASC' === $order ? '' : $order;
    162         $orderby = $args['orderby'] ? 'ORDER BY ' . $args['orderby'] . ' ' . $order : '';
    163         $offset  = absint( $args['offset'] );
    164         $limit   = absint( $args['limit'] );
     168        $args['dates'] = $args['dates'] ?: self::get_default_dates();
    165169
    166170        $table_name = $wpdb->prefix . self::TABLE_NAME;
     171        $where_date = self::get_where_date_gmt( $args );
     172        $orderby    = self::get_order_by( $args );
     173        $offset     = absint( $args['offset'] );
     174        $limit      = absint( $args['limit'] );
    167175
    168176        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    169177        $results = (array) $wpdb->get_results(
    170178            $wpdb->prepare(
    171             // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    172                 "SELECT SQL_CALC_FOUND_ROWS id, source, form_id, COUNT(*) as served FROM $table_name GROUP BY source, form_id $orderby LIMIT %d, %d",
     179            // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     180                "SELECT
     181                        SQL_CALC_FOUND_ROWS
     182                        source, form_id, COUNT(*) as served
     183                        FROM $table_name
     184                        WHERE $where_date
     185                        GROUP BY source, form_id
     186                        $orderby
     187                        LIMIT %d, %d",
    173188                $offset,
    174189                $limit
     190            // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    175191            )
    176192        );
     
    179195        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    180196
    181         $where = 'WHERE 1=0';
     197        $where = '1=0';
    182198
    183199        foreach ( $results as $result ) {
     
    188204        }
    189205
     206        $where = "($where) AND " . $where_date;
     207
    190208        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    191209        $served = (array) $wpdb->get_results(
    192             // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    193             "SELECT date_gmt FROM $table_name $where"
    194         );
     210        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     211            "SELECT date_gmt FROM $table_name WHERE $where"
     212        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     213        );
     214
     215        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    195216
    196217        return [
     
    209230        global $wpdb;
    210231
     232        $table_name = self::TABLE_NAME;
     233
     234        if ( self::table_exists( $wpdb->prefix . $table_name ) ) {
     235            // @codeCoverageIgnoreStart
     236            return;
     237            // @codeCoverageIgnoreEnd
     238        }
     239
    211240        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    212241
    213242        $charset_collate = $wpdb->get_charset_collate();
    214         $table_name      = self::TABLE_NAME;
    215 
    216         $sql = "CREATE TABLE IF NOT EXISTS $wpdb->prefix$table_name (
     243
     244        $sql = "CREATE TABLE $wpdb->prefix$table_name (
    217245            id          BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    218246            source      VARCHAR(256)    NOT NULL,
     
    230258            KEY uuid (uuid),
    231259            KEY date_gmt (date_gmt)
    232         ) $charset_collate;";
     260        ) $charset_collate";
    233261
    234262        dbDelta( $sql );
    235263    }
     264
     265    /**
     266     * Get where date GMT.
     267     *
     268     * @param array $args Arguments.
     269     *
     270     * @return string
     271     */
     272    public static function get_where_date_gmt( array $args ): string {
     273        $dates = $args['dates'];
     274
     275        if ( $dates ) {
     276            $dates[1] = $dates[1] ?? $dates[0];
     277
     278            $dates[0] .= ' 00:00:00';
     279            $dates[1] .= ' 23:59:59';
     280
     281            foreach ( $dates as &$date ) {
     282                $date = wp_date( 'Y-m-d H:i:s', strtotime( $date ) );
     283            }
     284
     285            unset( $date );
     286
     287            $where_date = sprintf(
     288                "date_gmt BETWEEN '%s' AND '%s'",
     289                esc_sql( $dates[0] ),
     290                esc_sql( $dates[1] )
     291            );
     292        } else {
     293            $where_date = '1=1';
     294        }
     295
     296        return $where_date;
     297    }
     298
     299    /**
     300     * Get ODER BY / ORDER clause
     301     *
     302     * @param array $args Arguments.
     303     *
     304     * @return string
     305     */
     306    private static function get_order_by( array $args ): string {
     307        $order = strtoupper( $args['order'] );
     308        $order = 'ASC' === $order ? '' : $order;
     309
     310        return $args['orderby'] ? 'ORDER BY ' . $args['orderby'] . ' ' . $order : '';
     311    }
     312
     313    /**
     314     * Get default dates.
     315     *
     316     * @return array
     317     */
     318    private static function get_default_dates(): array {
     319        $end_date   = date_create_immutable( 'now', wp_timezone() );
     320        $start_date = $end_date;
     321        $start_date = $start_date->modify( '-30 day' );
     322        $start_date = $start_date->setTime( 0, 0 );
     323        $end_date   = $end_date->setTime( 23, 59, 59 );
     324        $format     = 'Y-m-d';
     325
     326        return [ $start_date->format( $format ), $end_date->format( $format ) ];
     327    }
     328
     329    /**
     330     * Check if the database table exists and cache the result.
     331     *
     332     * @param string $table_name Table name. Can have SQL wildcard.
     333     *
     334     * @return bool
     335     */
     336    private static function table_exists( string $table_name ): bool {
     337        foreach ( self::get_existing_tables( $table_name ) as $existing_table ) {
     338            if ( self::wildcard_match( $table_name, $existing_table ) ) {
     339                return true;
     340            }
     341        }
     342
     343        return false;
     344    }
     345
     346    /**
     347     * Get the list of existing tables and cache the result.
     348     *
     349     * @param string $table_name Table name. Can have SQL wildcard.
     350     *
     351     * @return array List of table names.
     352     */
     353    private static function get_existing_tables( string $table_name ): array {
     354        global $wpdb;
     355
     356        // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
     357        $tables = $wpdb->get_results(
     358            $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ),
     359            'ARRAY_N'
     360        );
     361        // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
     362
     363        return ! empty( $tables ) ? wp_list_pluck( $tables, 0 ) : [];
     364    }
     365
     366    /**
     367     * Wildcard match.
     368     * Works as MySQL LIKE match.
     369     *
     370     * @param string $pattern Pattern.
     371     * @param string $subject String to search into.
     372     *
     373     * @return false|int
     374     */
     375    private static function wildcard_match( string $pattern, string $subject ) {
     376        $regex = str_replace(
     377            [ '%', '_' ], // MySQL wildcard chars.
     378            [ '.*', '.' ],  // Regexp chars.
     379            preg_quote( $pattern, '/' )
     380        );
     381
     382        return preg_match( '/^' . $regex . '$/is', $subject );
     383    }
    236384}
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Admin/Events/EventsTable.php

    r3080217 r3095958  
    88namespace HCaptcha\Admin\Events;
    99
     10use HCaptcha\Settings\ListPageBase;
    1011use WP_List_Table;
    1112
     
    181182        $order   = isset( $_GET['order'] ) ? sanitize_key( $_GET['order'] ) : 'DESC';
    182183        $orderby = isset( $_GET['orderby'] ) ? sanitize_key( $_GET['orderby'] ) : 'date_gmt';
     184        $date    = isset( $_GET['date'] )
     185            ? filter_input( INPUT_GET, 'date', FILTER_SANITIZE_FULL_SPECIAL_CHARS )
     186            : ''; // We need filter_input here to keep delimiter intact.
    183187        // phpcs:enable WordPress.Security.NonceVerification.Recommended
    184188
     189        $dates        = explode( ListPageBase::TIMESPAN_DELIMITER, $date );
     190        $dates        = array_filter( array_map( 'trim', $dates ) );
    185191        $column_slugs = str_replace( 'name', 'source', array_keys( $this->columns ) );
    186192        $per_page     = $this->get_items_per_page( self::EVENTS_PER_PAGE, $this->per_page_default );
     
    192198            'order'   => $order,
    193199            'orderby' => $orderby,
     200            'dates'   => $dates,
    194201        ];
    195202
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Admin/Events/FormsTable.php

    r3080217 r3095958  
    88namespace HCaptcha\Admin\Events;
    99
     10use HCaptcha\Settings\ListPageBase;
    1011use WP_List_Table;
    1112
     
    154155    public function get_sortable_columns(): array {
    155156        return [
    156             'name'    => [ 'name', false, __( 'Source', 'hcaptcha-for-forms-and-more' ), __( 'Table ordered by Source.' ) ],
    157             'form_id' => [ 'form_id', false, __( 'Form Id', 'hcaptcha-for-forms-and-more' ), __( 'Table ordered by Form Id.' ) ],
    158             'served'  => [ 'served', false, __( 'Served', 'hcaptcha-for-forms-and-more' ), __( 'Table ordered by Served Count.' ) ],
     157            'name'    => [
     158                'name',
     159                false,
     160                __( 'Source', 'hcaptcha-for-forms-and-more' ),
     161                __( 'Table ordered by Source.' ),
     162            ],
     163            'form_id' => [
     164                'form_id',
     165                false,
     166                __( 'Form Id', 'hcaptcha-for-forms-and-more' ),
     167                __( 'Table ordered by Form Id.' ),
     168            ],
     169            'served'  => [
     170                'served',
     171                false,
     172                __( 'Served', 'hcaptcha-for-forms-and-more' ),
     173                __( 'Table ordered by Served Count.' ),
     174            ],
    159175        ];
    160176    }
     
    172188        $order   = isset( $_GET['order'] ) ? sanitize_key( $_GET['order'] ) : 'ASC';
    173189        $orderby = isset( $_GET['orderby'] ) ? sanitize_key( $_GET['orderby'] ) : 'source';
     190        $date    = isset( $_GET['date'] )
     191            ? filter_input( INPUT_GET, 'date', FILTER_SANITIZE_FULL_SPECIAL_CHARS )
     192            : ''; // We need filter_input here to keep delimiter intact.
    174193        // phpcs:enable WordPress.Security.NonceVerification.Recommended
    175194
     195        $dates    = explode( ListPageBase::TIMESPAN_DELIMITER, $date );
     196        $dates    = array_filter( array_map( 'trim', $dates ) );
    176197        $per_page = $this->get_items_per_page( self::FORMS_PER_PAGE, $this->per_page_default );
    177198        $offset   = ( $paged - 1 ) * $per_page;
     
    181202            'order'   => $order,
    182203            'orderby' => $orderby,
     204            'dates'   => $dates,
    183205        ];
    184206
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Admin/Notifications.php

    r3081325 r3095958  
    248248        }
    249249
    250         if ( hcaptcha()->is_pro() ) {
     250        if ( $settings->is_pro() ) {
    251251            unset( $this->notifications['pro-free-trial'] );
    252252        }
     
    283283            if ( $this->shuffle ) {
    284284                $notifications = $this->shuffle_assoc( $notifications );
     285                $notifications = $this->make_key_first( $notifications, 'register' );
    285286            }
    286287
     
    474475        return $new_arr;
    475476    }
     477
     478    /**
     479     * Make a key the first element in an associative array.
     480     *
     481     * @param array  $arr An array.
     482     * @param string $key Key.
     483     *
     484     * @return array
     485     */
     486    protected function make_key_first( array $arr, string $key ): array {
     487        if ( ! array_key_exists( $key, $arr ) ) {
     488            return $arr;
     489        }
     490
     491        // Remove the key-value pair from the original array.
     492        $value = $arr[ $key ];
     493        unset( $arr[ $key ] );
     494
     495        // Merge the key-value pair back into the array at the beginning.
     496        return array_merge( [ $key => $value ], $arr );
     497    }
    476498}
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Admin/PluginStats.php

    r3080217 r3095958  
    145145
    146146        $settings   = hcaptcha()->settings();
    147         $license    = (int) hcaptcha()->is_pro() ? 'Pro' : 'Publisher';
     147        $license    = (int) $settings->is_pro() ? 'Pro' : 'Publisher';
    148148        $api_host   = $settings->get( 'api_host' );
    149149        $backend    = $settings->get( 'backend' );
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/BeaverBuilder/Base.php

    r3064004 r3095958  
    8080            self::HANDLE,
    8181            HCAPTCHA_URL . "/assets/js/hcaptcha-beaver-builder$min.js",
    82             [ 'jquery', 'wp-hooks' ],
     82            [ 'jquery' ],
    8383            HCAPTCHA_VERSION,
    8484            true
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Main.php

    r3086102 r3095958  
    3232use HCaptcha\Settings\General;
    3333use HCaptcha\Settings\Integrations;
     34use HCaptcha\Settings\PluginSettingsBase;
    3435use HCaptcha\Settings\Settings;
    3536use HCaptcha\Settings\SystemInfo;
     
    4849
    4950    /**
     51     * WP hooks handle.
     52     */
     53    const WP_HOOKS_HANDLE = 'wp-hooks';
     54
     55    /**
    5056     * Main script localization object.
    5157     */
     
    134140    public function init_hooks() {
    135141        $this->load_textdomain();
    136 
    137         $settings      = get_option( 'hcaptcha_settings', [] );
    138         $menu_position = $settings['menu_position'] ?? [];
    139         $args          = [
    140             'mode' => [ 'on' ] === $menu_position ? SettingsBase::MODE_TABS : SettingsBase::MODE_PAGES,
    141         ];
    142142
    143143        /**
     
    146146         * @param array $args Settings system initialization arguments.
    147147         */
    148         $args = (array) apply_filters( 'hcap_settings_init_args', $args );
     148        $args = (array) apply_filters( 'hcap_settings_init_args', [] );
    149149
    150150        $this->settings = new Settings(
     
    255255
    256256    /**
    257      * Check if it is a Pro account.
    258      *
    259      * @return false
    260      */
    261     public function is_pro(): bool {
    262         return 'pro' === $this->settings->get_license();
    263     }
    264 
    265     /**
    266257     * Whether we are on the Elementor Pro edit post/page and hCaptcha for Elementor Pro is active.
    267258     *
     
    497488CSS;
    498489
     490        $settings = $this->settings();
     491
     492        if ( $settings->is_on( 'custom_themes' ) && $settings->is_pro_or_general() ) {
     493            $bg = $settings->get_config_params()['theme']['component']['checkbox']['main']['fill'] ?? '';
     494
     495            if ( $bg ) {
     496                $css .= <<<CSS
     497    .h-captcha::before {
     498        background-color: $bg !important;   
     499    }
     500CSS;
     501            }
     502        }
     503
    499504        HCaptcha::css_display( $css );
    500505    }
     
    578583        }
    579584
    580         if ( $settings->is_on( 'custom_themes' ) && $this->is_pro_or_general() ) {
     585        if ( $settings->is_on( 'custom_themes' ) && $settings->is_pro_or_general() ) {
    581586            $params['custom'] = 'true';
    582587        }
     
    676681        DelayedScript::launch( [ 'src' => $this->get_api_src() ], $delay );
    677682
     683        wp_enqueue_script( self::WP_HOOKS_HANDLE );
    678684        wp_enqueue_script(
    679685            self::HANDLE,
    680686            HCAPTCHA_URL . '/assets/js/apps/hcaptcha.js',
    681             [ 'wp-hooks' ],
     687            [ self::WP_HOOKS_HANDLE ],
    682688            HCAPTCHA_VERSION,
    683689            true
     
    698704        }
    699705
    700         $config_params = [];
    701 
    702         if ( $settings->is_on( 'custom_themes' ) && $this->is_pro_or_general() ) {
    703             $config_params = $settings->get_config_params();
    704         }
     706        $config_params = $settings->is_on( 'custom_themes' ) && $settings->is_pro_or_general()
     707            ? $settings->get_config_params()
     708            : [];
    705709
    706710        $params = array_merge( $params, $config_params );
     
    825829            'Affiliates Login'                     => [
    826830                [ 'affiliates_status', 'login' ],
    827                 [ 'affiliates/affiliates.php' ],
     831                'affiliates/affiliates.php',
    828832                Affiliates\Login::class,
    829833            ],
    830834            'Affiliates Register'                  => [
    831835                [ 'affiliates_status', 'register' ],
    832                 [ 'affiliates/affiliates.php' ],
     836                'affiliates/affiliates.php',
    833837                Affiliates\Register::class,
    834838            ],
     
    13151319     * @return bool
    13161320     */
    1317     private function plugin_or_theme_active( $plugin_or_theme_names ): bool {
     1321    public function plugin_or_theme_active( $plugin_or_theme_names ): bool {
    13181322        foreach ( (array) $plugin_or_theme_names as $plugin_or_theme_name ) {
    13191323            if ( '' === $plugin_or_theme_name ) {
     
    13641368        return defined( 'XMLRPC_REQUEST' ) && constant( 'XMLRPC_REQUEST' );
    13651369    }
    1366 
    1367     /**
    1368      * Whether option is allowed to use.
    1369      *
    1370      * @return bool
    1371      */
    1372     private function is_pro_or_general(): bool {
    1373         return $this->is_pro() || ( is_admin() && 'General' === $this->settings->get_active_tab_name() );
    1374     }
    13751370}
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Migrations/Migrations.php

    r3064004 r3095958  
    99
    1010use HCaptcha\Admin\Events\Events;
     11use HCaptcha\Settings\PluginSettingsBase;
    1112
    1213/**
     
    305306        }
    306307
    307         update_option( 'hcaptcha_settings', $new_options );
     308        update_option( PluginSettingsBase::OPTION_NAME, $new_options );
    308309
    309310        foreach ( array_keys( $options_map ) as $old_option_name ) {
     
    321322     */
    322323    protected function migrate_360() {
    323         $option         = get_option( 'hcaptcha_settings', [] );
     324        $option         = get_option( PluginSettingsBase::OPTION_NAME, [] );
    324325        $wpforms_status = $option['wpforms_status'] ?? [];
    325326
     
    331332        $option['wpforms_status'] = [ 'form' ];
    332333
    333         update_option( 'hcaptcha_settings', $option );
     334        update_option( PluginSettingsBase::OPTION_NAME, $option );
    334335
    335336        return true;
     
    365366        $pro               = $result['features']['custom_theme'] ?? false;
    366367        $license           = $pro ? 'pro' : 'free';
    367         $option            = get_option( 'hcaptcha_settings', [] );
     368        $option            = get_option( PluginSettingsBase::OPTION_NAME, [] );
    368369        $option['license'] = $license;
    369370
    370371        // Save license level in settings.
    371         update_option( 'hcaptcha_settings', $option );
     372        update_option( PluginSettingsBase::OPTION_NAME, $option );
    372373    }
    373374}
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/NF/NF.php

    r3080217 r3095958  
    295295            self::HANDLE,
    296296            HCAPTCHA_URL . "/assets/js/hcaptcha-nf$min.js",
    297             [ 'jquery', Main::HANDLE, 'nf-front-end', 'nf-front-end-deps', 'wp-hooks' ],
     297            [ 'jquery', Main::HANDLE, 'nf-front-end', 'nf-front-end-deps' ],
    298298            HCAPTCHA_VERSION,
    299299            true
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Otter/Form.php

    r3064004 r3095958  
    155155            self::HANDLE,
    156156            HCAPTCHA_URL . "/assets/js/hcaptcha-otter$min.js",
    157             [ 'wp-hooks' ],
     157            [],
    158158            HCAPTCHA_VERSION,
    159159            true
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Passster/Protect.php

    r3064004 r3095958  
    130130            self::HANDLE,
    131131            HCAPTCHA_URL . "/assets/js/hcaptcha-passster$min.js",
    132             [ 'jquery', 'wp-hooks' ],
     132            [ 'jquery' ],
    133133            HCAPTCHA_VERSION,
    134134            true
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Settings/Abstracts/SettingsBase.php

    r3081325 r3095958  
    5151
    5252    /**
     53     * Network-wide menu position.
     54     *
     55     * A number before 25 (Settings) to avoid conflicts with other plugins.
     56     */
     57    const NETWORK_WIDE_POSITION = 24.99;
     58
     59    /**
    5360     * Form fields.
    5461     *
     
    214221        $this->tabs = $tabs;
    215222
    216         $args = wp_parse_args(
    217             $args,
    218             [
    219                 'mode'     => self::MODE_PAGES,
    220                 'parent'   => null,
    221                 'position' => null,
    222             ]
    223         );
    224 
    225         $this->admin_mode = in_array( $args['mode'], [ self::MODE_PAGES, self::MODE_TABS ], true ) ?
    226             $args['mode'] :
    227             self::MODE_PAGES;
    228 
    229         if ( null === $args['parent'] ) {
    230             $this->parent_slug = self::MODE_PAGES === $this->admin_mode ? '' : 'options-general.php';
    231         } else {
    232             $this->parent_slug = $args['parent'];
    233         }
    234 
    235         if ( null === $args['position'] ) {
    236             $hash           = hexdec( sha1( self::PREFIX ) );
    237             $pow            = floor( log10( $hash ) );
    238             $this->position = round( self::POSITION + $hash / 10 ** ( $pow + 4 ), 6 );
    239         } else {
    240             $this->position = (float) $args['position'];
    241         }
     223        $this->process_args( $args );
    242224
    243225        $this->fields = [
     
    257239        if ( self::MODE_PAGES === $this->admin_mode || ! $this->is_tab() ) {
    258240            add_action( 'current_screen', [ $this, 'setup_tabs_section' ], 9 );
    259             add_action( 'admin_menu', [ $this, 'add_settings_page' ] );
     241
     242            $tag = $this->is_network_wide() ? 'network_admin_menu' : 'admin_menu';
     243
     244            add_action( $tag, [ $this, 'add_settings_page' ] );
    260245        }
    261246
     
    284269    protected function init_hooks() {
    285270        add_action( 'admin_enqueue_scripts', [ $this, 'base_admin_enqueue_scripts' ] );
     271        add_action( 'admin_page_access_denied', [ $this, 'base_admin_page_access_denied' ] );
    286272
    287273        if ( $this->is_main_menu_page() ) {
     
    312298
    313299    /**
     300     * Process arguments.
     301     *
     302     * @param array $args Arguments.
     303     *
     304     * @return void
     305     */
     306    protected function process_args( array $args ) {
     307        $args = wp_parse_args(
     308            $args,
     309            [
     310                'mode'     => $this->get_menu_position(),
     311                'parent'   => null,
     312                'position' => null,
     313            ]
     314        );
     315
     316        $this->admin_mode = in_array( $args['mode'], [ self::MODE_PAGES, self::MODE_TABS ], true ) ?
     317            $args['mode'] :
     318            self::MODE_PAGES;
     319
     320        if ( null === $args['parent'] ) {
     321            $wp_settings_slug  = is_multisite() && $this->is_network_wide() ? 'settings.php' : 'options-general.php';
     322            $this->parent_slug = self::MODE_PAGES === $this->admin_mode ? '' : $wp_settings_slug;
     323        } else {
     324            $this->parent_slug = $args['parent'];
     325        }
     326
     327        if ( null === $args['position'] ) {
     328            $hash           = hexdec( sha1( self::PREFIX ) );
     329            $pow            = floor( log10( $hash ) );
     330            $position       = is_multisite() && $this->is_network_wide() ? self::NETWORK_WIDE_POSITION : self::POSITION;
     331            $this->position = round( $position + $hash / 10 ** ( $pow + 4 ), 6 );
     332        } else {
     333            $this->position = (float) $args['position'];
     334        }
     335    }
     336
     337    /**
    314338     * Is this the main menu page?
    315339     *
     
    381405     */
    382406    protected function init_settings() {
    383         $network_wide = get_site_option( $this->option_name() . self::NETWORK_WIDE, [] );
    384 
    385         if ( empty( $network_wide ) ) {
     407        if ( $this->is_network_wide() ) {
     408            $this->settings = get_site_option( $this->option_name(), null );
     409        } else {
    386410            $this->settings = get_option( $this->option_name(), null );
    387         } else {
    388             $this->settings = get_site_option( $this->option_name(), null );
    389411        }
    390412
     
    394416        $network_wide_setting                 = array_key_exists( self::NETWORK_WIDE, $this->settings ) ?
    395417            $this->settings[ self::NETWORK_WIDE ] :
    396             $network_wide;
     418            $this->get_network_wide();
    397419        $this->settings[ self::NETWORK_WIDE ] = $network_wide_setting;
    398420
     
    567589
    568590    /**
     591     * Filter denied access to the settings page.
     592     * It is needed when switching network_wide option.
     593     *
     594     * @return void
     595     */
     596    public function base_admin_page_access_denied() {
     597        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     598        $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
     599
     600        if ( static::PREFIX !== $page ) {
     601            return;
     602        }
     603
     604        $url = is_multisite() && $this->is_network_wide() ?
     605            network_admin_url( 'admin.php?page=' . $this->option_page() ) :
     606            admin_url( 'admin.php?page=' . $this->option_page() );
     607
     608        if ( wp_get_raw_referer() === $url ) {
     609            // Prevent infinite loop.
     610            return;
     611        }
     612
     613        wp_safe_redirect( $url );
     614        $this->exit();
     615    }
     616
     617    /**
     618     * Exit wrapper for test purposes.
     619     *
     620     * @return void
     621     */
     622    protected function exit() {
     623        // @codeCoverageIgnoreStart
     624        exit();
     625        // @codeCoverageIgnoreEnd
     626    }
     627
     628    /**
    569629     * Setup settings sections.
    570630     *
     
    658718     */
    659719    private function tab_link( SettingsBase $tab ) {
    660         $url = menu_page_url( $tab->option_page(), false );
     720        $url = is_multisite() && $this->is_network_wide() ?
     721            network_admin_url( 'admin.php?page=' . $tab->option_page() ) :
     722            menu_page_url( $tab->option_page(), false );
    661723
    662724        if ( self::MODE_TABS === $this->admin_mode ) {
     
    14081470        $current_suffix = preg_replace( '/.+_page_/', '', $current_screen->id );
    14091471
     1472        if ( is_multisite() && $this->is_network_wide() ) {
     1473            $current_suffix = preg_replace( '/-network$/', '', $current_suffix );
     1474        }
     1475
    14101476        return $this->option_page() === $current_suffix || in_array( $current_suffix, $ids, true );
    14111477    }
     
    14301496
    14311497    /**
    1432      * Print supplemental id it exists.
     1498     * Print supplemental id if it exists.
    14331499     *
    14341500     * @param string $supplemental Supplemental.
     
    14461512        );
    14471513    }
     1514
     1515    /**
     1516     * Get network_wide setting.
     1517     *
     1518     * @return array
     1519     */
     1520    protected function get_network_wide(): array {
     1521        static $network_wide = null;
     1522
     1523        if ( null === $network_wide ) {
     1524            $network_wide = (array) get_site_option( $this->option_name() . self::NETWORK_WIDE, [] );
     1525        }
     1526
     1527        return $network_wide;
     1528    }
     1529
     1530    /**
     1531     * Whether network_wide setting is on.
     1532     *
     1533     * @return bool
     1534     */
     1535    protected function is_network_wide(): bool {
     1536        return ! empty( $this->get_network_wide() );
     1537    }
     1538
     1539    /**
     1540     * Get menu position.
     1541     *
     1542     * @return string
     1543     */
     1544    protected function get_menu_position(): string {
     1545        return [ 'on' ] === $this->get( 'menu_position' ) ? self::MODE_TABS : self::MODE_PAGES;
     1546    }
     1547
     1548    /**
     1549     * Print header.
     1550     *
     1551     * @return void
     1552     */
     1553    protected function print_header() {
     1554        ?>
     1555        <div class="<?php echo esc_attr( static::PREFIX . '-header-bar' ); ?>">
     1556            <div class="<?php echo esc_attr( static::PREFIX . '-header' ); ?>">
     1557                <h2>
     1558                    <?php echo esc_html( $this->page_title() ); ?>
     1559                </h2>
     1560            </div>
     1561            <?php
     1562
     1563            /**
     1564             * Fires before settings tab closing tag.
     1565             */
     1566            do_action( 'kagg_settings_header' );
     1567
     1568            ?>
     1569        </div>
     1570        <?php
     1571    }
    14481572}
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Settings/EventsPage.php

    r3081325 r3095958  
    5050
    5151    /**
    52      * The page is allowed to be shown.
    53      *
    54      * @var bool
    55      */
    56     protected $allowed = false;
    57 
    58     /**
    5952     * Get page title.
    6053     *
     
    9083
    9184        add_action( 'admin_init', [ $this, 'admin_init' ] );
     85        add_action( 'kagg_settings_header', [ $this, 'date_picker_display' ] );
    9286    }
    9387
     
    9892     */
    9993    public function admin_init() {
    100         $this->allowed = ( hcaptcha()->settings()->is_on( 'statistics' ) && hcaptcha()->is_pro() );
     94        $settings = hcaptcha()->settings();
     95
     96        $this->allowed = ( $settings->is_on( 'statistics' ) && $settings->is_pro() );
    10197
    10298        if ( ! $this->allowed ) {
     
    124120        }
    125121
    126         wp_enqueue_script(
    127             'chart',
    128             constant( 'HCAPTCHA_URL' ) . '/assets/lib/chart.umd.min.js',
    129             [],
    130             'v4.4.2',
    131             true
    132         );
    133 
    134         wp_enqueue_script(
    135             'chart-adapter-date-fns',
    136             constant( 'HCAPTCHA_URL' ) . '/assets/lib/chartjs-adapter-date-fns.bundle.min.js',
    137             [ 'chart' ],
    138             'v3.0.0',
    139             true
    140         );
     122        parent::admin_enqueue_scripts();
    141123
    142124        wp_enqueue_script(
     
    156138                'succeedLabel' => __( 'Succeed', 'hcaptcha-for-forms-and-more' ),
    157139                'failedLabel'  => __( 'Failed', 'hcaptcha-for-forms-and-more' ),
     140                'unit'         => $this->unit,
    158141            ]
    159142        );
     
    168151     */
    169152    public function section_callback( array $arguments ) {
    170         ?>
    171         <h2>
    172             <?php echo esc_html( $this->page_title() ); ?>
    173         </h2>
    174         <?php
     153        $this->print_header();
    175154
    176155        if ( ! $this->allowed ) {
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Settings/FormsPage.php

    r3081325 r3095958  
    4343
    4444    /**
    45      * The page is allowed to be shown.
    46      *
    47      * @var bool
    48      */
    49     protected $allowed = false;
    50 
    51     /**
    5245     * Get page title.
    5346     *
     
    8376
    8477        add_action( 'admin_init', [ $this, 'admin_init' ] );
     78        add_action( 'kagg_settings_header', [ $this, 'date_picker_display' ] );
    8579    }
    8680
     
    117111        }
    118112
    119         wp_enqueue_script(
    120             'chart',
    121             constant( 'HCAPTCHA_URL' ) . '/assets/lib/chart.umd.min.js',
    122             [],
    123             'v4.4.2',
    124             true
    125         );
    126 
    127         wp_enqueue_script(
    128             'chart-adapter-date-fns',
    129             constant( 'HCAPTCHA_URL' ) . '/assets/lib/chartjs-adapter-date-fns.bundle.min.js',
    130             [ 'chart' ],
    131             'v3.0.0',
    132             true
    133         );
     113        parent::admin_enqueue_scripts();
    134114
    135115        wp_enqueue_script(
     
    147127                'served'      => $this->served,
    148128                'servedLabel' => __( 'Served', 'hcaptcha-for-forms-and-more' ),
     129                'unit'        => $this->unit,
    149130            ]
    150131        );
     
    159140     */
    160141    public function section_callback( array $arguments ) {
    161         ?>
    162         <h2>
    163             <?php echo esc_html( $this->page_title() ); ?>
    164         </h2>
    165         <?php
     142        $this->print_header();
    166143
    167144        if ( ! $this->allowed ) {
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Settings/General.php

    r3086102 r3095958  
    620620        switch ( $arguments['id'] ) {
    621621            case self::SECTION_KEYS:
    622                 ?>
    623                 <h2>
    624                     <?php echo esc_html( $this->page_title() ); ?>
    625                 </h2>
    626                 <div id="hcaptcha-message"></div>
    627                 <?php
     622                $this->print_header();
    628623                $this->notifications->show();
    629624                $this->print_section_header( $arguments['id'], __( 'Keys', 'hcaptcha-for-forms-and-more' ) );
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Settings/Integrations.php

    r3081325 r3095958  
    99
    1010use KAGG\Settings\Abstracts\SettingsBase;
     11use WP_Error;
    1112use WP_Theme;
    1213
     
    4950
    5051    /**
     52     * Plugin dependencies not specified in their headers.
     53     * Key is a plugin slug.
     54     * Value is a plugin slug or an array of slugs.
     55     */
     56    const PLUGIN_DEPENDENCIES = [
     57        // phpcs:disable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned
     58        'back-in-stock-notifier-for-woocommerce/cwginstocknotifier.php' => 'woocommerce/woocommerce.php',
     59        'elementor-pro/elementor-pro.php'                               => 'elementor/elementor.php',
     60        'woocommerce-wishlists/woocommerce-wishlists.php'               => 'woocommerce/woocommerce.php',
     61        // phpcs:enable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned
     62    ];
     63
     64    /**
    5165     * Entity name to activate/deactivate. Can be 'plugin' or 'theme'.
    5266     *
     
    5468     */
    5569    protected $entity = '';
     70
     71    /**
     72     * Plugins tree.
     73     *
     74     * @var array
     75     */
     76    protected $plugins_tree;
    5677
    5778    /**
     
    79100        parent::init_hooks();
    80101
    81         add_action( 'kagg_settings_tab', [ $this, 'search_box' ] );
     102        add_action( 'kagg_settings_header', [ $this, 'search_box' ] );
    82103        add_action( 'wp_ajax_' . self::ACTIVATE_ACTION, [ $this, 'activate' ] );
    83104    }
     
    629650    public function search_box() {
    630651        ?>
    631         <span id="hcaptcha-integrations-search-wrap">
     652        <div id="hcaptcha-integrations-search-wrap">
    632653            <label for="hcaptcha-integrations-search"></label>
    633654            <input
    634655                    type="search" id="hcaptcha-integrations-search"
    635656                    placeholder="<?php esc_html_e( 'Search plugins and themes...', 'hcaptcha-for-forms-and-more' ); ?>">
    636         </span>
     657        </div>
    637658        <?php
    638659    }
     
    657678        }
    658679
     680        $this->print_header();
     681
    659682        ?>
    660         <h2>
    661             <?php echo esc_html( $this->page_title() ); ?>
    662         </h2>
    663683        <div id="hcaptcha-message"></div>
    664684        <p>
     
    815835            }
    816836
    817             $message = sprintf(
     837            $plugin_names = $this->plugin_names_from_tree( $this->plugins_tree );
     838            $message      = sprintf(
    818839            /* translators: 1: Plugin name. */
    819                 __( '%s plugin is activated.', 'hcaptcha-for-forms-and-more' ),
    820                 $plugin_name
     840                _n(
     841                    '%s plugin is activated.',
     842                    '%s plugins are activated.',
     843                    count( $plugin_names ),
     844                    'hcaptcha-for-forms-and-more'
     845                ),
     846                implode( ', ', $plugin_names )
    821847            );
    822848
     
    874900    protected function activate_plugins( array $plugins ): bool {
    875901        foreach ( $plugins as $plugin ) {
    876             ob_start();
    877 
    878             $result = activate_plugin( $plugin );
    879 
    880             ob_end_clean();
     902            $this->plugins_tree = $this->build_plugins_tree( $plugin );
     903            $result             = $this->activate_plugin_tree( $this->plugins_tree );
    881904
    882905            if ( null === $result ) {
     
    890913
    891914    /**
     915     * Activate plugins.
     916     *
     917     * @param array $node Node of the plugin tree.
     918     *
     919     * @return int|null|true|WP_Error
     920     */
     921    protected function activate_plugin_tree( array &$node ) {
     922        if ( $node['children'] ) {
     923            foreach ( $node['children'] as $child ) {
     924                $result = $this->activate_plugin_tree( $child );
     925
     926                if ( null !== $result ) {
     927                    return $result;
     928                }
     929            }
     930        }
     931
     932        ob_start();
     933        $result = activate_plugin( $node['plugin'] );
     934        ob_end_clean();
     935
     936        $node['result'] = $result;
     937
     938        return $result;
     939    }
     940
     941    /**
     942     * Get plugins' tree.
     943     *
     944     * @param string $plugin Plugin slug.
     945     *
     946     * @return array
     947     */
     948    protected function build_plugins_tree( string $plugin ): array {
     949        $dependencies = $this->plugin_dependencies( $plugin );
     950        $tree         = [
     951            'plugin'   => $plugin,
     952            'children' => [],
     953        ];
     954
     955        foreach ( $dependencies as $dependency ) {
     956            $tree['children'][] = $this->build_plugins_tree( $dependency );
     957        }
     958
     959        return $tree;
     960    }
     961
     962    /**
     963     * Get plugin dependencies.
     964     *
     965     * @param string $plugin Plugin slug.
     966     *
     967     * @return array
     968     */
     969    private function plugin_dependencies( string $plugin ): array {
     970        $plugin_headers   = get_plugin_data( constant( 'WP_PLUGIN_DIR' ) . '/' . $plugin );
     971        $requires_plugins = $plugin_headers['RequiresPlugins'] ?? '';
     972        $wp_dependencies  = $this->plugin_dirs_to_slugs(
     973            array_filter( array_map( 'trim', explode( ',', $requires_plugins ) ) )
     974        );
     975        $dependencies     = (array) ( self::PLUGIN_DEPENDENCIES[ $plugin ] ?? [] );
     976
     977        return array_merge( $wp_dependencies, $dependencies );
     978    }
     979
     980    /**
     981     * Convert plugin directories to slugs.
     982     *
     983     * @param array $dirs Plugin directories.
     984     *
     985     * @return array
     986     */
     987    protected function plugin_dirs_to_slugs( array $dirs ): array {
     988        if ( ! $dirs ) {
     989            return $dirs;
     990        }
     991
     992        $slugs = array_keys( get_plugins() );
     993
     994        foreach ( $dirs as &$dir ) {
     995            $slug = preg_grep( "#^$dir/#", $slugs );
     996
     997            if ( $slug ) {
     998                $dir = reset( $slug );
     999            }
     1000        }
     1001
     1002        return $dirs;
     1003    }
     1004
     1005    /**
     1006     * Get plugin names from the tree.
     1007     *
     1008     * @param array $node Node of the plugin tree.
     1009     *
     1010     * @return array
     1011     */
     1012    protected function plugin_names_from_tree( array $node ): array {
     1013        $plugin_names = [];
     1014
     1015        if ( $node['children'] ) {
     1016            foreach ( $node['children'] as $child ) {
     1017                $plugin_names[] = $this->plugin_names_from_tree( $child );
     1018            }
     1019
     1020            $plugin_names = array_merge( [], ...$plugin_names );
     1021        }
     1022
     1023        $status = '';
     1024
     1025        foreach ( hcaptcha()->modules as $module ) {
     1026            if ( $module[1] === $node['plugin'] ) {
     1027                $status = $module[0][0];
     1028
     1029                break;
     1030            }
     1031        }
     1032
     1033        $plugin_name = $this->form_fields[ $status ]['label'] ?? '';
     1034
     1035        if ( ! $plugin_name ) {
     1036            $plugin_data = get_plugin_data( constant( 'WP_PLUGIN_DIR' ) . '/' . $node['plugin'] );
     1037            $plugin_name = $plugin_data['Name'] ?? '';
     1038        }
     1039
     1040        return array_unique( array_merge( [ $plugin_name ], $plugin_names ) );
     1041    }
     1042
     1043    /**
    8921044     * Activate theme.
    8931045     *
     
    9421094        $data = [ 'message' => esc_html( $message ) ];
    9431095
     1096        if ( 'plugin' === $this->entity ) {
     1097            $data['stati'] = $this->get_activation_stati();
     1098        }
     1099
    9441100        if ( 'theme' === $this->entity ) {
    9451101            $data['themes']       = $this->get_themes();
     
    9481104
    9491105        return $data;
     1106    }
     1107
     1108    /**
     1109     * Get activation stati of all integrated plugins and themes.
     1110     *
     1111     * @return array
     1112     */
     1113    protected function get_activation_stati(): array {
     1114        $stati = [];
     1115
     1116        foreach ( hcaptcha()->modules as $module ) {
     1117            $stati[ $module[0][0] ] = hcaptcha()->plugin_or_theme_active( $module[1] );
     1118        }
     1119
     1120        return $stati;
    9501121    }
    9511122
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Settings/ListPageBase.php

    r3072795 r3095958  
    88namespace HCaptcha\Settings;
    99
     10use DateTimeImmutable;
     11
    1012/**
    1113 * Class ListPageBase.
     
    1618
    1719    /**
     20     * Chart handle.
     21     */
     22    const CHART_HANDLE = 'chart';
     23
     24    /**
     25     * Flatpickr handle.
     26     */
     27    const FLATPICKR_HANDLE = 'flatpickr';
     28
     29    /**
     30     * Base handle.
     31     */
     32    const HANDLE = 'settings-list-page-base';
     33
     34    /**
     35     * Base object.
     36     */
     37    const OBJECT = 'HCaptchaFlatPickerObject';
     38
     39    /**
     40     * Number of timespan days by default.
     41     * "Last 30 Days", by default.
     42     */
     43    const DEFAULT_TIMESPAN_DAYS = '30';
     44
     45    /**
     46     * Timespan (date range) delimiter.
     47     */
     48    const TIMESPAN_DELIMITER = ' - ';
     49
     50    /**
     51     * Default date format.
     52     */
     53    const DATE_FORMAT = 'Y-m-d';
     54
     55    /**
     56     * Chart time unit.
     57     *
     58     * @var string
     59     */
     60    protected $unit;
     61
     62    /**
     63     * The page is allowed to be shown.
     64     *
     65     * @var bool
     66     */
     67    protected $allowed = false;
     68
     69    /**
    1870     * Get suggested data format from items array.
    1971     *
     
    3486
    3587        $time_diff = $max_time - $min_time;
     88
     89        $time_units = [
     90            [ 1, 'second' ],
     91            [ constant( 'MINUTE_IN_SECONDS' ), 'minute' ],
     92            [ constant( 'HOUR_IN_SECONDS' ), 'hour' ],
     93            [ constant( 'DAY_IN_SECONDS' ), 'day' ],
     94            [ constant( 'WEEK_IN_SECONDS' ), 'week' ],
     95            [ constant( 'MONTH_IN_SECONDS' ), 'month' ],
     96            [ constant( 'YEAR_IN_SECONDS' ), 'year' ],
     97        ];
     98
     99        foreach ( $time_units as $index => $time_unit ) {
     100            $i          = max( 0, $index - 1 );
     101            $this->unit = $time_units[ $i ][1];
     102
     103            if ( $time_diff < $time_unit[0] * 2 ) {
     104                break;
     105            }
     106        }
    36107
    37108        if ( $time_diff < constant( 'MINUTE_IN_SECONDS' ) ) {
     
    45116        return $date_format;
    46117    }
     118
     119    /**
     120     * Enqueue class scripts.
     121     */
     122    public function admin_enqueue_scripts() {
     123        $min = hcap_min_suffix();
     124
     125        wp_enqueue_script(
     126            self::CHART_HANDLE,
     127            constant( 'HCAPTCHA_URL' ) . '/assets/lib/chartjs/chart.umd.min.js',
     128            [],
     129            'v4.4.2',
     130            true
     131        );
     132
     133        wp_enqueue_script(
     134            'chart-adapter-date-fns',
     135            constant( 'HCAPTCHA_URL' ) . '/assets/lib/chartjs/chartjs-adapter-date-fns.bundle.min.js',
     136            [ self::CHART_HANDLE ],
     137            'v3.0.0',
     138            true
     139        );
     140
     141        wp_enqueue_style(
     142            self::FLATPICKR_HANDLE,
     143            constant( 'HCAPTCHA_URL' ) . '/assets/lib/flatpickr/flatpickr.min.css',
     144            [],
     145            '4.6.13'
     146        );
     147
     148        wp_enqueue_script(
     149            self::FLATPICKR_HANDLE,
     150            constant( 'HCAPTCHA_URL' ) . '/assets/lib/flatpickr/flatpickr.min.js',
     151            [],
     152            '4.6.13',
     153            true
     154        );
     155
     156        wp_enqueue_style(
     157            self::HANDLE,
     158            constant( 'HCAPTCHA_URL' ) . "/assets/css/settings-list-page-base$min.css",
     159            [ self::FLATPICKR_HANDLE ],
     160            constant( 'HCAPTCHA_VERSION' )
     161        );
     162
     163        wp_enqueue_script(
     164            self::HANDLE,
     165            constant( 'HCAPTCHA_URL' ) . "/assets/js/settings-list-page-base$min.js",
     166            [ self::FLATPICKR_HANDLE ],
     167            constant( 'HCAPTCHA_VERSION' ),
     168            true
     169        );
     170
     171        wp_localize_script(
     172            self::HANDLE,
     173            self::OBJECT,
     174            [
     175                'delimiter' => self::TIMESPAN_DELIMITER,
     176                'locale'    => $this->get_language_code(),
     177            ]
     178        );
     179    }
     180
     181    /**
     182     * Display datepicker element.
     183     *
     184     * @return void
     185     */
     186    public function date_picker_display() {
     187        if ( ! $this->allowed ) {
     188            return;
     189        }
     190
     191        list( $choices, $chosen_filter, $value ) = $this->process_datepicker_choices();
     192
     193        // An array of allowed HTML elements and attributes for the datepicker choices.
     194        $choices_allowed_html = [
     195            'li'    => [],
     196            'label' => [],
     197            'input' => [
     198                'type'         => [],
     199                'name'         => [],
     200                'value'        => [],
     201                'checked'      => [],
     202                'aria-hidden'  => [],
     203                'data-default' => [],
     204            ],
     205        ];
     206
     207        ?>
     208        <div class="hcaptcha-filter">
     209            <button id="hcaptcha-datepicker-popover-button" class="button" role="button" aria-haspopup="true">
     210                <?php echo esc_html( $chosen_filter ); ?>
     211            </button>
     212            <div class="hcaptcha-datepicker-popover">
     213                <div class="hcaptcha-datepicker-popover-content">
     214                    <ul class="hcaptcha-datepicker-choices"
     215                        aria-label="<?php esc_attr_e( 'Datepicker options', 'hcaptcha-for-forms-and-more' ); ?>"
     216                        aria-orientation="vertical">
     217                        <?php echo wp_kses( '<li>' . implode( '</li><li>', $choices ) . '</li>', $choices_allowed_html ); ?>
     218                    </ul>
     219                    <div class="hcaptcha-datepicker-calendar">
     220                        <label for="hcaptcha-datepicker">
     221                            <input
     222                                type="text"
     223                                name="date"
     224                                tabindex="-1"
     225                                aria-hidden="true"
     226                                id="hcaptcha-datepicker"
     227                                value="<?php echo esc_attr( $value ); ?>">
     228                        </label>
     229                    </div>
     230                    <div class="hcaptcha-datepicker-action">
     231                        <button class="button-secondary" type="reset">
     232                            <?php esc_html_e( 'Cancel', 'hcaptcha-for-forms-and-more' ); ?>
     233                        </button>
     234                        <button class="button-primary hcaptcha-btn-blue" type="submit">
     235                            <?php esc_html_e( 'Apply', 'hcaptcha-for-forms-and-more' ); ?>
     236                        </button>
     237                    </div>
     238                </div>
     239            </div>
     240        </div>
     241        <?php
     242    }
     243
     244    /**
     245     * Sets the timespan (or date range) for performing mysql queries.
     246     *
     247     * Includes:
     248     * 1. A list of date filter options for the datepicker module.
     249     * 2. Currently selected filter or date range values. Last "X" days, or i.e. Feb 8, 2023 - Mar 9, 2023.
     250     * 3. Assigned timespan dates.
     251     *
     252     * @param array|null $timespan Given timespan (dates) preferably in WP timezone.
     253     *
     254     * @return array
     255     * @noinspection PhpMissingParamTypeInspection
     256     * @noinspection HtmlUnknownAttribute
     257     */
     258    protected function process_datepicker_choices( $timespan = null ): array {
     259        // Retrieve and validate timespan if none is given.
     260        if ( empty( $timespan ) || ! is_array( $timespan ) ) {
     261            $timespan = $this->process_timespan();
     262        }
     263
     264        list( $start_date, $end_date, $days ) = $timespan;
     265
     266        $filters       = $this->get_date_filter_choices();
     267        $selected      = isset( $filters[ $days ] ) ? $days : 'custom';
     268        $value         = $this->concat_dates( $start_date, $end_date );
     269        $chosen_filter = 'custom' === $selected ? $value : $filters[ $selected ];
     270        $choices       = [];
     271
     272        foreach ( $filters as $choice => $label ) {
     273            $timespan_dates = $this->get_timespan_dates( $choice );
     274            $checked        = checked( $selected, $choice, false );
     275            $default        = (int) self::DEFAULT_TIMESPAN_DAYS === $choice ? 'data-default' : '';
     276            $choices[]      = sprintf(
     277                '<label %s>%s<input type="radio" aria-hidden="true" name="timespan" value="%s" %s %s></label>',
     278                $checked ? 'class="is-selected"' : '',
     279                esc_html( $label ),
     280                esc_attr( $this->concat_dates( ...$timespan_dates ) ),
     281                esc_attr( $checked ),
     282                esc_attr( $default )
     283            );
     284        }
     285
     286        return [ $choices, $chosen_filter, $value ];
     287    }
     288
     289    /**
     290     * Sets the timespan (or date range) selected.
     291     *
     292     * Includes:
     293     * 1. Start date object in WP timezone.
     294     * 2. End date object in WP timezone.
     295     * 3. Number of "Last X days", if applicable, otherwise returns "custom".
     296     * 4. Label associated with the selected date filter choice. @see "get_date_filter_choices".
     297     *
     298     * @return array
     299     */
     300    protected function process_timespan(): array {
     301        $dates = (string) filter_input( INPUT_GET, 'date', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
     302
     303        // Return default timespan if dates are empty.
     304        if ( empty( $dates ) ) {
     305            return $this->get_timespan_dates( self::DEFAULT_TIMESPAN_DAYS );
     306        }
     307
     308        $dates = $this->maybe_validate_string_timespan( $dates );
     309
     310        list( $start_date, $end_date ) = explode( self::TIMESPAN_DELIMITER, $dates );
     311
     312        // Return default timespan if the start date is more recent than the end date.
     313        if ( strtotime( $start_date ) > strtotime( $end_date ) ) {
     314            return $this->get_timespan_dates( self::DEFAULT_TIMESPAN_DAYS );
     315        }
     316
     317        $timezone   = wp_timezone(); // Retrieve the timezone string for the site.
     318        $start_date = date_create_immutable( $start_date, $timezone );
     319        $end_date   = date_create_immutable( $end_date, $timezone );
     320
     321        // Return default timespan if date creation fails.
     322        if ( ! $start_date || ! $end_date ) {
     323            // @codeCoverageIgnoreStart
     324            return $this->get_timespan_dates( self::DEFAULT_TIMESPAN_DAYS );
     325            // @codeCoverageIgnoreEnd
     326        }
     327
     328        // Set time to 0:0:0 for start date and 23:59:59 for end date.
     329        $start_date = $start_date->setTime( 0, 0 );
     330        $end_date   = $end_date->setTime( 23, 59, 59 );
     331
     332        $days_diff    = '';
     333        $current_date = date_create_immutable( 'now', $timezone )->setTime( 23, 59, 59 );
     334
     335        // Calculate day difference only if the end date is equal to the current date.
     336        if ( ! $current_date->diff( $end_date )->format( '%a' ) ) {
     337            $days_diff = $end_date->diff( $start_date )->format( '%a' );
     338        }
     339
     340        list( $days, $timespan_label ) = $this->get_date_filter_choices( $days_diff );
     341
     342        return [
     343            $start_date,     // WP timezone.
     344            $end_date,       // WP timezone.
     345            $days,           // e.g., 22.
     346            $timespan_label, // e.g., Custom.
     347        ];
     348    }
     349
     350    /**
     351     * Check the delimiter to see if the end date is specified.
     352     * We can assume that the start and end dates are the same if the end date is missing.
     353     *
     354     * @param string $dates Given timespan (dates) in string. i.e. "2024-04-16 - 2024-05-16" or "2024-04-16".
     355     *
     356     * @return string
     357     */
     358    protected function maybe_validate_string_timespan( string $dates ): string {
     359        // The '-' is used as a delimiter for the datepicker module.
     360        if ( false !== strpos( $dates, self::TIMESPAN_DELIMITER ) ) {
     361            return $dates;
     362        }
     363
     364        return $dates . self::TIMESPAN_DELIMITER . $dates;
     365    }
     366
     367    /**
     368     * The number of days is converted to the start and end date range.
     369     *
     370     * @param string $days Timespan days.
     371     *
     372     * @return array
     373     */
     374    protected function get_timespan_dates( string $days ): array {
     375        list( $timespan_key, $timespan_label ) = $this->get_date_filter_choices( $days );
     376
     377        // Bail early, if the given number of days is NOT a number nor a numeric string.
     378        if ( ! is_numeric( $days ) ) {
     379            return [ '', '', $timespan_key, $timespan_label ];
     380        }
     381
     382        $end_date   = date_create_immutable( 'now', wp_timezone() );
     383        $start_date = $end_date;
     384
     385        if ( (int) $days > 0 ) {
     386            $start_date = $start_date->modify( "-$days day" );
     387        }
     388
     389        $start_date = $start_date->setTime( 0, 0 );
     390        $end_date   = $end_date->setTime( 23, 59, 59 );
     391
     392        return [
     393            $start_date,     // WP timezone.
     394            $end_date,       // WP timezone.
     395            $timespan_key,   // i.e. 30.
     396            $timespan_label, // i.e. Last 30 days.
     397        ];
     398    }
     399
     400    /**
     401     * Returns a list of date filter options for the datepicker module.
     402     *
     403     * @param string|null $key Optional. Key associated with available filters.
     404     *
     405     * @return array
     406     * @noinspection PhpMissingParamTypeInspection
     407     */
     408    protected function get_date_filter_choices( $key = null ): array {
     409        // Available date filters.
     410        $choices = [
     411            '0'      => esc_html__( 'Today', 'wpforms-lite' ),
     412            '1'      => esc_html__( 'Yesterday', 'wpforms-lite' ),
     413            '7'      => esc_html__( 'Last 7 days', 'wpforms-lite' ),
     414            '30'     => esc_html__( 'Last 30 days', 'wpforms-lite' ),
     415            '90'     => esc_html__( 'Last 90 days', 'wpforms-lite' ),
     416            '365'    => esc_html__( 'Last 1 year', 'wpforms-lite' ),
     417            'custom' => esc_html__( 'Custom', 'wpforms-lite' ),
     418        ];
     419
     420        // Bail early, and return the full list of options.
     421        if ( is_null( $key ) ) {
     422            return $choices;
     423        }
     424
     425        // Return the "Custom" filter if the given key is not found.
     426        $key = isset( $choices[ $key ] ) ? $key : 'custom';
     427
     428        return [ $key, $choices[ $key ] ];
     429    }
     430
     431    /**
     432     * Concatenate given dates into a single string. i.e. "2024-04-16 - 2024-05-16".
     433     *
     434     * @param DateTimeImmutable|mixed $start_date Start date.
     435     * @param DateTimeImmutable|mixed $end_date   End date.
     436     * @param int|string              $fallback   Fallback value if dates are not valid.
     437     *
     438     * @return string
     439     */
     440    private function concat_dates( $start_date, $end_date, $fallback = '' ) {
     441        // Bail early, if the given dates are not valid.
     442        if ( ! ( $start_date instanceof DateTimeImmutable ) || ! ( $end_date instanceof DateTimeImmutable ) ) {
     443            return $fallback;
     444        }
     445
     446        return implode(
     447            self::TIMESPAN_DELIMITER,
     448            [
     449                $start_date->format( self::DATE_FORMAT ),
     450                $end_date->format( self::DATE_FORMAT ),
     451            ]
     452        );
     453    }
     454
     455    /**
     456     * Get the ISO 639-2 Language Code from user/site locale.
     457     *
     458     * @see   http://www.loc.gov/standards/iso639-2/php/code_list.php
     459     *
     460     * @return string
     461     */
     462    private function get_language_code(): string {
     463        $default_lang = 'en';
     464        $locale       = get_user_locale();
     465
     466        if ( ! empty( $locale ) ) {
     467            $lang = explode( '_', $locale );
     468
     469            if ( ! empty( $lang ) && is_array( $lang ) ) {
     470                $default_lang = strtolower( $lang[0] );
     471            }
     472        }
     473
     474        return $default_lang;
     475    }
    47476}
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Settings/PluginSettingsBase.php

    r3080217 r3095958  
    2323
    2424    /**
     25     * Settings option name.
     26     */
     27    const OPTION_NAME = 'hcaptcha_settings';
     28
     29    /**
    2530     * The 'submit' button was shown.
    2631     *
     
    98103     */
    99104    protected function option_name(): string {
    100         return 'hcaptcha_settings';
     105        return self::OPTION_NAME;
    101106    }
    102107
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Settings/Settings.php

    r3081325 r3095958  
    105105
    106106        return $first_tab ? $first_tab->get_active_tab()->tab_name() : '';
     107    }
     108
     109    /**
     110     * Check if it is a Pro account.
     111     *
     112     * @return false
     113     */
     114    public function is_pro(): bool {
     115        return 'pro' === $this->get_license();
     116    }
     117
     118    /**
     119     * Check if it is a Pro account or General admin page.
     120     *
     121     * @return bool
     122     */
     123    public function is_pro_or_general(): bool {
     124        return $this->is_pro() || ( is_admin() && 'General' === $this->get_active_tab_name() );
    107125    }
    108126
     
    274292     */
    275293    public function get_theme(): string {
     294        $theme = $this->get( 'theme' );
     295
     296        if ( $this->is_on( 'custom_themes' ) && $this->is_pro_or_general() ) {
     297            $theme = $this->get_config_params()['theme']['palette']['mode'] ?? $theme;
     298        }
    276299
    277300        /**
     
    280303         * @param string $mode Current theme.
    281304         */
    282         return (string) apply_filters( 'hcap_theme', $this->get( 'theme' ) );
     305        return (string) apply_filters( 'hcap_theme', $theme );
    283306    }
    284307
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/Settings/SystemInfo.php

    r3081325 r3095958  
    107107     */
    108108    public function section_callback( array $arguments ) {
     109        $this->print_header();
     110
    109111        ?>
    110         <h2>
    111             <?php echo esc_html__( 'System Information', 'hcaptcha-for-forms-and-more' ); ?>
    112         </h2>
    113112        <div id="hcaptcha-system-info-wrap">
    114113            <span class="helper">
  • hcaptcha-for-forms-and-more/tags/4.2.0/src/php/WPDiscuz/Comment.php

    r3064004 r3095958  
    115115            self::HANDLE,
    116116            HCAPTCHA_URL . "/assets/js/hcaptcha-wpdiscuz-comment$min.js",
    117             [ 'wp-hooks' ],
     117            [],
    118118            HCAPTCHA_VERSION,
    119119            true
  • hcaptcha-for-forms-and-more/tags/4.2.0/vendor/composer/installed.php

    r3086102 r3095958  
    22    'root' => array(
    33        'name' => 'hcaptcha/hcaptcha-wordpress-plugin',
    4         'pretty_version' => '4.1.2',
    5         'version' => '4.1.2.0',
    6         'reference' => '77825b68c9bf0dee38f9da73b634861e79f9e69b',
     4        'pretty_version' => '4.2.0',
     5        'version' => '4.2.0.0',
     6        'reference' => 'aa580b1c05ee0aff974fbf1d99e92341a6f82094',
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../',
     
    1212    'versions' => array(
    1313        'hcaptcha/hcaptcha-wordpress-plugin' => array(
    14             'pretty_version' => '4.1.2',
    15             'version' => '4.1.2.0',
    16             'reference' => '77825b68c9bf0dee38f9da73b634861e79f9e69b',
     14            'pretty_version' => '4.2.0',
     15            'version' => '4.2.0.0',
     16            'reference' => 'aa580b1c05ee0aff974fbf1d99e92341a6f82094',
    1717            'type' => 'wordpress-plugin',
    1818            'install_path' => __DIR__ . '/../../',
  • hcaptcha-for-forms-and-more/trunk/assets/css/settings-base.css

    r3086102 r3095958  
    4545}
    4646
     47.hcaptcha-header-bar {
     48    display: flex;
     49    justify-content: space-between;
     50    align-items: center;
     51    margin: 0;
     52}
     53
    4754#hcaptcha-options h2 {
    4855    font-size: 1.5em;
     
    269276        z-index: 1;
    270277    }
    271 }
     278
     279    .hcaptcha-settings-tab {
     280        margin-right: 15px;
     281    }
     282}
  • hcaptcha-for-forms-and-more/trunk/assets/css/settings-base.min.css

    r3086102 r3095958  
    1 body.settings_page_hcaptcha{background:#f0f2f5;color:#5c6f8a}.wrap h1.hcaptcha-settings-header{align-items:center;display:flex;font-size:34px;font-weight:700}.hcaptcha-logo{height:64px;margin:10px 5px 10px 0}.hcaptcha-settings-tabs{background:#fff;display:flex;flex-wrap:wrap;justify-content:space-between;line-height:4.5em;margin:10px -20px 0;padding:0 20px}.hcaptcha-settings-tab{border-bottom:2px solid transparent;color:#646970;display:inline-block;font-size:1.1em;margin-right:30px;text-decoration:none}.hcaptcha-settings-tab:hover{border-bottom-color:#025176!important;border-bottom:2px solid;color:#666}.hcaptcha-settings-tab.active{border-bottom:2px solid #0075ab}#hcaptcha-options h2{color:#5c6f8a;font-size:1.5em}#hcaptcha-options h3{color:#5c6f8a;margin:1.5em 0 1em}#hcaptcha-options .notice-dismiss:before{color:#5c6f8a}#hcaptcha-options table tbody tr td{margin:0;padding:0;position:relative}#hcaptcha-options table tr td input[type=checkbox]{border:none;box-shadow:none;display:inline;height:1.25rem;margin:-.125rem .5rem 0 0;width:2.3611rem}#hcaptcha-options table tr td input[type=checkbox]:before{background:url(../images/checkbox-off.svg);background-size:cover;content:"";display:inline-block;height:1.25rem;margin:0;width:2.3611rem}#hcaptcha-options table tr td input[type=checkbox]:checked:before{background:no-repeat url(../images/checkbox-on.svg);background-size:cover}#hcaptcha-options fieldset:disabled{color:#dadada}#hcaptcha-options .button-primary{background-color:#026593;border-color:#026593;color:#fff}#hcaptcha-options .button-primary:hover{background-color:#025176}#hcaptcha-options .button-secondary{background-color:#fff;border-color:#026593;color:#026593}#hcaptcha-options .button-secondary:hover{background-color:#ccc}#hcaptcha-options a{color:#0075ab}#hcaptcha-navigation a{border-color:#0075ab}#hcaptcha-options a.hcaptcha-settings-tab{color:#5c6f8a}#hcaptcha-options .helper:before{background:#5c6f8a;border-radius:1.2em;color:#fff;content:"?";height:1.2em;position:absolute;right:0;text-align:center;top:0;transform:translateY(-26px);width:1.2em}#hcaptcha-options fieldset+.helper:before{top:50%;transform:translate(25px,-.8em)}#hcaptcha-options .helper .helper-content{background:#5c6f8a;box-sizing:border-box;color:#f0f2f5;display:none;padding:.5em 1em;position:absolute;right:0;top:0;transform:translate(1px,10px);width:100%}#hcaptcha-options fieldset+.helper .helper-content{top:50%;transform:translate(25px,25px);width:calc(100% + 25px)}#hcaptcha-options .helper:hover{cursor:help}#hcaptcha-options .helper:hover .helper-content{display:block;z-index:1}#hcaptcha-options .helper .helper-content:after{border:10px solid transparent;border-bottom-color:#5c6f8a;content:"";position:absolute;right:0;top:0;transform:translateY(-100%)}#hcaptcha-options .helper .helper-content a{color:#fff}#hcaptcha-message{box-sizing:border-box}#hcaptcha-message p{font-size:13px;font-weight:600;line-height:1.5;margin:.5em 0}@keyframes blink{0%{opacity:1}16.7%{opacity:0}33.3%{opacity:1}50%{opacity:0}66.7%{opacity:1}83.3%{opacity:0}to{opacity:1}}.blink{animation:blink 3s linear}.hcaptcha-hide{display:none}.hcaptcha-excerpt{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hcaptcha-excerpt:hover .hcaptcha-hide{background:#5c6f8a;border:1px solid #c3c4c7;border-radius:6px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.1);color:#f0f2f5;display:block;left:0;max-width:300px;padding:8px 10px;position:absolute;text-align:center;top:0;white-space:normal;width:max-content;z-index:1}@media (max-width:782px){.hcaptcha-settings-tabs{margin:10px -12px 0 -10px;padding:0 12px 0 10px}}@media (max-width:600px){#hcaptcha-options table tbody{grid-template-columns:1fr}#hcaptcha-options table tbody tr{position:relative}#hcaptcha-options fieldset+.helper:before{transform:translateY(-.7em)}#hcaptcha-options fieldset+.helper .helper-content{transform:translateY(25px);width:100%}#hcaptcha-options .helper{z-index:1}}
     1body.settings_page_hcaptcha{background:#f0f2f5;color:#5c6f8a}.wrap h1.hcaptcha-settings-header{align-items:center;display:flex;font-size:34px;font-weight:700}.hcaptcha-logo{height:64px;margin:10px 5px 10px 0}.hcaptcha-settings-tabs{background:#fff;display:flex;flex-wrap:wrap;justify-content:space-between;line-height:4.5em;margin:10px -20px 0;padding:0 20px}.hcaptcha-settings-tab{border-bottom:2px solid transparent;color:#646970;display:inline-block;font-size:1.1em;margin-right:30px;text-decoration:none}.hcaptcha-settings-tab:hover{border-bottom-color:#025176!important;border-bottom:2px solid;color:#666}.hcaptcha-settings-tab.active{border-bottom:2px solid #0075ab}.hcaptcha-header-bar{align-items:center;display:flex;justify-content:space-between;margin:0}#hcaptcha-options h2{color:#5c6f8a;font-size:1.5em}#hcaptcha-options h3{color:#5c6f8a;margin:1.5em 0 1em}#hcaptcha-options .notice-dismiss:before{color:#5c6f8a}#hcaptcha-options table tbody tr td{margin:0;padding:0;position:relative}#hcaptcha-options table tr td input[type=checkbox]{border:none;box-shadow:none;display:inline;height:1.25rem;margin:-.125rem .5rem 0 0;width:2.3611rem}#hcaptcha-options table tr td input[type=checkbox]:before{background:url(../images/checkbox-off.svg);background-size:cover;content:"";display:inline-block;height:1.25rem;margin:0;width:2.3611rem}#hcaptcha-options table tr td input[type=checkbox]:checked:before{background:no-repeat url(../images/checkbox-on.svg);background-size:cover}#hcaptcha-options fieldset:disabled{color:#dadada}#hcaptcha-options .button-primary{background-color:#026593;border-color:#026593;color:#fff}#hcaptcha-options .button-primary:hover{background-color:#025176}#hcaptcha-options .button-secondary{background-color:#fff;border-color:#026593;color:#026593}#hcaptcha-options .button-secondary:hover{background-color:#ccc}#hcaptcha-options a{color:#0075ab}#hcaptcha-navigation a{border-color:#0075ab}#hcaptcha-options a.hcaptcha-settings-tab{color:#5c6f8a}#hcaptcha-options .helper:before{background:#5c6f8a;border-radius:1.2em;color:#fff;content:"?";height:1.2em;position:absolute;right:0;text-align:center;top:0;transform:translateY(-26px);width:1.2em}#hcaptcha-options fieldset+.helper:before{top:50%;transform:translate(25px,-.8em)}#hcaptcha-options .helper .helper-content{background:#5c6f8a;box-sizing:border-box;color:#f0f2f5;display:none;padding:.5em 1em;position:absolute;right:0;top:0;transform:translate(1px,10px);width:100%}#hcaptcha-options fieldset+.helper .helper-content{top:50%;transform:translate(25px,25px);width:calc(100% + 25px)}#hcaptcha-options .helper:hover{cursor:help}#hcaptcha-options .helper:hover .helper-content{display:block;z-index:1}#hcaptcha-options .helper .helper-content:after{border:10px solid transparent;border-bottom-color:#5c6f8a;content:"";position:absolute;right:0;top:0;transform:translateY(-100%)}#hcaptcha-options .helper .helper-content a{color:#fff}#hcaptcha-message{box-sizing:border-box}#hcaptcha-message p{font-size:13px;font-weight:600;line-height:1.5;margin:.5em 0}@keyframes blink{0%{opacity:1}16.7%{opacity:0}33.3%{opacity:1}50%{opacity:0}66.7%{opacity:1}83.3%{opacity:0}to{opacity:1}}.blink{animation:blink 3s linear}.hcaptcha-hide{display:none}.hcaptcha-excerpt{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hcaptcha-excerpt:hover .hcaptcha-hide{background:#5c6f8a;border:1px solid #c3c4c7;border-radius:6px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.1);color:#f0f2f5;display:block;left:0;max-width:300px;padding:8px 10px;position:absolute;text-align:center;top:0;white-space:normal;width:max-content;z-index:1}@media (max-width:782px){.hcaptcha-settings-tabs{margin:10px -12px 0 -10px;padding:0 12px 0 10px}}@media (max-width:600px){#hcaptcha-options table tbody{grid-template-columns:1fr}#hcaptcha-options table tbody tr{position:relative}#hcaptcha-options fieldset+.helper:before{transform:translateY(-.7em)}#hcaptcha-options fieldset+.helper .helper-content{transform:translateY(25px);width:100%}#hcaptcha-options .helper{z-index:1}.hcaptcha-settings-tab{margin-right:15px}}
  • hcaptcha-for-forms-and-more/trunk/assets/js/events.js

    r3086102 r3095958  
    22
    33/**
     4 * @param HCaptchaEventsObject.failed
     5 * @param HCaptchaEventsObject.failedLabel
    46 * @param HCaptchaEventsObject.succeed
    5  * @param HCaptchaEventsObject.failed
    67 * @param HCaptchaEventsObject.succeedLabel
    7  * @param HCaptchaEventsObject.failedLabel
     8 * @param HCaptchaEventsObject.unit
    89 */
    910document.addEventListener( 'DOMContentLoaded', function() {
     
    4748                        },
    4849                        tooltipFormat: 'dd.MM.yyyy HH:mm',
     50                        unit: HCaptchaEventsObject.unit,
    4951                    },
    5052                },
  • hcaptcha-for-forms-and-more/trunk/assets/js/events.min.js

    r3086102 r3095958  
    1 document.addEventListener("DOMContentLoaded",(function(){var e=document.getElementById("eventsChart"),t=window.innerWidth>600?3:2;new Chart(e,{type:"bar",data:{datasets:[{label:HCaptchaEventsObject.succeedLabel,data:HCaptchaEventsObject.succeed,borderWidth:1},{label:HCaptchaEventsObject.failedLabel,data:HCaptchaEventsObject.failed,borderWidth:1}]},options:{responsive:!0,maintainAspectRatio:!0,aspectRatio:t,scales:{x:{type:"time",time:{displayFormats:{millisecond:"HH:mm:ss",second:"HH:mm:ss",minute:"HH:mm",hour:"HH:mm",day:"dd.MM.yyyy",week:"dd.MM.yyyy",month:"dd.MM.yyyy",quarter:"dd.MM.yyyy",year:"dd.MM.yyyy"},tooltipFormat:"dd.MM.yyyy HH:mm"}},y:{beginAtZero:!0,ticks:{precision:0}}}}})}));
     1document.addEventListener("DOMContentLoaded",(function(){var e=document.getElementById("eventsChart"),t=window.innerWidth>600?3:2;new Chart(e,{type:"bar",data:{datasets:[{label:HCaptchaEventsObject.succeedLabel,data:HCaptchaEventsObject.succeed,borderWidth:1},{label:HCaptchaEventsObject.failedLabel,data:HCaptchaEventsObject.failed,borderWidth:1}]},options:{responsive:!0,maintainAspectRatio:!0,aspectRatio:t,scales:{x:{type:"time",time:{displayFormats:{millisecond:"HH:mm:ss",second:"HH:mm:ss",minute:"HH:mm",hour:"HH:mm",day:"dd.MM.yyyy",week:"dd.MM.yyyy",month:"dd.MM.yyyy",quarter:"dd.MM.yyyy",year:"dd.MM.yyyy"},tooltipFormat:"dd.MM.yyyy HH:mm",unit:HCaptchaEventsObject.unit}},y:{beginAtZero:!0,ticks:{precision:0}}}}})}));
  • hcaptcha-for-forms-and-more/trunk/assets/js/forms.js

    r3086102 r3095958  
    44 * @param HCaptchaFormsObject.served
    55 * @param HCaptchaFormsObject.servedLabel
     6 * @param HCaptchaFormsObject.unit
    67 */
    78document.addEventListener( 'DOMContentLoaded', function() {
     
    4142                        },
    4243                        tooltipFormat: 'dd.MM.yyyy HH:mm',
     44                        unit: HCaptchaFormsObject.unit,
    4345                    },
    4446                },
  • hcaptcha-for-forms-and-more/trunk/assets/js/forms.min.js

    r3086102 r3095958  
    1 document.addEventListener("DOMContentLoaded",(function(){var e=document.getElementById("formsChart"),t=window.innerWidth>600?3:2;new Chart(e,{type:"bar",data:{datasets:[{label:HCaptchaFormsObject.servedLabel,backgroundColor:"rgba(2,101,147,0.5)",data:HCaptchaFormsObject.served,borderWidth:1}]},options:{responsive:!0,maintainAspectRatio:!0,aspectRatio:t,scales:{x:{type:"time",time:{displayFormats:{millisecond:"HH:mm:ss",second:"HH:mm:ss",minute:"HH:mm",hour:"HH:mm",day:"dd.MM.yyyy",week:"dd.MM.yyyy",month:"dd.MM.yyyy",quarter:"dd.MM.yyyy",year:"dd.MM.yyyy"},tooltipFormat:"dd.MM.yyyy HH:mm"}},y:{beginAtZero:!0,ticks:{precision:0}}}}})}));
     1document.addEventListener("DOMContentLoaded",(function(){var t=document.getElementById("formsChart"),e=window.innerWidth>600?3:2;new Chart(t,{type:"bar",data:{datasets:[{label:HCaptchaFormsObject.servedLabel,backgroundColor:"rgba(2,101,147,0.5)",data:HCaptchaFormsObject.served,borderWidth:1}]},options:{responsive:!0,maintainAspectRatio:!0,aspectRatio:e,scales:{x:{type:"time",time:{displayFormats:{millisecond:"HH:mm:ss",second:"HH:mm:ss",minute:"HH:mm",hour:"HH:mm",day:"dd.MM.yyyy",week:"dd.MM.yyyy",month:"dd.MM.yyyy",quarter:"dd.MM.yyyy",year:"dd.MM.yyyy"},tooltipFormat:"dd.MM.yyyy HH:mm",unit:HCaptchaFormsObject.unit}},y:{beginAtZero:!0,ticks:{precision:0}}}}})}));
  • hcaptcha-for-forms-and-more/trunk/assets/js/general.js

    r3081325 r3095958  
    104104
    105105    function getCleanConsoleLogs() {
    106         const ignore = [ 'recaptchacompat disabled' ];
     106        const ignore = [
     107            'recaptchacompat disabled',
     108            'Missing sitekey - https://hcaptcha.com/docs/configuration#jsapi',
     109        ];
    107110        const logs = [];
    108111
     
    200203        const sampleHCaptcha = document.querySelector( '#hcaptcha-options .h-captcha' );
    201204        sampleHCaptcha.innerHTML = '';
     205
     206        // Map the theme to the palette mode.
     207        params.theme = params?.theme?.palette?.mode;
     208
     209        if ( ! params.theme ) {
     210            // Remove the theme if it's not set.
     211            delete params.theme;
     212        }
    202213
    203214        for ( const key in params ) {
  • hcaptcha-for-forms-and-more/trunk/assets/js/general.min.js

    r3081325 r3095958  
    1 (()=>{var t={};function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},e(t)}t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}();var a=function(a){var n="#hcaptcha-message",c=a(n),o=a("form.hcaptcha-general"),r=a('[name="hcaptcha_settings[site_key]"]'),i=a('[name="hcaptcha_settings[secret_key]"]'),s=a("#check_config"),l=a("#reset_notifications"),h=a('[name="hcaptcha_settings[theme]"]'),p=a('[name="hcaptcha_settings[size]"]'),u=a('[name="hcaptcha_settings[language]"]'),d=a('[name="hcaptcha_settings[mode]"]'),f=a('[name="hcaptcha_settings[custom_themes][]"]'),v=a(".hcaptcha-general-custom-prop select"),m=a(".hcaptcha-general-custom-value input"),g=a('[name="hcaptcha_settings[config_params]"]'),b=a(".hcaptcha-section-enterprise + table input"),y=a('[name="hcaptcha_settings[recaptcha_compat_off][]"]'),C=o.find("#submit"),j={},O=r.val(),H=i.val(),k=T();j[HCaptchaGeneralObject.modeLive]=HCaptchaGeneralObject.siteKey,j[HCaptchaGeneralObject.modeTestPublisher]=HCaptchaGeneralObject.modeTestPublisherSiteKey,j[HCaptchaGeneralObject.modeTestEnterpriseSafeEndUser]=HCaptchaGeneralObject.modeTestEnterpriseSafeEndUserSiteKey,j[HCaptchaGeneralObject.modeTestEnterpriseBotDetected]=HCaptchaGeneralObject.modeTestEnterpriseBotDetectedSiteKey;var G=!1,S=!1,_=[];function w(t){var e={};return t.each((function(){var t=a(this),n=t.attr("name").replace(/hcaptcha_settings\[(.+)]/,"$1");e[n]=t.val()})),e}function T(){return w(b)}function A(){c.remove(),a('<div id="hcaptcha-message"></div>').insertAfter("#hcaptcha-options h2"),c=a(n)}function E(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(t=void 0===t?"":String(t),t=(t+="\n"+function(){for(var t=["recaptchacompat disabled"],e=[],a=0;a<_.length;a++){for(var n=_[a],c=n[0],o=n[1],r=Object.keys(o),i=[],s=0;s<r.length;s++){var l=o[s];"string"==typeof l&&-1===t.indexOf(l)&&i.push([c,l].join(" "))}e.push(i.join("\n"))}return _=[],e.join("\n")}()).trim()){c.removeClass(),c.addClass(e+" notice is-dismissible");var n=t.split("\n").map((function(t){return"<p>".concat(t,"</p>")}));c.html(n.join("")),a(document).trigger("wp-updates-notice-added");var o=a("#wpwrap").position().top;a("html, body").animate({scrollTop:c.offset().top-o-parseInt(c.css("margin-bottom"))},1e3)}}function x(){E(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"","notice-success")}function N(){E(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"","notice-error")}function L(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=Object.assign(hCaptcha.getParams(),t);hCaptcha.setParams(e);var a=document.querySelector("#hcaptcha-options .h-captcha");for(var n in a.innerHTML="",t)a.setAttribute("data-".concat(n),"".concat(t[n]));hCaptcha.bindEvents()}function K(t,a){var n=function(t){return t&&"object"===e(t)};return n(t)&&n(a)?(Object.keys(a).forEach((function(e){var c=t[e],o=a[e];Array.isArray(c)&&Array.isArray(o)?t[e]=c.concat(o):n(c)&&n(o)?t[e]=K(Object.assign({},c),o):t[e]=o})),t):a}function U(t){var a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";for(var n in t){var c=a?"".concat(a,"--").concat(n):n;if("object"===e(t[n])&&null!==t[n])U(t[n],c);else{var o=t[n],r=c.replace(/theme--/g,""),i="".concat(r,"=").concat(o),s=v.find('option[value*="'.concat(r,'="]'));1===s.length&&(s.attr("value",i),s.is(":selected")&&m.val(o))}}}function B(){var t,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},a=g.val().trim();a=a||null;try{t=JSON.parse(a)}catch(t){return g.css("background-color","#ffabaf"),C.attr("disabled",!0),void N("Bad JSON!")}t=K(t,e),g.val(JSON.stringify(t,null,2)),U(t),f.prop("checked")||(t={sitekey:r.val(),theme:h.val(),size:p.val(),hl:u.val()}),L(t)}function P(){r.val()===O&&i.val()===H?(G=!1,A(),C.attr("disabled",!1)):G||(G=!0,N(HCaptchaGeneralObject.checkConfigNotice),C.attr("disabled",!0))}function J(t){return t=t.replace(/(http|https):\/\//,""),"https://"+new URL("https://"+t).host}!function(){_=[];var t=console.log,e=console.warn,a=console.info,n=console.error,c=console.clear;console.log=function(e){_.push(["Console log:",arguments]),t.apply(console,arguments)},console.warn=function(t){_.push(["Console warn:",arguments]),e.apply(console,arguments)},console.info=function(t){_.push(["Console info:",arguments]),a.apply(console,arguments)},console.error=function(t){_.push(["Console error:",arguments]),n.apply(console,arguments)},console.clear=function(){_=[],c()}}(),document.addEventListener("hCaptchaLoaded",(function(){N()})),s.on("click",(function(t){t.preventDefault(),""!==a(".hcaptcha-general-sample-hcaptcha iframe").attr("data-hcaptcha-response")?function(){A(),C.attr("disabled",!0);var t={action:HCaptchaGeneralObject.checkConfigAction,nonce:HCaptchaGeneralObject.checkConfigNonce,mode:d.val(),siteKey:r.val(),secretKey:i.val(),"h-captcha-response":a('textarea[name="h-captcha-response"]').val()};a.post({url:HCaptchaGeneralObject.ajaxUrl,data:t,beforeSend:function(){return x(HCaptchaGeneralObject.checkingConfigMsg)}}).done((function(t){t.success?(O=r.val(),H=i.val(),k=w(b),S=!1,x(t.data),C.attr("disabled",!1)):N(t.data)})).fail((function(t){N(t.statusText)})).always((function(){L()}))}():kaggDialog.confirm({title:HCaptchaGeneralObject.completeHCaptchaTitle,content:HCaptchaGeneralObject.completeHCaptchaContent,type:"info",buttons:{ok:{text:HCaptchaGeneralObject.OKBtnText}},onAction:function(){return window.hCaptchaReset(document.querySelector(".hcaptcha-general-sample-hcaptcha"))}})})),r.on("change",(function(t){L({sitekey:a(t.target).val()}),P()})),i.on("change",(function(){P()})),h.on("change",(function(t){L({theme:a(t.target).val()})})),p.on("change",(function(t){var e=a("#hcaptcha-invisible-notice"),n=a(t.target).val();"invisible"===n?e.show():e.hide(),L({size:n})})),u.on("change",(function(t){L({hl:a(t.target).val()})})),d.on("change",(function(t){var e=a(t.target).val();j.hasOwnProperty(e)&&(e===HCaptchaGeneralObject.modeLive?(r.attr("disabled",!1),i.attr("disabled",!1)):(r.attr("disabled",!0),i.attr("disabled",!0)),L({sitekey:j[e]}))})),f.on("change",(function(){B()})),g.on("blur",(function(){B()})),g.on("focus",(function(){g.css("background-color","unset"),C.attr("disabled",!1)})),b.on("change",(function(){!function(){var e={onload:"hCaptchaOnLoad",render:"explicit"};y.prop("checked")&&(e.recaptchacompat="off"),f.prop("checked")&&(e.custom="true");var a={asset_host:"assethost",endpoint:"endpoint",host:"host",image_host:"imghost",report_api:"reportapi",sentry:"sentry"},n=T();for(var c in a){var o=n[c].trim();o&&(e[a[c]]=encodeURIComponent(J(o)))}var r=n.api_host.trim();r=J(r=r||"js.hcaptcha.com")+"/1/api.js";var i=new URL(r);for(var s in e)i.searchParams.append(s,e[s]);document.getElementById("hcaptcha-api").remove(),delete t.g.hcaptcha,document.querySelector("#hcaptcha-options .h-captcha").innerHTML="";var l=document.getElementsByTagName("head")[0],h=document.createElement("script");h.type="text/javascript",h.id="hcaptcha-api",h.src=i.href,l.appendChild(h)}(),JSON.stringify(T())===JSON.stringify(k)?(S=!1,A(),C.attr("disabled",!1)):S||(S=!0,N(HCaptchaGeneralObject.checkConfigNotice),C.attr("disabled",!0))})),a(".hcaptcha-general h3").on("click",(function(t){var e=a(t.currentTarget);e.toggleClass("closed");var n={action:HCaptchaGeneralObject.toggleSectionAction,nonce:HCaptchaGeneralObject.toggleSectionNonce,section:e.attr("class").replaceAll(/(hcaptcha-section-|closed)/g,"").trim(),status:!e.hasClass("closed")};a.post({url:HCaptchaGeneralObject.ajaxUrl,data:n}).done((function(t){t.success||N(t.data)})).fail((function(t){N(t.statusText)}))})),s.removeAttr("name"),l.removeAttr("name"),v.removeAttr("name"),m.removeAttr("name"),v.find("option").each((function(){var t=a(this);t.val().split("=")[1]||t.attr("disabled",!0)})),m.val(""),v.on("change",(function(){var t=a(this).find("option:selected").val().split("="),e=t[0],n=t[1];"palette--mode"===e?(m.attr("type","text"),m.val(n)):(m.val(n),m.attr("type","color"))})),m.on("change",(function(t){var e=a(t.target).val(),n=v.find("option:selected"),c=n.val().split("="),o=c[0],r=e;n.val(o+"="+e),B(r=(o="theme--"+c[0]).split("--").reverse().reduce((function(t,e){var a={};return a[e]=t,a}),r))}))};window.hCaptchaGeneral=a,jQuery(document).ready(a)})();
     1(()=>{var e={};function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t(e)}e.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}();var a=function(a){var n="#hcaptcha-message",c=a(n),o=a("form.hcaptcha-general"),r=a('[name="hcaptcha_settings[site_key]"]'),i=a('[name="hcaptcha_settings[secret_key]"]'),s=a("#check_config"),l=a("#reset_notifications"),h=a('[name="hcaptcha_settings[theme]"]'),p=a('[name="hcaptcha_settings[size]"]'),u=a('[name="hcaptcha_settings[language]"]'),d=a('[name="hcaptcha_settings[mode]"]'),f=a('[name="hcaptcha_settings[custom_themes][]"]'),v=a(".hcaptcha-general-custom-prop select"),m=a(".hcaptcha-general-custom-value input"),g=a('[name="hcaptcha_settings[config_params]"]'),b=a(".hcaptcha-section-enterprise + table input"),y=a('[name="hcaptcha_settings[recaptcha_compat_off][]"]'),C=o.find("#submit"),j={},O=r.val(),H=i.val(),k=T();j[HCaptchaGeneralObject.modeLive]=HCaptchaGeneralObject.siteKey,j[HCaptchaGeneralObject.modeTestPublisher]=HCaptchaGeneralObject.modeTestPublisherSiteKey,j[HCaptchaGeneralObject.modeTestEnterpriseSafeEndUser]=HCaptchaGeneralObject.modeTestEnterpriseSafeEndUserSiteKey,j[HCaptchaGeneralObject.modeTestEnterpriseBotDetected]=HCaptchaGeneralObject.modeTestEnterpriseBotDetectedSiteKey;var G=!1,S=!1,_=[];function w(e){var t={};return e.each((function(){var e=a(this),n=e.attr("name").replace(/hcaptcha_settings\[(.+)]/,"$1");t[n]=e.val()})),t}function T(){return w(b)}function A(){c.remove(),a('<div id="hcaptcha-message"></div>').insertAfter("#hcaptcha-options h2"),c=a(n)}function E(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(e=void 0===e?"":String(e),e=(e+="\n"+function(){for(var e=["recaptchacompat disabled","Missing sitekey - https://hcaptcha.com/docs/configuration#jsapi"],t=[],a=0;a<_.length;a++){for(var n=_[a],c=n[0],o=n[1],r=Object.keys(o),i=[],s=0;s<r.length;s++){var l=o[s];"string"==typeof l&&-1===e.indexOf(l)&&i.push([c,l].join(" "))}t.push(i.join("\n"))}return _=[],t.join("\n")}()).trim()){c.removeClass(),c.addClass(t+" notice is-dismissible");var n=e.split("\n").map((function(e){return"<p>".concat(e,"</p>")}));c.html(n.join("")),a(document).trigger("wp-updates-notice-added");var o=a("#wpwrap").position().top;a("html, body").animate({scrollTop:c.offset().top-o-parseInt(c.css("margin-bottom"))},1e3)}}function x(){E(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"","notice-success")}function N(){E(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"","notice-error")}function L(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},a=Object.assign(hCaptcha.getParams(),t);hCaptcha.setParams(a);var n=document.querySelector("#hcaptcha-options .h-captcha");for(var c in n.innerHTML="",t.theme=null==t||null===(e=t.theme)||void 0===e||null===(e=e.palette)||void 0===e?void 0:e.mode,t.theme||delete t.theme,t)n.setAttribute("data-".concat(c),"".concat(t[c]));hCaptcha.bindEvents()}function K(e,a){var n=function(e){return e&&"object"===t(e)};return n(e)&&n(a)?(Object.keys(a).forEach((function(t){var c=e[t],o=a[t];Array.isArray(c)&&Array.isArray(o)?e[t]=c.concat(o):n(c)&&n(o)?e[t]=K(Object.assign({},c),o):e[t]=o})),e):a}function U(e){var a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";for(var n in e){var c=a?"".concat(a,"--").concat(n):n;if("object"===t(e[n])&&null!==e[n])U(e[n],c);else{var o=e[n],r=c.replace(/theme--/g,""),i="".concat(r,"=").concat(o),s=v.find('option[value*="'.concat(r,'="]'));1===s.length&&(s.attr("value",i),s.is(":selected")&&m.val(o))}}}function B(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},a=g.val().trim();a=a||null;try{e=JSON.parse(a)}catch(e){return g.css("background-color","#ffabaf"),C.attr("disabled",!0),void N("Bad JSON!")}e=K(e,t),g.val(JSON.stringify(e,null,2)),U(e),f.prop("checked")||(e={sitekey:r.val(),theme:h.val(),size:p.val(),hl:u.val()}),L(e)}function P(){r.val()===O&&i.val()===H?(G=!1,A(),C.attr("disabled",!1)):G||(G=!0,N(HCaptchaGeneralObject.checkConfigNotice),C.attr("disabled",!0))}function J(e){return e=e.replace(/(http|https):\/\//,""),"https://"+new URL("https://"+e).host}!function(){_=[];var e=console.log,t=console.warn,a=console.info,n=console.error,c=console.clear;console.log=function(t){_.push(["Console log:",arguments]),e.apply(console,arguments)},console.warn=function(e){_.push(["Console warn:",arguments]),t.apply(console,arguments)},console.info=function(e){_.push(["Console info:",arguments]),a.apply(console,arguments)},console.error=function(e){_.push(["Console error:",arguments]),n.apply(console,arguments)},console.clear=function(){_=[],c()}}(),document.addEventListener("hCaptchaLoaded",(function(){N()})),s.on("click",(function(e){e.preventDefault(),""!==a(".hcaptcha-general-sample-hcaptcha iframe").attr("data-hcaptcha-response")?function(){A(),C.attr("disabled",!0);var e={action:HCaptchaGeneralObject.checkConfigAction,nonce:HCaptchaGeneralObject.checkConfigNonce,mode:d.val(),siteKey:r.val(),secretKey:i.val(),"h-captcha-response":a('textarea[name="h-captcha-response"]').val()};a.post({url:HCaptchaGeneralObject.ajaxUrl,data:e,beforeSend:function(){return x(HCaptchaGeneralObject.checkingConfigMsg)}}).done((function(e){e.success?(O=r.val(),H=i.val(),k=w(b),S=!1,x(e.data),C.attr("disabled",!1)):N(e.data)})).fail((function(e){N(e.statusText)})).always((function(){L()}))}():kaggDialog.confirm({title:HCaptchaGeneralObject.completeHCaptchaTitle,content:HCaptchaGeneralObject.completeHCaptchaContent,type:"info",buttons:{ok:{text:HCaptchaGeneralObject.OKBtnText}},onAction:function(){return window.hCaptchaReset(document.querySelector(".hcaptcha-general-sample-hcaptcha"))}})})),r.on("change",(function(e){L({sitekey:a(e.target).val()}),P()})),i.on("change",(function(){P()})),h.on("change",(function(e){L({theme:a(e.target).val()})})),p.on("change",(function(e){var t=a("#hcaptcha-invisible-notice"),n=a(e.target).val();"invisible"===n?t.show():t.hide(),L({size:n})})),u.on("change",(function(e){L({hl:a(e.target).val()})})),d.on("change",(function(e){var t=a(e.target).val();j.hasOwnProperty(t)&&(t===HCaptchaGeneralObject.modeLive?(r.attr("disabled",!1),i.attr("disabled",!1)):(r.attr("disabled",!0),i.attr("disabled",!0)),L({sitekey:j[t]}))})),f.on("change",(function(){B()})),g.on("blur",(function(){B()})),g.on("focus",(function(){g.css("background-color","unset"),C.attr("disabled",!1)})),b.on("change",(function(){!function(){var t={onload:"hCaptchaOnLoad",render:"explicit"};y.prop("checked")&&(t.recaptchacompat="off"),f.prop("checked")&&(t.custom="true");var a={asset_host:"assethost",endpoint:"endpoint",host:"host",image_host:"imghost",report_api:"reportapi",sentry:"sentry"},n=T();for(var c in a){var o=n[c].trim();o&&(t[a[c]]=encodeURIComponent(J(o)))}var r=n.api_host.trim();r=J(r=r||"js.hcaptcha.com")+"/1/api.js";var i=new URL(r);for(var s in t)i.searchParams.append(s,t[s]);document.getElementById("hcaptcha-api").remove(),delete e.g.hcaptcha,document.querySelector("#hcaptcha-options .h-captcha").innerHTML="";var l=document.getElementsByTagName("head")[0],h=document.createElement("script");h.type="text/javascript",h.id="hcaptcha-api",h.src=i.href,l.appendChild(h)}(),JSON.stringify(T())===JSON.stringify(k)?(S=!1,A(),C.attr("disabled",!1)):S||(S=!0,N(HCaptchaGeneralObject.checkConfigNotice),C.attr("disabled",!0))})),a(".hcaptcha-general h3").on("click",(function(e){var t=a(e.currentTarget);t.toggleClass("closed");var n={action:HCaptchaGeneralObject.toggleSectionAction,nonce:HCaptchaGeneralObject.toggleSectionNonce,section:t.attr("class").replaceAll(/(hcaptcha-section-|closed)/g,"").trim(),status:!t.hasClass("closed")};a.post({url:HCaptchaGeneralObject.ajaxUrl,data:n}).done((function(e){e.success||N(e.data)})).fail((function(e){N(e.statusText)}))})),s.removeAttr("name"),l.removeAttr("name"),v.removeAttr("name"),m.removeAttr("name"),v.find("option").each((function(){var e=a(this);e.val().split("=")[1]||e.attr("disabled",!0)})),m.val(""),v.on("change",(function(){var e=a(this).find("option:selected").val().split("="),t=e[0],n=e[1];"palette--mode"===t?(m.attr("type","text"),m.val(n)):(m.val(n),m.attr("type","color"))})),m.on("change",(function(e){var t=a(e.target).val(),n=v.find("option:selected"),c=n.val().split("="),o=c[0],r=t;n.val(o+"="+t),B(r=(o="theme--"+c[0]).split("--").reverse().reduce((function(e,t){var a={};return a[t]=e,a}),r))}))};window.hCaptchaGeneral=a,jQuery(document).ready(a)})();
  • hcaptcha-for-forms-and-more/trunk/assets/js/integrations.js

    r3064004 r3095958  
    156156        }
    157157
     158        function updateActivationStati( stati ) {
     159            const $tables = $( '.form-table' );
     160
     161            for ( const [ key, status ] of Object.entries( stati ) ) {
     162                const statusClass = 'hcaptcha-integrations-' + key.replace( /_/g, '-' );
     163
     164                const $tr = $( `tr.${ statusClass }` );
     165                const currStatus = isActiveTable( $tr.closest( '.form-table' ) );
     166
     167                if ( currStatus !== status ) {
     168                    const $toTable = $tables.eq( status ? 0 : 1 );
     169                    const alt = $tr.find( '.hcaptcha-integrations-logo img' ).attr( 'alt' );
     170
     171                    insertIntoTable( $toTable, alt, $tr );
     172                }
     173            }
     174        }
     175
    158176        function toggleActivation() {
    159177            const activateClass = activate ? 'on' : 'off';
     
    175193                data,
    176194            } )
     195                /**
     196                 * @param {Object} response.data
     197                 * @param {Object} response.data.defaultTheme
     198                 * @param {Object} response.data.message
     199                 * @param {Object} response.data.stati
     200                 * @param {Object} response.data.themes
     201                 * @param {Object} response.success
     202                 */
    177203                .done( function( response ) {
    178204                    if ( response.success === undefined ) {
     
    201227                    insertIntoTable( $table, alt, $tr );
    202228                    showSuccessMessage( response.data.message );
     229                    updateActivationStati( response.data.stati );
    203230
    204231                    $( 'html, body' ).animate(
     
    330357            const search = $search.val().trim().toLowerCase();
    331358            const $logo = $( '.hcaptcha-integrations-logo img' );
     359            let $trFirst = null;
    332360
    333361            $logo.each( function( i, el ) {
     
    342370                if ( $el.data( 'label' ).toLowerCase().includes( search ) ) {
    343371                    $tr.show();
     372                    $trFirst = $trFirst ?? $tr;
    344373                } else {
    345374                    $tr.hide();
    346375                }
    347376            } );
     377
     378            if ( ! $trFirst ) {
     379                return;
     380            }
     381
     382            const scrollTop = $trFirst.offset().top + $trFirst.outerHeight() - $( window ).height() + 5;
     383
     384            $( 'html' ).stop().animate(
     385                { scrollTop },
     386                1000
     387            );
    348388        },
    349389        100
  • hcaptcha-for-forms-and-more/trunk/assets/js/integrations.min.js

    r3064004 r3095958  
    1 (()=>{var t=function(t){var e="#hcaptcha-message",a=t(e),n=t("#wpwrap"),i=t("#adminmenuwrap"),o=t("#hcaptcha-integrations-search");function c(e,o){a.removeClass(),a.addClass(o+" notice settings-error is-dismissible"),a.html("<p>".concat(e,"</p>")),t(document).trigger("wp-updates-notice-added");var c=a.clone();a.css("visibility","hidden"),c.css("margin","0px"),c.css("top",n.position().top),c.css("z-index","999999");var s="block"===i.css("display")?i.width():0;c.css("left",s),c.width(t(window).width()-s),c.css("position","fixed"),t("body").append(c),setTimeout((function(){a.css("visibility","unset"),c.remove()}),3e3)}function s(t){c(t,"notice-error")}function r(e,a,n){var i=!1,o=a.toLowerCase(),c=!function(t){return t.is(jQuery(".form-table").eq(0))}(e),s=n.find("fieldset");s.attr("disabled",c),s.find("input").attr("disabled",c),e.find("tbody").children().each((function(e,a){var c=t(a).find(".hcaptcha-integrations-logo img").attr("alt");if((c=(c=c||"").replace(" Logo","")).toLowerCase()>o)return n.insertBefore(t(a)),i=!0,!1})),i||e.find("tbody").append(n)}t(".form-table img").on("click",(function(i){function o(){var e,i,o=u?"on":"off",l=(i=document.querySelector(".kagg-dialog select"))&&null!==(e=i.value)&&void 0!==e?e:"",f={action:HCaptchaIntegrationsObject.action,nonce:HCaptchaIntegrationsObject.nonce,activate:u,entity:d,status:g,newTheme:l};p.addClass(o),t.post({url:HCaptchaIntegrationsObject.ajaxUrl,data:f}).done((function(e){if(void 0!==e.success)if(void 0!==e.data.themes&&(window.HCaptchaIntegrationsObject.themes=e.data.themes,window.HCaptchaIntegrationsObject.defaultTheme=e.data.defaultTheme),e.success){var i=t(".form-table").eq(u?0:1),o=n.position().top;!function(e,a,n){if("theme"===a){var i=t(".form-table"),o=e?"":'[data-label="'+n+'"]',c=i.eq(e?0:1).find('.hcaptcha-integrations-logo img[data-entity="theme"]'+o);if(c.length){var s=i.eq(e?1:0),l=c.closest("tr");r(s,c.attr("data-label"),l)}}}(u,d,l),r(i,h,p),function(t){c(t,"notice-success")}(e.data.message),t("html, body").animate({scrollTop:p.offset().top-o-a.outerHeight()},1e3)}else{var g,f;s(null!==(g=null===(f=e.data)||void 0===f?void 0:f.message)&&void 0!==g?g:e.data)}else c(HCaptchaIntegrationsObject.unexpectedErrorMsg,"notice-error")})).fail((function(t){s(t.statusText)})).always((function(){p.removeClass("on off")}))}i.preventDefault(),a.remove(),t('<div id="hcaptcha-message"></div>').insertAfter("#hcaptcha-options h2"),a=t(e);var l=t(i.target),d=l.data("entity");if(d=d||"",-1!==t.inArray(d,["core","theme","plugin"])&&-1===t.inArray(d,["core"])){var h=l.attr("alt");h=(h=h||"").replace(" Logo","");var p=l.closest("tr"),g=p.attr("class");g=g.replace("hcaptcha-integrations-","");var f,u,m="";if(p.find("fieldset").attr("disabled"))f="plugin"===d?HCaptchaIntegrationsObject.activateMsg:HCaptchaIntegrationsObject.activateThemeMsg,u=!0;else{if("plugin"===d)f=HCaptchaIntegrationsObject.deactivateMsg;else{for(var v in f=HCaptchaIntegrationsObject.deactivateThemeMsg,m="<p>"+HCaptchaIntegrationsObject.selectThemeMsg+"</p>",m+="<select>",HCaptchaIntegrationsObject.themes){var b=v===HCaptchaIntegrationsObject.defaultTheme?' selected="selected"':"";m+='<option value="'.concat(v,'"').concat(b,">").concat(HCaptchaIntegrationsObject.themes[v],"</option>")}m+="</select>"}u=!1}-1===t.inArray(d,["theme"])||u||0!==Object.keys(HCaptchaIntegrationsObject.themes).length?(f=f.replace("%s",h),i.ctrlKey?o():kaggDialog.confirm({title:f,content:m,type:u?"activate":"deactivate",buttons:{ok:{text:HCaptchaIntegrationsObject.OKBtnText},cancel:{text:HCaptchaIntegrationsObject.CancelBtnText}},onAction:function(t){t&&o()}})):kaggDialog.confirm({title:HCaptchaIntegrationsObject.onlyOneThemeMsg,content:"",type:"info",buttons:{ok:{text:HCaptchaIntegrationsObject.OKBtnText}}})}}));var l,d,h;o.on("input",(l=function(){var e=o.val().trim().toLowerCase();t(".hcaptcha-integrations-logo img").each((function(a,n){var i=t(n);if("core"!==i.data("entity")){var o=i.closest("tr");i.data("label").toLowerCase().includes(e)?o.show():o.hide()}}))},d=100,function(){var t=this,e=arguments;clearTimeout(h),h=setTimeout((function(){return l.apply(t,e)}),d)})),t("#hcaptcha-options").keydown((function(e){t(e.target).is(o)&&13===e.which&&e.preventDefault()}))};window.hCaptchaIntegrations=t,jQuery(document).ready(t)})();
     1(()=>{function t(t,a){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var a=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=a){var n,i,o,r,c=[],s=!0,l=!1;try{if(o=(a=a.call(t)).next,0===e){if(Object(a)!==a)return;s=!1}else for(;!(s=(n=o.call(a)).done)&&(c.push(n.value),c.length!==e);s=!0);}catch(t){l=!0,i=t}finally{try{if(!s&&null!=a.return&&(r=a.return(),Object(r)!==r))return}finally{if(l)throw i}}return c}}(t,a)||function(t,a){if(!t)return;if("string"==typeof t)return e(t,a);var n=Object.prototype.toString.call(t).slice(8,-1);"Object"===n&&t.constructor&&(n=t.constructor.name);if("Map"===n||"Set"===n)return Array.from(t);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return e(t,a)}(t,a)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function e(t,e){(null==e||e>t.length)&&(e=t.length);for(var a=0,n=new Array(e);a<e;a++)n[a]=t[a];return n}var a=function(e){var a="#hcaptcha-message",n=e(a),i=e("#wpwrap"),o=e("#adminmenuwrap"),r=e("#hcaptcha-integrations-search");function c(t,a){n.removeClass(),n.addClass(a+" notice settings-error is-dismissible"),n.html("<p>".concat(t,"</p>")),e(document).trigger("wp-updates-notice-added");var r=n.clone();n.css("visibility","hidden"),r.css("margin","0px"),r.css("top",i.position().top),r.css("z-index","999999");var c="block"===o.css("display")?o.width():0;r.css("left",c),r.width(e(window).width()-c),r.css("position","fixed"),e("body").append(r),setTimeout((function(){n.css("visibility","unset"),r.remove()}),3e3)}function s(t){c(t,"notice-error")}function l(t){return t.is(jQuery(".form-table").eq(0))}function u(t,a,n){var i=!1,o=a.toLowerCase(),r=!l(t),c=n.find("fieldset");c.attr("disabled",r),c.find("input").attr("disabled",r),t.find("tbody").children().each((function(t,a){var r=e(a).find(".hcaptcha-integrations-logo img").attr("alt");if((r=(r=r||"").replace(" Logo","")).toLowerCase()>o)return n.insertBefore(e(a)),i=!0,!1})),i||t.find("tbody").append(n)}e(".form-table img").on("click",(function(o){function r(){var a,o,r=v?"on":"off",d=(o=document.querySelector(".kagg-dialog select"))&&null!==(a=o.value)&&void 0!==a?a:"",m={action:HCaptchaIntegrationsObject.action,nonce:HCaptchaIntegrationsObject.nonce,activate:v,entity:f,status:g,newTheme:d};p.addClass(r),e.post({url:HCaptchaIntegrationsObject.ajaxUrl,data:m}).done((function(a){if(void 0!==a.success)if(void 0!==a.data.themes&&(window.HCaptchaIntegrationsObject.themes=a.data.themes,window.HCaptchaIntegrationsObject.defaultTheme=a.data.defaultTheme),a.success){var o=e(".form-table").eq(v?0:1),r=i.position().top;!function(t,a,n){if("theme"===a){var i=e(".form-table"),o=t?"":'[data-label="'+n+'"]',r=i.eq(t?0:1).find('.hcaptcha-integrations-logo img[data-entity="theme"]'+o);if(r.length){var c=i.eq(t?1:0),s=r.closest("tr");u(c,r.attr("data-label"),s)}}}(v,f,d),u(o,h,p),function(t){c(t,"notice-success")}(a.data.message),function(a){for(var n=e(".form-table"),i=0,o=Object.entries(a);i<o.length;i++){var r=t(o[i],2),c=r[0],s=r[1],d="hcaptcha-integrations-"+c.replace(/_/g,"-"),f=e("tr.".concat(d));l(f.closest(".form-table"))!==s&&u(n.eq(s?0:1),f.find(".hcaptcha-integrations-logo img").attr("alt"),f)}}(a.data.stati),e("html, body").animate({scrollTop:p.offset().top-r-n.outerHeight()},1e3)}else{var g,m;s(null!==(g=null===(m=a.data)||void 0===m?void 0:m.message)&&void 0!==g?g:a.data)}else c(HCaptchaIntegrationsObject.unexpectedErrorMsg,"notice-error")})).fail((function(t){s(t.statusText)})).always((function(){p.removeClass("on off")}))}o.preventDefault(),n.remove(),e('<div id="hcaptcha-message"></div>').insertAfter("#hcaptcha-options h2"),n=e(a);var d=e(o.target),f=d.data("entity");if(f=f||"",-1!==e.inArray(f,["core","theme","plugin"])&&-1===e.inArray(f,["core"])){var h=d.attr("alt");h=(h=h||"").replace(" Logo","");var p=d.closest("tr"),g=p.attr("class");g=g.replace("hcaptcha-integrations-","");var m,v,b="";if(p.find("fieldset").attr("disabled"))m="plugin"===f?HCaptchaIntegrationsObject.activateMsg:HCaptchaIntegrationsObject.activateThemeMsg,v=!0;else{if("plugin"===f)m=HCaptchaIntegrationsObject.deactivateMsg;else{for(var y in m=HCaptchaIntegrationsObject.deactivateThemeMsg,b="<p>"+HCaptchaIntegrationsObject.selectThemeMsg+"</p>",b+="<select>",HCaptchaIntegrationsObject.themes){var w=y===HCaptchaIntegrationsObject.defaultTheme?' selected="selected"':"";b+='<option value="'.concat(y,'"').concat(w,">").concat(HCaptchaIntegrationsObject.themes[y],"</option>")}b+="</select>"}v=!1}-1===e.inArray(f,["theme"])||v||0!==Object.keys(HCaptchaIntegrationsObject.themes).length?(m=m.replace("%s",h),o.ctrlKey?r():kaggDialog.confirm({title:m,content:b,type:v?"activate":"deactivate",buttons:{ok:{text:HCaptchaIntegrationsObject.OKBtnText},cancel:{text:HCaptchaIntegrationsObject.CancelBtnText}},onAction:function(t){t&&r()}})):kaggDialog.confirm({title:HCaptchaIntegrationsObject.onlyOneThemeMsg,content:"",type:"info",buttons:{ok:{text:HCaptchaIntegrationsObject.OKBtnText}}})}}));var d,f,h;r.on("input",(d=function(){var t=r.val().trim().toLowerCase(),a=e(".hcaptcha-integrations-logo img"),n=null;if(a.each((function(a,i){var o=e(i);if("core"!==o.data("entity")){var r,c=o.closest("tr");o.data("label").toLowerCase().includes(t)?(c.show(),n=null!==(r=n)&&void 0!==r?r:c):c.hide()}})),n){var i=n.offset().top+n.outerHeight()-e(window).height()+5;e("html").stop().animate({scrollTop:i},1e3)}},f=100,function(){var t=this,e=arguments;clearTimeout(h),h=setTimeout((function(){return d.apply(t,e)}),f)})),e("#hcaptcha-options").keydown((function(t){e(t.target).is(r)&&13===t.which&&t.preventDefault()}))};window.hCaptchaIntegrations=a,jQuery(document).ready(a)})();
  • hcaptcha-for-forms-and-more/trunk/changelog.txt

    r3086102 r3095958  
     1= 4.2.0 =
     2* The minimum required WordPress version is now 5.3.
     3* Added support for Multisite Network Admin synced with network-wide plugin options.
     4* Added selection by date range on Forms and Events pages.
     5* Added automatic activation of dependent plugins on the Integrations page.
     6* Added scrolling on the Integrations page during the search.
     7* Fixed color flickering of hCaptcha placeholder with custom themes.
     8* Fixed JS error on the Lost Password page.
     9* Fixed missing site key notification on the General page.
     10* Fixed fatal error on some sites during migration to 4.0.0.
     11
    112= 4.1.2 =
    213* Added option to have the hCaptcha admin menu under Settings.
  • hcaptcha-for-forms-and-more/trunk/hcaptcha.php

    r3086102 r3095958  
    1111 * Plugin URI:           https://www.hcaptcha.com/
    1212 * Description:          hCaptcha keeps out bots and spam while putting privacy first. It is a drop-in replacement for reCAPTCHA.
    13  * Version:              4.1.2
     13 * Version:              4.2.0
    1414 * Requires at least:    5.1
    1515 * Requires PHP:         7.0
     
    2222 *
    2323 * WC requires at least: 3.0
    24  * WC tested up to:      8.8
     24 * WC tested up to:      8.9
    2525 */
    2626
     
    4040 * Plugin version.
    4141 */
    42 const HCAPTCHA_VERSION = '4.1.2';
     42const HCAPTCHA_VERSION = '4.2.0';
    4343
    4444/**
  • hcaptcha-for-forms-and-more/trunk/readme.txt

    r3086102 r3095958  
    22Contributors: hcaptcha, kaggdesign
    33Tags: captcha, hcaptcha, antispam, abuse, protect form
    4 Requires at least: 5.1
     4Requires at least: 5.3
    55Tested up to: 6.5
    66Requires PHP: 7.0.0
    7 Stable tag: 4.1.2
     7Stable tag: 4.2.0
    88License: GPLv2 or later
    99License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    354354* Filters delay time for hCaptcha API script.
    355355*
    356 * Any negative value will prevent API script from loading at all,
     356* Any negative value will prevent the API script from loading at all,
    357357* until user interaction: mouseenter, click, scroll or touch.
    358358* This significantly improves Google Pagespeed Insights score.
     
    448448`parent`: a string — the parent menu item. Default '' for 'pages' mode and 'options-general.php' for 'tabs' mode;
    449449`position`: a number — the position of the menu item. Default 58.990225 for 'pages' mode. It Has no effect on 'tabs' mode;
    450 
    451 = Why isn't my WPForms Lite installation working? =
    452 
    453 Please make sure you have removed the reCAPTCHA keys under WPForms > Settings > reCAPTCHA to avoid a conflict.
    454450
    455451= Where can I get more information about hCaptcha? =
     
    555551We also suggest emailing the authors of plugins you'd like to support hCaptcha: it will usually take them only an hour or two to add native support. This will simplify your use of hCaptcha, and is the best solution in the long run.
    556552
    557 Some plugins listed have been superseded by native support, and are included only for legacy purposes.
    558 
    559 You should always use native hCaptcha support if available for your plugin.
    560 Please check with your plugin author if native support is not yet available.
     553You may use native hCaptcha support if available for your plugin. Please check with your plugin author if native support is not yet available.
     554
     555However, the hCaptcha plugin provides a broader set of options and features so that you can use it with any form on your site.
    561556
    562557Instructions for popular native integrations are below:
     
    565560
    566561== Changelog ==
     562
     563= 4.2.0 =
     564* The minimum required WordPress version is now 5.3.
     565* Added support for Multisite Network Admin synced with network-wide plugin options.
     566* Added selection by date range on Forms and Events pages.
     567* Added automatic activation of dependent plugins on the Integrations page.
     568* Added scrolling on the Integrations page during the search.
     569* Fixed color flickering of hCaptcha placeholder with custom themes.
     570* Fixed JS error on the Lost Password page.
     571* Fixed missing site key notification on the General page.
     572* Fixed fatal error on some sites during migration to 4.0.0.
    567573
    568574= 4.1.2 =
  • hcaptcha-for-forms-and-more/trunk/src/php/Admin/Events/Events.php

    r3072795 r3095958  
    3939        }
    4040
    41         add_action( 'hcap_verify_request', [ $this, 'save_event' ], - PHP_INT_MAX, 2 );
     41        add_action( 'hcap_verify_request', [ $this, 'save_event' ], -PHP_INT_MAX, 2 );
    4242    }
    4343
     
    4848     * @param array             $error_codes Error codes.
    4949     *
    50      * @return string|null|mixed
     50     * @return void
    5151     */
    5252    public function save_event( $result, array $error_codes ) {
     
    5454
    5555        if ( ! ( is_string( $result ) || is_null( $result ) ) ) {
    56             return $result;
     56            return;
    5757        }
    5858
     
    8686            ]
    8787        );
    88 
    89         return $result;
    9088    }
    9189
     
    10098        global $wpdb;
    10199
    102         $args    = wp_parse_args(
     100        $args          = wp_parse_args(
    103101            $args,
    104102            [
     
    108106                'order'   => 'ASC',
    109107                'orderby' => '',
     108                'dates'   => [],
    110109            ]
    111110        );
    112         $columns = implode( ',', $args['columns'] );
    113         $columns = $columns ?: '*';
    114         $order   = strtoupper( $args['order'] );
    115         $order   = 'ASC' === $order ? '' : $order;
    116         $orderby = $args['orderby'] ? 'ORDER BY ' . $args['orderby'] . ' ' . $order : '';
    117         $offset  = absint( $args['offset'] );
    118         $limit   = absint( $args['limit'] );
    119 
     111        $args['dates'] = $args['dates'] ?: self::get_default_dates();
     112
     113        $columns    = implode( ',', $args['columns'] );
     114        $columns    = $columns ?: '*';
    120115        $table_name = $wpdb->prefix . self::TABLE_NAME;
     116        $where_date = self::get_where_date_gmt( $args );
     117        $orderby    = self::get_order_by( $args );
     118        $offset     = absint( $args['offset'] );
     119        $limit      = absint( $args['limit'] );
    121120
    122121        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    123122        $results = (array) $wpdb->get_results(
    124123            $wpdb->prepare(
    125             // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    126                 "SELECT SQL_CALC_FOUND_ROWS $columns FROM $table_name $orderby LIMIT %d, %d",
     124            // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     125                "SELECT
     126                        SQL_CALC_FOUND_ROWS
     127                        $columns
     128                        FROM $table_name
     129                        WHERE $where_date
     130                        $orderby
     131                        LIMIT %d, %d",
    127132                $offset,
    128133                $limit
     134            // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    129135            )
    130136        );
    131137
    132138        $total = (int) $wpdb->get_var( 'SELECT FOUND_ROWS()' );
     139
    133140        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    134141
     
    149156        global $wpdb;
    150157
    151         $args    = wp_parse_args(
     158        $args          = wp_parse_args(
    152159            $args,
    153160            [
     
    156163                'order'   => 'ASC',
    157164                'orderby' => '',
     165                'dates'   => [],
    158166            ]
    159167        );
    160         $order   = strtoupper( $args['order'] );
    161         $order   = 'ASC' === $order ? '' : $order;
    162         $orderby = $args['orderby'] ? 'ORDER BY ' . $args['orderby'] . ' ' . $order : '';
    163         $offset  = absint( $args['offset'] );
    164         $limit   = absint( $args['limit'] );
     168        $args['dates'] = $args['dates'] ?: self::get_default_dates();
    165169
    166170        $table_name = $wpdb->prefix . self::TABLE_NAME;
     171        $where_date = self::get_where_date_gmt( $args );
     172        $orderby    = self::get_order_by( $args );
     173        $offset     = absint( $args['offset'] );
     174        $limit      = absint( $args['limit'] );
    167175
    168176        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    169177        $results = (array) $wpdb->get_results(
    170178            $wpdb->prepare(
    171             // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    172                 "SELECT SQL_CALC_FOUND_ROWS id, source, form_id, COUNT(*) as served FROM $table_name GROUP BY source, form_id $orderby LIMIT %d, %d",
     179            // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     180                "SELECT
     181                        SQL_CALC_FOUND_ROWS
     182                        source, form_id, COUNT(*) as served
     183                        FROM $table_name
     184                        WHERE $where_date
     185                        GROUP BY source, form_id
     186                        $orderby
     187                        LIMIT %d, %d",
    173188                $offset,
    174189                $limit
     190            // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    175191            )
    176192        );
     
    179195        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    180196
    181         $where = 'WHERE 1=0';
     197        $where = '1=0';
    182198
    183199        foreach ( $results as $result ) {
     
    188204        }
    189205
     206        $where = "($where) AND " . $where_date;
     207
    190208        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    191209        $served = (array) $wpdb->get_results(
    192             // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    193             "SELECT date_gmt FROM $table_name $where"
    194         );
     210        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     211            "SELECT date_gmt FROM $table_name WHERE $where"
     212        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     213        );
     214
     215        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    195216
    196217        return [
     
    209230        global $wpdb;
    210231
     232        $table_name = self::TABLE_NAME;
     233
     234        if ( self::table_exists( $wpdb->prefix . $table_name ) ) {
     235            // @codeCoverageIgnoreStart
     236            return;
     237            // @codeCoverageIgnoreEnd
     238        }
     239
    211240        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    212241
    213242        $charset_collate = $wpdb->get_charset_collate();
    214         $table_name      = self::TABLE_NAME;
    215 
    216         $sql = "CREATE TABLE IF NOT EXISTS $wpdb->prefix$table_name (
     243
     244        $sql = "CREATE TABLE $wpdb->prefix$table_name (
    217245            id          BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    218246            source      VARCHAR(256)    NOT NULL,
     
    230258            KEY uuid (uuid),
    231259            KEY date_gmt (date_gmt)
    232         ) $charset_collate;";
     260        ) $charset_collate";
    233261
    234262        dbDelta( $sql );
    235263    }
     264
     265    /**
     266     * Get where date GMT.
     267     *
     268     * @param array $args Arguments.
     269     *
     270     * @return string
     271     */
     272    public static function get_where_date_gmt( array $args ): string {
     273        $dates = $args['dates'];
     274
     275        if ( $dates ) {
     276            $dates[1] = $dates[1] ?? $dates[0];
     277
     278            $dates[0] .= ' 00:00:00';
     279            $dates[1] .= ' 23:59:59';
     280
     281            foreach ( $dates as &$date ) {
     282                $date = wp_date( 'Y-m-d H:i:s', strtotime( $date ) );
     283            }
     284
     285            unset( $date );
     286
     287            $where_date = sprintf(
     288                "date_gmt BETWEEN '%s' AND '%s'",
     289                esc_sql( $dates[0] ),
     290                esc_sql( $dates[1] )
     291            );
     292        } else {
     293            $where_date = '1=1';
     294        }
     295
     296        return $where_date;
     297    }
     298
     299    /**
     300     * Get ODER BY / ORDER clause
     301     *
     302     * @param array $args Arguments.
     303     *
     304     * @return string
     305     */
     306    private static function get_order_by( array $args ): string {
     307        $order = strtoupper( $args['order'] );
     308        $order = 'ASC' === $order ? '' : $order;
     309
     310        return $args['orderby'] ? 'ORDER BY ' . $args['orderby'] . ' ' . $order : '';
     311    }
     312
     313    /**
     314     * Get default dates.
     315     *
     316     * @return array
     317     */
     318    private static function get_default_dates(): array {
     319        $end_date   = date_create_immutable( 'now', wp_timezone() );
     320        $start_date = $end_date;
     321        $start_date = $start_date->modify( '-30 day' );
     322        $start_date = $start_date->setTime( 0, 0 );
     323        $end_date   = $end_date->setTime( 23, 59, 59 );
     324        $format     = 'Y-m-d';
     325
     326        return [ $start_date->format( $format ), $end_date->format( $format ) ];
     327    }
     328
     329    /**
     330     * Check if the database table exists and cache the result.
     331     *
     332     * @param string $table_name Table name. Can have SQL wildcard.
     333     *
     334     * @return bool
     335     */
     336    private static function table_exists( string $table_name ): bool {
     337        foreach ( self::get_existing_tables( $table_name ) as $existing_table ) {
     338            if ( self::wildcard_match( $table_name, $existing_table ) ) {
     339                return true;
     340            }
     341        }
     342
     343        return false;
     344    }
     345
     346    /**
     347     * Get the list of existing tables and cache the result.
     348     *
     349     * @param string $table_name Table name. Can have SQL wildcard.
     350     *
     351     * @return array List of table names.
     352     */
     353    private static function get_existing_tables( string $table_name ): array {
     354        global $wpdb;
     355
     356        // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
     357        $tables = $wpdb->get_results(
     358            $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ),
     359            'ARRAY_N'
     360        );
     361        // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
     362
     363        return ! empty( $tables ) ? wp_list_pluck( $tables, 0 ) : [];
     364    }
     365
     366    /**
     367     * Wildcard match.
     368     * Works as MySQL LIKE match.
     369     *
     370     * @param string $pattern Pattern.
     371     * @param string $subject String to search into.
     372     *
     373     * @return false|int
     374     */
     375    private static function wildcard_match( string $pattern, string $subject ) {
     376        $regex = str_replace(
     377            [ '%', '_' ], // MySQL wildcard chars.
     378            [ '.*', '.' ],  // Regexp chars.
     379            preg_quote( $pattern, '/' )
     380        );
     381
     382        return preg_match( '/^' . $regex . '$/is', $subject );
     383    }
    236384}
  • hcaptcha-for-forms-and-more/trunk/src/php/Admin/Events/EventsTable.php

    r3080217 r3095958  
    88namespace HCaptcha\Admin\Events;
    99
     10use HCaptcha\Settings\ListPageBase;
    1011use WP_List_Table;
    1112
     
    181182        $order   = isset( $_GET['order'] ) ? sanitize_key( $_GET['order'] ) : 'DESC';
    182183        $orderby = isset( $_GET['orderby'] ) ? sanitize_key( $_GET['orderby'] ) : 'date_gmt';
     184        $date    = isset( $_GET['date'] )
     185            ? filter_input( INPUT_GET, 'date', FILTER_SANITIZE_FULL_SPECIAL_CHARS )
     186            : ''; // We need filter_input here to keep delimiter intact.
    183187        // phpcs:enable WordPress.Security.NonceVerification.Recommended
    184188
     189        $dates        = explode( ListPageBase::TIMESPAN_DELIMITER, $date );
     190        $dates        = array_filter( array_map( 'trim', $dates ) );
    185191        $column_slugs = str_replace( 'name', 'source', array_keys( $this->columns ) );
    186192        $per_page     = $this->get_items_per_page( self::EVENTS_PER_PAGE, $this->per_page_default );
     
    192198            'order'   => $order,
    193199            'orderby' => $orderby,
     200            'dates'   => $dates,
    194201        ];
    195202
  • hcaptcha-for-forms-and-more/trunk/src/php/Admin/Events/FormsTable.php

    r3080217 r3095958  
    88namespace HCaptcha\Admin\Events;
    99
     10use HCaptcha\Settings\ListPageBase;
    1011use WP_List_Table;
    1112
     
    154155    public function get_sortable_columns(): array {
    155156        return [
    156             'name'    => [ 'name', false, __( 'Source', 'hcaptcha-for-forms-and-more' ), __( 'Table ordered by Source.' ) ],
    157             'form_id' => [ 'form_id', false, __( 'Form Id', 'hcaptcha-for-forms-and-more' ), __( 'Table ordered by Form Id.' ) ],
    158             'served'  => [ 'served', false, __( 'Served', 'hcaptcha-for-forms-and-more' ), __( 'Table ordered by Served Count.' ) ],
     157            'name'    => [
     158                'name',
     159                false,
     160                __( 'Source', 'hcaptcha-for-forms-and-more' ),
     161                __( 'Table ordered by Source.' ),
     162            ],
     163            'form_id' => [
     164                'form_id',
     165                false,
     166                __( 'Form Id', 'hcaptcha-for-forms-and-more' ),
     167                __( 'Table ordered by Form Id.' ),
     168            ],
     169            'served'  => [
     170                'served',
     171                false,
     172                __( 'Served', 'hcaptcha-for-forms-and-more' ),
     173                __( 'Table ordered by Served Count.' ),
     174            ],
    159175        ];
    160176    }
     
    172188        $order   = isset( $_GET['order'] ) ? sanitize_key( $_GET['order'] ) : 'ASC';
    173189        $orderby = isset( $_GET['orderby'] ) ? sanitize_key( $_GET['orderby'] ) : 'source';
     190        $date    = isset( $_GET['date'] )
     191            ? filter_input( INPUT_GET, 'date', FILTER_SANITIZE_FULL_SPECIAL_CHARS )
     192            : ''; // We need filter_input here to keep delimiter intact.
    174193        // phpcs:enable WordPress.Security.NonceVerification.Recommended
    175194
     195        $dates    = explode( ListPageBase::TIMESPAN_DELIMITER, $date );
     196        $dates    = array_filter( array_map( 'trim', $dates ) );
    176197        $per_page = $this->get_items_per_page( self::FORMS_PER_PAGE, $this->per_page_default );
    177198        $offset   = ( $paged - 1 ) * $per_page;
     
    181202            'order'   => $order,
    182203            'orderby' => $orderby,
     204            'dates'   => $dates,
    183205        ];
    184206
  • hcaptcha-for-forms-and-more/trunk/src/php/Admin/Notifications.php

    r3081325 r3095958  
    248248        }
    249249
    250         if ( hcaptcha()->is_pro() ) {
     250        if ( $settings->is_pro() ) {
    251251            unset( $this->notifications['pro-free-trial'] );
    252252        }
     
    283283            if ( $this->shuffle ) {
    284284                $notifications = $this->shuffle_assoc( $notifications );
     285                $notifications = $this->make_key_first( $notifications, 'register' );
    285286            }
    286287
     
    474475        return $new_arr;
    475476    }
     477
     478    /**
     479     * Make a key the first element in an associative array.
     480     *
     481     * @param array  $arr An array.
     482     * @param string $key Key.
     483     *
     484     * @return array
     485     */
     486    protected function make_key_first( array $arr, string $key ): array {
     487        if ( ! array_key_exists( $key, $arr ) ) {
     488            return $arr;
     489        }
     490
     491        // Remove the key-value pair from the original array.
     492        $value = $arr[ $key ];
     493        unset( $arr[ $key ] );
     494
     495        // Merge the key-value pair back into the array at the beginning.
     496        return array_merge( [ $key => $value ], $arr );
     497    }
    476498}
  • hcaptcha-for-forms-and-more/trunk/src/php/Admin/PluginStats.php

    r3080217 r3095958  
    145145
    146146        $settings   = hcaptcha()->settings();
    147         $license    = (int) hcaptcha()->is_pro() ? 'Pro' : 'Publisher';
     147        $license    = (int) $settings->is_pro() ? 'Pro' : 'Publisher';
    148148        $api_host   = $settings->get( 'api_host' );
    149149        $backend    = $settings->get( 'backend' );
  • hcaptcha-for-forms-and-more/trunk/src/php/BeaverBuilder/Base.php

    r3064004 r3095958  
    8080            self::HANDLE,
    8181            HCAPTCHA_URL . "/assets/js/hcaptcha-beaver-builder$min.js",
    82             [ 'jquery', 'wp-hooks' ],
     82            [ 'jquery' ],
    8383            HCAPTCHA_VERSION,
    8484            true
  • hcaptcha-for-forms-and-more/trunk/src/php/Main.php

    r3086102 r3095958  
    3232use HCaptcha\Settings\General;
    3333use HCaptcha\Settings\Integrations;
     34use HCaptcha\Settings\PluginSettingsBase;
    3435use HCaptcha\Settings\Settings;
    3536use HCaptcha\Settings\SystemInfo;
     
    4849
    4950    /**
     51     * WP hooks handle.
     52     */
     53    const WP_HOOKS_HANDLE = 'wp-hooks';
     54
     55    /**
    5056     * Main script localization object.
    5157     */
     
    134140    public function init_hooks() {
    135141        $this->load_textdomain();
    136 
    137         $settings      = get_option( 'hcaptcha_settings', [] );
    138         $menu_position = $settings['menu_position'] ?? [];
    139         $args          = [
    140             'mode' => [ 'on' ] === $menu_position ? SettingsBase::MODE_TABS : SettingsBase::MODE_PAGES,
    141         ];
    142142
    143143        /**
     
    146146         * @param array $args Settings system initialization arguments.
    147147         */
    148         $args = (array) apply_filters( 'hcap_settings_init_args', $args );
     148        $args = (array) apply_filters( 'hcap_settings_init_args', [] );
    149149
    150150        $this->settings = new Settings(
     
    255255
    256256    /**
    257      * Check if it is a Pro account.
    258      *
    259      * @return false
    260      */
    261     public function is_pro(): bool {
    262         return 'pro' === $this->settings->get_license();
    263     }
    264 
    265     /**
    266257     * Whether we are on the Elementor Pro edit post/page and hCaptcha for Elementor Pro is active.
    267258     *
     
    497488CSS;
    498489
     490        $settings = $this->settings();
     491
     492        if ( $settings->is_on( 'custom_themes' ) && $settings->is_pro_or_general() ) {
     493            $bg = $settings->get_config_params()['theme']['component']['checkbox']['main']['fill'] ?? '';
     494
     495            if ( $bg ) {
     496                $css .= <<<CSS
     497    .h-captcha::before {
     498        background-color: $bg !important;   
     499    }
     500CSS;
     501            }
     502        }
     503
    499504        HCaptcha::css_display( $css );
    500505    }
     
    578583        }
    579584
    580         if ( $settings->is_on( 'custom_themes' ) && $this->is_pro_or_general() ) {
     585        if ( $settings->is_on( 'custom_themes' ) && $settings->is_pro_or_general() ) {
    581586            $params['custom'] = 'true';
    582587        }
     
    676681        DelayedScript::launch( [ 'src' => $this->get_api_src() ], $delay );
    677682
     683        wp_enqueue_script( self::WP_HOOKS_HANDLE );
    678684        wp_enqueue_script(
    679685            self::HANDLE,
    680686            HCAPTCHA_URL . '/assets/js/apps/hcaptcha.js',
    681             [ 'wp-hooks' ],
     687            [ self::WP_HOOKS_HANDLE ],
    682688            HCAPTCHA_VERSION,
    683689            true
     
    698704        }
    699705
    700         $config_params = [];
    701 
    702         if ( $settings->is_on( 'custom_themes' ) && $this->is_pro_or_general() ) {
    703             $config_params = $settings->get_config_params();
    704         }
     706        $config_params = $settings->is_on( 'custom_themes' ) && $settings->is_pro_or_general()
     707            ? $settings->get_config_params()
     708            : [];
    705709
    706710        $params = array_merge( $params, $config_params );
     
    825829            'Affiliates Login'                     => [
    826830                [ 'affiliates_status', 'login' ],
    827                 [ 'affiliates/affiliates.php' ],
     831                'affiliates/affiliates.php',
    828832                Affiliates\Login::class,
    829833            ],
    830834            'Affiliates Register'                  => [
    831835                [ 'affiliates_status', 'register' ],
    832                 [ 'affiliates/affiliates.php' ],
     836                'affiliates/affiliates.php',
    833837                Affiliates\Register::class,
    834838            ],
     
    13151319     * @return bool
    13161320     */
    1317     private function plugin_or_theme_active( $plugin_or_theme_names ): bool {
     1321    public function plugin_or_theme_active( $plugin_or_theme_names ): bool {
    13181322        foreach ( (array) $plugin_or_theme_names as $plugin_or_theme_name ) {
    13191323            if ( '' === $plugin_or_theme_name ) {
     
    13641368        return defined( 'XMLRPC_REQUEST' ) && constant( 'XMLRPC_REQUEST' );
    13651369    }
    1366 
    1367     /**
    1368      * Whether option is allowed to use.
    1369      *
    1370      * @return bool
    1371      */
    1372     private function is_pro_or_general(): bool {
    1373         return $this->is_pro() || ( is_admin() && 'General' === $this->settings->get_active_tab_name() );
    1374     }
    13751370}
  • hcaptcha-for-forms-and-more/trunk/src/php/Migrations/Migrations.php

    r3064004 r3095958  
    99
    1010use HCaptcha\Admin\Events\Events;
     11use HCaptcha\Settings\PluginSettingsBase;
    1112
    1213/**
     
    305306        }
    306307
    307         update_option( 'hcaptcha_settings', $new_options );
     308        update_option( PluginSettingsBase::OPTION_NAME, $new_options );
    308309
    309310        foreach ( array_keys( $options_map ) as $old_option_name ) {
     
    321322     */
    322323    protected function migrate_360() {
    323         $option         = get_option( 'hcaptcha_settings', [] );
     324        $option         = get_option( PluginSettingsBase::OPTION_NAME, [] );
    324325        $wpforms_status = $option['wpforms_status'] ?? [];
    325326
     
    331332        $option['wpforms_status'] = [ 'form' ];
    332333
    333         update_option( 'hcaptcha_settings', $option );
     334        update_option( PluginSettingsBase::OPTION_NAME, $option );
    334335
    335336        return true;
     
    365366        $pro               = $result['features']['custom_theme'] ?? false;
    366367        $license           = $pro ? 'pro' : 'free';
    367         $option            = get_option( 'hcaptcha_settings', [] );
     368        $option            = get_option( PluginSettingsBase::OPTION_NAME, [] );
    368369        $option['license'] = $license;
    369370
    370371        // Save license level in settings.
    371         update_option( 'hcaptcha_settings', $option );
     372        update_option( PluginSettingsBase::OPTION_NAME, $option );
    372373    }
    373374}
  • hcaptcha-for-forms-and-more/trunk/src/php/NF/NF.php

    r3080217 r3095958  
    295295            self::HANDLE,
    296296            HCAPTCHA_URL . "/assets/js/hcaptcha-nf$min.js",
    297             [ 'jquery', Main::HANDLE, 'nf-front-end', 'nf-front-end-deps', 'wp-hooks' ],
     297            [ 'jquery', Main::HANDLE, 'nf-front-end', 'nf-front-end-deps' ],
    298298            HCAPTCHA_VERSION,
    299299            true
  • hcaptcha-for-forms-and-more/trunk/src/php/Otter/Form.php

    r3064004 r3095958  
    155155            self::HANDLE,
    156156            HCAPTCHA_URL . "/assets/js/hcaptcha-otter$min.js",
    157             [ 'wp-hooks' ],
     157            [],
    158158            HCAPTCHA_VERSION,
    159159            true
  • hcaptcha-for-forms-and-more/trunk/src/php/Passster/Protect.php

    r3064004 r3095958  
    130130            self::HANDLE,
    131131            HCAPTCHA_URL . "/assets/js/hcaptcha-passster$min.js",
    132             [ 'jquery', 'wp-hooks' ],
     132            [ 'jquery' ],
    133133            HCAPTCHA_VERSION,
    134134            true
  • hcaptcha-for-forms-and-more/trunk/src/php/Settings/Abstracts/SettingsBase.php

    r3081325 r3095958  
    5151
    5252    /**
     53     * Network-wide menu position.
     54     *
     55     * A number before 25 (Settings) to avoid conflicts with other plugins.
     56     */
     57    const NETWORK_WIDE_POSITION = 24.99;
     58
     59    /**
    5360     * Form fields.
    5461     *
     
    214221        $this->tabs = $tabs;
    215222
    216         $args = wp_parse_args(
    217             $args,
    218             [
    219                 'mode'     => self::MODE_PAGES,
    220                 'parent'   => null,
    221                 'position' => null,
    222             ]
    223         );
    224 
    225         $this->admin_mode = in_array( $args['mode'], [ self::MODE_PAGES, self::MODE_TABS ], true ) ?
    226             $args['mode'] :
    227             self::MODE_PAGES;
    228 
    229         if ( null === $args['parent'] ) {
    230             $this->parent_slug = self::MODE_PAGES === $this->admin_mode ? '' : 'options-general.php';
    231         } else {
    232             $this->parent_slug = $args['parent'];
    233         }
    234 
    235         if ( null === $args['position'] ) {
    236             $hash           = hexdec( sha1( self::PREFIX ) );
    237             $pow            = floor( log10( $hash ) );
    238             $this->position = round( self::POSITION + $hash / 10 ** ( $pow + 4 ), 6 );
    239         } else {
    240             $this->position = (float) $args['position'];
    241         }
     223        $this->process_args( $args );
    242224
    243225        $this->fields = [
     
    257239        if ( self::MODE_PAGES === $this->admin_mode || ! $this->is_tab() ) {
    258240            add_action( 'current_screen', [ $this, 'setup_tabs_section' ], 9 );
    259             add_action( 'admin_menu', [ $this, 'add_settings_page' ] );
     241
     242            $tag = $this->is_network_wide() ? 'network_admin_menu' : 'admin_menu';
     243
     244            add_action( $tag, [ $this, 'add_settings_page' ] );
    260245        }
    261246
     
    284269    protected function init_hooks() {
    285270        add_action( 'admin_enqueue_scripts', [ $this, 'base_admin_enqueue_scripts' ] );
     271        add_action( 'admin_page_access_denied', [ $this, 'base_admin_page_access_denied' ] );
    286272
    287273        if ( $this->is_main_menu_page() ) {
     
    312298
    313299    /**
     300     * Process arguments.
     301     *
     302     * @param array $args Arguments.
     303     *
     304     * @return void
     305     */
     306    protected function process_args( array $args ) {
     307        $args = wp_parse_args(
     308            $args,
     309            [
     310                'mode'     => $this->get_menu_position(),
     311                'parent'   => null,
     312                'position' => null,
     313            ]
     314        );
     315
     316        $this->admin_mode = in_array( $args['mode'], [ self::MODE_PAGES, self::MODE_TABS ], true ) ?
     317            $args['mode'] :
     318            self::MODE_PAGES;
     319
     320        if ( null === $args['parent'] ) {
     321            $wp_settings_slug  = is_multisite() && $this->is_network_wide() ? 'settings.php' : 'options-general.php';
     322            $this->parent_slug = self::MODE_PAGES === $this->admin_mode ? '' : $wp_settings_slug;
     323        } else {
     324            $this->parent_slug = $args['parent'];
     325        }
     326
     327        if ( null === $args['position'] ) {
     328            $hash           = hexdec( sha1( self::PREFIX ) );
     329            $pow            = floor( log10( $hash ) );
     330            $position       = is_multisite() && $this->is_network_wide() ? self::NETWORK_WIDE_POSITION : self::POSITION;
     331            $this->position = round( $position + $hash / 10 ** ( $pow + 4 ), 6 );
     332        } else {
     333            $this->position = (float) $args['position'];
     334        }
     335    }
     336
     337    /**
    314338     * Is this the main menu page?
    315339     *
     
    381405     */
    382406    protected function init_settings() {
    383         $network_wide = get_site_option( $this->option_name() . self::NETWORK_WIDE, [] );
    384 
    385         if ( empty( $network_wide ) ) {
     407        if ( $this->is_network_wide() ) {
     408            $this->settings = get_site_option( $this->option_name(), null );
     409        } else {
    386410            $this->settings = get_option( $this->option_name(), null );
    387         } else {
    388             $this->settings = get_site_option( $this->option_name(), null );
    389411        }
    390412
     
    394416        $network_wide_setting                 = array_key_exists( self::NETWORK_WIDE, $this->settings ) ?
    395417            $this->settings[ self::NETWORK_WIDE ] :
    396             $network_wide;
     418            $this->get_network_wide();
    397419        $this->settings[ self::NETWORK_WIDE ] = $network_wide_setting;
    398420
     
    567589
    568590    /**
     591     * Filter denied access to the settings page.
     592     * It is needed when switching network_wide option.
     593     *
     594     * @return void
     595     */
     596    public function base_admin_page_access_denied() {
     597        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     598        $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
     599
     600        if ( static::PREFIX !== $page ) {
     601            return;
     602        }
     603
     604        $url = is_multisite() && $this->is_network_wide() ?
     605            network_admin_url( 'admin.php?page=' . $this->option_page() ) :
     606            admin_url( 'admin.php?page=' . $this->option_page() );
     607
     608        if ( wp_get_raw_referer() === $url ) {
     609            // Prevent infinite loop.
     610            return;
     611        }
     612
     613        wp_safe_redirect( $url );
     614        $this->exit();
     615    }
     616
     617    /**
     618     * Exit wrapper for test purposes.
     619     *
     620     * @return void
     621     */
     622    protected function exit() {
     623        // @codeCoverageIgnoreStart
     624        exit();
     625        // @codeCoverageIgnoreEnd
     626    }
     627
     628    /**
    569629     * Setup settings sections.
    570630     *
     
    658718     */
    659719    private function tab_link( SettingsBase $tab ) {
    660         $url = menu_page_url( $tab->option_page(), false );
     720        $url = is_multisite() && $this->is_network_wide() ?
     721            network_admin_url( 'admin.php?page=' . $tab->option_page() ) :
     722            menu_page_url( $tab->option_page(), false );
    661723
    662724        if ( self::MODE_TABS === $this->admin_mode ) {
     
    14081470        $current_suffix = preg_replace( '/.+_page_/', '', $current_screen->id );
    14091471
     1472        if ( is_multisite() && $this->is_network_wide() ) {
     1473            $current_suffix = preg_replace( '/-network$/', '', $current_suffix );
     1474        }
     1475
    14101476        return $this->option_page() === $current_suffix || in_array( $current_suffix, $ids, true );
    14111477    }
     
    14301496
    14311497    /**
    1432      * Print supplemental id it exists.
     1498     * Print supplemental id if it exists.
    14331499     *
    14341500     * @param string $supplemental Supplemental.
     
    14461512        );
    14471513    }
     1514
     1515    /**
     1516     * Get network_wide setting.
     1517     *
     1518     * @return array
     1519     */
     1520    protected function get_network_wide(): array {
     1521        static $network_wide = null;
     1522
     1523        if ( null === $network_wide ) {
     1524            $network_wide = (array) get_site_option( $this->option_name() . self::NETWORK_WIDE, [] );
     1525        }
     1526
     1527        return $network_wide;
     1528    }
     1529
     1530    /**
     1531     * Whether network_wide setting is on.
     1532     *
     1533     * @return bool
     1534     */
     1535    protected function is_network_wide(): bool {
     1536        return ! empty( $this->get_network_wide() );
     1537    }
     1538
     1539    /**
     1540     * Get menu position.
     1541     *
     1542     * @return string
     1543     */
     1544    protected function get_menu_position(): string {
     1545        return [ 'on' ] === $this->get( 'menu_position' ) ? self::MODE_TABS : self::MODE_PAGES;
     1546    }
     1547
     1548    /**
     1549     * Print header.
     1550     *
     1551     * @return void
     1552     */
     1553    protected function print_header() {
     1554        ?>
     1555        <div class="<?php echo esc_attr( static::PREFIX . '-header-bar' ); ?>">
     1556            <div class="<?php echo esc_attr( static::PREFIX . '-header' ); ?>">
     1557                <h2>
     1558                    <?php echo esc_html( $this->page_title() ); ?>
     1559                </h2>
     1560            </div>
     1561            <?php
     1562
     1563            /**
     1564             * Fires before settings tab closing tag.
     1565             */
     1566            do_action( 'kagg_settings_header' );
     1567
     1568            ?>
     1569        </div>
     1570        <?php
     1571    }
    14481572}
  • hcaptcha-for-forms-and-more/trunk/src/php/Settings/EventsPage.php

    r3081325 r3095958  
    5050
    5151    /**
    52      * The page is allowed to be shown.
    53      *
    54      * @var bool
    55      */
    56     protected $allowed = false;
    57 
    58     /**
    5952     * Get page title.
    6053     *
     
    9083
    9184        add_action( 'admin_init', [ $this, 'admin_init' ] );
     85        add_action( 'kagg_settings_header', [ $this, 'date_picker_display' ] );
    9286    }
    9387
     
    9892     */
    9993    public function admin_init() {
    100         $this->allowed = ( hcaptcha()->settings()->is_on( 'statistics' ) && hcaptcha()->is_pro() );
     94        $settings = hcaptcha()->settings();
     95
     96        $this->allowed = ( $settings->is_on( 'statistics' ) && $settings->is_pro() );
    10197
    10298        if ( ! $this->allowed ) {
     
    124120        }
    125121
    126         wp_enqueue_script(
    127             'chart',
    128             constant( 'HCAPTCHA_URL' ) . '/assets/lib/chart.umd.min.js',
    129             [],
    130             'v4.4.2',
    131             true
    132         );
    133 
    134         wp_enqueue_script(
    135             'chart-adapter-date-fns',
    136             constant( 'HCAPTCHA_URL' ) . '/assets/lib/chartjs-adapter-date-fns.bundle.min.js',
    137             [ 'chart' ],
    138             'v3.0.0',
    139             true
    140         );
     122        parent::admin_enqueue_scripts();
    141123
    142124        wp_enqueue_script(
     
    156138                'succeedLabel' => __( 'Succeed', 'hcaptcha-for-forms-and-more' ),
    157139                'failedLabel'  => __( 'Failed', 'hcaptcha-for-forms-and-more' ),
     140                'unit'         => $this->unit,
    158141            ]
    159142        );
     
    168151     */
    169152    public function section_callback( array $arguments ) {
    170         ?>
    171         <h2>
    172             <?php echo esc_html( $this->page_title() ); ?>
    173         </h2>
    174         <?php
     153        $this->print_header();
    175154
    176155        if ( ! $this->allowed ) {
  • hcaptcha-for-forms-and-more/trunk/src/php/Settings/FormsPage.php

    r3081325 r3095958  
    4343
    4444    /**
    45      * The page is allowed to be shown.
    46      *
    47      * @var bool
    48      */
    49     protected $allowed = false;
    50 
    51     /**
    5245     * Get page title.
    5346     *
     
    8376
    8477        add_action( 'admin_init', [ $this, 'admin_init' ] );
     78        add_action( 'kagg_settings_header', [ $this, 'date_picker_display' ] );
    8579    }
    8680
     
    117111        }
    118112
    119         wp_enqueue_script(
    120             'chart',
    121             constant( 'HCAPTCHA_URL' ) . '/assets/lib/chart.umd.min.js',
    122             [],
    123             'v4.4.2',
    124             true
    125         );
    126 
    127         wp_enqueue_script(
    128             'chart-adapter-date-fns',
    129             constant( 'HCAPTCHA_URL' ) . '/assets/lib/chartjs-adapter-date-fns.bundle.min.js',
    130             [ 'chart' ],
    131             'v3.0.0',
    132             true
    133         );
     113        parent::admin_enqueue_scripts();
    134114
    135115        wp_enqueue_script(
     
    147127                'served'      => $this->served,
    148128                'servedLabel' => __( 'Served', 'hcaptcha-for-forms-and-more' ),
     129                'unit'        => $this->unit,
    149130            ]
    150131        );
     
    159140     */
    160141    public function section_callback( array $arguments ) {
    161         ?>
    162         <h2>
    163             <?php echo esc_html( $this->page_title() ); ?>
    164         </h2>
    165         <?php
     142        $this->print_header();
    166143
    167144        if ( ! $this->allowed ) {
  • hcaptcha-for-forms-and-more/trunk/src/php/Settings/General.php

    r3086102 r3095958  
    620620        switch ( $arguments['id'] ) {
    621621            case self::SECTION_KEYS:
    622                 ?>
    623                 <h2>
    624                     <?php echo esc_html( $this->page_title() ); ?>
    625                 </h2>
    626                 <div id="hcaptcha-message"></div>
    627                 <?php
     622                $this->print_header();
    628623                $this->notifications->show();
    629624                $this->print_section_header( $arguments['id'], __( 'Keys', 'hcaptcha-for-forms-and-more' ) );
  • hcaptcha-for-forms-and-more/trunk/src/php/Settings/Integrations.php

    r3081325 r3095958  
    99
    1010use KAGG\Settings\Abstracts\SettingsBase;
     11use WP_Error;
    1112use WP_Theme;
    1213
     
    4950
    5051    /**
     52     * Plugin dependencies not specified in their headers.
     53     * Key is a plugin slug.
     54     * Value is a plugin slug or an array of slugs.
     55     */
     56    const PLUGIN_DEPENDENCIES = [
     57        // phpcs:disable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned
     58        'back-in-stock-notifier-for-woocommerce/cwginstocknotifier.php' => 'woocommerce/woocommerce.php',
     59        'elementor-pro/elementor-pro.php'                               => 'elementor/elementor.php',
     60        'woocommerce-wishlists/woocommerce-wishlists.php'               => 'woocommerce/woocommerce.php',
     61        // phpcs:enable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned
     62    ];
     63
     64    /**
    5165     * Entity name to activate/deactivate. Can be 'plugin' or 'theme'.
    5266     *
     
    5468     */
    5569    protected $entity = '';
     70
     71    /**
     72     * Plugins tree.
     73     *
     74     * @var array
     75     */
     76    protected $plugins_tree;
    5677
    5778    /**
     
    79100        parent::init_hooks();
    80101
    81         add_action( 'kagg_settings_tab', [ $this, 'search_box' ] );
     102        add_action( 'kagg_settings_header', [ $this, 'search_box' ] );
    82103        add_action( 'wp_ajax_' . self::ACTIVATE_ACTION, [ $this, 'activate' ] );
    83104    }
     
    629650    public function search_box() {
    630651        ?>
    631         <span id="hcaptcha-integrations-search-wrap">
     652        <div id="hcaptcha-integrations-search-wrap">
    632653            <label for="hcaptcha-integrations-search"></label>
    633654            <input
    634655                    type="search" id="hcaptcha-integrations-search"
    635656                    placeholder="<?php esc_html_e( 'Search plugins and themes...', 'hcaptcha-for-forms-and-more' ); ?>">
    636         </span>
     657        </div>
    637658        <?php
    638659    }
     
    657678        }
    658679
     680        $this->print_header();
     681
    659682        ?>
    660         <h2>
    661             <?php echo esc_html( $this->page_title() ); ?>
    662         </h2>
    663683        <div id="hcaptcha-message"></div>
    664684        <p>
     
    815835            }
    816836
    817             $message = sprintf(
     837            $plugin_names = $this->plugin_names_from_tree( $this->plugins_tree );
     838            $message      = sprintf(
    818839            /* translators: 1: Plugin name. */
    819                 __( '%s plugin is activated.', 'hcaptcha-for-forms-and-more' ),
    820                 $plugin_name
     840                _n(
     841                    '%s plugin is activated.',
     842                    '%s plugins are activated.',
     843                    count( $plugin_names ),
     844                    'hcaptcha-for-forms-and-more'
     845                ),
     846                implode( ', ', $plugin_names )
    821847            );
    822848
     
    874900    protected function activate_plugins( array $plugins ): bool {
    875901        foreach ( $plugins as $plugin ) {
    876             ob_start();
    877 
    878             $result = activate_plugin( $plugin );
    879 
    880             ob_end_clean();
     902            $this->plugins_tree = $this->build_plugins_tree( $plugin );
     903            $result             = $this->activate_plugin_tree( $this->plugins_tree );
    881904
    882905            if ( null === $result ) {
     
    890913
    891914    /**
     915     * Activate plugins.
     916     *
     917     * @param array $node Node of the plugin tree.
     918     *
     919     * @return int|null|true|WP_Error
     920     */
     921    protected function activate_plugin_tree( array &$node ) {
     922        if ( $node['children'] ) {
     923            foreach ( $node['children'] as $child ) {
     924                $result = $this->activate_plugin_tree( $child );
     925
     926                if ( null !== $result ) {
     927                    return $result;
     928                }
     929            }
     930        }
     931
     932        ob_start();
     933        $result = activate_plugin( $node['plugin'] );
     934        ob_end_clean();
     935
     936        $node['result'] = $result;
     937
     938        return $result;
     939    }
     940
     941    /**
     942     * Get plugins' tree.
     943     *
     944     * @param string $plugin Plugin slug.
     945     *
     946     * @return array
     947     */
     948    protected function build_plugins_tree( string $plugin ): array {
     949        $dependencies = $this->plugin_dependencies( $plugin );
     950        $tree         = [
     951            'plugin'   => $plugin,
     952            'children' => [],
     953        ];
     954
     955        foreach ( $dependencies as $dependency ) {
     956            $tree['children'][] = $this->build_plugins_tree( $dependency );
     957        }
     958
     959        return $tree;
     960    }
     961
     962    /**
     963     * Get plugin dependencies.
     964     *
     965     * @param string $plugin Plugin slug.
     966     *
     967     * @return array
     968     */
     969    private function plugin_dependencies( string $plugin ): array {
     970        $plugin_headers   = get_plugin_data( constant( 'WP_PLUGIN_DIR' ) . '/' . $plugin );
     971        $requires_plugins = $plugin_headers['RequiresPlugins'] ?? '';
     972        $wp_dependencies  = $this->plugin_dirs_to_slugs(
     973            array_filter( array_map( 'trim', explode( ',', $requires_plugins ) ) )
     974        );
     975        $dependencies     = (array) ( self::PLUGIN_DEPENDENCIES[ $plugin ] ?? [] );
     976
     977        return array_merge( $wp_dependencies, $dependencies );
     978    }
     979
     980    /**
     981     * Convert plugin directories to slugs.
     982     *
     983     * @param array $dirs Plugin directories.
     984     *
     985     * @return array
     986     */
     987    protected function plugin_dirs_to_slugs( array $dirs ): array {
     988        if ( ! $dirs ) {
     989            return $dirs;
     990        }
     991
     992        $slugs = array_keys( get_plugins() );
     993
     994        foreach ( $dirs as &$dir ) {
     995            $slug = preg_grep( "#^$dir/#", $slugs );
     996
     997            if ( $slug ) {
     998                $dir = reset( $slug );
     999            }
     1000        }
     1001
     1002        return $dirs;
     1003    }
     1004
     1005    /**
     1006     * Get plugin names from the tree.
     1007     *
     1008     * @param array $node Node of the plugin tree.
     1009     *
     1010     * @return array
     1011     */
     1012    protected function plugin_names_from_tree( array $node ): array {
     1013        $plugin_names = [];
     1014
     1015        if ( $node['children'] ) {
     1016            foreach ( $node['children'] as $child ) {
     1017                $plugin_names[] = $this->plugin_names_from_tree( $child );
     1018            }
     1019
     1020            $plugin_names = array_merge( [], ...$plugin_names );
     1021        }
     1022
     1023        $status = '';
     1024
     1025        foreach ( hcaptcha()->modules as $module ) {
     1026            if ( $module[1] === $node['plugin'] ) {
     1027                $status = $module[0][0];
     1028
     1029                break;
     1030            }
     1031        }
     1032
     1033        $plugin_name = $this->form_fields[ $status ]['label'] ?? '';
     1034
     1035        if ( ! $plugin_name ) {
     1036            $plugin_data = get_plugin_data( constant( 'WP_PLUGIN_DIR' ) . '/' . $node['plugin'] );
     1037            $plugin_name = $plugin_data['Name'] ?? '';
     1038        }
     1039
     1040        return array_unique( array_merge( [ $plugin_name ], $plugin_names ) );
     1041    }
     1042
     1043    /**
    8921044     * Activate theme.
    8931045     *
     
    9421094        $data = [ 'message' => esc_html( $message ) ];
    9431095
     1096        if ( 'plugin' === $this->entity ) {
     1097            $data['stati'] = $this->get_activation_stati();
     1098        }
     1099
    9441100        if ( 'theme' === $this->entity ) {
    9451101            $data['themes']       = $this->get_themes();
     
    9481104
    9491105        return $data;
     1106    }
     1107
     1108    /**
     1109     * Get activation stati of all integrated plugins and themes.
     1110     *
     1111     * @return array
     1112     */
     1113    protected function get_activation_stati(): array {
     1114        $stati = [];
     1115
     1116        foreach ( hcaptcha()->modules as $module ) {
     1117            $stati[ $module[0][0] ] = hcaptcha()->plugin_or_theme_active( $module[1] );
     1118        }
     1119
     1120        return $stati;
    9501121    }
    9511122
  • hcaptcha-for-forms-and-more/trunk/src/php/Settings/ListPageBase.php

    r3072795 r3095958  
    88namespace HCaptcha\Settings;
    99
     10use DateTimeImmutable;
     11
    1012/**
    1113 * Class ListPageBase.
     
    1618
    1719    /**
     20     * Chart handle.
     21     */
     22    const CHART_HANDLE = 'chart';
     23
     24    /**
     25     * Flatpickr handle.
     26     */
     27    const FLATPICKR_HANDLE = 'flatpickr';
     28
     29    /**
     30     * Base handle.
     31     */
     32    const HANDLE = 'settings-list-page-base';
     33
     34    /**
     35     * Base object.
     36     */
     37    const OBJECT = 'HCaptchaFlatPickerObject';
     38
     39    /**
     40     * Number of timespan days by default.
     41     * "Last 30 Days", by default.
     42     */
     43    const DEFAULT_TIMESPAN_DAYS = '30';
     44
     45    /**
     46     * Timespan (date range) delimiter.
     47     */
     48    const TIMESPAN_DELIMITER = ' - ';
     49
     50    /**
     51     * Default date format.
     52     */
     53    const DATE_FORMAT = 'Y-m-d';
     54
     55    /**
     56     * Chart time unit.
     57     *
     58     * @var string
     59     */
     60    protected $unit;
     61
     62    /**
     63     * The page is allowed to be shown.
     64     *
     65     * @var bool
     66     */
     67    protected $allowed = false;
     68
     69    /**
    1870     * Get suggested data format from items array.
    1971     *
     
    3486
    3587        $time_diff = $max_time - $min_time;
     88
     89        $time_units = [
     90            [ 1, 'second' ],
     91            [ constant( 'MINUTE_IN_SECONDS' ), 'minute' ],
     92            [ constant( 'HOUR_IN_SECONDS' ), 'hour' ],
     93            [ constant( 'DAY_IN_SECONDS' ), 'day' ],
     94            [ constant( 'WEEK_IN_SECONDS' ), 'week' ],
     95            [ constant( 'MONTH_IN_SECONDS' ), 'month' ],
     96            [ constant( 'YEAR_IN_SECONDS' ), 'year' ],
     97        ];
     98
     99        foreach ( $time_units as $index => $time_unit ) {
     100            $i          = max( 0, $index - 1 );
     101            $this->unit = $time_units[ $i ][1];
     102
     103            if ( $time_diff < $time_unit[0] * 2 ) {
     104                break;
     105            }
     106        }
    36107
    37108        if ( $time_diff < constant( 'MINUTE_IN_SECONDS' ) ) {
     
    45116        return $date_format;
    46117    }
     118
     119    /**
     120     * Enqueue class scripts.
     121     */
     122    public function admin_enqueue_scripts() {
     123        $min = hcap_min_suffix();
     124
     125        wp_enqueue_script(
     126            self::CHART_HANDLE,
     127            constant( 'HCAPTCHA_URL' ) . '/assets/lib/chartjs/chart.umd.min.js',
     128            [],
     129            'v4.4.2',
     130            true
     131        );
     132
     133        wp_enqueue_script(
     134            'chart-adapter-date-fns',
     135            constant( 'HCAPTCHA_URL' ) . '/assets/lib/chartjs/chartjs-adapter-date-fns.bundle.min.js',
     136            [ self::CHART_HANDLE ],
     137            'v3.0.0',
     138            true
     139        );
     140
     141        wp_enqueue_style(
     142            self::FLATPICKR_HANDLE,
     143            constant( 'HCAPTCHA_URL' ) . '/assets/lib/flatpickr/flatpickr.min.css',
     144            [],
     145            '4.6.13'
     146        );
     147
     148        wp_enqueue_script(
     149            self::FLATPICKR_HANDLE,
     150            constant( 'HCAPTCHA_URL' ) . '/assets/lib/flatpickr/flatpickr.min.js',
     151            [],
     152            '4.6.13',
     153            true
     154        );
     155
     156        wp_enqueue_style(
     157            self::HANDLE,
     158            constant( 'HCAPTCHA_URL' ) . "/assets/css/settings-list-page-base$min.css",
     159            [ self::FLATPICKR_HANDLE ],
     160            constant( 'HCAPTCHA_VERSION' )
     161        );
     162
     163        wp_enqueue_script(
     164            self::HANDLE,
     165            constant( 'HCAPTCHA_URL' ) . "/assets/js/settings-list-page-base$min.js",
     166            [ self::FLATPICKR_HANDLE ],
     167            constant( 'HCAPTCHA_VERSION' ),
     168            true
     169        );
     170
     171        wp_localize_script(
     172            self::HANDLE,
     173            self::OBJECT,
     174            [
     175                'delimiter' => self::TIMESPAN_DELIMITER,
     176                'locale'    => $this->get_language_code(),
     177            ]
     178        );
     179    }
     180
     181    /**
     182     * Display datepicker element.
     183     *
     184     * @return void
     185     */
     186    public function date_picker_display() {
     187        if ( ! $this->allowed ) {
     188            return;
     189        }
     190
     191        list( $choices, $chosen_filter, $value ) = $this->process_datepicker_choices();
     192
     193        // An array of allowed HTML elements and attributes for the datepicker choices.
     194        $choices_allowed_html = [
     195            'li'    => [],
     196            'label' => [],
     197            'input' => [
     198                'type'         => [],
     199                'name'         => [],
     200                'value'        => [],
     201                'checked'      => [],
     202                'aria-hidden'  => [],
     203                'data-default' => [],
     204            ],
     205        ];
     206
     207        ?>
     208        <div class="hcaptcha-filter">
     209            <button id="hcaptcha-datepicker-popover-button" class="button" role="button" aria-haspopup="true">
     210                <?php echo esc_html( $chosen_filter ); ?>
     211            </button>
     212            <div class="hcaptcha-datepicker-popover">
     213                <div class="hcaptcha-datepicker-popover-content">
     214                    <ul class="hcaptcha-datepicker-choices"
     215                        aria-label="<?php esc_attr_e( 'Datepicker options', 'hcaptcha-for-forms-and-more' ); ?>"
     216                        aria-orientation="vertical">
     217                        <?php echo wp_kses( '<li>' . implode( '</li><li>', $choices ) . '</li>', $choices_allowed_html ); ?>
     218                    </ul>
     219                    <div class="hcaptcha-datepicker-calendar">
     220                        <label for="hcaptcha-datepicker">
     221                            <input
     222                                type="text"
     223                                name="date"
     224                                tabindex="-1"
     225                                aria-hidden="true"
     226                                id="hcaptcha-datepicker"
     227                                value="<?php echo esc_attr( $value ); ?>">
     228                        </label>
     229                    </div>
     230                    <div class="hcaptcha-datepicker-action">
     231                        <button class="button-secondary" type="reset">
     232                            <?php esc_html_e( 'Cancel', 'hcaptcha-for-forms-and-more' ); ?>
     233                        </button>
     234                        <button class="button-primary hcaptcha-btn-blue" type="submit">
     235                            <?php esc_html_e( 'Apply', 'hcaptcha-for-forms-and-more' ); ?>
     236                        </button>
     237                    </div>
     238                </div>
     239            </div>
     240        </div>
     241        <?php
     242    }
     243
     244    /**
     245     * Sets the timespan (or date range) for performing mysql queries.
     246     *
     247     * Includes:
     248     * 1. A list of date filter options for the datepicker module.
     249     * 2. Currently selected filter or date range values. Last "X" days, or i.e. Feb 8, 2023 - Mar 9, 2023.
     250     * 3. Assigned timespan dates.
     251     *
     252     * @param array|null $timespan Given timespan (dates) preferably in WP timezone.
     253     *
     254     * @return array
     255     * @noinspection PhpMissingParamTypeInspection
     256     * @noinspection HtmlUnknownAttribute
     257     */
     258    protected function process_datepicker_choices( $timespan = null ): array {
     259        // Retrieve and validate timespan if none is given.
     260        if ( empty( $timespan ) || ! is_array( $timespan ) ) {
     261            $timespan = $this->process_timespan();
     262        }
     263
     264        list( $start_date, $end_date, $days ) = $timespan;
     265
     266        $filters       = $this->get_date_filter_choices();
     267        $selected      = isset( $filters[ $days ] ) ? $days : 'custom';
     268        $value         = $this->concat_dates( $start_date, $end_date );
     269        $chosen_filter = 'custom' === $selected ? $value : $filters[ $selected ];
     270        $choices       = [];
     271
     272        foreach ( $filters as $choice => $label ) {
     273            $timespan_dates = $this->get_timespan_dates( $choice );
     274            $checked        = checked( $selected, $choice, false );
     275            $default        = (int) self::DEFAULT_TIMESPAN_DAYS === $choice ? 'data-default' : '';
     276            $choices[]      = sprintf(
     277                '<label %s>%s<input type="radio" aria-hidden="true" name="timespan" value="%s" %s %s></label>',
     278                $checked ? 'class="is-selected"' : '',
     279                esc_html( $label ),
     280                esc_attr( $this->concat_dates( ...$timespan_dates ) ),
     281                esc_attr( $checked ),
     282                esc_attr( $default )
     283            );
     284        }
     285
     286        return [ $choices, $chosen_filter, $value ];
     287    }
     288
     289    /**
     290     * Sets the timespan (or date range) selected.
     291     *
     292     * Includes:
     293     * 1. Start date object in WP timezone.
     294     * 2. End date object in WP timezone.
     295     * 3. Number of "Last X days", if applicable, otherwise returns "custom".
     296     * 4. Label associated with the selected date filter choice. @see "get_date_filter_choices".
     297     *
     298     * @return array
     299     */
     300    protected function process_timespan(): array {
     301        $dates = (string) filter_input( INPUT_GET, 'date', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
     302
     303        // Return default timespan if dates are empty.
     304        if ( empty( $dates ) ) {
     305            return $this->get_timespan_dates( self::DEFAULT_TIMESPAN_DAYS );
     306        }
     307
     308        $dates = $this->maybe_validate_string_timespan( $dates );
     309
     310        list( $start_date, $end_date ) = explode( self::TIMESPAN_DELIMITER, $dates );
     311
     312        // Return default timespan if the start date is more recent than the end date.
     313        if ( strtotime( $start_date ) > strtotime( $end_date ) ) {
     314            return $this->get_timespan_dates( self::DEFAULT_TIMESPAN_DAYS );
     315        }
     316
     317        $timezone   = wp_timezone(); // Retrieve the timezone string for the site.
     318        $start_date = date_create_immutable( $start_date, $timezone );
     319        $end_date   = date_create_immutable( $end_date, $timezone );
     320
     321        // Return default timespan if date creation fails.
     322        if ( ! $start_date || ! $end_date ) {
     323            // @codeCoverageIgnoreStart
     324            return $this->get_timespan_dates( self::DEFAULT_TIMESPAN_DAYS );
     325            // @codeCoverageIgnoreEnd
     326        }
     327
     328        // Set time to 0:0:0 for start date and 23:59:59 for end date.
     329        $start_date = $start_date->setTime( 0, 0 );
     330        $end_date   = $end_date->setTime( 23, 59, 59 );
     331
     332        $days_diff    = '';
     333        $current_date = date_create_immutable( 'now', $timezone )->setTime( 23, 59, 59 );
     334
     335        // Calculate day difference only if the end date is equal to the current date.
     336        if ( ! $current_date->diff( $end_date )->format( '%a' ) ) {
     337            $days_diff = $end_date->diff( $start_date )->format( '%a' );
     338        }
     339
     340        list( $days, $timespan_label ) = $this->get_date_filter_choices( $days_diff );
     341
     342        return [
     343            $start_date,     // WP timezone.
     344            $end_date,       // WP timezone.
     345            $days,           // e.g., 22.
     346            $timespan_label, // e.g., Custom.
     347        ];
     348    }
     349
     350    /**
     351     * Check the delimiter to see if the end date is specified.
     352     * We can assume that the start and end dates are the same if the end date is missing.
     353     *
     354     * @param string $dates Given timespan (dates) in string. i.e. "2024-04-16 - 2024-05-16" or "2024-04-16".
     355     *
     356     * @return string
     357     */
     358    protected function maybe_validate_string_timespan( string $dates ): string {
     359        // The '-' is used as a delimiter for the datepicker module.
     360        if ( false !== strpos( $dates, self::TIMESPAN_DELIMITER ) ) {
     361            return $dates;
     362        }
     363
     364        return $dates . self::TIMESPAN_DELIMITER . $dates;
     365    }
     366
     367    /**
     368     * The number of days is converted to the start and end date range.
     369     *
     370     * @param string $days Timespan days.
     371     *
     372     * @return array
     373     */
     374    protected function get_timespan_dates( string $days ): array {
     375        list( $timespan_key, $timespan_label ) = $this->get_date_filter_choices( $days );
     376
     377        // Bail early, if the given number of days is NOT a number nor a numeric string.
     378        if ( ! is_numeric( $days ) ) {
     379            return [ '', '', $timespan_key, $timespan_label ];
     380        }
     381
     382        $end_date   = date_create_immutable( 'now', wp_timezone() );
     383        $start_date = $end_date;
     384
     385        if ( (int) $days > 0 ) {
     386            $start_date = $start_date->modify( "-$days day" );
     387        }
     388
     389        $start_date = $start_date->setTime( 0, 0 );
     390        $end_date   = $end_date->setTime( 23, 59, 59 );
     391
     392        return [
     393            $start_date,     // WP timezone.
     394            $end_date,       // WP timezone.
     395            $timespan_key,   // i.e. 30.
     396            $timespan_label, // i.e. Last 30 days.
     397        ];
     398    }
     399
     400    /**
     401     * Returns a list of date filter options for the datepicker module.
     402     *
     403     * @param string|null $key Optional. Key associated with available filters.
     404     *
     405     * @return array
     406     * @noinspection PhpMissingParamTypeInspection
     407     */
     408    protected function get_date_filter_choices( $key = null ): array {
     409        // Available date filters.
     410        $choices = [
     411            '0'      => esc_html__( 'Today', 'wpforms-lite' ),
     412            '1'      => esc_html__( 'Yesterday', 'wpforms-lite' ),
     413            '7'      => esc_html__( 'Last 7 days', 'wpforms-lite' ),
     414            '30'     => esc_html__( 'Last 30 days', 'wpforms-lite' ),
     415            '90'     => esc_html__( 'Last 90 days', 'wpforms-lite' ),
     416            '365'    => esc_html__( 'Last 1 year', 'wpforms-lite' ),
     417            'custom' => esc_html__( 'Custom', 'wpforms-lite' ),
     418        ];
     419
     420        // Bail early, and return the full list of options.
     421        if ( is_null( $key ) ) {
     422            return $choices;
     423        }
     424
     425        // Return the "Custom" filter if the given key is not found.
     426        $key = isset( $choices[ $key ] ) ? $key : 'custom';
     427
     428        return [ $key, $choices[ $key ] ];
     429    }
     430
     431    /**
     432     * Concatenate given dates into a single string. i.e. "2024-04-16 - 2024-05-16".
     433     *
     434     * @param DateTimeImmutable|mixed $start_date Start date.
     435     * @param DateTimeImmutable|mixed $end_date   End date.
     436     * @param int|string              $fallback   Fallback value if dates are not valid.
     437     *
     438     * @return string
     439     */
     440    private function concat_dates( $start_date, $end_date, $fallback = '' ) {
     441        // Bail early, if the given dates are not valid.
     442        if ( ! ( $start_date instanceof DateTimeImmutable ) || ! ( $end_date instanceof DateTimeImmutable ) ) {
     443            return $fallback;
     444        }
     445
     446        return implode(
     447            self::TIMESPAN_DELIMITER,
     448            [
     449                $start_date->format( self::DATE_FORMAT ),
     450                $end_date->format( self::DATE_FORMAT ),
     451            ]
     452        );
     453    }
     454
     455    /**
     456     * Get the ISO 639-2 Language Code from user/site locale.
     457     *
     458     * @see   http://www.loc.gov/standards/iso639-2/php/code_list.php
     459     *
     460     * @return string
     461     */
     462    private function get_language_code(): string {
     463        $default_lang = 'en';
     464        $locale       = get_user_locale();
     465
     466        if ( ! empty( $locale ) ) {
     467            $lang = explode( '_', $locale );
     468
     469            if ( ! empty( $lang ) && is_array( $lang ) ) {
     470                $default_lang = strtolower( $lang[0] );
     471            }
     472        }
     473
     474        return $default_lang;
     475    }
    47476}
  • hcaptcha-for-forms-and-more/trunk/src/php/Settings/PluginSettingsBase.php

    r3080217 r3095958  
    2323
    2424    /**
     25     * Settings option name.
     26     */
     27    const OPTION_NAME = 'hcaptcha_settings';
     28
     29    /**
    2530     * The 'submit' button was shown.
    2631     *
     
    98103     */
    99104    protected function option_name(): string {
    100         return 'hcaptcha_settings';
     105        return self::OPTION_NAME;
    101106    }
    102107
  • hcaptcha-for-forms-and-more/trunk/src/php/Settings/Settings.php

    r3081325 r3095958  
    105105
    106106        return $first_tab ? $first_tab->get_active_tab()->tab_name() : '';
     107    }
     108
     109    /**
     110     * Check if it is a Pro account.
     111     *
     112     * @return false
     113     */
     114    public function is_pro(): bool {
     115        return 'pro' === $this->get_license();
     116    }
     117
     118    /**
     119     * Check if it is a Pro account or General admin page.
     120     *
     121     * @return bool
     122     */
     123    public function is_pro_or_general(): bool {
     124        return $this->is_pro() || ( is_admin() && 'General' === $this->get_active_tab_name() );
    107125    }
    108126
     
    274292     */
    275293    public function get_theme(): string {
     294        $theme = $this->get( 'theme' );
     295
     296        if ( $this->is_on( 'custom_themes' ) && $this->is_pro_or_general() ) {
     297            $theme = $this->get_config_params()['theme']['palette']['mode'] ?? $theme;
     298        }
    276299
    277300        /**
     
    280303         * @param string $mode Current theme.
    281304         */
    282         return (string) apply_filters( 'hcap_theme', $this->get( 'theme' ) );
     305        return (string) apply_filters( 'hcap_theme', $theme );
    283306    }
    284307
  • hcaptcha-for-forms-and-more/trunk/src/php/Settings/SystemInfo.php

    r3081325 r3095958  
    107107     */
    108108    public function section_callback( array $arguments ) {
     109        $this->print_header();
     110
    109111        ?>
    110         <h2>
    111             <?php echo esc_html__( 'System Information', 'hcaptcha-for-forms-and-more' ); ?>
    112         </h2>
    113112        <div id="hcaptcha-system-info-wrap">
    114113            <span class="helper">
  • hcaptcha-for-forms-and-more/trunk/src/php/WPDiscuz/Comment.php

    r3064004 r3095958  
    115115            self::HANDLE,
    116116            HCAPTCHA_URL . "/assets/js/hcaptcha-wpdiscuz-comment$min.js",
    117             [ 'wp-hooks' ],
     117            [],
    118118            HCAPTCHA_VERSION,
    119119            true
  • hcaptcha-for-forms-and-more/trunk/vendor/composer/installed.php

    r3086102 r3095958  
    22    'root' => array(
    33        'name' => 'hcaptcha/hcaptcha-wordpress-plugin',
    4         'pretty_version' => '4.1.2',
    5         'version' => '4.1.2.0',
    6         'reference' => '77825b68c9bf0dee38f9da73b634861e79f9e69b',
     4        'pretty_version' => '4.2.0',
     5        'version' => '4.2.0.0',
     6        'reference' => 'aa580b1c05ee0aff974fbf1d99e92341a6f82094',
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../',
     
    1212    'versions' => array(
    1313        'hcaptcha/hcaptcha-wordpress-plugin' => array(
    14             'pretty_version' => '4.1.2',
    15             'version' => '4.1.2.0',
    16             'reference' => '77825b68c9bf0dee38f9da73b634861e79f9e69b',
     14            'pretty_version' => '4.2.0',
     15            'version' => '4.2.0.0',
     16            'reference' => 'aa580b1c05ee0aff974fbf1d99e92341a6f82094',
    1717            'type' => 'wordpress-plugin',
    1818            'install_path' => __DIR__ . '/../../',
Note: See TracChangeset for help on using the changeset viewer.