Happy Addons for Elementor (Mega Menu, Post Grid, Woocommerce Product Grid, Table, Event Calendar, Slider Elementor Widget) - Version 2.14.3

Version Description

  • 12 October 2020 =

  • Tweak: Added Calendy pro feature notice

  • Tweak: Added Calendy default username "happyaddons"

  • Tweak: Common cached files are loaded once as internal css

  • Fix: Card widget badge dynamic tag issue

  • Fix: Happy templates popup button auto duplicate issue

  • Fix: Removed duplicate On demand assets cache file enqueue

  • Fix: Removed broken Review widget schema data

  • Fix: Team member widget email envelope icon issue

Download this release

Release Info

Developer thehappymonster
Plugin Icon 128x128 Happy Addons for Elementor (Mega Menu, Post Grid, Woocommerce Product Grid, Table, Event Calendar, Slider Elementor Widget)
Version 2.14.3
Comparing to
See all releases

Code changes from version 2.14.2 to 2.14.3

assets/admin/js/template-library.min.js CHANGED
@@ -1 +1 @@
1
- !function(e,t,i){var a={Views:{},Models:{},Collections:{},Behaviors:{},Layout:null,Manager:null};a.Models.Template=Backbone.Model.extend({defaults:{template_id:0,title:"",type:"",thumbnail:"",url:"",tags:[],isPro:!1}}),a.Collections.Template=Backbone.Collection.extend({model:a.Models.Template}),a.Behaviors.InsertTemplate=Marionette.Behavior.extend({ui:{insertButton:".haTemplateLibrary__insert-button"},events:{"click @ui.insertButton":"onInsertButtonClick"},onInsertButtonClick:function(){i.library.insertTemplate({model:this.view.model})}}),a.Views.EmptyTemplateCollection=Marionette.ItemView.extend({id:"elementor-template-library-templates-empty",template:"#tmpl-haTemplateLibrary__empty",ui:{title:".elementor-template-library-blank-title",message:".elementor-template-library-blank-message"},modesStrings:{empty:{title:i.translate("templatesEmptyTitle"),message:i.translate("templatesEmptyMessage")},noResults:{title:i.translate("templatesNoResultsTitle"),message:i.translate("templatesNoResultsMessage")}},getCurrentMode:function(){return i.library.getFilter("text")?"noResults":"empty"},onRender:function(){var e=this.modesStrings[this.getCurrentMode()];this.ui.title.html(e.title),this.ui.message.html(e.message)}}),a.Views.Loading=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__loading",id:"haTemplateLibrary__loading"}),a.Views.Logo=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-logo",className:"haTemplateLibrary__header-logo",templateHelpers:function(){return{title:this.getOption("title")}}}),a.Views.BackButton=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-back",id:"elementor-template-library-header-preview-back",className:"haTemplateLibrary__header-back",events:function(){return{click:"onClick"}},onClick:function(){i.library.showBlocksView()}}),a.Views.Menu=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-menu",id:"elementor-template-library-header-menu",className:"haTemplateLibrary__header-menu",templateHelpers:function(){return i.library.getTabs()}}),a.Views.ResponsiveMenu=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-menu-responsive",id:"elementor-template-library-header-menu-responsive",className:"haTemplateLibrary__header-menu-responsive",ui:{items:"> .elementor-component-tab"},events:{"click @ui.items":"onTabItemClick"},onTabItemClick:function(t){var a=e(t.currentTarget),n=a.data("tab");i.library.channels.tabs.trigger("change:device",n,a)}}),a.Views.Actions=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-actions",id:"elementor-template-library-header-actions",ui:{sync:"#haTemplateLibrary__header-sync i"},events:{"click @ui.sync":"onSyncClick"},onSyncClick:function(){var e=this;e.ui.sync.addClass("eicon-animation-spin"),i.library.requestLibraryData({onUpdate:function(){e.ui.sync.removeClass("eicon-animation-spin"),i.library.updateBlocksView()},forceUpdate:!0,forceSync:!0})}}),a.Views.InsertWrapper=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-insert",id:"elementor-template-library-header-preview",behaviors:{insertTemplate:{behaviorClass:a.Behaviors.InsertTemplate}}}),a.Views.Preview=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__preview",className:"haTemplateLibrary__preview",ui:function(){return{iframe:"> iframe"}},onRender:function(){this.ui.iframe.attr("src",this.getOption("url")).hide();var e=this,t=(new a.Views.Loading).render();this.$el.append(t.el),this.ui.iframe.on("load",function(){e.$el.find("#haTemplateLibrary__loading").remove(),e.ui.iframe.show()})}}),a.Views.TemplateCollection=Marionette.CompositeView.extend({template:"#tmpl-haTemplateLibrary__templates",id:"haTemplateLibrary__templates",childViewContainer:"#haTemplateLibrary__templates-list",emptyView:function(){return new a.Views.EmptyTemplateCollection},ui:{templatesWindow:".haTemplateLibrary__templates-window",textFilter:"#haTemplateLibrary__search",tagsFilter:"#haTemplateLibrary__filter-tags",filterBar:"#haTemplateLibrary__toolbar-filter"},events:{"input @ui.textFilter":"onTextFilterInput","click @ui.tagsFilter li":"onTagsFilterClick"},getChildView:function(e){return a.Views.Template},initialize:function(){this.listenTo(i.library.channels.templates,"filter:change",this._renderChildren)},filter:function(e){var t=i.library.getFilterTerms(),a=!0;return _.each(t,function(t,n){var r=i.library.getFilter(n);if(r&&t.callback){var o=t.callback.call(e,r);return o||(a=!1),o}}),a},setMasonrySkin:function(){var e=new elementorModules.utils.Masonry({container:this.$childViewContainer,items:this.$childViewContainer.children()});this.$childViewContainer.imagesLoaded(e.run.bind(e))},onRenderCollection:function(){this.setMasonrySkin(),this.updatePerfectScrollbar()},onTextFilterInput:function(){var e=this;_.defer(function(){i.library.setFilter("text",e.ui.textFilter.val())})},onTagsFilterClick:function(t){var a=e(t.currentTarget),n=a.data("tag");i.library.setFilter("tags",n),a.addClass("active").siblings().removeClass("active"),n=n?i.library.getTags()[n]:"Filter",this.ui.filterBar.find(".haTemplateLibrary__filter-btn").html(n)},updatePerfectScrollbar:function(){this.perfectScrollbar||(this.perfectScrollbar=new PerfectScrollbar(this.ui.templatesWindow[0],{suppressScrollX:!0})),this.perfectScrollbar.isRtl=!1,this.perfectScrollbar.update()},setTagsFilterHover:function(){var e=this;e.ui.filterBar.hoverIntent(function(){e.ui.tagsFilter.css("display","block"),e.ui.filterBar.find(".haTemplateLibrary__filter-btn i").addClass("eicon-caret-down").removeClass("eicon-caret-right")},function(){e.ui.tagsFilter.css("display","none"),e.ui.filterBar.find(".haTemplateLibrary__filter-btn i").addClass("eicon-caret-right").removeClass("eicon-caret-down")},{sensitivity:50,interval:150,timeout:100})},onRender:function(){this.setTagsFilterHover(),this.updatePerfectScrollbar()}}),a.Views.Template=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__template",className:"haTemplateLibrary__template",ui:{previewButton:".haTemplateLibrary__preview-button, .haTemplateLibrary__template-preview"},events:{"click @ui.previewButton":"onPreviewButtonClick"},behaviors:{insertTemplate:{behaviorClass:a.Behaviors.InsertTemplate}},onPreviewButtonClick:function(){i.library.showPreviewView(this.model)}}),a.Modal=elementorModules.common.views.modal.Layout.extend({getModalOptions:function(){return{id:"haTemplateLibrary__modal",hide:{onOutsideClick:!1,onEscKeyPress:!0,onBackgroundClick:!1}}},getTemplateActionButton:function(e){var t=e.isPro&&!HappyAddonsEditor.hasPro?"pro-button":"insert-button";return viewId="#tmpl-haTemplateLibrary__"+t,template=Marionette.TemplateCache.get(viewId),Marionette.Renderer.render(template)},showLogo:function(e){this.getHeaderView().logoArea.show(new a.Views.Logo(e))},showDefaultHeader:function(){this.showLogo({title:"HAPPY LIBRARY"});var e=this.getHeaderView();e.tools.show(new a.Views.Actions),e.menuArea.reset()},showPreviewView:function(e){var t=this.getHeaderView();t.menuArea.show(new a.Views.ResponsiveMenu),t.logoArea.show(new a.Views.BackButton),t.tools.show(new a.Views.InsertWrapper({model:e})),this.modalContent.show(new a.Views.Preview({url:e.get("url")}))},showBlocksView:function(e){this.modalContent.show(new a.Views.TemplateCollection({collection:e}))}}),a.Manager=function(){function i(){var i=e(this).closest(".elementor-top-section"),a=i.data("id"),n=t.documents.getCurrent().container.children;n&&_.each(n,function(e,t){a===e.id&&(m.atIndex=t)}),i.prev(".elementor-add-section").find(FIND_SELECTOR).before($openLibraryButton)}function n(e){var t=e.find(FIND_SELECTOR);t.length&&t.before($openLibraryButton),e.on("click.onAddElement",".elementor-editor-section-settings .elementor-editor-element-add",i)}function r(t,i){i.addClass("elementor-active").siblings().removeClass("elementor-active");var a=devicesResponsiveMap[t]||devicesResponsiveMap.desktop;e(".haTemplateLibrary__preview").css("width",a)}function o(){var e=window.elementor.$previewContents,t=setInterval(function(){n(e),e.find(".elementor-add-new-section").length>0&&clearInterval(t)},100);e.on("click.onAddTemplateButton",".elementor-add-ha-button",m.showModal.bind(m)),this.channels.tabs.on("change:device",r)}var l,s,d,c,m=this;FIND_SELECTOR=".elementor-add-new-section .elementor-add-section-drag-title",$openLibraryButton='<div class="elementor-add-section-area-button elementor-add-ha-button"> <i class="hm hm-happyaddons"></i> </div>',devicesResponsiveMap={desktop:"100%",tab:"768px",mobile:"360px"},this.atIndex=-1,this.channels={tabs:Backbone.Radio.channel("tabs"),templates:Backbone.Radio.channel("templates")},this.updateBlocksView=function(){m.setFilter("tags","",!0),m.setFilter("text","",!0),m.getModal().showBlocksView(d)},this.setFilter=function(e,t,i){m.channels.templates.reply("filter:"+e,t),i||m.channels.templates.trigger("filter:change")},this.getFilter=function(e){return m.channels.templates.request("filter:"+e)},this.getFilterTerms=function(){return{tags:{callback:function(e){return _.any(this.get("tags"),function(t){return t.indexOf(e)>=0})}},text:{callback:function(e){return e=e.toLowerCase(),this.get("title").toLowerCase().indexOf(e)>=0||_.any(this.get("tags"),function(t){return t.indexOf(e)>=0})}}}},this.showModal=function(){m.getModal().showModal(),m.showBlocksView()},this.closeModal=function(){this.getModal().hideModal()},this.getModal=function(){return l||(l=new a.Modal),l},this.init=function(){t.on("preview:loaded",o.bind(this))},this.getTabs=function(){return{tabs:{blocks:{title:"Blocks",active:!0}}}},this.getTags=function(){return s},this.showBlocksView=function(){m.getModal().showDefaultHeader(),m.setFilter("tags","",!0),m.setFilter("text","",!0),m.loadTemplates(function(){m.getModal().showBlocksView(d)})},this.showPreviewView=function(e){m.getModal().showPreviewView(e)},this.loadTemplates=function(e){m.requestLibraryData({onBeforeUpdate:m.getModal().showLoadingView.bind(m.getModal()),onUpdate:function(){m.getModal().hideLoadingView(),e&&e()}})},this.requestLibraryData=function(e){if(d&&!e.forceUpdate)return void(e.onUpdate&&e.onUpdate());e.onBeforeUpdate&&e.onBeforeUpdate();var t={data:{},success:function(t){d=new a.Collections.Template(t.templates),t.tags&&(s=t.tags),e.onUpdate&&e.onUpdate()}};e.forceSync&&(t.data.sync=!0),elementorCommon.ajax.addRequest("get_ha_library_data",t)},this.requestTemplateData=function(e,t){var i={unique_id:e,data:{edit_mode:!0,display:!0,template_id:e}};t&&jQuery.extend(!0,i,t),elementorCommon.ajax.addRequest("get_ha_template_data",i)},this.insertTemplate=function(e){var t=e.model,i=this;i.getModal().showLoadingView(),i.requestTemplateData(t.get("template_id"),{success:function(e){i.getModal().hideLoadingView(),i.getModal().hideModal();var a={};-1!==i.atIndex&&(a.at=i.atIndex),$e.run("document/elements/import",{model:t,data:e,options:a}),i.atIndex=-1},error:function(e){i.showErrorDialog(e)},complete:function(e){i.getModal().hideLoadingView(),window.elementor.$previewContents.find(".elementor-add-section .elementor-add-section-close").click()}})},this.showErrorDialog=function(e){if("object"==typeof e){var t="";_.each(e,function(e){t+="<div>"+e.message+".</div>"}),e=t}else e?e+=".":e="<i>&#60;The error message is empty&#62;</i>";m.getErrorDialog().setMessage('The following error(s) occurred while processing the request:<div id="elementor-template-library-error-info">'+e+"</div>").show()},this.getErrorDialog=function(){return c||(c=elementorCommon.dialogsManager.createWidget("alert",{id:"elementor-template-library-error-dialog",headerMessage:"An error occurred"})),c}},i.library=new a.Manager,i.library.init(),window.ha=i}(jQuery,window.elementor,window.ha||{});
1
+ !function(e,t,i){var a={Views:{},Models:{},Collections:{},Behaviors:{},Layout:null,Manager:null};a.Models.Template=Backbone.Model.extend({defaults:{template_id:0,title:"",type:"",thumbnail:"",url:"",tags:[],isPro:!1}}),a.Collections.Template=Backbone.Collection.extend({model:a.Models.Template}),a.Behaviors.InsertTemplate=Marionette.Behavior.extend({ui:{insertButton:".haTemplateLibrary__insert-button"},events:{"click @ui.insertButton":"onInsertButtonClick"},onInsertButtonClick:function(){i.library.insertTemplate({model:this.view.model})}}),a.Views.EmptyTemplateCollection=Marionette.ItemView.extend({id:"elementor-template-library-templates-empty",template:"#tmpl-haTemplateLibrary__empty",ui:{title:".elementor-template-library-blank-title",message:".elementor-template-library-blank-message"},modesStrings:{empty:{title:i.translate("templatesEmptyTitle"),message:i.translate("templatesEmptyMessage")},noResults:{title:i.translate("templatesNoResultsTitle"),message:i.translate("templatesNoResultsMessage")}},getCurrentMode:function(){return i.library.getFilter("text")?"noResults":"empty"},onRender:function(){var e=this.modesStrings[this.getCurrentMode()];this.ui.title.html(e.title),this.ui.message.html(e.message)}}),a.Views.Loading=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__loading",id:"haTemplateLibrary__loading"}),a.Views.Logo=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-logo",className:"haTemplateLibrary__header-logo",templateHelpers:function(){return{title:this.getOption("title")}}}),a.Views.BackButton=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-back",id:"elementor-template-library-header-preview-back",className:"haTemplateLibrary__header-back",events:function(){return{click:"onClick"}},onClick:function(){i.library.showBlocksView()}}),a.Views.Menu=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-menu",id:"elementor-template-library-header-menu",className:"haTemplateLibrary__header-menu",templateHelpers:function(){return i.library.getTabs()}}),a.Views.ResponsiveMenu=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-menu-responsive",id:"elementor-template-library-header-menu-responsive",className:"haTemplateLibrary__header-menu-responsive",ui:{items:"> .elementor-component-tab"},events:{"click @ui.items":"onTabItemClick"},onTabItemClick:function(t){var a=e(t.currentTarget),n=a.data("tab");i.library.channels.tabs.trigger("change:device",n,a)}}),a.Views.Actions=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-actions",id:"elementor-template-library-header-actions",ui:{sync:"#haTemplateLibrary__header-sync i"},events:{"click @ui.sync":"onSyncClick"},onSyncClick:function(){var e=this;e.ui.sync.addClass("eicon-animation-spin"),i.library.requestLibraryData({onUpdate:function(){e.ui.sync.removeClass("eicon-animation-spin"),i.library.updateBlocksView()},forceUpdate:!0,forceSync:!0})}}),a.Views.InsertWrapper=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__header-insert",id:"elementor-template-library-header-preview",behaviors:{insertTemplate:{behaviorClass:a.Behaviors.InsertTemplate}}}),a.Views.Preview=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__preview",className:"haTemplateLibrary__preview",ui:function(){return{iframe:"> iframe"}},onRender:function(){this.ui.iframe.attr("src",this.getOption("url")).hide();var e=this,t=(new a.Views.Loading).render();this.$el.append(t.el),this.ui.iframe.on("load",function(){e.$el.find("#haTemplateLibrary__loading").remove(),e.ui.iframe.show()})}}),a.Views.TemplateCollection=Marionette.CompositeView.extend({template:"#tmpl-haTemplateLibrary__templates",id:"haTemplateLibrary__templates",childViewContainer:"#haTemplateLibrary__templates-list",emptyView:function(){return new a.Views.EmptyTemplateCollection},ui:{templatesWindow:".haTemplateLibrary__templates-window",textFilter:"#haTemplateLibrary__search",tagsFilter:"#haTemplateLibrary__filter-tags",filterBar:"#haTemplateLibrary__toolbar-filter"},events:{"input @ui.textFilter":"onTextFilterInput","click @ui.tagsFilter li":"onTagsFilterClick"},getChildView:function(e){return a.Views.Template},initialize:function(){this.listenTo(i.library.channels.templates,"filter:change",this._renderChildren)},filter:function(e){var t=i.library.getFilterTerms(),a=!0;return _.each(t,function(t,n){var r=i.library.getFilter(n);if(r&&t.callback){var o=t.callback.call(e,r);return o||(a=!1),o}}),a},setMasonrySkin:function(){var e=new elementorModules.utils.Masonry({container:this.$childViewContainer,items:this.$childViewContainer.children()});this.$childViewContainer.imagesLoaded(e.run.bind(e))},onRenderCollection:function(){this.setMasonrySkin(),this.updatePerfectScrollbar()},onTextFilterInput:function(){var e=this;_.defer(function(){i.library.setFilter("text",e.ui.textFilter.val())})},onTagsFilterClick:function(t){var a=e(t.currentTarget),n=a.data("tag");i.library.setFilter("tags",n),a.addClass("active").siblings().removeClass("active"),n=n?i.library.getTags()[n]:"Filter",this.ui.filterBar.find(".haTemplateLibrary__filter-btn").html(n)},updatePerfectScrollbar:function(){this.perfectScrollbar||(this.perfectScrollbar=new PerfectScrollbar(this.ui.templatesWindow[0],{suppressScrollX:!0})),this.perfectScrollbar.isRtl=!1,this.perfectScrollbar.update()},setTagsFilterHover:function(){var e=this;e.ui.filterBar.hoverIntent(function(){e.ui.tagsFilter.css("display","block"),e.ui.filterBar.find(".haTemplateLibrary__filter-btn i").addClass("eicon-caret-down").removeClass("eicon-caret-right")},function(){e.ui.tagsFilter.css("display","none"),e.ui.filterBar.find(".haTemplateLibrary__filter-btn i").addClass("eicon-caret-right").removeClass("eicon-caret-down")},{sensitivity:50,interval:150,timeout:100})},onRender:function(){this.setTagsFilterHover(),this.updatePerfectScrollbar()}}),a.Views.Template=Marionette.ItemView.extend({template:"#tmpl-haTemplateLibrary__template",className:"haTemplateLibrary__template",ui:{previewButton:".haTemplateLibrary__preview-button, .haTemplateLibrary__template-preview"},events:{"click @ui.previewButton":"onPreviewButtonClick"},behaviors:{insertTemplate:{behaviorClass:a.Behaviors.InsertTemplate}},onPreviewButtonClick:function(){i.library.showPreviewView(this.model)}}),a.Modal=elementorModules.common.views.modal.Layout.extend({getModalOptions:function(){return{id:"haTemplateLibrary__modal",hide:{onOutsideClick:!1,onEscKeyPress:!0,onBackgroundClick:!1}}},getTemplateActionButton:function(e){var t=e.isPro&&!HappyAddonsEditor.hasPro?"pro-button":"insert-button";return viewId="#tmpl-haTemplateLibrary__"+t,template=Marionette.TemplateCache.get(viewId),Marionette.Renderer.render(template)},showLogo:function(e){this.getHeaderView().logoArea.show(new a.Views.Logo(e))},showDefaultHeader:function(){this.showLogo({title:"HAPPY LIBRARY"});var e=this.getHeaderView();e.tools.show(new a.Views.Actions),e.menuArea.reset()},showPreviewView:function(e){var t=this.getHeaderView();t.menuArea.show(new a.Views.ResponsiveMenu),t.logoArea.show(new a.Views.BackButton),t.tools.show(new a.Views.InsertWrapper({model:e})),this.modalContent.show(new a.Views.Preview({url:e.get("url")}))},showBlocksView:function(e){this.modalContent.show(new a.Views.TemplateCollection({collection:e}))}}),a.Manager=function(){function i(){var i=e(this).closest(".elementor-top-section"),a=i.data("id"),n=t.documents.getCurrent().container.children,r=i.prev(".elementor-add-section");n&&_.each(n,function(e,t){a===e.id&&(m.atIndex=t)}),r.find(".elementor-add-ha-button").length||r.find(FIND_SELECTOR).before($openLibraryButton)}function n(e){var t=e.find(FIND_SELECTOR);t.length&&!e.find(".elementor-add-ha-button").length&&t.before($openLibraryButton),e.on("click.onAddElement",".elementor-editor-section-settings .elementor-editor-element-add",i)}function r(t,i){i.addClass("elementor-active").siblings().removeClass("elementor-active");var a=devicesResponsiveMap[t]||devicesResponsiveMap.desktop;e(".haTemplateLibrary__preview").css("width",a)}function o(){var e=window.elementor.$previewContents,t=setInterval(function(){n(e),e.find(".elementor-add-new-section").length>0&&clearInterval(t)},100);e.on("click.onAddTemplateButton",".elementor-add-ha-button",m.showModal.bind(m)),this.channels.tabs.on("change:device",r)}var l,s,d,c,m=this;FIND_SELECTOR=".elementor-add-new-section .elementor-add-section-drag-title",$openLibraryButton='<div class="elementor-add-section-area-button elementor-add-ha-button"> <i class="hm hm-happyaddons"></i> </div>',devicesResponsiveMap={desktop:"100%",tab:"768px",mobile:"360px"},this.atIndex=-1,this.channels={tabs:Backbone.Radio.channel("tabs"),templates:Backbone.Radio.channel("templates")},this.updateBlocksView=function(){m.setFilter("tags","",!0),m.setFilter("text","",!0),m.getModal().showBlocksView(d)},this.setFilter=function(e,t,i){m.channels.templates.reply("filter:"+e,t),i||m.channels.templates.trigger("filter:change")},this.getFilter=function(e){return m.channels.templates.request("filter:"+e)},this.getFilterTerms=function(){return{tags:{callback:function(e){return _.any(this.get("tags"),function(t){return t.indexOf(e)>=0})}},text:{callback:function(e){return e=e.toLowerCase(),this.get("title").toLowerCase().indexOf(e)>=0||_.any(this.get("tags"),function(t){return t.indexOf(e)>=0})}}}},this.showModal=function(){m.getModal().showModal(),m.showBlocksView()},this.closeModal=function(){this.getModal().hideModal()},this.getModal=function(){return l||(l=new a.Modal),l},this.init=function(){t.on("preview:loaded",o.bind(this))},this.getTabs=function(){return{tabs:{blocks:{title:"Blocks",active:!0}}}},this.getTags=function(){return s},this.showBlocksView=function(){m.getModal().showDefaultHeader(),m.setFilter("tags","",!0),m.setFilter("text","",!0),m.loadTemplates(function(){m.getModal().showBlocksView(d)})},this.showPreviewView=function(e){m.getModal().showPreviewView(e)},this.loadTemplates=function(e){m.requestLibraryData({onBeforeUpdate:m.getModal().showLoadingView.bind(m.getModal()),onUpdate:function(){m.getModal().hideLoadingView(),e&&e()}})},this.requestLibraryData=function(e){if(d&&!e.forceUpdate)return void(e.onUpdate&&e.onUpdate());e.onBeforeUpdate&&e.onBeforeUpdate();var t={data:{},success:function(t){d=new a.Collections.Template(t.templates),t.tags&&(s=t.tags),e.onUpdate&&e.onUpdate()}};e.forceSync&&(t.data.sync=!0),elementorCommon.ajax.addRequest("get_ha_library_data",t)},this.requestTemplateData=function(e,t){var i={unique_id:e,data:{edit_mode:!0,display:!0,template_id:e}};t&&jQuery.extend(!0,i,t),elementorCommon.ajax.addRequest("get_ha_template_data",i)},this.insertTemplate=function(e){var t=e.model,i=this;i.getModal().showLoadingView(),i.requestTemplateData(t.get("template_id"),{success:function(e){i.getModal().hideLoadingView(),i.getModal().hideModal();var a={};-1!==i.atIndex&&(a.at=i.atIndex),$e.run("document/elements/import",{model:t,data:e,options:a}),i.atIndex=-1},error:function(e){i.showErrorDialog(e)},complete:function(e){i.getModal().hideLoadingView(),window.elementor.$previewContents.find(".elementor-add-section .elementor-add-section-close").click()}})},this.showErrorDialog=function(e){if("object"==typeof e){var t="";_.each(e,function(e){t+="<div>"+e.message+".</div>"}),e=t}else e?e+=".":e="<i>&#60;The error message is empty&#62;</i>";m.getErrorDialog().setMessage('The following error(s) occurred while processing the request:<div id="elementor-template-library-error-info">'+e+"</div>").show()},this.getErrorDialog=function(){return c||(c=elementorCommon.dialogsManager.createWidget("alert",{id:"elementor-template-library-error-dialog",headerMessage:"An error occurred"})),c}},i.library=new a.Manager,i.library.init(),window.ha=i}(jQuery,window.elementor,window.ha||{});
changelog.txt CHANGED
@@ -1,3 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = 2.14.2 - 20 September 2020 =
2
 
3
  - Fix: JS loading issue for non logged in users
1
+ = 2.14.3 - 2.14.3 October 2020 =
2
+
3
+ - Update: Appsero client updated to `v1.2.0`
4
+ - Tweak: Added Calendy pro feature notice
5
+ - Tweak: Added Calendy default username "happyaddons"
6
+ - Tweak: Common cached files are loaded once as internal css
7
+ - Fix: Card widget badge dynamic tag issue
8
+ - Fix: Happy templates popup button auto duplicate issue
9
+ - Fix: Removed duplicate On demand assets cache file enqueue
10
+ - Fix: Removed broken Review widget schema data
11
+ - Fix: Team member widget email envelope icon issue
12
+ - Fix: Removed forced open in new window for Logo grid widget
13
+
14
  = 2.14.2 - 20 September 2020 =
15
 
16
  - Fix: JS loading issue for non logged in users
classes/assets-cache.php CHANGED
@@ -1,190 +1,222 @@
1
- <?php
2
- namespace Happy_Addons\Elementor;
3
-
4
- defined( 'ABSPATH' ) || die();
5
-
6
- class Assets_Cache {
7
-
8
- const FILE_PREFIX = 'happy-';
9
-
10
- /**
11
- * @var int
12
- */
13
- protected $post_id = 0;
14
-
15
- /**
16
- * @var Widgets_Cache
17
- */
18
- protected $widgets_cache = null;
19
-
20
- protected $upload_path;
21
-
22
- protected $upload_url;
23
-
24
- public function __construct( $post_id = 0, Widgets_Cache $widget_cache_instance = null ) {
25
- $this->post_id = $post_id;
26
- $this->widgets_cache = $widget_cache_instance;
27
-
28
- $upload_dir = wp_upload_dir();
29
- $this->upload_path = trailingslashit( $upload_dir['basedir'] );
30
- $this->upload_url = trailingslashit( $upload_dir['baseurl'] );
31
- }
32
-
33
- public function get_widgets_cache() {
34
- if ( is_null( $this->widgets_cache ) ) {
35
- $this->widgets_cache = new Widgets_Cache( $this->get_post_id() );
36
- }
37
- return $this->widgets_cache;
38
- }
39
-
40
- public function get_cache_dir_name() {
41
- return trailingslashit( 'happyaddons' ) . trailingslashit( 'cache' );
42
- }
43
-
44
- public function get_post_id() {
45
- return $this->post_id;
46
- }
47
-
48
- public function get_cache_dir() {
49
- return $this->upload_path . $this->get_cache_dir_name();
50
- }
51
-
52
- public function get_cache_url() {
53
- return $this->upload_url . $this->get_cache_dir_name();
54
- }
55
-
56
- public function get_file_name() {
57
- return $this->get_cache_dir() . self::FILE_PREFIX . "{$this->get_post_id()}.css";
58
- }
59
-
60
- public function get_file_url() {
61
- return $this->get_cache_url() . self::FILE_PREFIX . "{$this->get_post_id()}.css";
62
- }
63
-
64
- public function cache_exists() {
65
- return file_exists( $this->get_file_name() );
66
- }
67
-
68
- public function has() {
69
- if ( ! $this->cache_exists() ) {
70
- $this->save();
71
- }
72
- return $this->cache_exists();
73
- }
74
-
75
- public function delete() {
76
- if ( $this->cache_exists() ) {
77
- unlink( $this->get_file_name() );
78
- }
79
- }
80
-
81
- public function delete_all() {
82
- $files = glob( $this->get_cache_dir() . '*' );
83
- foreach ( $files as $file ) {
84
- if ( is_file( $file ) ) {
85
- unlink( $file );
86
- }
87
- }
88
- }
89
-
90
- public function enqueue() {
91
- if ( $this->has() ) {
92
- wp_enqueue_style(
93
- 'happy-elementor-addons-' . $this->get_post_id(),
94
- $this->get_file_url(),
95
- [ 'elementor-frontend' ],
96
- HAPPY_ADDONS_VERSION . '.' . get_post_modified_time()
97
- );
98
- }
99
- }
100
-
101
- public function enqueue_libraries() {
102
- $widgets_map = Widgets_Manager::get_widgets_map();
103
- $base_widget = isset( $widgets_map[ Widgets_Manager::get_base_widget_key() ] ) ? $widgets_map[ Widgets_Manager::get_base_widget_key() ] : [];
104
-
105
- if ( isset( $base_widget['vendor'], $base_widget['vendor']['css'] ) && is_array( $base_widget['vendor']['css'] ) ) {
106
- foreach ( $base_widget['vendor']['css'] as $vendor_css_handle ) {
107
- wp_enqueue_style( $vendor_css_handle );
108
- }
109
- }
110
-
111
- if ( isset( $base_widget['vendor'], $base_widget['vendor']['js'] ) && is_array( $base_widget['vendor']['js'] ) ) {
112
- foreach ( $base_widget['vendor']['js'] as $vendor_js_handle ) {
113
- wp_enqueue_script( $vendor_js_handle );
114
- }
115
- }
116
-
117
- /**
118
- * Return early if there's no widget cache
119
- */
120
- $widgets = $this->get_widgets_cache()->get();
121
-
122
- if ( empty( $widgets ) || ! is_array( $widgets ) ) {
123
- return;
124
- }
125
-
126
- foreach ( $widgets as $widget_key ) {
127
- if ( ! isset( $widgets_map[ $widget_key ], $widgets_map[ $widget_key ]['vendor'] ) ) {
128
- continue;
129
- }
130
-
131
- $vendor = $widgets_map[ $widget_key ]['vendor'];
132
-
133
- if ( isset( $vendor['css'] ) && is_array( $vendor['css'] ) ) {
134
- foreach ( $vendor['css'] as $vendor_css_handle ) {
135
- wp_enqueue_style( $vendor_css_handle );
136
- }
137
- }
138
-
139
- if ( isset( $vendor['js'] ) && is_array( $vendor['js'] ) ) {
140
- foreach ( $vendor['js'] as $vendor_js_handle ) {
141
- wp_enqueue_script( $vendor_js_handle );
142
- }
143
- }
144
- }
145
- }
146
-
147
- public function save() {
148
- $widgets = $this->get_widgets_cache()->get();
149
-
150
- $widgets_map = Widgets_Manager::get_widgets_map();
151
- $base_widget = isset( $widgets_map[ Widgets_Manager::get_base_widget_key() ] ) ? $widgets_map[ Widgets_Manager::get_base_widget_key() ] : [];
152
- $styles = '';
153
-
154
- // Get common css styles
155
- if ( isset( $base_widget['css'] ) && is_array( $base_widget['css'] ) ) {
156
- $styles = $this->get_styles( $base_widget['css'] );
157
- }
158
-
159
- $cached_widgets = [];
160
- foreach ( $widgets as $widget_key ) {
161
- if ( isset( $cached_widgets[ $widget_key ] ) ||
162
- ! isset( $widgets_map[ $widget_key ], $widgets_map[ $widget_key ]['css'] )
163
- ) {
164
- continue;
165
- }
166
- $is_pro = ( isset( $widgets_map[ $widget_key ]['is_pro'] ) && $widgets_map[ $widget_key ]['is_pro'] );
167
- $styles .= $this->get_styles( $widgets_map[ $widget_key ]['css'], $is_pro );
168
- $cached_widgets[ $widget_key ] = true;
169
- }
170
- $styles .= sprintf( '/** Compiled CSS for: %s **/', implode(', ', array_keys( $cached_widgets ) ) );
171
-
172
- if ( ! is_dir( $this->get_cache_dir() ) ) {
173
- @mkdir( $this->get_cache_dir(), 0755, true );
174
- }
175
-
176
- file_put_contents( $this->get_file_name(), $styles );
177
- }
178
-
179
- protected function get_styles( $files_name, $is_pro = false ) {
180
- $styles = '';
181
- foreach ( $files_name as $file_name ) {
182
- $file_path = HAPPY_ADDONS_DIR_PATH . "assets/css/widgets/{$file_name}.min.css";
183
- $file_path = apply_filters( 'happyaddons_get_styles_file_path', $file_path, $file_name, $is_pro );
184
- if ( is_readable( $file_path ) ) {
185
- $styles .= file_get_contents( $file_path );
186
- };
187
- }
188
- return $styles;
189
- }
190
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Happy_Addons\Elementor;
3
+
4
+ defined( 'ABSPATH' ) || die();
5
+
6
+ class Assets_Cache {
7
+
8
+ const FILE_PREFIX = 'happy-';
9
+
10
+ protected static $is_common_loaded = false;
11
+
12
+ /**
13
+ * @var int
14
+ */
15
+ protected $post_id = 0;
16
+
17
+ /**
18
+ * @var Widgets_Cache
19
+ */
20
+ protected $widgets_cache = null;
21
+
22
+ protected $upload_path;
23
+
24
+ protected $upload_url;
25
+
26
+ public function __construct( $post_id = 0, Widgets_Cache $widget_cache_instance = null ) {
27
+ $this->post_id = $post_id;
28
+ $this->widgets_cache = $widget_cache_instance;
29
+
30
+ $upload_dir = wp_upload_dir();
31
+ $this->upload_path = trailingslashit( $upload_dir['basedir'] );
32
+ $this->upload_url = trailingslashit( $upload_dir['baseurl'] );
33
+ }
34
+
35
+ public function get_widgets_cache() {
36
+ if ( is_null( $this->widgets_cache ) ) {
37
+ $this->widgets_cache = new Widgets_Cache( $this->get_post_id() );
38
+ }
39
+ return $this->widgets_cache;
40
+ }
41
+
42
+ public function get_cache_dir_name() {
43
+ return trailingslashit( 'happyaddons' ) . trailingslashit( 'cache' );
44
+ }
45
+
46
+ public function get_post_id() {
47
+ return $this->post_id;
48
+ }
49
+
50
+ public function get_cache_dir() {
51
+ return $this->upload_path . $this->get_cache_dir_name();
52
+ }
53
+
54
+ public function get_cache_url() {
55
+ return $this->upload_url . $this->get_cache_dir_name();
56
+ }
57
+
58
+ public function get_file_name() {
59
+ return $this->get_cache_dir() . self::FILE_PREFIX . "{$this->get_post_id()}.css";
60
+ }
61
+
62
+ public function get_file_url() {
63
+ return $this->get_cache_url() . self::FILE_PREFIX . "{$this->get_post_id()}.css";
64
+ }
65
+
66
+ public function cache_exists() {
67
+ return file_exists( $this->get_file_name() );
68
+ }
69
+
70
+ public function has() {
71
+ if ( ! $this->cache_exists() ) {
72
+ $this->save();
73
+ }
74
+ return $this->cache_exists();
75
+ }
76
+
77
+ public function delete() {
78
+ if ( $this->cache_exists() ) {
79
+ unlink( $this->get_file_name() );
80
+ }
81
+ }
82
+
83
+ public function delete_all() {
84
+ $files = glob( $this->get_cache_dir() . '*' );
85
+ foreach ( $files as $file ) {
86
+ if ( is_file( $file ) ) {
87
+ unlink( $file );
88
+ }
89
+ }
90
+ }
91
+
92
+ public function enqueue() {
93
+ $this->enqueue_common();
94
+
95
+ if ( $this->has() ) {
96
+ wp_enqueue_style(
97
+ 'happy-elementor-addons-' . $this->get_post_id(),
98
+ $this->get_file_url(),
99
+ [ 'elementor-frontend' ],
100
+ HAPPY_ADDONS_VERSION . '.' . get_post_modified_time()
101
+ );
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Added common style as inline style
107
+ *
108
+ * Optimize css loading by extracting the common styles from all widgets
109
+ * and load as inline style.
110
+ *
111
+ * @since 2.14.3
112
+ *
113
+ * @return void
114
+ */
115
+ public function enqueue_common() {
116
+ if ( self::$is_common_loaded ) {
117
+ return;
118
+ }
119
+
120
+ $widgets_map = Widgets_Manager::get_widgets_map();
121
+ $base_widget = isset( $widgets_map[ Widgets_Manager::get_base_widget_key() ] ) ? $widgets_map[ Widgets_Manager::get_base_widget_key() ] : [];
122
+
123
+ // Get common css styles
124
+ if ( ! isset( $base_widget['css'] ) || ! is_array( $base_widget['css'] ) ) {
125
+ return;
126
+ }
127
+
128
+ // TODO: Update style handler, now it's dependent on elementor-frontend
129
+ wp_add_inline_style(
130
+ 'elementor-frontend',
131
+ $this->get_styles( $base_widget['css'] )
132
+ );
133
+
134
+ self::$is_common_loaded = true;
135
+ }
136
+
137
+ public function enqueue_libraries() {
138
+ $widgets_map = Widgets_Manager::get_widgets_map();
139
+ $base_widget = isset( $widgets_map[ Widgets_Manager::get_base_widget_key() ] ) ? $widgets_map[ Widgets_Manager::get_base_widget_key() ] : [];
140
+
141
+ if ( isset( $base_widget['vendor'], $base_widget['vendor']['css'] ) && is_array( $base_widget['vendor']['css'] ) ) {
142
+ foreach ( $base_widget['vendor']['css'] as $vendor_css_handle ) {
143
+ wp_enqueue_style( $vendor_css_handle );
144
+ }
145
+ }
146
+
147
+ if ( isset( $base_widget['vendor'], $base_widget['vendor']['js'] ) && is_array( $base_widget['vendor']['js'] ) ) {
148
+ foreach ( $base_widget['vendor']['js'] as $vendor_js_handle ) {
149
+ wp_enqueue_script( $vendor_js_handle );
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Return early if there's no widget cache
155
+ */
156
+ $widgets = $this->get_widgets_cache()->get();
157
+
158
+ if ( empty( $widgets ) || ! is_array( $widgets ) ) {
159
+ return;
160
+ }
161
+
162
+ foreach ( $widgets as $widget_key ) {
163
+ if ( ! isset( $widgets_map[ $widget_key ], $widgets_map[ $widget_key ]['vendor'] ) ) {
164
+ continue;
165
+ }
166
+
167
+ $vendor = $widgets_map[ $widget_key ]['vendor'];
168
+
169
+ if ( isset( $vendor['css'] ) && is_array( $vendor['css'] ) ) {
170
+ foreach ( $vendor['css'] as $vendor_css_handle ) {
171
+ wp_enqueue_style( $vendor_css_handle );
172
+ }
173
+ }
174
+
175
+ if ( isset( $vendor['js'] ) && is_array( $vendor['js'] ) ) {
176
+ foreach ( $vendor['js'] as $vendor_js_handle ) {
177
+ wp_enqueue_script( $vendor_js_handle );
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ public function save() {
184
+ $widgets = $this->get_widgets_cache()->get();
185
+ $widgets_map = Widgets_Manager::get_widgets_map();
186
+ $cached_widgets = [];
187
+ $styles = '';
188
+
189
+ foreach ( $widgets as $widget_key ) {
190
+ if ( isset( $cached_widgets[ $widget_key ] ) ||
191
+ ! isset( $widgets_map[ $widget_key ], $widgets_map[ $widget_key ]['css'] )
192
+ ) {
193
+ continue;
194
+ }
195
+ $is_pro = ( isset( $widgets_map[ $widget_key ]['is_pro'] ) && $widgets_map[ $widget_key ]['is_pro'] );
196
+ $styles .= $this->get_styles( $widgets_map[ $widget_key ]['css'], $is_pro );
197
+ $cached_widgets[ $widget_key ] = true;
198
+ }
199
+
200
+ $styles .= sprintf( '/** Compiled CSS for: %s **/', implode(', ', array_keys( $cached_widgets ) ) );
201
+
202
+ if ( ! is_dir( $this->get_cache_dir() ) ) {
203
+ @mkdir( $this->get_cache_dir(), 0755, true );
204
+ }
205
+
206
+ file_put_contents( $this->get_file_name(), $styles );
207
+ }
208
+
209
+ protected function get_styles( $files_name, $is_pro = false ) {
210
+ $styles = '';
211
+
212
+ foreach ( $files_name as $file_name ) {
213
+ $file_path = HAPPY_ADDONS_DIR_PATH . "assets/css/widgets/{$file_name}.min.css";
214
+ $file_path = apply_filters( 'happyaddons_get_styles_file_path', $file_path, $file_name, $is_pro );
215
+ if ( is_readable( $file_path ) ) {
216
+ $styles .= file_get_contents( $file_path );
217
+ };
218
+ }
219
+
220
+ return $styles;
221
+ }
222
+ }
classes/wpml-manager.php CHANGED
@@ -1,519 +1,519 @@
1
- <?php
2
- /**
3
- * WPML integration and compatibility manager
4
- */
5
- namespace Happy_Addons\Elementor;
6
-
7
- defined( 'ABSPATH' ) || die();
8
-
9
- class WPML_Manager {
10
-
11
- public static function init() {
12
- add_filter( 'wpml_elementor_widgets_to_translate', [ __CLASS__, 'add_widgets_to_translate' ] );
13
- }
14
-
15
- public static function load_integration_files() {
16
- include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/bar-chart.php' );
17
- include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/carousel.php' );
18
- include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/image-grid.php' );
19
- include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/justified-gallery.php' );
20
- include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/logo-grid.php' );
21
- include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/pricing-table.php' );
22
- include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/skills.php' );
23
- include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/slider.php' );
24
- include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/social-icons.php' );
25
- }
26
-
27
- public static function add_widgets_to_translate( $widgets ) {
28
- self::load_integration_files();
29
-
30
- $widgets_map = [
31
- /**
32
- * Bar Chart
33
- */
34
- 'bar-chart' => [
35
- 'fields' => [
36
- [
37
- 'field' => 'labels',
38
- 'type' => __( 'Bar Chart: Labels', 'happy-elementor-addons' ),
39
- 'editor_type' => 'LINE',
40
- ],
41
- [
42
- 'field' => 'chart_title',
43
- 'type' => __( 'Bar Chart: Title', 'happy-elementor-addons' ),
44
- 'editor_type' => 'LINE',
45
- ],
46
- ],
47
- 'integration-class' => __NAMESPACE__ . '\\WPML_Bar_Chart',
48
- ],
49
-
50
- /**
51
- * Card
52
- */
53
- 'card' => [
54
- 'fields' => [
55
- [
56
- 'field' => 'badge_text',
57
- 'type' => __( 'Card: Badge Text', 'happy-elementor-addons' ),
58
- 'editor_type' => 'LINE',
59
- ],
60
- [
61
- 'field' => 'title',
62
- 'type' => __( 'Card: Title', 'happy-elementor-addons' ),
63
- 'editor_type' => 'LINE',
64
- ],
65
- [
66
- 'field' => 'description',
67
- 'type' => __( 'Card: Description', 'happy-elementor-addons' ),
68
- 'editor_type' => 'AREA'
69
- ],
70
- [
71
- 'field' => 'button_text',
72
- 'type' => __( 'Card: Button Text', 'happy-elementor-addons' ),
73
- 'editor_type' => 'LINE',
74
- ],
75
- 'button_link' => [
76
- 'field' => 'url',
77
- 'type' => __( 'Card: Button Link', 'happy-elementor-addons' ),
78
- 'editor_type' => 'LINK',
79
- ],
80
- ],
81
- ],
82
-
83
- /**
84
- * Carousel
85
- */
86
- 'carousel' => [
87
- 'fields' => [],
88
- 'integration-class' => __NAMESPACE__ . '\\WPML_Carousel',
89
- ],
90
-
91
- /**
92
- * Dual Button
93
- */
94
- 'dual-button' => [
95
- 'fields' => [
96
- [
97
- 'field' => 'left_button_text',
98
- 'type' => __( 'Dual Button: Primary Button Text', 'happy-elementor-addons' ),
99
- 'editor_type' => 'LINE',
100
- ],
101
- 'left_button_link' => [
102
- 'field' => 'url',
103
- 'type' => __( 'Dual Button: Primary Button Link', 'happy-elementor-addons' ),
104
- 'editor_type' => 'LINK',
105
- ],
106
- [
107
- 'field' => 'button_connector_text',
108
- 'type' => __( 'Dual Button: Connector Text', 'happy-elementor-addons' ),
109
- 'editor_type' => 'LINE',
110
- ],
111
- [
112
- 'field' => 'right_button_text',
113
- 'type' => __( 'Dual Button: Secondary Button Text', 'happy-elementor-addons' ),
114
- 'editor_type' => 'LINE',
115
- ],
116
- 'right_button_link' => [
117
- 'field' => 'url',
118
- 'type' => __( 'Dual Button: Secondary Button Link', 'happy-elementor-addons' ),
119
- 'editor_type' => 'LINK',
120
- ],
121
- ],
122
- ],
123
-
124
- /**
125
- * Flip Box
126
- */
127
- 'flip-box' => [
128
- 'fields' => [
129
- [
130
- 'field' => 'front_title',
131
- 'type' => __( 'Flip Box: Front Title', 'happy-elementor-addons' ),
132
- 'editor_type' => 'LINE',
133
- ],
134
- [
135
- 'field' => 'front_description',
136
- 'type' => __( 'Flip Box: Front Description', 'happy-elementor-addons' ),
137
- 'editor_type' => 'AREA',
138
- ],
139
- [
140
- 'field' => 'back_title',
141
- 'type' => __( 'Flip Box: Back Title', 'happy-elementor-addons' ),
142
- 'editor_type' => 'LINE',
143
- ],
144
- [
145
- 'field' => 'back_description',
146
- 'type' => __( 'Flip Box: Back Description', 'happy-elementor-addons' ),
147
- 'editor_type' => 'AREA',
148
- ],
149
- ],
150
- ],
151
-
152
- /**
153
- * Fun Factor
154
- */
155
- 'fun-factor' => [
156
- 'fields' => [
157
- [
158
- 'field' => 'fun_factor_title',
159
- 'type' => __( 'Fun Factor: Title', 'happy-elementor-addons' ),
160
- 'editor_type' => 'LINE',
161
- ],
162
- ],
163
- ],
164
-
165
- /**
166
- * Gradient Heading
167
- */
168
- 'gradient-heading' => [
169
- 'fields' => [
170
- [
171
- 'field' => 'title',
172
- 'type' => __( 'Gradient_Heading: Title', 'happy-elementor-addons' ),
173
- 'editor_type' => 'AREA',
174
- ],
175
- 'link' => [
176
- 'field' => 'url',
177
- 'type' => __( 'Gradient_Heading: Link', 'happy-elementor-addons' ),
178
- 'editor_type' => 'LINK',
179
- ],
180
- ],
181
- ],
182
-
183
- /**
184
- * Icon Box
185
- */
186
- 'icon-box' => [
187
- 'fields' => [
188
- [
189
- 'field' => 'title',
190
- 'type' => __( 'Icon Box: Title', 'happy-elementor-addons' ),
191
- 'editor_type' => 'LINE',
192
- ],
193
- [
194
- 'field' => 'badge_text',
195
- 'type' => __( 'Icon Box: Badge Text', 'happy-elementor-addons' ),
196
- 'editor_type' => 'LINE',
197
- ],
198
- 'link' => [
199
- 'field' => 'url',
200
- 'type' => __( 'Icon Box: Link', 'happy-elementor-addons' ),
201
- 'editor_type' => 'LINK',
202
- ],
203
- ],
204
- ],
205
-
206
- /**
207
- * Image Compare
208
- */
209
- 'image-compare' => [
210
- 'fields' => [
211
- [
212
- 'field' => 'before_label',
213
- 'type' => __( 'Image Compare: Before Label', 'happy-elementor-addons' ),
214
- 'editor_type' => 'LINE',
215
- ],
216
- [
217
- 'field' => 'after_label',
218
- 'type' => __( 'Image Compare: After Label', 'happy-elementor-addons' ),
219
- 'editor_type' => 'LINE',
220
- ],
221
- ],
222
- ],
223
-
224
- /**
225
- * Image Grid
226
- */
227
- 'image-grid' => [
228
- 'fields' => [
229
- [
230
- 'field' => 'all_filter_label',
231
- 'type' => __( 'Image Grid: All Filter Label', 'happy-elementor-addons' ),
232
- 'editor_type' => 'LINE',
233
- ],
234
- ],
235
- 'integration-class' => __NAMESPACE__ . '\\WPML_Image_Grid',
236
- ],
237
-
238
- /**
239
- * Info Box
240
- */
241
- 'infobox' => [
242
- 'fields' => [
243
- [
244
- 'field' => 'title',
245
- 'type' => __( 'Info Box: Title', 'happy-elementor-addons' ),
246
- 'editor_type' => 'LINE',
247
- ],
248
- [
249
- 'field' => 'description',
250
- 'type' => __( 'Info Box: Description', 'happy-elementor-addons' ),
251
- 'editor_type' => 'AREA',
252
- ],
253
- [
254
- 'field' => 'button_text',
255
- 'type' => __( 'Info Box: Button Text', 'happy-elementor-addons' ),
256
- 'editor_type' => 'LINE',
257
- ],
258
- 'button_link' => [
259
- 'field' => 'url',
260
- 'type' => __( 'Info Box: Button Link', 'happy-elementor-addons' ),
261
- 'editor_type' => 'LINK',
262
- ],
263
- ],
264
- ],
265
-
266
- /**
267
- * Justified Gallery
268
- */
269
- 'justified-gallery' => [
270
- 'fields' => [
271
- [
272
- 'field' => 'all_filter_label',
273
- 'type' => __( 'Justified Grid: All Filter Label', 'happy-elementor-addons' ),
274
- 'editor_type' => 'LINE',
275
- ],
276
- ],
277
- 'integration-class' => __NAMESPACE__ . '\\WPML_Justified_Gallery',
278
- ],
279
-
280
- /**
281
- * Logo Grid
282
- */
283
- 'logo-grid' => [
284
- 'fields' => [],
285
- 'integration-class' => __NAMESPACE__ . '\\WPML_Logo_Grid',
286
- ],
287
-
288
- /**
289
- * Team Member
290
- */
291
- 'member' => [
292
- 'fields' => [
293
- [
294
- 'field' => 'title',
295
- 'type' => __( 'Team Member: Name', 'happy-elementor-addons' ),
296
- 'editor_type' => 'LINE',
297
- ],
298
- [
299
- 'field' => 'job_title',
300
- 'type' => __( 'Team Member: Job Title', 'happy-elementor-addons' ),
301
- 'editor_type' => 'LINE',
302
- ],
303
- [
304
- 'field' => 'bio',
305
- 'type' => __( 'Team Member: Short Bio', 'happy-elementor-addons' ),
306
- 'editor_type' => 'AREA',
307
- ],
308
- ],
309
- ],
310
-
311
- /**
312
- * News Ticker
313
- */
314
- 'news-ticker' => [
315
- 'fields' => [
316
- [
317
- 'field' => 'sticky_title',
318
- 'type' => __( 'News Ticker: Sticky Title', 'happy-elementor-addons' ),
319
- 'editor_type' => 'LINE',
320
- ],
321
- ],
322
- ],
323
-
324
- /**
325
- * Number
326
- */
327
- 'number' => [
328
- 'fields' => [
329
- [
330
- 'field' => 'number_text',
331
- 'type' => __( 'Number: Text', 'happy-elementor-addons' ),
332
- 'editor_type' => 'LINE',
333
- ],
334
- ],
335
- ],
336
-
337
- /**
338
- * Pricing Table
339
- */
340
- 'pricing-table' => [
341
- 'fields' => [
342
- [
343
- 'field' => 'title',
344
- 'type' => __( 'Pricing Table: Title', 'happy-elementor-addons' ),
345
- 'editor_type' => 'LINE',
346
- ],
347
- [
348
- 'field' => 'price',
349
- 'type' => __( 'Pricing Table: Price', 'happy-elementor-addons' ),
350
- 'editor_type' => 'LINE',
351
- ],
352
- [
353
- 'field' => 'period',
354
- 'type' => __( 'Pricing Table: Period', 'happy-elementor-addons' ),
355
- 'editor_type' => 'LINE',
356
- ],
357
- [
358
- 'field' => 'features_title',
359
- 'type' => __( 'Pricing Table: Features Title', 'happy-elementor-addons' ),
360
- 'editor_type' => 'LINE',
361
- ],
362
- [
363
- 'field' => 'button_text',
364
- 'type' => __( 'Pricing Table: Button Text', 'happy-elementor-addons' ),
365
- 'editor_type' => 'LINE',
366
- ],
367
- 'button_link' => [
368
- 'field' => 'url',
369
- 'type' => __( 'Pricing Table: Button Link', 'happy-elementor-addons' ),
370
- 'editor_type' => 'LINK',
371
- ],
372
- [
373
- 'field' => 'badge_text',
374
- 'type' => __( 'Pricing Table: Badge Text', 'happy-elementor-addons' ),
375
- 'editor_type' => 'LINE',
376
- ],
377
- ],
378
- 'integration-class' => __NAMESPACE__ . '\\WPML_Pricing_Table',
379
- ],
380
-
381
- /**
382
- * Review
383
- */
384
- 'review' => [
385
- 'fields' => [
386
- [
387
- 'field' => 'review',
388
- 'type' => __( 'Review: Review Text', 'happy-elementor-addons' ),
389
- 'editor_type' => 'AREA',
390
- ],
391
- [
392
- 'field' => 'title',
393
- 'type' => __( 'Review: Reviewer Name', 'happy-elementor-addons' ),
394
- 'editor_type' => 'LINE',
395
- ],
396
- [
397
- 'field' => 'job_title',
398
- 'type' => __( 'Review: Job Title', 'happy-elementor-addons' ),
399
- 'editor_type' => 'LINE',
400
- ],
401
- ],
402
- ],
403
-
404
- /**
405
- * Skills
406
- */
407
- 'skills' => [
408
- 'fields' => [],
409
- 'integration-class' => __NAMESPACE__ . '\\WPML_Skills',
410
- ],
411
-
412
- /**
413
- * Slider
414
- */
415
- 'slider' => [
416
- 'fields' => [],
417
- 'integration-class' => __NAMESPACE__ . '\\WPML_Slider',
418
- ],
419
-
420
- /**
421
- * Social Icons
422
- */
423
- 'social-icons' => [
424
- 'fields' => [],
425
- 'integration-class' => __NAMESPACE__ . '\\WPML_Social_Icons',
426
- ],
427
-
428
- /**
429
- * Step Flow
430
- */
431
- 'step-flow' => [
432
- 'fields' => [
433
- [
434
- 'field' => 'badge',
435
- 'type' => __( 'Step Flow: Badge Text', 'happy-elementor-addons' ),
436
- 'editor_type' => 'LINE',
437
- ],
438
- [
439
- 'field' => 'title',
440
- 'type' => __( 'Step Flow: Title', 'happy-elementor-addons' ),
441
- 'editor_type' => 'LINE',
442
- ],
443
- [
444
- 'field' => 'description',
445
- 'type' => __( 'Step Flow: Description', 'happy-elementor-addons' ),
446
- 'editor_type' => 'AREA',
447
- ],
448
- 'link' => [
449
- 'field' => 'url',
450
- 'type' => __( 'Step Flow: Link', 'happy-elementor-addons' ),
451
- 'editor_type' => 'LINK',
452
- ],
453
- ],
454
- ],
455
-
456
- /**
457
- * Testimonial
458
- */
459
- 'testimonial' => [
460
- 'fields' => [
461
- [
462
- 'field' => 'testimonial',
463
- 'type' => __( 'Testimonial: Testimonial Text', 'happy-elementor-addons' ),
464
- 'editor_type' => 'AREA',
465
- ],
466
- [
467
- 'field' => 'name',
468
- 'type' => __( 'Testimonial: Reviewer Name', 'happy-elementor-addons' ),
469
- 'editor_type' => 'LINE',
470
- ],
471
- [
472
- 'field' => 'title',
473
- 'type' => __( 'Testimonial: Job Title', 'happy-elementor-addons' ),
474
- 'editor_type' => 'LINE',
475
- ],
476
- ],
477
- ],
478
-
479
- /**
480
- * Twitter Feed
481
- */
482
- 'twitter-feed' => [
483
- 'fields' => [
484
- [
485
- 'field' => 'read_more_text',
486
- 'type' => __( 'Twitter Feed: Read More Text', 'happy-elementor-addons' ),
487
- 'editor_type' => 'AREA',
488
- ],
489
- [
490
- 'field' => 'load_more_text',
491
- 'type' => __( 'Twitter Feed: Load More Text', 'happy-elementor-addons' ),
492
- 'editor_type' => 'LINE',
493
- ],
494
- ],
495
- ],
496
- ];
497
-
498
- foreach ( $widgets_map as $key => $data ) {
499
- $widget_name = 'ha-'.$key;
500
-
501
- $entry = [
502
- 'conditions' => [
503
- 'widgetType' => $widget_name,
504
- ],
505
- 'fields' => $data['fields'],
506
- ];
507
-
508
- if ( isset( $data['integration-class'] ) ) {
509
- $entry['integration-class'] = $data['integration-class'];
510
- }
511
-
512
- $widgets[ $widget_name ] = $entry;
513
- }
514
-
515
- return $widgets;
516
- }
517
- }
518
-
519
- WPML_Manager::init();
1
+ <?php
2
+ /**
3
+ * WPML integration and compatibility manager
4
+ */
5
+ namespace Happy_Addons\Elementor;
6
+
7
+ defined( 'ABSPATH' ) || die();
8
+
9
+ class WPML_Manager {
10
+
11
+ public static function init() {
12
+ add_filter( 'wpml_elementor_widgets_to_translate', [ __CLASS__, 'add_widgets_to_translate' ] );
13
+ }
14
+
15
+ public static function load_integration_files() {
16
+ include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/bar-chart.php' );
17
+ include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/carousel.php' );
18
+ include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/image-grid.php' );
19
+ include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/justified-gallery.php' );
20
+ include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/logo-grid.php' );
21
+ include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/pricing-table.php' );
22
+ include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/skills.php' );
23
+ include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/slider.php' );
24
+ include_once( HAPPY_ADDONS_DIR_PATH . 'wpml/social-icons.php' );
25
+ }
26
+
27
+ public static function add_widgets_to_translate( $widgets ) {
28
+ self::load_integration_files();
29
+
30
+ $widgets_map = [
31
+ /**
32
+ * Bar Chart
33
+ */
34
+ 'bar-chart' => [
35
+ 'fields' => [
36
+ [
37
+ 'field' => 'labels',
38
+ 'type' => __( 'Bar Chart: Labels', 'happy-elementor-addons' ),
39
+ 'editor_type' => 'LINE',
40
+ ],
41
+ [
42
+ 'field' => 'chart_title',
43
+ 'type' => __( 'Bar Chart: Title', 'happy-elementor-addons' ),
44
+ 'editor_type' => 'LINE',
45
+ ],
46
+ ],
47
+ 'integration-class' => __NAMESPACE__ . '\\WPML_Bar_Chart',
48
+ ],
49
+
50
+ /**
51
+ * Card
52
+ */
53
+ 'card' => [
54
+ 'fields' => [
55
+ [
56
+ 'field' => 'badge_text',
57
+ 'type' => __( 'Card: Badge Text', 'happy-elementor-addons' ),
58
+ 'editor_type' => 'LINE',
59
+ ],
60
+ [
61
+ 'field' => 'title',
62
+ 'type' => __( 'Card: Title', 'happy-elementor-addons' ),
63
+ 'editor_type' => 'LINE',
64
+ ],
65
+ [
66
+ 'field' => 'description',
67
+ 'type' => __( 'Card: Description', 'happy-elementor-addons' ),
68
+ 'editor_type' => 'AREA'
69
+ ],
70
+ [
71
+ 'field' => 'button_text',
72
+ 'type' => __( 'Card: Button Text', 'happy-elementor-addons' ),
73
+ 'editor_type' => 'LINE',
74
+ ],
75
+ 'button_link' => [
76
+ 'field' => 'url',
77
+ 'type' => __( 'Card: Button Link', 'happy-elementor-addons' ),
78
+ 'editor_type' => 'LINK',
79
+ ],
80
+ ],
81
+ ],
82
+
83
+ /**
84
+ * Carousel
85
+ */
86
+ 'carousel' => [
87
+ 'fields' => [],
88
+ 'integration-class' => __NAMESPACE__ . '\\WPML_Carousel',
89
+ ],
90
+
91
+ /**
92
+ * Dual Button
93
+ */
94
+ 'dual-button' => [
95
+ 'fields' => [
96
+ [
97
+ 'field' => 'left_button_text',
98
+ 'type' => __( 'Dual Button: Primary Button Text', 'happy-elementor-addons' ),
99
+ 'editor_type' => 'LINE',
100
+ ],
101
+ 'left_button_link' => [
102
+ 'field' => 'url',
103
+ 'type' => __( 'Dual Button: Primary Button Link', 'happy-elementor-addons' ),
104
+ 'editor_type' => 'LINK',
105
+ ],
106
+ [
107
+ 'field' => 'button_connector_text',
108
+ 'type' => __( 'Dual Button: Connector Text', 'happy-elementor-addons' ),
109
+ 'editor_type' => 'LINE',
110
+ ],
111
+ [
112
+ 'field' => 'right_button_text',
113
+ 'type' => __( 'Dual Button: Secondary Button Text', 'happy-elementor-addons' ),
114
+ 'editor_type' => 'LINE',
115
+ ],
116
+ 'right_button_link' => [
117
+ 'field' => 'url',
118
+ 'type' => __( 'Dual Button: Secondary Button Link', 'happy-elementor-addons' ),
119
+ 'editor_type' => 'LINK',
120
+ ],
121
+ ],
122
+ ],
123
+
124
+ /**
125
+ * Flip Box
126
+ */
127
+ 'flip-box' => [
128
+ 'fields' => [
129
+ [
130
+ 'field' => 'front_title',
131
+ 'type' => __( 'Flip Box: Front Title', 'happy-elementor-addons' ),
132
+ 'editor_type' => 'LINE',
133
+ ],
134
+ [
135
+ 'field' => 'front_description',
136
+ 'type' => __( 'Flip Box: Front Description', 'happy-elementor-addons' ),
137
+ 'editor_type' => 'AREA',
138
+ ],
139
+ [
140
+ 'field' => 'back_title',
141
+ 'type' => __( 'Flip Box: Back Title', 'happy-elementor-addons' ),
142
+ 'editor_type' => 'LINE',
143
+ ],
144
+ [
145
+ 'field' => 'back_description',
146
+ 'type' => __( 'Flip Box: Back Description', 'happy-elementor-addons' ),
147
+ 'editor_type' => 'AREA',
148
+ ],
149
+ ],
150
+ ],
151
+
152
+ /**
153
+ * Fun Factor
154
+ */
155
+ 'fun-factor' => [
156
+ 'fields' => [
157
+ [
158
+ 'field' => 'fun_factor_title',
159
+ 'type' => __( 'Fun Factor: Title', 'happy-elementor-addons' ),
160
+ 'editor_type' => 'LINE',
161
+ ],
162
+ ],
163
+ ],
164
+
165
+ /**
166
+ * Gradient Heading
167
+ */
168
+ 'gradient-heading' => [
169
+ 'fields' => [
170
+ [
171
+ 'field' => 'title',
172
+ 'type' => __( 'Gradient_Heading: Title', 'happy-elementor-addons' ),
173
+ 'editor_type' => 'AREA',
174
+ ],
175
+ 'link' => [
176
+ 'field' => 'url',
177
+ 'type' => __( 'Gradient_Heading: Link', 'happy-elementor-addons' ),
178
+ 'editor_type' => 'LINK',
179
+ ],
180
+ ],
181
+ ],
182
+
183
+ /**
184
+ * Icon Box
185
+ */
186
+ 'icon-box' => [
187
+ 'fields' => [
188
+ [
189
+ 'field' => 'title',
190
+ 'type' => __( 'Icon Box: Title', 'happy-elementor-addons' ),
191
+ 'editor_type' => 'LINE',
192
+ ],
193
+ [
194
+ 'field' => 'badge_text',
195
+ 'type' => __( 'Icon Box: Badge Text', 'happy-elementor-addons' ),
196
+ 'editor_type' => 'LINE',
197
+ ],
198
+ 'link' => [
199
+ 'field' => 'url',
200
+ 'type' => __( 'Icon Box: Link', 'happy-elementor-addons' ),
201
+ 'editor_type' => 'LINK',
202
+ ],
203
+ ],
204
+ ],
205
+
206
+ /**
207
+ * Image Compare
208
+ */
209
+ 'image-compare' => [
210
+ 'fields' => [
211
+ [
212
+ 'field' => 'before_label',
213
+ 'type' => __( 'Image Compare: Before Label', 'happy-elementor-addons' ),
214
+ 'editor_type' => 'LINE',
215
+ ],
216
+ [
217
+ 'field' => 'after_label',
218
+ 'type' => __( 'Image Compare: After Label', 'happy-elementor-addons' ),
219
+ 'editor_type' => 'LINE',
220
+ ],
221
+ ],
222
+ ],
223
+
224
+ /**
225
+ * Image Grid
226
+ */
227
+ 'image-grid' => [
228
+ 'fields' => [
229
+ [
230
+ 'field' => 'all_filter_label',
231
+ 'type' => __( 'Image Grid: All Filter Label', 'happy-elementor-addons' ),
232
+ 'editor_type' => 'LINE',
233
+ ],
234
+ ],
235
+ 'integration-class' => __NAMESPACE__ . '\\WPML_Image_Grid',
236
+ ],
237
+
238
+ /**
239
+ * Info Box
240
+ */
241
+ 'infobox' => [
242
+ 'fields' => [
243
+ [
244
+ 'field' => 'title',
245
+ 'type' => __( 'Info Box: Title', 'happy-elementor-addons' ),
246
+ 'editor_type' => 'LINE',
247
+ ],
248
+ [
249
+ 'field' => 'description',
250
+ 'type' => __( 'Info Box: Description', 'happy-elementor-addons' ),
251
+ 'editor_type' => 'AREA',
252
+ ],
253
+ [
254
+ 'field' => 'button_text',
255
+ 'type' => __( 'Info Box: Button Text', 'happy-elementor-addons' ),
256
+ 'editor_type' => 'LINE',
257
+ ],
258
+ 'button_link' => [
259
+ 'field' => 'url',
260
+ 'type' => __( 'Info Box: Button Link', 'happy-elementor-addons' ),
261
+ 'editor_type' => 'LINK',
262
+ ],
263
+ ],
264
+ ],
265
+
266
+ /**
267
+ * Justified Gallery
268
+ */
269
+ 'justified-gallery' => [
270
+ 'fields' => [
271
+ [
272
+ 'field' => 'all_filter_label',
273
+ 'type' => __( 'Justified Grid: All Filter Label', 'happy-elementor-addons' ),
274
+ 'editor_type' => 'LINE',
275
+ ],
276
+ ],
277
+ 'integration-class' => __NAMESPACE__ . '\\WPML_Justified_Gallery',
278
+ ],
279
+
280
+ /**
281
+ * Logo Grid
282
+ */
283
+ 'logo-grid' => [
284
+ 'fields' => [],
285
+ 'integration-class' => __NAMESPACE__ . '\\WPML_Logo_Grid',
286
+ ],
287
+
288
+ /**
289
+ * Team Member
290
+ */
291
+ 'member' => [
292
+ 'fields' => [
293
+ [
294
+ 'field' => 'title',
295
+ 'type' => __( 'Team Member: Name', 'happy-elementor-addons' ),
296
+ 'editor_type' => 'LINE',
297
+ ],
298
+ [
299
+ 'field' => 'job_title',
300
+ 'type' => __( 'Team Member: Job Title', 'happy-elementor-addons' ),
301
+ 'editor_type' => 'LINE',
302
+ ],
303
+ [
304
+ 'field' => 'bio',
305
+ 'type' => __( 'Team Member: Short Bio', 'happy-elementor-addons' ),
306
+ 'editor_type' => 'AREA',
307
+ ],
308
+ ],
309
+ ],
310
+
311
+ /**
312
+ * News Ticker
313
+ */
314
+ 'news-ticker' => [
315
+ 'fields' => [
316
+ [
317
+ 'field' => 'sticky_title',
318
+ 'type' => __( 'News Ticker: Sticky Title', 'happy-elementor-addons' ),
319
+ 'editor_type' => 'LINE',
320
+ ],
321
+ ],
322
+ ],
323
+
324
+ /**
325
+ * Number
326
+ */
327
+ 'number' => [
328
+ 'fields' => [
329
+ [
330
+ 'field' => 'number_text',
331
+ 'type' => __( 'Number: Text', 'happy-elementor-addons' ),
332
+ 'editor_type' => 'LINE',
333
+ ],
334
+ ],
335
+ ],
336
+
337
+ /**
338
+ * Pricing Table
339
+ */
340
+ 'pricing-table' => [
341
+ 'fields' => [
342
+ [
343
+ 'field' => 'title',
344
+ 'type' => __( 'Pricing Table: Title', 'happy-elementor-addons' ),
345
+ 'editor_type' => 'LINE',
346
+ ],
347
+ [
348
+ 'field' => 'price',
349
+ 'type' => __( 'Pricing Table: Price', 'happy-elementor-addons' ),
350
+ 'editor_type' => 'LINE',
351
+ ],
352
+ [
353
+ 'field' => 'period',
354
+ 'type' => __( 'Pricing Table: Period', 'happy-elementor-addons' ),
355
+ 'editor_type' => 'LINE',
356
+ ],
357
+ [
358
+ 'field' => 'features_title',
359
+ 'type' => __( 'Pricing Table: Features Title', 'happy-elementor-addons' ),
360
+ 'editor_type' => 'LINE',
361
+ ],
362
+ [
363
+ 'field' => 'button_text',
364
+ 'type' => __( 'Pricing Table: Button Text', 'happy-elementor-addons' ),
365
+ 'editor_type' => 'LINE',
366
+ ],
367
+ 'button_link' => [
368
+ 'field' => 'url',
369
+ 'type' => __( 'Pricing Table: Button Link', 'happy-elementor-addons' ),
370
+ 'editor_type' => 'LINK',
371
+ ],
372
+ [
373
+ 'field' => 'badge_text',
374
+ 'type' => __( 'Pricing Table: Badge Text', 'happy-elementor-addons' ),
375
+ 'editor_type' => 'LINE',
376
+ ],
377
+ ],
378
+ 'integration-class' => __NAMESPACE__ . '\\WPML_Pricing_Table',
379
+ ],
380
+
381
+ /**
382
+ * Review
383
+ */
384
+ 'review' => [
385
+ 'fields' => [
386
+ [
387
+ 'field' => 'review',
388
+ 'type' => __( 'Review: Review Text', 'happy-elementor-addons' ),
389
+ 'editor_type' => 'AREA',
390
+ ],
391
+ [
392
+ 'field' => 'title',
393
+ 'type' => __( 'Review: Reviewer Name', 'happy-elementor-addons' ),
394
+ 'editor_type' => 'LINE',
395
+ ],
396
+ [
397
+ 'field' => 'job_title',
398
+ 'type' => __( 'Review: Job Title', 'happy-elementor-addons' ),
399
+ 'editor_type' => 'LINE',
400
+ ],
401
+ ],
402
+ ],
403
+
404
+ /**
405
+ * Skills
406
+ */
407
+ 'skills' => [
408
+ 'fields' => [],
409
+ 'integration-class' => __NAMESPACE__ . '\\WPML_Skills',
410
+ ],
411
+
412
+ /**
413
+ * Slider
414
+ */
415
+ 'slider' => [
416
+ 'fields' => [],
417
+ 'integration-class' => __NAMESPACE__ . '\\WPML_Slider',
418
+ ],
419
+
420
+ /**
421
+ * Social Icons
422
+ */
423
+ 'social-icons' => [
424
+ 'fields' => [],
425
+ 'integration-class' => __NAMESPACE__ . '\\WPML_Social_Icons',
426
+ ],
427
+
428
+ /**
429
+ * Step Flow
430
+ */
431
+ 'step-flow' => [
432
+ 'fields' => [
433
+ [
434
+ 'field' => 'badge',
435
+ 'type' => __( 'Step Flow: Badge Text', 'happy-elementor-addons' ),
436
+ 'editor_type' => 'LINE',
437
+ ],
438
+ [
439
+ 'field' => 'title',
440
+ 'type' => __( 'Step Flow: Title', 'happy-elementor-addons' ),
441
+ 'editor_type' => 'LINE',
442
+ ],
443
+ [
444
+ 'field' => 'description',
445
+ 'type' => __( 'Step Flow: Description', 'happy-elementor-addons' ),
446
+ 'editor_type' => 'AREA',
447
+ ],
448
+ 'link' => [
449
+ 'field' => 'url',
450
+ 'type' => __( 'Step Flow: Link', 'happy-elementor-addons' ),
451
+ 'editor_type' => 'LINK',
452
+ ],
453
+ ],
454
+ ],
455
+
456
+ /**
457
+ * Testimonial
458
+ */
459
+ 'testimonial' => [
460
+ 'fields' => [
461
+ [
462
+ 'field' => 'testimonial',
463
+ 'type' => __( 'Testimonial: Testimonial Text', 'happy-elementor-addons' ),
464
+ 'editor_type' => 'AREA',
465
+ ],
466
+ [
467
+ 'field' => 'name',
468
+ 'type' => __( 'Testimonial: Reviewer Name', 'happy-elementor-addons' ),
469
+ 'editor_type' => 'LINE',
470
+ ],
471
+ [
472
+ 'field' => 'title',
473
+ 'type' => __( 'Testimonial: Job Title', 'happy-elementor-addons' ),
474
+ 'editor_type' => 'LINE',
475
+ ],
476
+ ],
477
+ ],
478
+
479
+ /**
480
+ * Twitter Feed
481
+ */
482
+ 'twitter-feed' => [
483
+ 'fields' => [
484
+ [
485
+ 'field' => 'read_more_text',
486
+ 'type' => __( 'Twitter Feed: Read More Text', 'happy-elementor-addons' ),
487
+ 'editor_type' => 'AREA',
488
+ ],
489
+ [
490
+ 'field' => 'load_more_text',
491
+ 'type' => __( 'Twitter Feed: Load More Text', 'happy-elementor-addons' ),
492
+ 'editor_type' => 'LINE',
493
+ ],
494
+ ],
495
+ ],
496
+ ];
497
+
498
+ foreach ( $widgets_map as $key => $data ) {
499
+ $widget_name = 'ha-'.$key;
500
+
501
+ $entry = [
502
+ 'conditions' => [
503
+ 'widgetType' => $widget_name,
504
+ ],
505
+ 'fields' => $data['fields'],
506
+ ];
507
+
508
+ if ( isset( $data['integration-class'] ) ) {
509
+ $entry['integration-class'] = $data['integration-class'];
510
+ }
511
+
512
+ $widgets[ $widget_name ] = $entry;
513
+ }
514
+
515
+ return $widgets;
516
+ }
517
+ }
518
+
519
+ WPML_Manager::init();
plugin.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Happy Elementor Addons
4
  * Plugin URI: https://happyaddons.com/
5
  * Description: <a href="https://happyaddons.com/">HappyAddons</a> is a collection of slick, powerful widgets that works seamlessly with Elementor page builder. It’s trendy look with detail customization features allows to create extraordinary designs instantly. <a href="https://happyaddons.com/">HappyAddons</a> is free, rapidly growing and comes with great support.
6
- * Version: 2.14.2
7
  * Author: weDevs
8
  * Author URI: https://happyaddons.com/
9
  * License: GPLv2
@@ -34,7 +34,7 @@ Copyright 2019 HappyMonster <http://happymonster.me>
34
 
35
  defined( 'ABSPATH' ) || die();
36
 
37
- define( 'HAPPY_ADDONS_VERSION', '2.14.2' );
38
  define( 'HAPPY_ADDONS__FILE__', __FILE__ );
39
  define( 'HAPPY_ADDONS_DIR_PATH', plugin_dir_path( HAPPY_ADDONS__FILE__ ) );
40
  define( 'HAPPY_ADDONS_DIR_URL', plugin_dir_url( HAPPY_ADDONS__FILE__ ) );
3
  * Plugin Name: Happy Elementor Addons
4
  * Plugin URI: https://happyaddons.com/
5
  * Description: <a href="https://happyaddons.com/">HappyAddons</a> is a collection of slick, powerful widgets that works seamlessly with Elementor page builder. It’s trendy look with detail customization features allows to create extraordinary designs instantly. <a href="https://happyaddons.com/">HappyAddons</a> is free, rapidly growing and comes with great support.
6
+ * Version: 2.14.3
7
  * Author: weDevs
8
  * Author URI: https://happyaddons.com/
9
  * License: GPLv2
34
 
35
  defined( 'ABSPATH' ) || die();
36
 
37
+ define( 'HAPPY_ADDONS_VERSION', '2.14.3' );
38
  define( 'HAPPY_ADDONS__FILE__', __FILE__ );
39
  define( 'HAPPY_ADDONS_DIR_PATH', plugin_dir_path( HAPPY_ADDONS__FILE__ ) );
40
  define( 'HAPPY_ADDONS_DIR_URL', plugin_dir_url( HAPPY_ADDONS__FILE__ ) );
readme.txt CHANGED
@@ -1,6 +1,6 @@
1
  === Happy Addons for Elementor ===
2
  Plugin Name: Happy Addons for Elementor
3
- Version: 2.14.2
4
  Author: weDevs
5
  Author URI: https://happyaddons.com/
6
  Contributors: thehappymonster, happyaddons, hasinhayder, mosaddek73, tareq1988, sourav926, wedevs, iqbalrony, mrokon, obiplabon
@@ -259,6 +259,17 @@ For a more detailed explanation check out the following documentation
259
 
260
  == Changelog ==
261
 
 
 
 
 
 
 
 
 
 
 
 
262
  = 2.14.2 - 20 September 2020 =
263
 
264
  - Fix: JS loading issue for non logged in users
1
  === Happy Addons for Elementor ===
2
  Plugin Name: Happy Addons for Elementor
3
+ Version: 2.14.3
4
  Author: weDevs
5
  Author URI: https://happyaddons.com/
6
  Contributors: thehappymonster, happyaddons, hasinhayder, mosaddek73, tareq1988, sourav926, wedevs, iqbalrony, mrokon, obiplabon
259
 
260
  == Changelog ==
261
 
262
+ = 2.14.3 - 12 October 2020 =
263
+
264
+ - Tweak: Added Calendy pro feature notice
265
+ - Tweak: Added Calendy default username "happyaddons"
266
+ - Tweak: Common cached files are loaded once as internal css
267
+ - Fix: Card widget badge dynamic tag issue
268
+ - Fix: Happy templates popup button auto duplicate issue
269
+ - Fix: Removed duplicate On demand assets cache file enqueue
270
+ - Fix: Removed broken Review widget schema data
271
+ - Fix: Team member widget email envelope icon issue
272
+
273
  = 2.14.2 - 20 September 2020 =
274
 
275
  - Fix: JS loading issue for non logged in users
templates/template-library/templates.php CHANGED
@@ -1,148 +1,148 @@
1
- <?php
2
- /**
3
- * Template library templates
4
- */
5
-
6
- defined( 'ABSPATH' ) || exit;
7
-
8
- ?>
9
- <script type="text/template" id="tmpl-haTemplateLibrary__header-logo">
10
- <span class="haTemplateLibrary__logo-wrap">
11
- <i class="hm hm-happyaddons"></i>
12
- </span>
13
- <span class="haTemplateLibrary__logo-title">{{{ title }}}</span>
14
- </script>
15
-
16
- <script type="text/template" id="tmpl-haTemplateLibrary__header-back">
17
- <i class="eicon-" aria-hidden="true"></i>
18
- <span><?php echo __( 'Back to Library', 'happy-elementor-addons' ); ?></span>
19
- </script>
20
-
21
- <script type="text/template" id="tmpl-haTemplateLibrary__header-menu">
22
- <# _.each( tabs, function( args, tab ) { var activeClass = args.active ? 'elementor-active' : ''; #>
23
- <div class="elementor-component-tab elementor-template-library-menu-item {{activeClass}}" data-tab="{{{ tab }}}">{{{ args.title }}}</div>
24
- <# } ); #>
25
- </script>
26
-
27
- <script type="text/template" id="tmpl-haTemplateLibrary__header-menu-responsive">
28
- <div class="elementor-component-tab haTemplateLibrary__responsive-menu-item elementor-active" data-tab="desktop">
29
- <i class="eicon-device-desktop" aria-hidden="true" title="<?php esc_attr_e( 'Desktop view', 'happy-elementor-addons' ); ?>"></i>
30
- <span class="elementor-screen-only"><?php esc_html_e( 'Desktop view', 'happy-elementor-addons' ); ?></span>
31
- </div>
32
- <div class="elementor-component-tab haTemplateLibrary__responsive-menu-item" data-tab="tab">
33
- <i class="eicon-device-tablet" aria-hidden="true" title="<?php esc_attr_e( 'Tab view', 'happy-elementor-addons' ); ?>"></i>
34
- <span class="elementor-screen-only"><?php esc_html_e( 'Tab view', 'happy-elementor-addons' ); ?></span>
35
- </div>
36
- <div class="elementor-component-tab haTemplateLibrary__responsive-menu-item" data-tab="mobile">
37
- <i class="eicon-device-mobile" aria-hidden="true" title="<?php esc_attr_e( 'Mobile view', 'happy-elementor-addons' ); ?>"></i>
38
- <span class="elementor-screen-only"><?php esc_html_e( 'Mobile view', 'happy-elementor-addons' ); ?></span>
39
- </div>
40
- </script>
41
-
42
- <script type="text/template" id="tmpl-haTemplateLibrary__header-actions">
43
- <div id="haTemplateLibrary__header-sync" class="elementor-templates-modal__header__item">
44
- <i class="eicon-sync" aria-hidden="true" title="<?php esc_attr_e( 'Sync Library', 'happy-elementor-addons' ); ?>"></i>
45
- <span class="elementor-screen-only"><?php esc_html_e( 'Sync Library', 'happy-elementor-addons' ); ?></span>
46
- </div>
47
- </script>
48
-
49
- <script type="text/template" id="tmpl-haTemplateLibrary__preview">
50
- <iframe></iframe>
51
- </script>
52
-
53
- <script type="text/template" id="tmpl-haTemplateLibrary__header-insert">
54
- <div id="elementor-template-library-header-preview-insert-wrapper" class="elementor-templates-modal__header__item">
55
- {{{ ha.library.getModal().getTemplateActionButton( obj ) }}}
56
- </div>
57
- </script>
58
-
59
- <script type="text/template" id="tmpl-haTemplateLibrary__insert-button">
60
- <a class="elementor-template-library-template-action elementor-button haTemplateLibrary__insert-button">
61
- <i class="eicon-file-download" aria-hidden="true"></i>
62
- <span class="elementor-button-title"><?php esc_html_e( 'Insert', 'happy-elementor-addons' ); ?></span>
63
- </a>
64
- </script>
65
-
66
- <script type="text/template" id="tmpl-haTemplateLibrary__pro-button">
67
- <a class="elementor-template-library-template-action elementor-button haTemplateLibrary__pro-button" href="https://happyaddons.com/pricing/" target="_blank">
68
- <i class="eicon-external-link-square" aria-hidden="true"></i>
69
- <span class="elementor-button-title"><?php esc_html_e( 'Get Pro', 'happy-elementor-addons' ); ?></span>
70
- </a>
71
- </script>
72
-
73
- <script type="text/template" id="tmpl-haTemplateLibrary__loading">
74
- <div class="elementor-loader-wrapper">
75
- <div class="elementor-loader">
76
- <div class="elementor-loader-boxes">
77
- <div class="elementor-loader-box"></div>
78
- <div class="elementor-loader-box"></div>
79
- <div class="elementor-loader-box"></div>
80
- <div class="elementor-loader-box"></div>
81
- </div>
82
- </div>
83
- <div class="elementor-loading-title"><?php esc_html_e( 'Loading', 'happy-elementor-addons' ); ?></div>
84
- </div>
85
- </script>
86
-
87
- <script type="text/template" id="tmpl-haTemplateLibrary__templates">
88
- <div id="haTemplateLibrary__toolbar">
89
- <div id="haTemplateLibrary__toolbar-filter" class="haTemplateLibrary__toolbar-filter">
90
- <# if ( ha.library.getTags() ) { var selectedTag = ha.library.getFilter( 'tags' ); #>
91
- <# if ( selectedTag ) { #>
92
- <span class="haTemplateLibrary__filter-btn">{{{ ha.library.getTags()[selectedTag] }}} <i class="eicon-caret-right"></i></span>
93
- <# } else { #>
94
- <span class="haTemplateLibrary__filter-btn"><?php esc_html_e( 'Filter', 'happy-elementor-addons' ); ?> <i class="eicon-caret-right"></i></span>
95
- <# } #>
96
- <ul id="haTemplateLibrary__filter-tags" class="haTemplateLibrary__filter-tags">
97
- <li data-tag="">All</li>
98
- <# _.each( ha.library.getTags(), function( name, slug ) {
99
- var selected = selectedTag === slug ? 'active' : '';
100
- #>
101
- <li data-tag="{{ slug }}" class="{{ selected }}">{{{ name }}}</li>
102
- <# } ); #>
103
- </ul>
104
- <# } #>
105
- </div>
106
-
107
- <div id="haTemplateLibrary__toolbar-search">
108
- <label for="haTemplateLibrary__search" class="elementor-screen-only"><?php esc_html_e( 'Search Templates:', 'happy-elementor-addons' ); ?></label>
109
- <input id="haTemplateLibrary__search" placeholder="<?php esc_attr_e( 'Search', 'happy-elementor-addons' ); ?>">
110
- <i class="eicon-search"></i>
111
- </div>
112
- </div>
113
-
114
- <div class="haTemplateLibrary__templates-window">
115
- <div id="haTemplateLibrary__templates-list"></div>
116
- </div>
117
- </script>
118
-
119
- <script type="text/template" id="tmpl-haTemplateLibrary__template">
120
- <div class="haTemplateLibrary__template-body" id="haTemplate-{{ template_id }}">
121
- <div class="haTemplateLibrary__template-preview">
122
- <i class="eicon-zoom-in-bold" aria-hidden="true"></i>
123
- </div>
124
- <img class="haTemplateLibrary__template-thumbnail" src="{{ thumbnail }}">
125
- <# if ( obj.isPro ) { #>
126
- <span class="haTemplateLibrary__template-badge"><?php esc_html_e( 'Pro', 'happy-elementor-addons' ); ?></span>
127
- <# } #>
128
- </div>
129
- <div class="haTemplateLibrary__template-footer">
130
- {{{ ha.library.getModal().getTemplateActionButton( obj ) }}}
131
- <a href="#" class="elementor-button haTemplateLibrary__preview-button">
132
- <i class="eicon-device-desktop" aria-hidden="true"></i>
133
- <?php esc_html_e( 'Preview', 'happy-elementor-addons' ); ?>
134
- </a>
135
- </div>
136
- </script>
137
-
138
- <script type="text/template" id="tmpl-haTemplateLibrary__empty">
139
- <div class="elementor-template-library-blank-icon">
140
- <img src="<?php echo ELEMENTOR_ASSETS_URL . 'images/no-search-results.svg'; ?>" class="elementor-template-library-no-results" />
141
- </div>
142
- <div class="elementor-template-library-blank-title"></div>
143
- <div class="elementor-template-library-blank-message"></div>
144
- <div class="elementor-template-library-blank-footer">
145
- <?php esc_html_e( 'Want to learn more about the Happy Library?', 'happy-elementor-addons' ); ?>
146
- <a class="elementor-template-library-blank-footer-link" href="https://happyaddons.com/docs/happy-addons-for-elementor/happy-features/happy-templates/" target="_blank"><?php echo __( 'Click here', 'happy-elementor-addons' ); ?></a>
147
- </div>
148
- </script>
1
+ <?php
2
+ /**
3
+ * Template library templates
4
+ */
5
+
6
+ defined( 'ABSPATH' ) || exit;
7
+
8
+ ?>
9
+ <script type="text/template" id="tmpl-haTemplateLibrary__header-logo">
10
+ <span class="haTemplateLibrary__logo-wrap">
11
+ <i class="hm hm-happyaddons"></i>
12
+ </span>
13
+ <span class="haTemplateLibrary__logo-title">{{{ title }}}</span>
14
+ </script>
15
+
16
+ <script type="text/template" id="tmpl-haTemplateLibrary__header-back">
17
+ <i class="eicon-" aria-hidden="true"></i>
18
+ <span><?php echo __( 'Back to Library', 'happy-elementor-addons' ); ?></span>
19
+ </script>
20
+
21
+ <script type="text/template" id="tmpl-haTemplateLibrary__header-menu">
22
+ <# _.each( tabs, function( args, tab ) { var activeClass = args.active ? 'elementor-active' : ''; #>
23
+ <div class="elementor-component-tab elementor-template-library-menu-item {{activeClass}}" data-tab="{{{ tab }}}">{{{ args.title }}}</div>
24
+ <# } ); #>
25
+ </script>
26
+
27
+ <script type="text/template" id="tmpl-haTemplateLibrary__header-menu-responsive">
28
+ <div class="elementor-component-tab haTemplateLibrary__responsive-menu-item elementor-active" data-tab="desktop">
29
+ <i class="eicon-device-desktop" aria-hidden="true" title="<?php esc_attr_e( 'Desktop view', 'happy-elementor-addons' ); ?>"></i>
30
+ <span class="elementor-screen-only"><?php esc_html_e( 'Desktop view', 'happy-elementor-addons' ); ?></span>
31
+ </div>
32
+ <div class="elementor-component-tab haTemplateLibrary__responsive-menu-item" data-tab="tab">
33
+ <i class="eicon-device-tablet" aria-hidden="true" title="<?php esc_attr_e( 'Tab view', 'happy-elementor-addons' ); ?>"></i>
34
+ <span class="elementor-screen-only"><?php esc_html_e( 'Tab view', 'happy-elementor-addons' ); ?></span>
35
+ </div>
36
+ <div class="elementor-component-tab haTemplateLibrary__responsive-menu-item" data-tab="mobile">
37
+ <i class="eicon-device-mobile" aria-hidden="true" title="<?php esc_attr_e( 'Mobile view', 'happy-elementor-addons' ); ?>"></i>
38
+ <span class="elementor-screen-only"><?php esc_html_e( 'Mobile view', 'happy-elementor-addons' ); ?></span>
39
+ </div>
40
+ </script>
41
+
42
+ <script type="text/template" id="tmpl-haTemplateLibrary__header-actions">
43
+ <div id="haTemplateLibrary__header-sync" class="elementor-templates-modal__header__item">
44
+ <i class="eicon-sync" aria-hidden="true" title="<?php esc_attr_e( 'Sync Library', 'happy-elementor-addons' ); ?>"></i>
45
+ <span class="elementor-screen-only"><?php esc_html_e( 'Sync Library', 'happy-elementor-addons' ); ?></span>
46
+ </div>
47
+ </script>
48
+
49
+ <script type="text/template" id="tmpl-haTemplateLibrary__preview">
50
+ <iframe></iframe>
51
+ </script>
52
+
53
+ <script type="text/template" id="tmpl-haTemplateLibrary__header-insert">
54
+ <div id="elementor-template-library-header-preview-insert-wrapper" class="elementor-templates-modal__header__item">
55
+ {{{ ha.library.getModal().getTemplateActionButton( obj ) }}}
56
+ </div>
57
+ </script>
58
+
59
+ <script type="text/template" id="tmpl-haTemplateLibrary__insert-button">
60
+ <a class="elementor-template-library-template-action elementor-button haTemplateLibrary__insert-button">
61
+ <i class="eicon-file-download" aria-hidden="true"></i>
62
+ <span class="elementor-button-title"><?php esc_html_e( 'Insert', 'happy-elementor-addons' ); ?></span>
63
+ </a>
64
+ </script>
65
+
66
+ <script type="text/template" id="tmpl-haTemplateLibrary__pro-button">
67
+ <a class="elementor-template-library-template-action elementor-button haTemplateLibrary__pro-button" href="https://happyaddons.com/pricing/" target="_blank">
68
+ <i class="eicon-external-link-square" aria-hidden="true"></i>
69
+ <span class="elementor-button-title"><?php esc_html_e( 'Get Pro', 'happy-elementor-addons' ); ?></span>
70
+ </a>
71
+ </script>
72
+
73
+ <script type="text/template" id="tmpl-haTemplateLibrary__loading">
74
+ <div class="elementor-loader-wrapper">
75
+ <div class="elementor-loader">
76
+ <div class="elementor-loader-boxes">
77
+ <div class="elementor-loader-box"></div>
78
+ <div class="elementor-loader-box"></div>
79
+ <div class="elementor-loader-box"></div>
80
+ <div class="elementor-loader-box"></div>
81
+ </div>
82
+ </div>
83
+ <div class="elementor-loading-title"><?php esc_html_e( 'Loading', 'happy-elementor-addons' ); ?></div>
84
+ </div>
85
+ </script>
86
+
87
+ <script type="text/template" id="tmpl-haTemplateLibrary__templates">
88
+ <div id="haTemplateLibrary__toolbar">
89
+ <div id="haTemplateLibrary__toolbar-filter" class="haTemplateLibrary__toolbar-filter">
90
+ <# if ( ha.library.getTags() ) { var selectedTag = ha.library.getFilter( 'tags' ); #>
91
+ <# if ( selectedTag ) { #>
92
+ <span class="haTemplateLibrary__filter-btn">{{{ ha.library.getTags()[selectedTag] }}} <i class="eicon-caret-right"></i></span>
93
+ <# } else { #>
94
+ <span class="haTemplateLibrary__filter-btn"><?php esc_html_e( 'Filter', 'happy-elementor-addons' ); ?> <i class="eicon-caret-right"></i></span>
95
+ <# } #>
96
+ <ul id="haTemplateLibrary__filter-tags" class="haTemplateLibrary__filter-tags">
97
+ <li data-tag="">All</li>
98
+ <# _.each( ha.library.getTags(), function( name, slug ) {
99
+ var selected = selectedTag === slug ? 'active' : '';
100
+ #>
101
+ <li data-tag="{{ slug }}" class="{{ selected }}">{{{ name }}}</li>
102
+ <# } ); #>
103
+ </ul>
104
+ <# } #>
105
+ </div>
106
+
107
+ <div id="haTemplateLibrary__toolbar-search">
108
+ <label for="haTemplateLibrary__search" class="elementor-screen-only"><?php esc_html_e( 'Search Templates:', 'happy-elementor-addons' ); ?></label>
109
+ <input id="haTemplateLibrary__search" placeholder="<?php esc_attr_e( 'Search', 'happy-elementor-addons' ); ?>">
110
+ <i class="eicon-search"></i>
111
+ </div>
112
+ </div>
113
+
114
+ <div class="haTemplateLibrary__templates-window">
115
+ <div id="haTemplateLibrary__templates-list"></div>
116
+ </div>
117
+ </script>
118
+
119
+ <script type="text/template" id="tmpl-haTemplateLibrary__template">
120
+ <div class="haTemplateLibrary__template-body" id="haTemplate-{{ template_id }}">
121
+ <div class="haTemplateLibrary__template-preview">
122
+ <i class="eicon-zoom-in-bold" aria-hidden="true"></i>
123
+ </div>
124
+ <img class="haTemplateLibrary__template-thumbnail" src="{{ thumbnail }}">
125
+ <# if ( obj.isPro ) { #>
126
+ <span class="haTemplateLibrary__template-badge"><?php esc_html_e( 'Pro', 'happy-elementor-addons' ); ?></span>
127
+ <# } #>
128
+ </div>
129
+ <div class="haTemplateLibrary__template-footer">
130
+ {{{ ha.library.getModal().getTemplateActionButton( obj ) }}}
131
+ <a href="#" class="elementor-button haTemplateLibrary__preview-button">
132
+ <i class="eicon-device-desktop" aria-hidden="true"></i>
133
+ <?php esc_html_e( 'Preview', 'happy-elementor-addons' ); ?>
134
+ </a>
135
+ </div>
136
+ </script>
137
+
138
+ <script type="text/template" id="tmpl-haTemplateLibrary__empty">
139
+ <div class="elementor-template-library-blank-icon">
140
+ <img src="<?php echo ELEMENTOR_ASSETS_URL . 'images/no-search-results.svg'; ?>" class="elementor-template-library-no-results" />
141
+ </div>
142
+ <div class="elementor-template-library-blank-title"></div>
143
+ <div class="elementor-template-library-blank-message"></div>
144
+ <div class="elementor-template-library-blank-footer">
145
+ <?php esc_html_e( 'Want to learn more about the Happy Library?', 'happy-elementor-addons' ); ?>
146
+ <a class="elementor-template-library-blank-footer-link" href="https://happyaddons.com/docs/happy-addons-for-elementor/happy-features/happy-templates/" target="_blank"><?php echo __( 'Click here', 'happy-elementor-addons' ); ?></a>
147
+ </div>
148
+ </script>
vendor/appsero/src/Client.php CHANGED
@@ -1,210 +1,238 @@
1
- <?php
2
- namespace Happy_Addons\Appsero;
3
-
4
- /**
5
- * Appsero Client
6
- *
7
- * This class is necessary to set project data
8
- */
9
- class Client {
10
-
11
- /**
12
- * The client version
13
- *
14
- * @var string
15
- */
16
- public $version = '1.1.9';
17
-
18
- /**
19
- * Hash identifier of the plugin
20
- *
21
- * @var string
22
- */
23
- public $hash;
24
-
25
- /**
26
- * Name of the plugin
27
- *
28
- * @var string
29
- */
30
- public $name;
31
-
32
- /**
33
- * The plugin/theme file path
34
- * @example .../wp-content/plugins/test-slug/test-slug.php
35
- *
36
- * @var string
37
- */
38
- public $file;
39
-
40
- /**
41
- * Main plugin file
42
- * @example test-slug/test-slug.php
43
- *
44
- * @var string
45
- */
46
- public $basename;
47
-
48
- /**
49
- * Slug of the plugin
50
- * @example test-slug
51
- *
52
- * @var string
53
- */
54
- public $slug;
55
-
56
- /**
57
- * The project version
58
- *
59
- * @var string
60
- */
61
- public $project_version;
62
-
63
- /**
64
- * The project type
65
- *
66
- * @var string
67
- */
68
- public $type;
69
-
70
- /**
71
- * textdomain
72
- *
73
- * @var string
74
- */
75
- public $textdomain;
76
-
77
- /**
78
- * Initialize the class
79
- *
80
- * @param string $hash hash of the plugin
81
- * @param string $name readable name of the plugin
82
- * @param string $file main plugin file path
83
- */
84
- public function __construct( $hash, $name, $file ) {
85
- $this->hash = $hash;
86
- $this->name = $name;
87
- $this->file = $file;
88
-
89
- $this->set_basename_and_slug();
90
- }
91
-
92
- /**
93
- * Initialize insights class
94
- *
95
- * @return Happy_Addons\Appsero\Insights
96
- */
97
- public function insights() {
98
-
99
- if ( ! class_exists( __NAMESPACE__ . '\Insights') ) {
100
- require_once __DIR__ . '/Insights.php';
101
- }
102
-
103
- return new Insights( $this );
104
- }
105
-
106
- /**
107
- * Initialize plugin/theme updater
108
- *
109
- * @return Happy_Addons\Appsero\Updater
110
- */
111
- public function updater() {
112
-
113
- if ( ! class_exists( __NAMESPACE__ . '\Updater') ) {
114
- require_once __DIR__ . '/Updater.php';
115
- }
116
-
117
- return new Updater( $this );
118
- }
119
-
120
- /**
121
- * Initialize license checker
122
- *
123
- * @return Happy_Addons\Appsero\License
124
- */
125
- public function license() {
126
-
127
- if ( ! class_exists( __NAMESPACE__ . '\License') ) {
128
- require_once __DIR__ . '/License.php';
129
- }
130
-
131
- return new License( $this );
132
- }
133
-
134
- /**
135
- * API Endpoint
136
- *
137
- * @return string
138
- */
139
- public function endpoint() {
140
- $endpoint = apply_filters( 'appsero_endpoint', 'https://api.appsero.com' );
141
-
142
- return trailingslashit( $endpoint );
143
- }
144
-
145
- /**
146
- * Set project basename, slug and version
147
- *
148
- * @return void
149
- */
150
- protected function set_basename_and_slug() {
151
-
152
- if ( strpos( $this->file, WP_CONTENT_DIR . '/themes/' ) === false ) {
153
-
154
- $this->basename = plugin_basename( $this->file );
155
-
156
- list( $this->slug, $mainfile) = explode( '/', $this->basename );
157
-
158
- require_once ABSPATH . 'wp-admin/includes/plugin.php';
159
-
160
- $plugin_data = get_plugin_data( $this->file );
161
-
162
- $this->project_version = $plugin_data['Version'];
163
- $this->type = 'plugin';
164
- $this->textdomain = $this->slug;
165
-
166
- } else {
167
-
168
- $this->basename = str_replace( WP_CONTENT_DIR . '/themes/', '', $this->file );
169
-
170
- list( $this->slug, $mainfile) = explode( '/', $this->basename );
171
-
172
- $theme = wp_get_theme( $this->slug );
173
-
174
- $this->project_version = $theme->version;
175
- $this->type = 'theme';
176
-
177
- }
178
- }
179
-
180
- /**
181
- * Send request to remote endpoint
182
- *
183
- * @param array $params
184
- * @param string $route
185
- *
186
- * @return array|WP_Error Array of results including HTTP headers or WP_Error if the request failed.
187
- */
188
- public function send_request( $params, $route, $blocking = false ) {
189
- $url = $this->endpoint() . $route;
190
-
191
- $headers = array(
192
- 'user-agent' => 'Appsero/' . md5( esc_url( home_url() ) ) . ';',
193
- 'Accept' => 'application/json',
194
- );
195
-
196
- $response = wp_remote_post( $url, array(
197
- 'method' => 'POST',
198
- 'timeout' => 30,
199
- 'redirection' => 5,
200
- 'httpversion' => '1.0',
201
- 'blocking' => $blocking,
202
- 'headers' => $headers,
203
- 'body' => array_merge( $params, array( 'client' => $this->version ) ),
204
- 'cookies' => array()
205
- ) );
206
-
207
- return $response;
208
- }
209
-
210
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Happy_Addons\Appsero;
3
+
4
+ /**
5
+ * Appsero Client
6
+ *
7
+ * This class is necessary to set project data
8
+ */
9
+ class Client {
10
+
11
+ /**
12
+ * The client version
13
+ *
14
+ * @var string
15
+ */
16
+ public $version = '1.2.0';
17
+
18
+ /**
19
+ * Hash identifier of the plugin
20
+ *
21
+ * @var string
22
+ */
23
+ public $hash;
24
+
25
+ /**
26
+ * Name of the plugin
27
+ *
28
+ * @var string
29
+ */
30
+ public $name;
31
+
32
+ /**
33
+ * The plugin/theme file path
34
+ * @example .../wp-content/plugins/test-slug/test-slug.php
35
+ *
36
+ * @var string
37
+ */
38
+ public $file;
39
+
40
+ /**
41
+ * Main plugin file
42
+ * @example test-slug/test-slug.php
43
+ *
44
+ * @var string
45
+ */
46
+ public $basename;
47
+
48
+ /**
49
+ * Slug of the plugin
50
+ * @example test-slug
51
+ *
52
+ * @var string
53
+ */
54
+ public $slug;
55
+
56
+ /**
57
+ * The project version
58
+ *
59
+ * @var string
60
+ */
61
+ public $project_version;
62
+
63
+ /**
64
+ * The project type
65
+ *
66
+ * @var string
67
+ */
68
+ public $type;
69
+
70
+ /**
71
+ * textdomain
72
+ *
73
+ * @var string
74
+ */
75
+ public $textdomain;
76
+
77
+ /**
78
+ * Initialize the class
79
+ *
80
+ * @param string $hash hash of the plugin
81
+ * @param string $name readable name of the plugin
82
+ * @param string $file main plugin file path
83
+ */
84
+ public function __construct( $hash, $name, $file ) {
85
+ $this->hash = $hash;
86
+ $this->name = $name;
87
+ $this->file = $file;
88
+
89
+ $this->set_basename_and_slug();
90
+ }
91
+
92
+ /**
93
+ * Initialize insights class
94
+ *
95
+ * @param Happy_Addons\Appsero\Insights
96
+ */
97
+ public function insights() {
98
+
99
+ if ( ! class_exists( __NAMESPACE__ . '\Insights') ) {
100
+ require_once __DIR__ . '/Insights.php';
101
+ }
102
+
103
+ return new Insights( $this );
104
+ }
105
+
106
+ /**
107
+ * Initialize plugin/theme updater
108
+ *
109
+ * @param Happy_Addons\Appsero\Updater
110
+ */
111
+ public function updater() {
112
+
113
+ if ( ! class_exists( __NAMESPACE__ . '\Updater') ) {
114
+ require_once __DIR__ . '/Updater.php';
115
+ }
116
+
117
+ return new Updater( $this );
118
+ }
119
+
120
+ /**
121
+ * Initialize license checker
122
+ *
123
+ * @param Happy_Addons\Appsero\License
124
+ */
125
+ public function license() {
126
+
127
+ if ( ! class_exists( __NAMESPACE__ . '\License') ) {
128
+ require_once __DIR__ . '/License.php';
129
+ }
130
+
131
+ return new License( $this );
132
+ }
133
+
134
+ /**
135
+ * API Endpoint
136
+ *
137
+ * @return string
138
+ */
139
+ public function endpoint() {
140
+ $endpoint = apply_filters( 'appsero_endpoint', 'https://api.appsero.com' );
141
+
142
+ return trailingslashit( $endpoint );
143
+ }
144
+
145
+ /**
146
+ * Set project basename, slug and version
147
+ *
148
+ * @return void
149
+ */
150
+ protected function set_basename_and_slug() {
151
+
152
+ if ( strpos( $this->file, WP_CONTENT_DIR . '/themes/' ) === false ) {
153
+ $this->basename = plugin_basename( $this->file );
154
+
155
+ list( $this->slug, $mainfile) = explode( '/', $this->basename );
156
+
157
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
158
+
159
+ $plugin_data = get_plugin_data( $this->file );
160
+
161
+ $this->project_version = $plugin_data['Version'];
162
+ $this->type = 'plugin';
163
+ } else {
164
+ $this->basename = str_replace( WP_CONTENT_DIR . '/themes/', '', $this->file );
165
+
166
+ list( $this->slug, $mainfile) = explode( '/', $this->basename );
167
+
168
+ $theme = wp_get_theme( $this->slug );
169
+
170
+ $this->project_version = $theme->version;
171
+ $this->type = 'theme';
172
+ }
173
+
174
+ $this->textdomain = $this->slug;
175
+ }
176
+
177
+ /**
178
+ * Send request to remote endpoint
179
+ *
180
+ * @param array $params
181
+ * @param string $route
182
+ *
183
+ * @return array|WP_Error Array of results including HTTP headers or WP_Error if the request failed.
184
+ */
185
+ public function send_request( $params, $route, $blocking = false ) {
186
+ $url = $this->endpoint() . $route;
187
+
188
+ $headers = array(
189
+ 'user-agent' => 'Appsero/' . md5( esc_url( home_url() ) ) . ';',
190
+ 'Accept' => 'application/json',
191
+ );
192
+
193
+ $response = wp_remote_post( $url, array(
194
+ 'method' => 'POST',
195
+ 'timeout' => 30,
196
+ 'redirection' => 5,
197
+ 'httpversion' => '1.0',
198
+ 'blocking' => $blocking,
199
+ 'headers' => $headers,
200
+ 'body' => array_merge( $params, array( 'client' => $this->version ) ),
201
+ 'cookies' => array()
202
+ ) );
203
+
204
+ return $response;
205
+ }
206
+
207
+ /**
208
+ * Check if the current server is localhost
209
+ *
210
+ * @return boolean
211
+ */
212
+ public function is_local_server() {
213
+ $is_local = in_array( $_SERVER['REMOTE_ADDR'], array( '127.0.0.1', '::1' ) );
214
+
215
+ return apply_filters( 'appsero_is_local', $is_local );
216
+ }
217
+
218
+ /**
219
+ * Translate function _e()
220
+ */
221
+ public function _etrans( $text ) {
222
+ call_user_func( '_e', $text, $this->textdomain );
223
+ }
224
+
225
+ /**
226
+ * Translate function __()
227
+ */
228
+ public function __trans( $text ) {
229
+ return call_user_func( '__', $text, $this->textdomain );
230
+ }
231
+
232
+ /**
233
+ * Set project textdomain
234
+ */
235
+ public function set_textdomain( $textdomain ) {
236
+ $this->textdomain = $textdomain;
237
+ }
238
+ }
vendor/appsero/src/Insights.php CHANGED
@@ -1,962 +1,1128 @@
1
- <?php
2
- namespace Happy_Addons\Appsero;
3
-
4
- /**
5
- * Appsero Insights
6
- *
7
- * This is a tracker class to track plugin usage based on if the customer has opted in.
8
- * No personal information is being tracked by this class, only general settings, active plugins, environment details
9
- * and admin email.
10
- */
11
- class Insights {
12
-
13
- /**
14
- * The notice text
15
- *
16
- * @var string
17
- */
18
- public $notice;
19
-
20
- /**
21
- * Wheather to the notice or not
22
- *
23
- * @var boolean
24
- */
25
- protected $show_notice = true;
26
-
27
- /**
28
- * If extra data needs to be sent
29
- *
30
- * @var array
31
- */
32
- protected $extra_data = array();
33
-
34
- /**
35
- * AppSero\Client
36
- *
37
- * @var object
38
- */
39
- protected $client;
40
-
41
- /**
42
- * Initialize the class
43
- *
44
- * @param Happy_Addons\Appsero\Client
45
- */
46
- public function __construct( $client, $name = null, $file = null ) {
47
-
48
- if ( is_string( $client ) && ! empty( $name ) && ! empty( $file ) ) {
49
- $client = new Client( $client, $name, $file );
50
- }
51
-
52
- if ( is_object( $client ) && is_a( $client, 'Happy_Addons\Appsero\Client' ) ) {
53
- $this->client = $client;
54
- }
55
- }
56
-
57
- /**
58
- * Don't show the notice
59
- *
60
- * @return \self
61
- */
62
- public function hide_notice() {
63
- $this->show_notice = false;
64
-
65
- return $this;
66
- }
67
-
68
- /**
69
- * Add extra data if needed
70
- *
71
- * @param array $data
72
- *
73
- * @return \self
74
- */
75
- public function add_extra( $data = array() ) {
76
- $this->extra_data = $data;
77
-
78
- return $this;
79
- }
80
-
81
- /**
82
- * Set custom notice text
83
- *
84
- * @param string $text
85
- *
86
- * @return \self
87
- */
88
- public function notice( $text ) {
89
- $this->notice = $text;
90
-
91
- return $this;
92
- }
93
-
94
- /**
95
- * Initialize insights
96
- *
97
- * @return void
98
- */
99
- public function init() {
100
- if ( $this->client->type == 'plugin' ) {
101
- $this->init_plugin();
102
- } else if ( $this->client->type == 'theme' ) {
103
- $this->init_theme();
104
- }
105
- }
106
-
107
- /**
108
- * Initialize theme hooks
109
- *
110
- * @return void
111
- */
112
- public function init_theme() {
113
- $this->init_common();
114
-
115
- add_action( 'switch_theme', array( $this, 'deactivation_cleanup' ) );
116
- add_action( 'switch_theme', array( $this, 'theme_deactivated' ), 12, 3 );
117
- }
118
-
119
- /**
120
- * Initialize plugin hooks
121
- *
122
- * @return void
123
- */
124
- public function init_plugin() {
125
- // plugin deactivate popup
126
- if ( ! $this->is_local_server() ) {
127
- add_filter( 'plugin_action_links_' . $this->client->basename, array( $this, 'plugin_action_links' ) );
128
- add_action( 'admin_footer', array( $this, 'deactivate_scripts' ) );
129
- }
130
-
131
- $this->init_common();
132
-
133
- register_activation_hook( $this->client->file, array( $this, 'activate_plugin' ) );
134
- register_deactivation_hook( $this->client->file, array( $this, 'deactivation_cleanup' ) );
135
- }
136
-
137
- /**
138
- * Initialize common hooks
139
- *
140
- * @return void
141
- */
142
- protected function init_common() {
143
-
144
- if ( $this->show_notice ) {
145
- // tracking notice
146
- add_action( 'admin_notices', array( $this, 'admin_notice' ) );
147
- }
148
-
149
- add_action( 'admin_init', array( $this, 'handle_optin_optout' ) );
150
-
151
- // uninstall reason
152
- add_action( 'wp_ajax_' . $this->client->slug . '_submit-uninstall-reason', array( $this, 'uninstall_reason_submission' ) );
153
-
154
- // cron events
155
- add_filter( 'cron_schedules', array( $this, 'add_weekly_schedule' ) );
156
- add_action( $this->client->slug . '_tracker_send_event', array( $this, 'send_tracking_data' ) );
157
- // add_action( 'admin_init', array( $this, 'send_tracking_data' ) ); // test
158
- }
159
-
160
- /**
161
- * Send tracking data to AppSero server
162
- *
163
- * @param boolean $override
164
- *
165
- * @return void
166
- */
167
- public function send_tracking_data( $override = false ) {
168
- // skip on AJAX Requests
169
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
170
- return;
171
- }
172
-
173
- if ( ! $this->tracking_allowed() && ! $override ) {
174
- return;
175
- }
176
-
177
- // Send a maximum of once per week
178
- $last_send = $this->get_last_send();
179
-
180
- if ( $last_send && $last_send > strtotime( '-1 week' ) ) {
181
- return;
182
- }
183
-
184
- $response = $this->client->send_request( $this->get_tracking_data(), 'track' );
185
-
186
- update_option( $this->client->slug . '_tracking_last_send', time() );
187
- }
188
-
189
- /**
190
- * Get the tracking data points
191
- *
192
- * @return array
193
- */
194
- protected function get_tracking_data() {
195
- $all_plugins = $this->get_all_plugins();
196
-
197
- $users = get_users( array(
198
- 'role' => 'administrator',
199
- 'orderby' => 'ID',
200
- 'order' => 'ASC',
201
- 'number' => 1,
202
- 'paged' => 1,
203
- ) );
204
-
205
- $admin_user = ( is_array( $users ) && ! empty( $users ) ) ? $users[0] : false;
206
- $first_name = $last_name = '';
207
-
208
- if ( $admin_user ) {
209
- $first_name = $admin_user->first_name ? $admin_user->first_name : $admin_user->display_name;
210
- $last_name = $admin_user->last_name;
211
- }
212
-
213
- $data = array(
214
- 'version' => $this->client->project_version,
215
- 'url' => esc_url( home_url() ),
216
- 'site' => $this->get_site_name(),
217
- 'admin_email' => get_option( 'admin_email' ),
218
- 'first_name' => $first_name,
219
- 'last_name' => $last_name,
220
- 'hash' => $this->client->hash,
221
- 'server' => $this->get_server_info(),
222
- 'wp' => $this->get_wp_info(),
223
- 'users' => $this->get_user_counts(),
224
- 'active_plugins' => count( $all_plugins['active_plugins'] ),
225
- 'inactive_plugins' => count( $all_plugins['inactive_plugins'] ),
226
- 'ip_address' => $this->get_user_ip_address(),
227
- 'theme' => get_stylesheet(),
228
- 'version' => $this->client->project_version,
229
- );
230
-
231
- // Add metadata
232
- if ( $extra = $this->get_extra_data() ) {
233
- $data['extra'] = $extra;
234
- }
235
-
236
- return apply_filters( $this->client->slug . '_tracker_data', $data );
237
- }
238
-
239
- /**
240
- * If a child class wants to send extra data
241
- *
242
- * @return mixed
243
- */
244
- protected function get_extra_data() {
245
- if ( is_callable( $this->extra_data ) ) {
246
- return call_user_func( $this->extra_data );
247
- }
248
-
249
- if ( is_array( $this->extra_data ) ) {
250
- return $this->extra_data;
251
- }
252
-
253
- return array();
254
- }
255
-
256
- /**
257
- * Explain the user which data we collect
258
- *
259
- * @return string
260
- */
261
- protected function data_we_collect() {
262
- $data = array(
263
- 'Server environment details (php, mysql, server, WordPress versions)',
264
- 'Number of users in your site',
265
- 'Site language',
266
- 'Number of active and inactive plugins',
267
- 'Site name and url',
268
- 'Your name and email address',
269
- );
270
-
271
- return $data;
272
- }
273
-
274
- /**
275
- * Check if the user has opted into tracking
276
- *
277
- * @return bool
278
- */
279
- public function tracking_allowed() {
280
- $allow_tracking = get_option( $this->client->slug . '_allow_tracking', 'no' );
281
-
282
- return $allow_tracking == 'yes';
283
- }
284
-
285
- /**
286
- * Get the last time a tracking was sent
287
- *
288
- * @return false|string
289
- */
290
- private function get_last_send() {
291
- return get_option( $this->client->slug . '_tracking_last_send', false );
292
- }
293
-
294
- /**
295
- * Check if the notice has been dismissed or enabled
296
- *
297
- * @return boolean
298
- */
299
- public function notice_dismissed() {
300
- $hide_notice = get_option( $this->client->slug . '_tracking_notice', null );
301
-
302
- if ( 'hide' == $hide_notice ) {
303
- return true;
304
- }
305
-
306
- return false;
307
- }
308
-
309
- /**
310
- * Check if the current server is localhost
311
- *
312
- * @return boolean
313
- */
314
- private function is_local_server() {
315
- return false;
316
-
317
- $is_local = in_array( $_SERVER['REMOTE_ADDR'], array( '127.0.0.1', '::1' ) );
318
-
319
- return apply_filters( 'appsero_is_local', $is_local );
320
- }
321
-
322
- /**
323
- * Schedule the event weekly
324
- *
325
- * @return void
326
- */
327
- private function schedule_event() {
328
- $hook_name = $this->client->slug . '_tracker_send_event';
329
-
330
- if ( ! wp_next_scheduled( $hook_name ) ) {
331
- wp_schedule_event( time(), 'weekly', $hook_name );
332
- }
333
- }
334
-
335
- /**
336
- * Clear any scheduled hook
337
- *
338
- * @return void
339
- */
340
- private function clear_schedule_event() {
341
- wp_clear_scheduled_hook( $this->client->slug . '_tracker_send_event' );
342
- }
343
-
344
- /**
345
- * Display the admin notice to users that have not opted-in or out
346
- *
347
- * @return void
348
- */
349
- public function admin_notice() {
350
-
351
- if ( $this->notice_dismissed() ) {
352
- return;
353
- }
354
-
355
- if ( $this->tracking_allowed() ) {
356
- return;
357
- }
358
-
359
- if ( ! current_user_can( 'manage_options' ) ) {
360
- return;
361
- }
362
-
363
- // don't show tracking if a local server
364
- if ( ! $this->is_local_server() ) {
365
- $optin_url = add_query_arg( $this->client->slug . '_tracker_optin', 'true' );
366
- $optout_url = add_query_arg( $this->client->slug . '_tracker_optout', 'true' );
367
-
368
- if ( empty( $this->notice ) ) {
369
- $notice = sprintf( __( 'Want to help make <strong>%1$s</strong> even more awesome? Allow %1$s to collect non-sensitive diagnostic data and usage information.', $this->client->textdomain ), $this->client->name );
370
- } else {
371
- $notice = $this->notice;
372
- }
373
-
374
- $notice .= ' (<a class="' . $this->client->slug . '-insights-data-we-collect" href="#">' . __( 'what we collect', $this->client->textdomain ) . '</a>)';
375
- $notice .= '<p class="description" style="display:none;">' . implode( ', ', $this->data_we_collect() ) . '. No sensitive data is tracked. ';
376
- $notice .= 'We are using Appsero to collect your data. <a href="https://appsero.com/privacy-policy/">Learn more</a> about how Appsero collects and handle your data.</p>';
377
-
378
- echo '<div class="updated"><p>';
379
- echo $notice;
380
- echo '</p><p class="submit">';
381
- echo '&nbsp;<a href="' . esc_url( $optin_url ) . '" class="button-primary button-large">' . __( 'Allow', $this->client->textdomain ) . '</a>';
382
- echo '&nbsp;<a href="' . esc_url( $optout_url ) . '" class="button-secondary button-large">' . __( 'No thanks', $this->client->textdomain ) . '</a>';
383
- echo '</p></div>';
384
-
385
- echo "<script type='text/javascript'>jQuery('." . $this->client->slug . "-insights-data-we-collect').on('click', function(e) {
386
- e.preventDefault();
387
- jQuery(this).parents('.updated').find('p.description').slideToggle('fast');
388
- });
389
- </script>
390
- ";
391
- }
392
- }
393
-
394
- /**
395
- * handle the optin/optout
396
- *
397
- * @return void
398
- */
399
- public function handle_optin_optout() {
400
-
401
- if ( isset( $_GET[ $this->client->slug . '_tracker_optin' ] ) && $_GET[ $this->client->slug . '_tracker_optin' ] == 'true' ) {
402
- $this->optin();
403
-
404
- wp_redirect( remove_query_arg( $this->client->slug . '_tracker_optin' ) );
405
- exit;
406
- }
407
-
408
- if ( isset( $_GET[ $this->client->slug . '_tracker_optout' ] ) && $_GET[ $this->client->slug . '_tracker_optout' ] == 'true' ) {
409
- $this->optout();
410
-
411
- wp_redirect( remove_query_arg( $this->client->slug . '_tracker_optout' ) );
412
- exit;
413
- }
414
- }
415
-
416
- /**
417
- * Tracking optin
418
- *
419
- * @return void
420
- */
421
- public function optin() {
422
- update_option( $this->client->slug . '_allow_tracking', 'yes' );
423
- update_option( $this->client->slug . '_tracking_notice', 'hide' );
424
-
425
- $this->clear_schedule_event();
426
- $this->schedule_event();
427
- $this->send_tracking_data();
428
- }
429
-
430
- /**
431
- * Optout from tracking
432
- *
433
- * @return void
434
- */
435
- public function optout() {
436
- update_option( $this->client->slug . '_allow_tracking', 'no' );
437
- update_option( $this->client->slug . '_tracking_notice', 'hide' );
438
-
439
- $this->clear_schedule_event();
440
- }
441
-
442
- /**
443
- * Get the number of post counts
444
- *
445
- * @param string $post_type
446
- *
447
- * @return integer
448
- */
449
- public function get_post_count( $post_type ) {
450
- global $wpdb;
451
-
452
- return (int) $wpdb->get_var( "SELECT count(ID) FROM $wpdb->posts WHERE post_type = '$post_type' and post_status = 'publish'");
453
- }
454
-
455
- /**
456
- * Get server related info.
457
- *
458
- * @return array
459
- */
460
- private static function get_server_info() {
461
- global $wpdb;
462
-
463
- $server_data = array();
464
-
465
- if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) {
466
- $server_data['software'] = $_SERVER['SERVER_SOFTWARE'];
467
- }
468
-
469
- if ( function_exists( 'phpversion' ) ) {
470
- $server_data['php_version'] = phpversion();
471
- }
472
-
473
- $server_data['mysql_version'] = $wpdb->db_version();
474
-
475
- $server_data['php_max_upload_size'] = size_format( wp_max_upload_size() );
476
- $server_data['php_default_timezone'] = date_default_timezone_get();
477
- $server_data['php_soap'] = class_exists( 'SoapClient' ) ? 'Yes' : 'No';
478
- $server_data['php_fsockopen'] = function_exists( 'fsockopen' ) ? 'Yes' : 'No';
479
- $server_data['php_curl'] = function_exists( 'curl_init' ) ? 'Yes' : 'No';
480
-
481
- return $server_data;
482
- }
483
-
484
- /**
485
- * Get WordPress related data.
486
- *
487
- * @return array
488
- */
489
- private function get_wp_info() {
490
- $wp_data = array();
491
-
492
- $wp_data['memory_limit'] = WP_MEMORY_LIMIT;
493
- $wp_data['debug_mode'] = ( defined('WP_DEBUG') && WP_DEBUG ) ? 'Yes' : 'No';
494
- $wp_data['locale'] = get_locale();
495
- $wp_data['version'] = get_bloginfo( 'version' );
496
- $wp_data['multisite'] = is_multisite() ? 'Yes' : 'No';
497
-
498
- return $wp_data;
499
- }
500
-
501
- /**
502
- * Get the list of active and inactive plugins
503
- *
504
- * @return array
505
- */
506
- private function get_all_plugins() {
507
- // Ensure get_plugins function is loaded
508
- if ( ! function_exists( 'get_plugins' ) ) {
509
- include ABSPATH . '/wp-admin/includes/plugin.php';
510
- }
511
-
512
- $plugins = get_plugins();
513
- $active_plugins_keys = get_option( 'active_plugins', array() );
514
- $active_plugins = array();
515
-
516
- foreach ( $plugins as $k => $v ) {
517
- // Take care of formatting the data how we want it.
518
- $formatted = array();
519
- $formatted['name'] = strip_tags( $v['Name'] );
520
-
521
- if ( isset( $v['Version'] ) ) {
522
- $formatted['version'] = strip_tags( $v['Version'] );
523
- }
524
-
525
- if ( isset( $v['Author'] ) ) {
526
- $formatted['author'] = strip_tags( $v['Author'] );
527
- }
528
-
529
- if ( isset( $v['Network'] ) ) {
530
- $formatted['network'] = strip_tags( $v['Network'] );
531
- }
532
-
533
- if ( isset( $v['PluginURI'] ) ) {
534
- $formatted['plugin_uri'] = strip_tags( $v['PluginURI'] );
535
- }
536
-
537
- if ( in_array( $k, $active_plugins_keys ) ) {
538
- // Remove active plugins from list so we can show active and inactive separately
539
- unset( $plugins[$k] );
540
- $active_plugins[$k] = $formatted;
541
- } else {
542
- $plugins[$k] = $formatted;
543
- }
544
- }
545
-
546
- return array( 'active_plugins' => $active_plugins, 'inactive_plugins' => $plugins );
547
- }
548
-
549
- /**
550
- * Get user totals based on user role.
551
- *
552
- * @return array
553
- */
554
- public function get_user_counts() {
555
- $user_count = array();
556
- $user_count_data = count_users();
557
- $user_count['total'] = $user_count_data['total_users'];
558
-
559
- // Get user count based on user role
560
- foreach ( $user_count_data['avail_roles'] as $role => $count ) {
561
- $user_count[ $role ] = $count;
562
- }
563
-
564
- return $user_count;
565
- }
566
-
567
- /**
568
- * Add weekly cron schedule
569
- *
570
- * @param array $schedules
571
- *
572
- * @return array
573
- */
574
- public function add_weekly_schedule( $schedules ) {
575
-
576
- $schedules['weekly'] = array(
577
- 'interval' => DAY_IN_SECONDS * 7,
578
- 'display' => 'Once Weekly',
579
- );
580
-
581
- return $schedules;
582
- }
583
-
584
- /**
585
- * Plugin activation hook
586
- *
587
- * @return void
588
- */
589
- public function activate_plugin() {
590
- $allowed = get_option( $this->client->slug . '_allow_tracking', 'no' );
591
-
592
- // if it wasn't allowed before, do nothing
593
- if ( 'yes' !== $allowed ) {
594
- return;
595
- }
596
-
597
- // re-schedule and delete the last sent time so we could force send again
598
- $hook_name = $this->client->slug . '_tracker_send_event';
599
- if ( ! wp_next_scheduled( $hook_name ) ) {
600
- wp_schedule_event( time(), 'weekly', $hook_name );
601
- }
602
-
603
- delete_option( $this->client->slug . '_tracking_last_send' );
604
-
605
- $this->send_tracking_data( true );
606
- }
607
-
608
- /**
609
- * Clear our options upon deactivation
610
- *
611
- * @return void
612
- */
613
- public function deactivation_cleanup() {
614
- $this->clear_schedule_event();
615
-
616
- if ( 'theme' == $this->client->type ) {
617
- delete_option( $this->client->slug . '_tracking_last_send' );
618
- delete_option( $this->client->slug . '_allow_tracking' );
619
- }
620
-
621
- delete_option( $this->client->slug . '_tracking_notice' );
622
- }
623
-
624
- /**
625
- * Hook into action links and modify the deactivate link
626
- *
627
- * @param array $links
628
- *
629
- * @return array
630
- */
631
- public function plugin_action_links( $links ) {
632
-
633
- if ( array_key_exists( 'deactivate', $links ) ) {
634
- $links['deactivate'] = str_replace( '<a', '<a class="' . $this->client->slug . '-deactivate-link"', $links['deactivate'] );
635
- }
636
-
637
- return $links;
638
- }
639
-
640
- private function get_uninstall_reasons() {
641
- $reasons = array(
642
- array(
643
- 'id' => 'could-not-understand',
644
- 'text' => 'I couldn\'t understand how to make it work',
645
- 'type' => 'textarea',
646
- 'placeholder' => 'Would you like us to assist you?'
647
- ),
648
- array(
649
- 'id' => 'found-better-plugin',
650
- 'text' => 'I found a better plugin',
651
- 'type' => 'text',
652
- 'placeholder' => 'Which plugin?'
653
- ),
654
- array(
655
- 'id' => 'not-have-that-feature',
656
- 'text' => 'The plugin is great, but I need specific feature that you don\'t support',
657
- 'type' => 'textarea',
658
- 'placeholder' => 'Could you tell us more about that feature?'
659
- ),
660
- array(
661
- 'id' => 'is-not-working',
662
- 'text' => 'The plugin is not working',
663
- 'type' => 'textarea',
664
- 'placeholder' => 'Could you tell us a bit more whats not working?'
665
- ),
666
- array(
667
- 'id' => 'looking-for-other',
668
- 'text' => 'It\'s not what I was looking for',
669
- 'type' => '',
670
- 'placeholder' => ''
671
- ),
672
- array(
673
- 'id' => 'did-not-work-as-expected',
674
- 'text' => 'The plugin didn\'t work as expected',
675
- 'type' => 'textarea',
676
- 'placeholder' => 'What did you expect?'
677
- ),
678
- array(
679
- 'id' => 'other',
680
- 'text' => 'Other',
681
- 'type' => 'textarea',
682
- 'placeholder' => 'Could you tell us a bit more?'
683
- ),
684
- );
685
-
686
- return $reasons;
687
- }
688
-
689
- /**
690
- * Plugin deactivation uninstall reason submission
691
- *
692
- * @return void
693
- */
694
- public function uninstall_reason_submission() {
695
-
696
- if ( ! isset( $_POST['reason_id'] ) ) {
697
- wp_send_json_error();
698
- }
699
-
700
- $current_user = wp_get_current_user();
701
-
702
- $data = array(
703
- 'hash' => $this->client->hash,
704
- 'reason_id' => sanitize_text_field( $_POST['reason_id'] ),
705
- 'reason_info' => isset( $_REQUEST['reason_info'] ) ? trim( stripslashes( $_REQUEST['reason_info'] ) ) : '',
706
- 'site' => $this->get_site_name(),
707
- 'url' => esc_url( home_url() ),
708
- 'admin_email' => get_option( 'admin_email' ),
709
- 'user_email' => $current_user->user_email,
710
- 'first_name' => $current_user->first_name,
711
- 'last_name' => $current_user->last_name,
712
- 'server' => $this->get_server_info(),
713
- 'wp' => $this->get_wp_info(),
714
- 'ip_address' => $this->get_user_ip_address(),
715
- 'theme' => get_stylesheet(),
716
- 'version' => $this->client->project_version,
717
- );
718
-
719
- // Add metadata
720
- if ( $extra = $this->get_extra_data() ) {
721
- $data['extra'] = $extra;
722
- }
723
-
724
- $this->client->send_request( $data, 'deactivate' );
725
-
726
- wp_send_json_success();
727
- }
728
-
729
- /**
730
- * Handle the plugin deactivation feedback
731
- *
732
- * @return void
733
- */
734
- public function deactivate_scripts() {
735
- global $pagenow;
736
-
737
- if ( 'plugins.php' != $pagenow ) {
738
- return;
739
- }
740
-
741
- $reasons = $this->get_uninstall_reasons();
742
- ?>
743
-
744
- <div class="wd-dr-modal" id="<?php echo $this->client->slug; ?>-wd-dr-modal">
745
- <div class="wd-dr-modal-wrap">
746
- <div class="wd-dr-modal-header">
747
- <h3><?php _e( 'If you have a moment, please let us know why you are deactivating:', $this->client->textdomain ); ?></h3>
748
- </div>
749
-
750
- <div class="wd-dr-modal-body">
751
- <ul class="reasons">
752
- <?php foreach ($reasons as $reason) { ?>
753
- <li data-type="<?php echo esc_attr( $reason['type'] ); ?>" data-placeholder="<?php echo esc_attr( $reason['placeholder'] ); ?>">
754
- <label><input type="radio" name="selected-reason" value="<?php echo $reason['id']; ?>"> <?php echo $reason['text']; ?></label>
755
- </li>
756
- <?php } ?>
757
- </ul>
758
- <p class="wd-dr-modal-reasons-bottom">We share your data with <a href="https://appsero.com/">Appsero</a> to troubleshoot problems &amp; make product improvements. <a href="https://appsero.com/privacy-policy/">Learn more</a> about how Appsero handles your data.</p>
759
- </div>
760
-
761
- <div class="wd-dr-modal-footer">
762
- <a href="#" class="dont-bother-me"><?php _e( 'I rather wouldn\'t say', $this->client->textdomain ); ?></a>
763
- <button class="button-secondary"><?php _e( 'Submit & Deactivate', $this->client->textdomain ); ?></button>
764
- <button class="button-primary"><?php _e( 'Cancel', $this->client->textdomain ); ?></button>
765
- </div>
766
- </div>
767
- </div>
768
-
769
- <style type="text/css">
770
- .wd-dr-modal {
771
- position: fixed;
772
- z-index: 99999;
773
- top: 0;
774
- right: 0;
775
- bottom: 0;
776
- left: 0;
777
- background: rgba(0,0,0,0.5);
778
- display: none;
779
- }
780
-
781
- .wd-dr-modal.modal-active {
782
- display: block;
783
- }
784
-
785
- .wd-dr-modal-wrap {
786
- width: 475px;
787
- position: relative;
788
- margin: 10% auto;
789
- background: #fff;
790
- }
791
-
792
- .wd-dr-modal-header {
793
- border-bottom: 1px solid #eee;
794
- padding: 8px 20px;
795
- }
796
-
797
- .wd-dr-modal-header h3 {
798
- line-height: 150%;
799
- margin: 0;
800
- }
801
-
802
- .wd-dr-modal-body {
803
- padding: 5px 20px 20px 20px;
804
- }
805
-
806
- .wd-dr-modal-body .reason-input {
807
- margin-top: 5px;
808
- margin-left: 20px;
809
- }
810
- .wd-dr-modal-footer {
811
- border-top: 1px solid #eee;
812
- padding: 12px 20px;
813
- text-align: right;
814
- }
815
- .wd-dr-modal-reasons-bottom {
816
- margin: 15px 0 0 0;
817
- }
818
- </style>
819
-
820
- <script type="text/javascript">
821
- (function($) {
822
- $(function() {
823
- var modal = $( '#<?php echo $this->client->slug; ?>-wd-dr-modal' );
824
- var deactivateLink = '';
825
-
826
- $( '#the-list' ).on('click', 'a.<?php echo $this->client->slug; ?>-deactivate-link', function(e) {
827
- e.preventDefault();
828
-
829
- modal.addClass('modal-active');
830
- deactivateLink = $(this).attr('href');
831
- modal.find('a.dont-bother-me').attr('href', deactivateLink).css('float', 'left');
832
- });
833
-
834
- modal.on('click', 'button.button-primary', function(e) {
835
- e.preventDefault();
836
-
837
- modal.removeClass('modal-active');
838
- });
839
-
840
- modal.on('click', 'input[type="radio"]', function () {
841
- var parent = $(this).parents('li:first');
842
-
843
- modal.find('.reason-input').remove();
844
-
845
- var inputType = parent.data('type'),
846
- inputPlaceholder = parent.data('placeholder'),
847
- reasonInputHtml = '<div class="reason-input">' + ( ( 'text' === inputType ) ? '<input type="text" size="40" />' : '<textarea rows="5" cols="45"></textarea>' ) + '</div>';
848
-
849
- if ( inputType !== '' ) {
850
- parent.append( $(reasonInputHtml) );
851
- parent.find('input, textarea').attr('placeholder', inputPlaceholder).focus();
852
- }
853
- });
854
-
855
- modal.on('click', 'button.button-secondary', function(e) {
856
- e.preventDefault();
857
-
858
- var button = $(this);
859
-
860
- if ( button.hasClass('disabled') ) {
861
- return;
862
- }
863
-
864
- var $radio = $( 'input[type="radio"]:checked', modal );
865
-
866
- var $selected_reason = $radio.parents('li:first'),
867
- $input = $selected_reason.find('textarea, input[type="text"]');
868
-
869
- $.ajax({
870
- url: ajaxurl,
871
- type: 'POST',
872
- data: {
873
- action: '<?php echo $this->client->slug; ?>_submit-uninstall-reason',
874
- reason_id: ( 0 === $radio.length ) ? 'none' : $radio.val(),
875
- reason_info: ( 0 !== $input.length ) ? $input.val().trim() : ''
876
- },
877
- beforeSend: function() {
878
- button.addClass('disabled');
879
- button.text('Processing...');
880
- },
881
- complete: function() {
882
- window.location.href = deactivateLink;
883
- }
884
- });
885
- });
886
- });
887
- }(jQuery));
888
- </script>
889
-
890
- <?php
891
- }
892
-
893
- /**
894
- * Run after theme deactivated
895
- * @param string $new_name
896
- * @param object $new_theme
897
- * @param object $old_theme
898
- * @return void
899
- */
900
- public function theme_deactivated( $new_name, $new_theme, $old_theme ) {
901
- // Make sure this is appsero theme
902
- if ( $old_theme->get_template() == $this->client->slug ) {
903
- $current_user = wp_get_current_user();
904
-
905
- $data = array(
906
- 'hash' => $this->client->hash,
907
- 'reason_id' => 'none',
908
- 'reason_info' => '',
909
- 'site' => $this->get_site_name(),
910
- 'url' => esc_url( home_url() ),
911
- 'admin_email' => get_option( 'admin_email' ),
912
- 'user_email' => $current_user->user_email,
913
- 'first_name' => $current_user->first_name,
914
- 'last_name' => $current_user->last_name,
915
- 'server' => $this->get_server_info(),
916
- 'wp' => $this->get_wp_info(),
917
- 'ip_address' => $this->get_user_ip_address(),
918
- 'theme' => get_stylesheet(),
919
- 'version' => $this->client->project_version,
920
- );
921
-
922
- $this->client->send_request( $data, 'deactivate' );
923
- }
924
- }
925
-
926
- /**
927
- * Get user IP Address
928
- */
929
- private function get_user_ip_address() {
930
- $response = wp_remote_get( 'https://icanhazip.com/' );
931
-
932
- if ( is_wp_error( $response ) ) {
933
- return '';
934
- }
935
-
936
- $ip = trim( wp_remote_retrieve_body( $response ) );
937
-
938
- if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
939
- return '';
940
- }
941
-
942
- return $ip;
943
- }
944
-
945
- /**
946
- * Get site name
947
- */
948
- private function get_site_name() {
949
- $site_name = get_bloginfo( 'name' );
950
-
951
- if ( empty( $site_name ) ) {
952
- $site_name = get_bloginfo( 'description' );
953
- $site_name = wp_trim_words( $site_name, 3, '' );
954
- }
955
-
956
- if ( empty( $site_name ) ) {
957
- $site_name = get_bloginfo( 'url' );
958
- }
959
-
960
- return $site_name;
961
- }
962
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Happy_Addons\Appsero;
3
+
4
+ /**
5
+ * Appsero Insights
6
+ *
7
+ * This is a tracker class to track plugin usage based on if the customer has opted in.
8
+ * No personal information is being tracked by this class, only general settings, active plugins, environment details
9
+ * and admin email.
10
+ */
11
+ class Insights {
12
+
13
+ /**
14
+ * The notice text
15
+ *
16
+ * @var string
17
+ */
18
+ public $notice;
19
+
20
+ /**
21
+ * Wheather to the notice or not
22
+ *
23
+ * @var boolean
24
+ */
25
+ protected $show_notice = true;
26
+
27
+ /**
28
+ * If extra data needs to be sent
29
+ *
30
+ * @var array
31
+ */
32
+ protected $extra_data = array();
33
+
34
+ /**
35
+ * AppSero\Client
36
+ *
37
+ * @var object
38
+ */
39
+ protected $client;
40
+
41
+ /**
42
+ * Initialize the class
43
+ *
44
+ * @param Happy_Addons\AppSero\Client
45
+ */
46
+ public function __construct( $client, $name = null, $file = null ) {
47
+
48
+ if ( is_string( $client ) && ! empty( $name ) && ! empty( $file ) ) {
49
+ $client = new Client( $client, $name, $file );
50
+ }
51
+
52
+ if ( is_object( $client ) && is_a( $client, 'Happy_Addons\Appsero\Client' ) ) {
53
+ $this->client = $client;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Don't show the notice
59
+ *
60
+ * @return \self
61
+ */
62
+ public function hide_notice() {
63
+ $this->show_notice = false;
64
+
65
+ return $this;
66
+ }
67
+
68
+ /**
69
+ * Add extra data if needed
70
+ *
71
+ * @param array $data
72
+ *
73
+ * @return \self
74
+ */
75
+ public function add_extra( $data = array() ) {
76
+ $this->extra_data = $data;
77
+
78
+ return $this;
79
+ }
80
+
81
+ /**
82
+ * Set custom notice text
83
+ *
84
+ * @param string $text
85
+ *
86
+ * @return \self
87
+ */
88
+ public function notice( $text ) {
89
+ $this->notice = $text;
90
+
91
+ return $this;
92
+ }
93
+
94
+ /**
95
+ * Initialize insights
96
+ *
97
+ * @return void
98
+ */
99
+ public function init() {
100
+ if ( $this->client->type == 'plugin' ) {
101
+ $this->init_plugin();
102
+ } else if ( $this->client->type == 'theme' ) {
103
+ $this->init_theme();
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Initialize theme hooks
109
+ *
110
+ * @return void
111
+ */
112
+ public function init_theme() {
113
+ $this->init_common();
114
+
115
+ add_action( 'switch_theme', array( $this, 'deactivation_cleanup' ) );
116
+ add_action( 'switch_theme', array( $this, 'theme_deactivated' ), 12, 3 );
117
+ }
118
+
119
+ /**
120
+ * Initialize plugin hooks
121
+ *
122
+ * @return void
123
+ */
124
+ public function init_plugin() {
125
+ // plugin deactivate popup
126
+ if ( ! $this->is_local_server() ) {
127
+ add_filter( 'plugin_action_links_' . $this->client->basename, array( $this, 'plugin_action_links' ) );
128
+ add_action( 'admin_footer', array( $this, 'deactivate_scripts' ) );
129
+ }
130
+
131
+ $this->init_common();
132
+
133
+ register_activation_hook( $this->client->file, array( $this, 'activate_plugin' ) );
134
+ register_deactivation_hook( $this->client->file, array( $this, 'deactivation_cleanup' ) );
135
+ }
136
+
137
+ /**
138
+ * Initialize common hooks
139
+ *
140
+ * @return void
141
+ */
142
+ protected function init_common() {
143
+
144
+ if ( $this->show_notice ) {
145
+ // tracking notice
146
+ add_action( 'admin_notices', array( $this, 'admin_notice' ) );
147
+ }
148
+
149
+ add_action( 'admin_init', array( $this, 'handle_optin_optout' ) );
150
+
151
+ // uninstall reason
152
+ add_action( 'wp_ajax_' . $this->client->slug . '_submit-uninstall-reason', array( $this, 'uninstall_reason_submission' ) );
153
+
154
+ // cron events
155
+ add_filter( 'cron_schedules', array( $this, 'add_weekly_schedule' ) );
156
+ add_action( $this->client->slug . '_tracker_send_event', array( $this, 'send_tracking_data' ) );
157
+ // add_action( 'admin_init', array( $this, 'send_tracking_data' ) ); // test
158
+ }
159
+
160
+ /**
161
+ * Send tracking data to AppSero server
162
+ *
163
+ * @param boolean $override
164
+ *
165
+ * @return void
166
+ */
167
+ public function send_tracking_data( $override = false ) {
168
+ // skip on AJAX Requests
169
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
170
+ return;
171
+ }
172
+
173
+ if ( ! $this->tracking_allowed() && ! $override ) {
174
+ return;
175
+ }
176
+
177
+ // Send a maximum of once per week
178
+ $last_send = $this->get_last_send();
179
+
180
+ if ( $last_send && $last_send > strtotime( '-1 week' ) ) {
181
+ return;
182
+ }
183
+
184
+ $tracking_data = $this->get_tracking_data();
185
+
186
+ $response = $this->client->send_request( $tracking_data, 'track' );
187
+
188
+ update_option( $this->client->slug . '_tracking_last_send', time() );
189
+ }
190
+
191
+ /**
192
+ * Get the tracking data points
193
+ *
194
+ * @return array
195
+ */
196
+ protected function get_tracking_data() {
197
+ $all_plugins = $this->get_all_plugins();
198
+
199
+ $users = get_users( array(
200
+ 'role' => 'administrator',
201
+ 'orderby' => 'ID',
202
+ 'order' => 'ASC',
203
+ 'number' => 1,
204
+ 'paged' => 1,
205
+ ) );
206
+
207
+ $admin_user = ( is_array( $users ) && ! empty( $users ) ) ? $users[0] : false;
208
+ $first_name = $last_name = '';
209
+
210
+ if ( $admin_user ) {
211
+ $first_name = $admin_user->first_name ? $admin_user->first_name : $admin_user->display_name;
212
+ $last_name = $admin_user->last_name;
213
+ }
214
+
215
+ $data = array(
216
+ 'url' => esc_url( home_url() ),
217
+ 'site' => $this->get_site_name(),
218
+ 'admin_email' => get_option( 'admin_email' ),
219
+ 'first_name' => $first_name,
220
+ 'last_name' => $last_name,
221
+ 'hash' => $this->client->hash,
222
+ 'server' => $this->get_server_info(),
223
+ 'wp' => $this->get_wp_info(),
224
+ 'users' => $this->get_user_counts(),
225
+ 'active_plugins' => count( $all_plugins['active_plugins'] ),
226
+ 'inactive_plugins' => count( $all_plugins['inactive_plugins'] ),
227
+ 'ip_address' => $this->get_user_ip_address(),
228
+ 'project_version' => $this->client->project_version,
229
+ 'tracking_skipped' => false,
230
+ );
231
+
232
+ // Add metadata
233
+ if ( $extra = $this->get_extra_data() ) {
234
+ $data['extra'] = $extra;
235
+ }
236
+
237
+ // Check this has previously skipped tracking
238
+ $skipped = get_option( $this->client->slug . '_tracking_skipped' );
239
+
240
+ if ( $skipped === 'yes' ) {
241
+ delete_option( $this->client->slug . '_tracking_skipped' );
242
+
243
+ $data['tracking_skipped'] = true;
244
+ }
245
+
246
+ return apply_filters( $this->client->slug . '_tracker_data', $data );
247
+ }
248
+
249
+ /**
250
+ * If a child class wants to send extra data
251
+ *
252
+ * @return mixed
253
+ */
254
+ protected function get_extra_data() {
255
+ if ( is_callable( $this->extra_data ) ) {
256
+ return call_user_func( $this->extra_data );
257
+ }
258
+
259
+ if ( is_array( $this->extra_data ) ) {
260
+ return $this->extra_data;
261
+ }
262
+
263
+ return array();
264
+ }
265
+
266
+ /**
267
+ * Explain the user which data we collect
268
+ *
269
+ * @return array
270
+ */
271
+ protected function data_we_collect() {
272
+ $data = array(
273
+ 'Server environment details (php, mysql, server, WordPress versions)',
274
+ 'Number of users in your site',
275
+ 'Site language',
276
+ 'Number of active and inactive plugins',
277
+ 'Site name and url',
278
+ 'Your name and email address',
279
+ );
280
+
281
+ return $data;
282
+ }
283
+
284
+ /**
285
+ * Check if the user has opted into tracking
286
+ *
287
+ * @return bool
288
+ */
289
+ public function tracking_allowed() {
290
+ $allow_tracking = get_option( $this->client->slug . '_allow_tracking', 'no' );
291
+
292
+ return $allow_tracking == 'yes';
293
+ }
294
+
295
+ /**
296
+ * Get the last time a tracking was sent
297
+ *
298
+ * @return false|string
299
+ */
300
+ private function get_last_send() {
301
+ return get_option( $this->client->slug . '_tracking_last_send', false );
302
+ }
303
+
304
+ /**
305
+ * Check if the notice has been dismissed or enabled
306
+ *
307
+ * @return boolean
308
+ */
309
+ public function notice_dismissed() {
310
+ $hide_notice = get_option( $this->client->slug . '_tracking_notice', null );
311
+
312
+ if ( 'hide' == $hide_notice ) {
313
+ return true;
314
+ }
315
+
316
+ return false;
317
+ }
318
+
319
+ /**
320
+ * Check if the current server is localhost
321
+ *
322
+ * @return boolean
323
+ */
324
+ private function is_local_server() {
325
+ return false;
326
+
327
+ $is_local = in_array( $_SERVER['REMOTE_ADDR'], array( '127.0.0.1', '::1' ) );
328
+
329
+ return apply_filters( 'appsero_is_local', $is_local );
330
+ }
331
+
332
+ /**
333
+ * Schedule the event weekly
334
+ *
335
+ * @return void
336
+ */
337
+ private function schedule_event() {
338
+ $hook_name = $this->client->slug . '_tracker_send_event';
339
+
340
+ if ( ! wp_next_scheduled( $hook_name ) ) {
341
+ wp_schedule_event( time(), 'weekly', $hook_name );
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Clear any scheduled hook
347
+ *
348
+ * @return void
349
+ */
350
+ private function clear_schedule_event() {
351
+ wp_clear_scheduled_hook( $this->client->slug . '_tracker_send_event' );
352
+ }
353
+
354
+ /**
355
+ * Display the admin notice to users that have not opted-in or out
356
+ *
357
+ * @return void
358
+ */
359
+ public function admin_notice() {
360
+
361
+ if ( $this->notice_dismissed() ) {
362
+ return;
363
+ }
364
+
365
+ if ( $this->tracking_allowed() ) {
366
+ return;
367
+ }
368
+
369
+ if ( ! current_user_can( 'manage_options' ) ) {
370
+ return;
371
+ }
372
+
373
+ // don't show tracking if a local server
374
+ if ( $this->is_local_server() ) {
375
+ return;
376
+ }
377
+
378
+ $optin_url = add_query_arg( $this->client->slug . '_tracker_optin', 'true' );
379
+ $optout_url = add_query_arg( $this->client->slug . '_tracker_optout', 'true' );
380
+
381
+ if ( empty( $this->notice ) ) {
382
+ $notice = sprintf( $this->client->__trans( 'Want to help make <strong>%1$s</strong> even more awesome? Allow %1$s to collect non-sensitive diagnostic data and usage information.' ), $this->client->name );
383
+ } else {
384
+ $notice = $this->notice;
385
+ }
386
+
387
+ $policy_url = 'https://' . 'appsero.com/privacy-policy/';
388
+
389
+ $notice .= ' (<a class="' . $this->client->slug . '-insights-data-we-collect" href="#">' . $this->client->__trans( 'what we collect' ) . '</a>)';
390
+ $notice .= '<p class="description" style="display:none;">' . implode( ', ', $this->data_we_collect() ) . '. No sensitive data is tracked. ';
391
+ $notice .= 'We are using Appsero to collect your data. <a href="' . $policy_url . '">Learn more</a> about how Appsero collects and handle your data.</p>';
392
+
393
+ echo '<div class="updated"><p>';
394
+ echo $notice;
395
+ echo '</p><p class="submit">';
396
+ echo '&nbsp;<a href="' . esc_url( $optin_url ) . '" class="button-primary button-large">' . $this->client->__trans( 'Allow' ) . '</a>';
397
+ echo '&nbsp;<a href="' . esc_url( $optout_url ) . '" class="button-secondary button-large">' . $this->client->__trans( 'No thanks' ) . '</a>';
398
+ echo '</p></div>';
399
+
400
+ echo "<script type='text/javascript'>jQuery('." . $this->client->slug . "-insights-data-we-collect').on('click', function(e) {
401
+ e.preventDefault();
402
+ jQuery(this).parents('.updated').find('p.description').slideToggle('fast');
403
+ });
404
+ </script>
405
+ ";
406
+ }
407
+
408
+ /**
409
+ * handle the optin/optout
410
+ *
411
+ * @return void
412
+ */
413
+ public function handle_optin_optout() {
414
+
415
+ if ( isset( $_GET[ $this->client->slug . '_tracker_optin' ] ) && $_GET[ $this->client->slug . '_tracker_optin' ] == 'true' ) {
416
+ $this->optin();
417
+
418
+ wp_redirect( remove_query_arg( $this->client->slug . '_tracker_optin' ) );
419
+ exit;
420
+ }
421
+
422
+ if ( isset( $_GET[ $this->client->slug . '_tracker_optout' ] ) && $_GET[ $this->client->slug . '_tracker_optout' ] == 'true' ) {
423
+ $this->optout();
424
+
425
+ wp_redirect( remove_query_arg( $this->client->slug . '_tracker_optout' ) );
426
+ exit;
427
+ }
428
+ }
429
+
430
+ /**
431
+ * Tracking optin
432
+ *
433
+ * @return void
434
+ */
435
+ public function optin() {
436
+ update_option( $this->client->slug . '_allow_tracking', 'yes' );
437
+ update_option( $this->client->slug . '_tracking_notice', 'hide' );
438
+
439
+ $this->clear_schedule_event();
440
+ $this->schedule_event();
441
+ $this->send_tracking_data();
442
+ }
443
+
444
+ /**
445
+ * Optout from tracking
446
+ *
447
+ * @return void
448
+ */
449
+ public function optout() {
450
+ update_option( $this->client->slug . '_allow_tracking', 'no' );
451
+ update_option( $this->client->slug . '_tracking_notice', 'hide' );
452
+
453
+ $this->send_tracking_skipped_request();
454
+
455
+ $this->clear_schedule_event();
456
+ }
457
+
458
+ /**
459
+ * Get the number of post counts
460
+ *
461
+ * @param string $post_type
462
+ *
463
+ * @return integer
464
+ */
465
+ public function get_post_count( $post_type ) {
466
+ global $wpdb;
467
+
468
+ return (int) $wpdb->get_var( "SELECT count(ID) FROM $wpdb->posts WHERE post_type = '$post_type' and post_status = 'publish'");
469
+ }
470
+
471
+ /**
472
+ * Get server related info.
473
+ *
474
+ * @return array
475
+ */
476
+ private static function get_server_info() {
477
+ global $wpdb;
478
+
479
+ $server_data = array();
480
+
481
+ if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) {
482
+ $server_data['software'] = $_SERVER['SERVER_SOFTWARE'];
483
+ }
484
+
485
+ if ( function_exists( 'phpversion' ) ) {
486
+ $server_data['php_version'] = phpversion();
487
+ }
488
+
489
+ $server_data['mysql_version'] = $wpdb->db_version();
490
+
491
+ $server_data['php_max_upload_size'] = size_format( wp_max_upload_size() );
492
+ $server_data['php_default_timezone'] = date_default_timezone_get();
493
+ $server_data['php_soap'] = class_exists( 'SoapClient' ) ? 'Yes' : 'No';
494
+ $server_data['php_fsockopen'] = function_exists( 'fsockopen' ) ? 'Yes' : 'No';
495
+ $server_data['php_curl'] = function_exists( 'curl_init' ) ? 'Yes' : 'No';
496
+
497
+ return $server_data;
498
+ }
499
+
500
+ /**
501
+ * Get WordPress related data.
502
+ *
503
+ * @return array
504
+ */
505
+ private function get_wp_info() {
506
+ $wp_data = array();
507
+
508
+ $wp_data['memory_limit'] = WP_MEMORY_LIMIT;
509
+ $wp_data['debug_mode'] = ( defined('WP_DEBUG') && WP_DEBUG ) ? 'Yes' : 'No';
510
+ $wp_data['locale'] = get_locale();
511
+ $wp_data['version'] = get_bloginfo( 'version' );
512
+ $wp_data['multisite'] = is_multisite() ? 'Yes' : 'No';
513
+ $wp_data['theme_slug'] = get_stylesheet();
514
+
515
+ $theme = wp_get_theme( $wp_data['theme_slug'] );
516
+
517
+ $wp_data['theme_name'] = $theme->get( 'Name' );
518
+ $wp_data['theme_version'] = $theme->get( 'Version' );
519
+ $wp_data['theme_uri'] = $theme->get( 'ThemeURI' );
520
+ $wp_data['theme_author'] = $theme->get( 'Author' );
521
+
522
+ return $wp_data;
523
+ }
524
+
525
+ /**
526
+ * Get the list of active and inactive plugins
527
+ *
528
+ * @return array
529
+ */
530
+ private function get_all_plugins() {
531
+ // Ensure get_plugins function is loaded
532
+ if ( ! function_exists( 'get_plugins' ) ) {
533
+ include ABSPATH . '/wp-admin/includes/plugin.php';
534
+ }
535
+
536
+ $plugins = get_plugins();
537
+ $active_plugins_keys = get_option( 'active_plugins', array() );
538
+ $active_plugins = array();
539
+
540
+ foreach ( $plugins as $k => $v ) {
541
+ // Take care of formatting the data how we want it.
542
+ $formatted = array();
543
+ $formatted['name'] = strip_tags( $v['Name'] );
544
+
545
+ if ( isset( $v['Version'] ) ) {
546
+ $formatted['version'] = strip_tags( $v['Version'] );
547
+ }
548
+
549
+ if ( isset( $v['Author'] ) ) {
550
+ $formatted['author'] = strip_tags( $v['Author'] );
551
+ }
552
+
553
+ if ( isset( $v['Network'] ) ) {
554
+ $formatted['network'] = strip_tags( $v['Network'] );
555
+ }
556
+
557
+ if ( isset( $v['PluginURI'] ) ) {
558
+ $formatted['plugin_uri'] = strip_tags( $v['PluginURI'] );
559
+ }
560
+
561
+ if ( in_array( $k, $active_plugins_keys ) ) {
562
+ // Remove active plugins from list so we can show active and inactive separately
563
+ unset( $plugins[$k] );
564
+ $active_plugins[$k] = $formatted;
565
+ } else {
566
+ $plugins[$k] = $formatted;
567
+ }
568
+ }
569
+
570
+ return array( 'active_plugins' => $active_plugins, 'inactive_plugins' => $plugins );
571
+ }
572
+
573
+ /**
574
+ * Get user totals based on user role.
575
+ *
576
+ * @return array
577
+ */
578
+ public function get_user_counts() {
579
+ $user_count = array();
580
+ $user_count_data = count_users();
581
+ $user_count['total'] = $user_count_data['total_users'];
582
+
583
+ // Get user count based on user role
584
+ foreach ( $user_count_data['avail_roles'] as $role => $count ) {
585
+ if ( ! $count ) {
586
+ continue;
587
+ }
588
+
589
+ $user_count[ $role ] = $count;
590
+ }
591
+
592
+ return $user_count;
593
+ }
594
+
595
+ /**
596
+ * Add weekly cron schedule
597
+ *
598
+ * @param array $schedules
599
+ *
600
+ * @return array
601
+ */
602
+ public function add_weekly_schedule( $schedules ) {
603
+
604
+ $schedules['weekly'] = array(
605
+ 'interval' => DAY_IN_SECONDS * 7,
606
+ 'display' => 'Once Weekly',
607
+ );
608
+
609
+ return $schedules;
610
+ }
611
+
612
+ /**
613
+ * Plugin activation hook
614
+ *
615
+ * @return void
616
+ */
617
+ public function activate_plugin() {
618
+ $allowed = get_option( $this->client->slug . '_allow_tracking', 'no' );
619
+
620
+ // if it wasn't allowed before, do nothing
621
+ if ( 'yes' !== $allowed ) {
622
+ return;
623
+ }
624
+
625
+ // re-schedule and delete the last sent time so we could force send again
626
+ $hook_name = $this->client->slug . '_tracker_send_event';
627
+ if ( ! wp_next_scheduled( $hook_name ) ) {
628
+ wp_schedule_event( time(), 'weekly', $hook_name );
629
+ }
630
+
631
+ delete_option( $this->client->slug . '_tracking_last_send' );
632
+
633
+ $this->send_tracking_data( true );
634
+ }
635
+
636
+ /**
637
+ * Clear our options upon deactivation
638
+ *
639
+ * @return void
640
+ */
641
+ public function deactivation_cleanup() {
642
+ $this->clear_schedule_event();
643
+
644
+ if ( 'theme' == $this->client->type ) {
645
+ delete_option( $this->client->slug . '_tracking_last_send' );
646
+ delete_option( $this->client->slug . '_allow_tracking' );
647
+ }
648
+
649
+ delete_option( $this->client->slug . '_tracking_notice' );
650
+ }
651
+
652
+ /**
653
+ * Hook into action links and modify the deactivate link
654
+ *
655
+ * @param array $links
656
+ *
657
+ * @return array
658
+ */
659
+ public function plugin_action_links( $links ) {
660
+
661
+ if ( array_key_exists( 'deactivate', $links ) ) {
662
+ $links['deactivate'] = str_replace( '<a', '<a class="' . $this->client->slug . '-deactivate-link"', $links['deactivate'] );
663
+ }
664
+
665
+ return $links;
666
+ }
667
+
668
+ /**
669
+ * Plugin uninstall reasons
670
+ *
671
+ * @return array
672
+ */
673
+ private function get_uninstall_reasons() {
674
+ $reasons = array(
675
+ array(
676
+ 'id' => 'could-not-understand',
677
+ 'text' => $this->client->__trans( "Couldn't understand" ),
678
+ 'placeholder' => $this->client->__trans( 'Would you like us to assist you?' ),
679
+ 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" width="23" height="23" viewBox="0 0 23 23"><g fill="none"><g fill="#3B86FF"><path d="M11.5 0C17.9 0 23 5.1 23 11.5 23 17.9 17.9 23 11.5 23 10.6 23 9.6 22.9 8.8 22.7L8.8 22.6C9.3 22.5 9.7 22.3 10 21.9 10.3 21.6 10.4 21.3 10.4 20.9 10.8 21 11.1 21 11.5 21 16.7 21 21 16.7 21 11.5 21 6.3 16.7 2 11.5 2 6.3 2 2 6.3 2 11.5 2 13 2.3 14.3 2.9 15.6 2.7 16 2.4 16.3 2.2 16.8L2.1 17.1 2.1 17.3C2 17.5 2 17.7 2 18 0.7 16.1 0 13.9 0 11.5 0 5.1 5.1 0 11.5 0ZM6 13.6C6 13.7 6.1 13.8 6.1 13.9 6.3 14.5 6.2 15.7 6.1 16.4 6.1 16.6 6 16.9 6 17.1 6 17.1 6.1 17.1 6.1 17.1 7.1 16.9 8.2 16 9.3 15.5 9.8 15.2 10.4 15 10.9 15 11.2 15 11.4 15 11.6 15.2 11.9 15.4 12.1 16 11.6 16.4 11.5 16.5 11.3 16.6 11.1 16.7 10.5 17 9.9 17.4 9.3 17.7 9 17.9 9 18.1 9.1 18.5 9.2 18.9 9.3 19.4 9.3 19.8 9.4 20.3 9.3 20.8 9 21.2 8.8 21.5 8.5 21.6 8.1 21.7 7.9 21.8 7.6 21.9 7.3 21.9L6.5 22C6.3 22 6 21.9 5.8 21.9 5 21.8 4.4 21.5 3.9 20.9 3.3 20.4 3.1 19.6 3 18.8L3 18.5C3 18.2 3 17.9 3.1 17.7L3.1 17.6C3.2 17.1 3.5 16.7 3.7 16.3 4 15.9 4.2 15.4 4.3 15 4.4 14.6 4.4 14.5 4.6 14.2 4.6 13.9 4.7 13.7 4.9 13.6 5.2 13.2 5.7 13.2 6 13.6ZM11.7 11.2C13.1 11.2 14.3 11.7 15.2 12.9 15.3 13 15.4 13.1 15.4 13.2 15.4 13.4 15.3 13.8 15.2 13.8 15 13.9 14.9 13.8 14.8 13.7 14.6 13.5 14.4 13.2 14.1 13.1 13.5 12.6 12.8 12.3 12 12.2 10.7 12.1 9.5 12.3 8.4 12.8 8.3 12.8 8.2 12.8 8.1 12.8 7.9 12.8 7.8 12.4 7.8 12.2 7.7 12.1 7.8 11.9 8 11.8 8.4 11.7 8.8 11.5 9.2 11.4 10 11.2 10.9 11.1 11.7 11.2ZM16.3 5.9C17.3 5.9 18 6.6 18 7.6 18 8.5 17.3 9.3 16.3 9.3 15.4 9.3 14.7 8.5 14.7 7.6 14.7 6.6 15.4 5.9 16.3 5.9ZM8.3 5C9.2 5 9.9 5.8 9.9 6.7 9.9 7.7 9.2 8.4 8.2 8.4 7.3 8.4 6.6 7.7 6.6 6.7 6.6 5.8 7.3 5 8.3 5Z"/></g></g></svg>'
680
+ ),
681
+ array(
682
+ 'id' => 'found-better-plugin',
683
+ 'text' => $this->client->__trans( 'Found a better plugin' ),
684
+ 'placeholder' => $this->client->__trans( 'Which plugin?' ),
685
+ 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" width="23" height="23" viewBox="0 0 23 23"><g fill="none"><g fill="#3B86FF"><path d="M17.1 14L22.4 19.3C23.2 20.2 23.2 21.5 22.4 22.4 21.5 23.2 20.2 23.2 19.3 22.4L19.3 22.4 14 17.1C15.3 16.3 16.3 15.3 17.1 14L17.1 14ZM8.6 0C13.4 0 17.3 3.9 17.3 8.6 17.3 13.4 13.4 17.2 8.6 17.2 3.9 17.2 0 13.4 0 8.6 0 3.9 3.9 0 8.6 0ZM8.6 2.2C5.1 2.2 2.2 5.1 2.2 8.6 2.2 12.2 5.1 15.1 8.6 15.1 12.2 15.1 15.1 12.2 15.1 8.6 15.1 5.1 12.2 2.2 8.6 2.2ZM8.6 3.6L8.6 5C6.6 5 5 6.6 5 8.6L5 8.6 3.6 8.6C3.6 5.9 5.9 3.6 8.6 3.6L8.6 3.6Z"/></g></g></svg>',
686
+ ),
687
+ array(
688
+ 'id' => 'not-have-that-feature',
689
+ 'text' => $this->client->__trans( "Missing a specific feature" ),
690
+ 'placeholder' => $this->client->__trans( 'Could you tell us more about that feature?' ),
691
+ 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="17" viewBox="0 0 24 17"><g fill="none"><g fill="#3B86FF"><path d="M19.4 0C19.7 0.6 19.8 1.3 19.8 2 19.8 3.2 19.4 4.4 18.5 5.3 17.6 6.2 16.5 6.7 15.2 6.7 15.2 6.7 15.2 6.7 15.2 6.7 14 6.7 12.9 6.2 12 5.3 11.2 4.4 10.7 3.3 10.7 2 10.7 1.3 10.8 0.6 11.1 0L7.6 0 7 0 6.5 0 6.5 5.7C6.3 5.6 5.9 5.3 5.6 5.1 5 4.6 4.3 4.3 3.5 4.3 3.5 4.3 3.5 4.3 3.4 4.3 1.6 4.4 0 5.9 0 7.9 0 8.6 0.2 9.2 0.5 9.7 1.1 10.8 2.2 11.5 3.5 11.5 4.3 11.5 5 11.2 5.6 10.8 6 10.5 6.3 10.3 6.5 10.2L6.5 10.2 6.5 17 6.5 17 7 17 7.6 17 22.5 17C23.3 17 24 16.3 24 15.5L24 0 19.4 0Z"/></g></g></svg>',
692
+ ),
693
+ array(
694
+ 'id' => 'is-not-working',
695
+ 'text' => $this->client->__trans( 'Not working' ),
696
+ 'placeholder' => $this->client->__trans( 'Could you tell us a bit more whats not working?' ),
697
+ 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" width="23" height="23" viewBox="0 0 23 23"><g fill="none"><g fill="#3B86FF"><path d="M11.5 0C17.9 0 23 5.1 23 11.5 23 17.9 17.9 23 11.5 23 5.1 23 0 17.9 0 11.5 0 5.1 5.1 0 11.5 0ZM11.8 14.4C11.2 14.4 10.7 14.8 10.7 15.4 10.7 16 11.2 16.4 11.8 16.4 12.4 16.4 12.8 16 12.8 15.4 12.8 14.8 12.4 14.4 11.8 14.4ZM12 7C10.1 7 9.1 8.1 9 9.6L10.5 9.6C10.5 8.8 11.1 8.3 11.9 8.3 12.7 8.3 13.2 8.8 13.2 9.5 13.2 10.1 13 10.4 12.2 10.9 11.3 11.4 10.9 12 11 12.9L11 13.4 12.5 13.4 12.5 13C12.5 12.4 12.7 12.1 13.5 11.6 14.4 11.1 14.9 10.4 14.9 9.4 14.9 8 13.7 7 12 7Z"/></g></g></svg>',
698
+ ),
699
+ array(
700
+ 'id' => 'looking-for-other',
701
+ 'text' => $this->client->__trans( "Not what I was looking" ),
702
+ 'placeholder' => $this->client->__trans( 'Could you tell us a bit more?' ),
703
+ 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="17" viewBox="0 0 24 17"><g fill="none"><g fill="#3B86FF"><path d="M23.5 9C23.5 9 23.5 8.9 23.5 8.9 23.5 8.9 23.5 8.9 23.5 8.9 23.4 8.6 23.2 8.3 23 8 22.2 6.5 20.6 3.7 19.8 2.6 18.8 1.3 17.7 0 16.1 0 15.7 0 15.3 0.1 14.9 0.2 13.8 0.6 12.6 1.2 12.3 2.7L11.7 2.7C11.4 1.2 10.2 0.6 9.1 0.2 8.7 0.1 8.3 0 7.9 0 6.3 0 5.2 1.3 4.2 2.6 3.4 3.7 1.8 6.5 1 8 0.8 8.3 0.6 8.6 0.5 8.9 0.5 8.9 0.5 8.9 0.5 8.9 0.5 8.9 0.5 9 0.5 9 0.2 9.7 0 10.5 0 11.3 0 14.4 2.5 17 5.5 17 7.3 17 8.8 16.1 9.8 14.8L14.2 14.8C15.2 16.1 16.7 17 18.5 17 21.5 17 24 14.4 24 11.3 24 10.5 23.8 9.7 23.5 9ZM5.5 15C3.6 15 2 13.2 2 11 2 8.8 3.6 7 5.5 7 7.4 7 9 8.8 9 11 9 13.2 7.4 15 5.5 15ZM18.5 15C16.6 15 15 13.2 15 11 15 8.8 16.6 7 18.5 7 20.4 7 22 8.8 22 11 22 13.2 20.4 15 18.5 15Z"/></g></g></svg>',
704
+ ),
705
+ array(
706
+ 'id' => 'did-not-work-as-expected',
707
+ 'text' => $this->client->__trans( "Didn't work as expected" ),
708
+ 'placeholder' => $this->client->__trans( 'What did you expect?' ),
709
+ 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" width="23" height="23" viewBox="0 0 23 23"><g fill="none"><g fill="#3B86FF"><path d="M11.5 0C17.9 0 23 5.1 23 11.5 23 17.9 17.9 23 11.5 23 5.1 23 0 17.9 0 11.5 0 5.1 5.1 0 11.5 0ZM11.5 2C6.3 2 2 6.3 2 11.5 2 16.7 6.3 21 11.5 21 16.7 21 21 16.7 21 11.5 21 6.3 16.7 2 11.5 2ZM12.5 12.9L12.7 5 10.2 5 10.5 12.9 12.5 12.9ZM11.5 17.4C12.4 17.4 13 16.8 13 15.9 13 15 12.4 14.4 11.5 14.4 10.6 14.4 10 15 10 15.9 10 16.8 10.6 17.4 11.5 17.4Z"/></g></g></svg>',
710
+ ),
711
+ array(
712
+ 'id' => 'other',
713
+ 'text' => $this->client->__trans( 'Others' ),
714
+ 'placeholder' => $this->client->__trans( 'Could you tell us a bit more?' ),
715
+ 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="23" viewBox="0 0 24 6"><g fill="none"><g fill="#3B86FF"><path d="M3 0C4.7 0 6 1.3 6 3 6 4.7 4.7 6 3 6 1.3 6 0 4.7 0 3 0 1.3 1.3 0 3 0ZM12 0C13.7 0 15 1.3 15 3 15 4.7 13.7 6 12 6 10.3 6 9 4.7 9 3 9 1.3 10.3 0 12 0ZM21 0C22.7 0 24 1.3 24 3 24 4.7 22.7 6 21 6 19.3 6 18 4.7 18 3 18 1.3 19.3 0 21 0Z"/></g></g></svg>',
716
+ ),
717
+ );
718
+
719
+ return $reasons;
720
+ }
721
+
722
+ /**
723
+ * Plugin deactivation uninstall reason submission
724
+ *
725
+ * @return void
726
+ */
727
+ public function uninstall_reason_submission() {
728
+
729
+ if ( ! isset( $_POST['reason_id'] ) ) {
730
+ wp_send_json_error();
731
+ }
732
+
733
+ $data = $this->get_tracking_data();
734
+ $data['reason_id'] = sanitize_text_field( $_POST['reason_id'] );
735
+ $data['reason_info'] = isset( $_REQUEST['reason_info'] ) ? trim( stripslashes( $_REQUEST['reason_info'] ) ) : '';
736
+
737
+ $this->client->send_request( $data, 'deactivate' );
738
+
739
+ wp_send_json_success();
740
+ }
741
+
742
+ /**
743
+ * Handle the plugin deactivation feedback
744
+ *
745
+ * @return void
746
+ */
747
+ public function deactivate_scripts() {
748
+ global $pagenow;
749
+
750
+ if ( 'plugins.php' != $pagenow ) {
751
+ return;
752
+ }
753
+
754
+ $this->deactivation_modal_styles();
755
+ $reasons = $this->get_uninstall_reasons();
756
+ $custom_reasons = apply_filters( 'appsero_custom_deactivation_reasons', [] );
757
+ ?>
758
+
759
+ <div class="wd-dr-modal" id="<?php echo $this->client->slug; ?>-wd-dr-modal">
760
+ <div class="wd-dr-modal-wrap">
761
+ <div class="wd-dr-modal-header">
762
+ <h3><?php $this->client->_etrans( 'Goodbyes are always hard. If you have a moment, please let us know how we can improve.' ); ?></h3>
763
+ </div>
764
+
765
+ <div class="wd-dr-modal-body">
766
+ <ul class="wd-de-reasons">
767
+ <?php foreach ( $reasons as $reason ) { ?>
768
+ <li data-placeholder="<?php echo esc_attr( $reason['placeholder'] ); ?>">
769
+ <label>
770
+ <input type="radio" name="selected-reason" value="<?php echo $reason['id']; ?>">
771
+ <div class="wd-de-reason-icon"><?php echo $reason['icon']; ?></div>
772
+ <div class="wd-de-reason-text"><?php echo $reason['text']; ?></div>
773
+ </label>
774
+ </li>
775
+ <?php } ?>
776
+ </ul>
777
+ <?php if ( $custom_reasons && is_array( $custom_reasons ) ) : ?>
778
+ <ul class="wd-de-reasons wd-de-others-reasons">
779
+ <?php foreach ( $custom_reasons as $reason ) { ?>
780
+ <li data-placeholder="<?php echo esc_attr( $reason['placeholder'] ); ?>" data-customreason="true">
781
+ <label>
782
+ <input type="radio" name="selected-reason" value="<?php echo $reason['id']; ?>">
783
+ <div class="wd-de-reason-icon"><?php echo $reason['icon']; ?></div>
784
+ <div class="wd-de-reason-text"><?php echo $reason['text']; ?></div>
785
+ </label>
786
+ </li>
787
+ <?php } ?>
788
+ </ul>
789
+ <?php endif; ?>
790
+ <div class="wd-dr-modal-reason-input"><textarea></textarea></div>
791
+ <p class="wd-dr-modal-reasons-bottom">
792
+ <?php
793
+ echo sprintf(
794
+ $this->client->__trans( 'We share your data with <a href="%1$s" target="_blank">Appsero</a> to troubleshoot problems &amp; make product improvements. <a href="%2$s" target="_blank">Learn more</a> about how Appsero handles your data.'),
795
+ esc_url( 'https://appsero.com/' ),
796
+ esc_url( 'https://appsero.com/privacy-policy' )
797
+ );
798
+ ?>
799
+ </p>
800
+ </div>
801
+
802
+ <div class="wd-dr-modal-footer">
803
+ <a href="#" class="dont-bother-me wd-dr-button-secondary"><?php $this->client->_etrans( "Skip & Deactivate" ); ?></a>
804
+ <button class="wd-dr-button-secondary wd-dr-cancel-modal"><?php $this->client->_etrans( 'Cancel' ); ?></button>
805
+ <button class="wd-dr-submit-modal"><?php $this->client->_etrans( 'Submit & Deactivate' ); ?></button>
806
+ </div>
807
+ </div>
808
+ </div>
809
+
810
+ <script type="text/javascript">
811
+ (function($) {
812
+ $(function() {
813
+ var modal = $( '#<?php echo $this->client->slug; ?>-wd-dr-modal' );
814
+ var deactivateLink = '';
815
+
816
+ // Open modal
817
+ $( '#the-list' ).on('click', 'a.<?php echo $this->client->slug; ?>-deactivate-link', function(e) {
818
+ e.preventDefault();
819
+
820
+ modal.addClass('modal-active');
821
+ deactivateLink = $(this).attr('href');
822
+ modal.find('a.dont-bother-me').attr('href', deactivateLink).css('float', 'left');
823
+ });
824
+
825
+ // Close modal; Cancel
826
+ modal.on('click', 'button.wd-dr-cancel-modal', function(e) {
827
+ e.preventDefault();
828
+ modal.removeClass('modal-active');
829
+ });
830
+
831
+ // Reason change
832
+ modal.on('click', 'input[type="radio"]', function () {
833
+ var parent = $(this).parents('li');
834
+ var isCustomReason = parent.data('customreason');
835
+ var inputValue = $(this).val();
836
+
837
+ if ( isCustomReason ) {
838
+ $('ul.wd-de-reasons.wd-de-others-reasons li').removeClass('wd-de-reason-selected');
839
+ } else {
840
+ $('ul.wd-de-reasons li').removeClass('wd-de-reason-selected');
841
+
842
+ if ( "other" != inputValue ) {
843
+ $('ul.wd-de-reasons.wd-de-others-reasons').css('display', 'none');
844
+ }
845
+ }
846
+
847
+ // Show if has custom reasons
848
+ if ( "other" == inputValue ) {
849
+ $('ul.wd-de-reasons.wd-de-others-reasons').css('display', 'flex');
850
+ }
851
+
852
+ parent.addClass('wd-de-reason-selected');
853
+ $('.wd-dr-modal-reason-input').show();
854
+
855
+ $('.wd-dr-modal-reason-input textarea').attr('placeholder', parent.data('placeholder')).focus();
856
+ });
857
+
858
+ // Submit response
859
+ modal.on('click', 'button.wd-dr-submit-modal', function(e) {
860
+ e.preventDefault();
861
+
862
+ var button = $(this);
863
+
864
+ if ( button.hasClass('disabled') ) {
865
+ return;
866
+ }
867
+
868
+ var $radio = $( 'input[type="radio"]:checked', modal );
869
+ var $input = $('.wd-dr-modal-reason-input textarea');
870
+
871
+ $.ajax({
872
+ url: ajaxurl,
873
+ type: 'POST',
874
+ data: {
875
+ action: '<?php echo $this->client->slug; ?>_submit-uninstall-reason',
876
+ reason_id: ( 0 === $radio.length ) ? 'none' : $radio.val(),
877
+ reason_info: ( 0 !== $input.length ) ? $input.val().trim() : ''
878
+ },
879
+ beforeSend: function() {
880
+ button.addClass('disabled');
881
+ button.text('Processing...');
882
+ },
883
+ complete: function() {
884
+ window.location.href = deactivateLink;
885
+ }
886
+ });
887
+ });
888
+ });
889
+ }(jQuery));
890
+ </script>
891
+
892
+ <?php
893
+ }
894
+
895
+ /**
896
+ * Run after theme deactivated
897
+ * @param string $new_name
898
+ * @param object $new_theme
899
+ * @param object $old_theme
900
+ * @return void
901
+ */
902
+ public function theme_deactivated( $new_name, $new_theme, $old_theme ) {
903
+ // Make sure this is appsero theme
904
+ if ( $old_theme->get_template() == $this->client->slug ) {
905
+ $this->client->send_request( $this->get_tracking_data(), 'deactivate' );
906
+ }
907
+ }
908
+
909
+ /**
910
+ * Get user IP Address
911
+ */
912
+ private function get_user_ip_address() {
913
+ $response = wp_remote_get( 'https://icanhazip.com/' );
914
+
915
+ if ( is_wp_error( $response ) ) {
916
+ return '';
917
+ }
918
+
919
+ $ip = trim( wp_remote_retrieve_body( $response ) );
920
+
921
+ if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
922
+ return '';
923
+ }
924
+
925
+ return $ip;
926
+ }
927
+
928
+ /**
929
+ * Get site name
930
+ */
931
+ private function get_site_name() {
932
+ $site_name = get_bloginfo( 'name' );
933
+
934
+ if ( empty( $site_name ) ) {
935
+ $site_name = get_bloginfo( 'description' );
936
+ $site_name = wp_trim_words( $site_name, 3, '' );
937
+ }
938
+
939
+ if ( empty( $site_name ) ) {
940
+ $site_name = esc_url( home_url() );
941
+ }
942
+
943
+ return $site_name;
944
+ }
945
+
946
+ /**
947
+ * Send request to appsero if user skip to send tracking data
948
+ */
949
+ private function send_tracking_skipped_request() {
950
+ $skipped = get_option( $this->client->slug . '_tracking_skipped' );
951
+
952
+ $data = [
953
+ 'hash' => $this->client->hash,
954
+ 'previously_skipped' => false,
955
+ ];
956
+
957
+ if ( $skipped === 'yes' ) {
958
+ $data['previously_skipped'] = true;
959
+ } else {
960
+ update_option( $this->client->slug . '_tracking_skipped', 'yes' );
961
+ }
962
+
963
+ $this->client->send_request( $data, 'tracking-skipped' );
964
+ }
965
+
966
+ /**
967
+ * Deactivation modal styles
968
+ */
969
+ private function deactivation_modal_styles() {
970
+ ?>
971
+ <style type="text/css">
972
+ .wd-dr-modal {
973
+ position: fixed;
974
+ z-index: 99999;
975
+ top: 0;
976
+ right: 0;
977
+ bottom: 0;
978
+ left: 0;
979
+ background: rgba(0,0,0,0.5);
980
+ display: none;
981
+ box-sizing: border-box;
982
+ overflow: scroll;
983
+ }
984
+ .wd-dr-modal * {
985
+ box-sizing: border-box;
986
+ }
987
+ .wd-dr-modal.modal-active {
988
+ display: block;
989
+ }
990
+ .wd-dr-modal-wrap {
991
+ max-width: 870px;
992
+ width: 100%;
993
+ position: relative;
994
+ margin: 10% auto;
995
+ background: #fff;
996
+ }
997
+ .wd-dr-modal-header {
998
+ border-bottom: 1px solid #E8E8E8;
999
+ padding: 20px 20px 18px 20px;
1000
+ }
1001
+ .wd-dr-modal-header h3 {
1002
+ line-height: 1.8;
1003
+ margin: 0;
1004
+ color: #4A5568;
1005
+ }
1006
+ .wd-dr-modal-body {
1007
+ padding: 5px 20px 20px 20px;
1008
+ }
1009
+ .wd-dr-modal-body .reason-input {
1010
+ margin-top: 5px;
1011
+ margin-left: 20px;
1012
+ }
1013
+ .wd-dr-modal-footer {
1014
+ border-top: 1px solid #E8E8E8;
1015
+ padding: 20px;
1016
+ text-align: right;
1017
+ }
1018
+ .wd-dr-modal-reasons-bottom {
1019
+ margin: 0;
1020
+ }
1021
+ ul.wd-de-reasons {
1022
+ display: flex;
1023
+ margin: 0 -5px 0 -5px;
1024
+ padding: 15px 0 20px 0;
1025
+ }
1026
+ ul.wd-de-reasons.wd-de-others-reasons {
1027
+ padding-top: 0;
1028
+ display: none;
1029
+ }
1030
+ ul.wd-de-reasons li {
1031
+ padding: 0 5px;
1032
+ margin: 0;
1033
+ width: 14.26%;
1034
+ }
1035
+ ul.wd-de-reasons label {
1036
+ position: relative;
1037
+ border: 1px solid #E8E8E8;
1038
+ border-radius: 4px;
1039
+ display: block;
1040
+ text-align: center;
1041
+ height: 100%;
1042
+ padding: 15px 3px 8px 3px;
1043
+ }
1044
+ ul.wd-de-reasons label:after {
1045
+ width: 0;
1046
+ height: 0;
1047
+ border-left: 8px solid transparent;
1048
+ border-right: 8px solid transparent;
1049
+ border-top: 10px solid #3B86FF;
1050
+ position: absolute;
1051
+ left: 50%;
1052
+ top: 100%;
1053
+ margin-left: -8px;
1054
+ }
1055
+ ul.wd-de-reasons label input[type="radio"] {
1056
+ position: absolute;
1057
+ left: 0;
1058
+ right: 0;
1059
+ visibility: hidden;
1060
+ }
1061
+ .wd-de-reason-text {
1062
+ color: #4A5568;
1063
+ font-size: 13px;
1064
+ }
1065
+ .wd-de-reason-icon {
1066
+ margin-bottom: 7px;
1067
+ }
1068
+ ul.wd-de-reasons li.wd-de-reason-selected label {
1069
+ background-color: #3B86FF;
1070
+ border-color: #3B86FF;
1071
+ }
1072
+ li.wd-de-reason-selected .wd-de-reason-icon svg,
1073
+ li.wd-de-reason-selected .wd-de-reason-icon svg g {
1074
+ fill: #fff;
1075
+ }
1076
+ li.wd-de-reason-selected .wd-de-reason-text {
1077
+ color: #fff;
1078
+ }
1079
+ ul.wd-de-reasons li.wd-de-reason-selected label:after {
1080
+ content: "";
1081
+ }
1082
+ .wd-dr-modal-reason-input {
1083
+ margin-bottom: 15px;
1084
+ display: none;
1085
+ }
1086
+ .wd-dr-modal-reason-input textarea {
1087
+ background: #FAFAFA;
1088
+ border: 1px solid #287EB8;
1089
+ border-radius: 4px;
1090
+ width: 100%;
1091
+ height: 100px;
1092
+ color: #524242;
1093
+ font-size: 13px;
1094
+ line-height: 1.4;
1095
+ padding: 11px 15px;
1096
+ resize: none;
1097
+ }
1098
+ .wd-dr-modal-reason-input textarea:focus {
1099
+ outline: 0 none;
1100
+ box-shadow: 0 0 0;
1101
+ }
1102
+ .wd-dr-button-secondary, .wd-dr-button-secondary:hover {
1103
+ border: 1px solid #EBEBEB;
1104
+ border-radius: 3px;
1105
+ font-size: 13px;
1106
+ line-height: 1.5;
1107
+ color: #718096;
1108
+ padding: 5px 12px;
1109
+ cursor: pointer;
1110
+ background-color: transparent;
1111
+ text-decoration: none;
1112
+ }
1113
+ .wd-dr-submit-modal, .wd-dr-submit-modal:hover {
1114
+ border: 1px solid #3B86FF;
1115
+ background-color: #3B86FF;
1116
+ border-radius: 3px;
1117
+ font-size: 13px;
1118
+ line-height: 1.5;
1119
+ color: #fff;
1120
+ padding: 5px 12px;
1121
+ cursor: pointer;
1122
+ margin-left: 4px;
1123
+ }
1124
+ </style>
1125
+ <?php
1126
+ }
1127
+
1128
+ }
vendor/appsero/src/License.php CHANGED
@@ -1,701 +1,705 @@
1
- <?php
2
- namespace Happy_Addons\Appsero;
3
-
4
- /**
5
- * Appsero License Checker
6
- *
7
- * This class will check, active and deactive license
8
- */
9
- class License {
10
-
11
- /**
12
- * AppSero\Client
13
- *
14
- * @var object
15
- */
16
- protected $client;
17
-
18
- /**
19
- * Arguments of create menu
20
- *
21
- * @var array
22
- */
23
- protected $menu_args;
24
-
25
- /**
26
- * `option_name` of `wp_options` table
27
- *
28
- * @var string
29
- */
30
- protected $option_key;
31
-
32
- /**
33
- * Error message of HTTP request
34
- *
35
- * @var string
36
- */
37
- public $error;
38
-
39
- /**
40
- * Success message on form submit
41
- *
42
- * @var string
43
- */
44
- public $success;
45
-
46
- /**
47
- * Corn schedule hook name
48
- *
49
- * @var string
50
- */
51
- protected $schedule_hook;
52
-
53
- /**
54
- * Set value for valid licnese
55
- *
56
- * @var boolean
57
- */
58
- private $is_valid_licnese = null;
59
-
60
- /**
61
- * Initialize the class
62
- *
63
- * @param Happy_Addons\Appsero\Client
64
- */
65
- public function __construct( Client $client ) {
66
- $this->client = $client;
67
-
68
- $this->option_key = 'appsero_' . md5( $this->client->slug ) . '_manage_license';
69
-
70
- $this->schedule_hook = $this->client->slug . '_license_check_event';
71
-
72
- // Run hook to check license status daily
73
- add_action( $this->schedule_hook, array( $this, 'check_license_status' ) );
74
-
75
- // Active/Deactive corn schedule
76
- $this->run_schedule();
77
- }
78
-
79
- /**
80
- * Check license
81
- *
82
- * @return boolean
83
- */
84
- public function check( $license_key ) {
85
- $route = 'public/license/' . $this->client->hash . '/check';
86
-
87
- return $this->send_request( $license_key, $route );
88
- }
89
-
90
- /**
91
- * Active a license
92
- *
93
- * @return boolean
94
- */
95
- public function activate( $license_key ) {
96
- $route = 'public/license/' . $this->client->hash . '/activate';
97
-
98
- return $this->send_request( $license_key, $route );
99
- }
100
-
101
- /**
102
- * Deactivate a license
103
- *
104
- * @return boolean
105
- */
106
- public function deactivate( $license_key ) {
107
- $route = 'public/license/' . $this->client->hash . '/deactivate';
108
-
109
- return $this->send_request( $license_key, $route );
110
- }
111
-
112
- /**
113
- * Send common request
114
- *
115
- * @param $license_key
116
- * @param $route
117
- *
118
- * @return array
119
- */
120
- protected function send_request( $license_key, $route ) {
121
- $params = array(
122
- 'license_key' => $license_key,
123
- 'url' => esc_url( home_url() ),
124
- );
125
-
126
- $response = $this->client->send_request( $params, $route, true );
127
-
128
- if ( is_wp_error( $response ) ) {
129
- return array(
130
- 'success' => false,
131
- 'error' => $response->get_error_message()
132
- );
133
- }
134
-
135
- $response = json_decode( wp_remote_retrieve_body( $response ), true );
136
-
137
- if ( empty( $response ) || isset( $response['exception'] )) {
138
- return array(
139
- 'success' => false,
140
- 'error' => 'Unknown error occurred, Please try again.'
141
- );
142
- }
143
-
144
- if ( isset( $response['errors'] ) && isset( $response['errors']['license_key'] ) ) {
145
- $response = array(
146
- 'success' => false,
147
- 'error' => $response['errors']['license_key'][0]
148
- );
149
- }
150
-
151
- return $response;
152
- }
153
-
154
- /**
155
- * Add settings page for license
156
- *
157
- * @param array $args
158
- *
159
- * @return void
160
- */
161
- public function add_settings_page( $args = array() ) {
162
- $defaults = array(
163
- 'type' => 'menu', // Can be: menu, options, submenu
164
- 'page_title' => 'Manage License',
165
- 'menu_title' => 'Manage License',
166
- 'capability' => 'manage_options',
167
- 'menu_slug' => $this->client->slug . '-manage-license',
168
- 'icon_url' => '',
169
- 'position' => null,
170
- 'parent_slug' => '',
171
- );
172
-
173
- $this->menu_args = wp_parse_args( $args, $defaults );
174
-
175
- add_action( 'admin_menu', array( $this, 'admin_menu' ), 99 );
176
- }
177
-
178
- /**
179
- * Admin Menu hook
180
- *
181
- * @return void
182
- */
183
- public function admin_menu() {
184
- switch ( $this->menu_args['type'] ) {
185
- case 'menu':
186
- $this->add_menu_page();
187
- break;
188
-
189
- case 'submenu':
190
- $this->add_submenu_page();
191
- break;
192
-
193
- case 'options':
194
- $this->add_options_page();
195
- break;
196
- }
197
- }
198
-
199
- /**
200
- * License menu output
201
- */
202
- public function menu_output() {
203
-
204
- if ( isset( $_POST['submit'] ) ) {
205
- $this->license_form_submit( $_POST );
206
- }
207
-
208
- $license = get_option( $this->option_key, null );
209
- $action = ( $license && isset( $license['status'] ) && 'activate' == $license['status'] ) ? 'deactive' : 'active';
210
- $this->licenses_style();
211
- ?>
212
-
213
- <div class="wrap appsero-license-settings-wrapper">
214
- <h1>License Settings</h1>
215
-
216
- <?php
217
- $this->show_license_page_notices();
218
- do_action( 'before_appsero_license_section' );
219
- ?>
220
-
221
- <div class="appsero-license-settings appsero-license-section">
222
- <?php $this->show_license_page_card_header(); ?>
223
-
224
- <div class="appsero-license-details">
225
- <p>Active <strong><?php echo $this->client->name; ?></strong> by your license key to get professional support and automatic update from your WordPress dashboard.</p>
226
- <form method="post" action="<?php $this->formActionUrl(); ?>" novalidate="novalidate" spellcheck="false">
227
- <input type="hidden" name="_action" value="<?php echo $action; ?>">
228
- <input type="hidden" name="_nonce" value="<?php echo wp_create_nonce( $this->client->name ); ?>">
229
- <div class="license-input-fields">
230
- <div class="license-input-key">
231
- <svg enable-background="new 0 0 512 512" version="1.1" viewBox="0 0 512 512" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
232
- <path d="m463.75 48.251c-64.336-64.336-169.01-64.335-233.35 1e-3 -43.945 43.945-59.209 108.71-40.181 167.46l-185.82 185.82c-2.813 2.813-4.395 6.621-4.395 10.606v84.858c0 8.291 6.709 15 15 15h84.858c3.984 0 7.793-1.582 10.605-4.395l21.211-21.226c3.237-3.237 4.819-7.778 4.292-12.334l-2.637-22.793 31.582-2.974c7.178-0.674 12.847-6.343 13.521-13.521l2.974-31.582 22.793 2.651c4.233 0.571 8.496-0.85 11.704-3.691 3.193-2.856 5.024-6.929 5.024-11.206v-27.929h27.422c3.984 0 7.793-1.582 10.605-4.395l38.467-37.958c58.74 19.043 122.38 4.929 166.33-39.046 64.336-64.335 64.336-169.01 0-233.35zm-42.435 106.07c-17.549 17.549-46.084 17.549-63.633 0s-17.549-46.084 0-63.633 46.084-17.549 63.633 0 17.548 46.084 0 63.633z"/>
233
- </svg>
234
- <input type="text" value="<?php echo $this->get_input_license_value( $action, $license ); ?>"
235
- placeholder="Enter your license key to activate" name="license_key"
236
- <?php echo ( 'deactive' == $action ) ? 'readonly="readonly"' : ''; ?>
237
- />
238
- </div>
239
- <button type="submit" name="submit" class="<?php echo 'deactive' == $action ? 'deactive-button' : ''; ?>">
240
- <?php echo $action == 'active' ? 'Activate License' : 'Deactivate License' ; ?>
241
- </button>
242
- </div>
243
- </form>
244
-
245
- <?php
246
- if ( 'deactive' == $action && isset( $license['remaining'] ) ) {
247
- $this->show_active_license_info( $license );
248
- }
249
- ?>
250
- </div>
251
- </div> <!-- /.appsero-license-settings -->
252
-
253
- <?php do_action( 'after_appsero_license_section' ); ?>
254
- </div>
255
- <?php
256
- }
257
-
258
- /**
259
- * License form submit
260
- */
261
- public function license_form_submit( $form ) {
262
- if ( ! isset( $form['_nonce'], $form['_action'] ) ) {
263
- $this->error = "Please add all information";
264
- return;
265
- }
266
-
267
- if ( ! wp_verify_nonce( $form['_nonce'], $this->client->name ) ) {
268
- $this->error = "You don't have permission to manage license.";
269
- return;
270
- }
271
-
272
- switch ( $form['_action'] ) {
273
- case 'active':
274
- $this->active_client_license( $form );
275
- break;
276
-
277
- case 'deactive':
278
- $this->deactive_client_license( $form );
279
- break;
280
- }
281
- }
282
-
283
- /**
284
- * Check license status on schedule
285
- */
286
- public function check_license_status() {
287
- $license = get_option( $this->option_key, null );
288
-
289
- if ( isset( $license['key'] ) && ! empty( $license['key'] ) ) {
290
- $response = $this->check( $license['key'] );
291
-
292
- if ( isset( $response['success'] ) && $response['success'] ) {
293
- $license['status'] = 'activate';
294
- $license['remaining'] = $response['remaining'];
295
- $license['activation_limit'] = $response['activation_limit'];
296
- $license['expiry_days'] = $response['expiry_days'];
297
- $license['title'] = $response['title'];
298
- $license['source_id'] = $response['source_identifier'];
299
- $license['recurring'] = $response['recurring'];
300
- } else {
301
- $license['status'] = 'deactivate';
302
- $license['expiry_days'] = 0;
303
- }
304
-
305
- update_option( $this->option_key, $license, false );
306
- }
307
- }
308
-
309
- /**
310
- * Check this is a valid license
311
- */
312
- public function is_valid() {
313
- if ( null !== $this->is_valid_licnese ) {
314
- return $this->is_valid_licnese;
315
- }
316
-
317
- $license = get_option( $this->option_key, null );
318
- if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] == 'activate' ) {
319
- $this->is_valid_licnese = true;
320
- } else {
321
- $this->is_valid_licnese = false;
322
- }
323
-
324
- return $this->is_valid_licnese;
325
- }
326
-
327
- /**
328
- * Check this is a valid license
329
- */
330
- public function is_valid_by( $option, $value ) {
331
- $license = get_option( $this->option_key, null );
332
-
333
- if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] == 'activate' ) {
334
- if ( isset( $license[ $option ] ) && $license[ $option ] == $value ) {
335
- return true;
336
- }
337
- }
338
-
339
- return false;
340
- }
341
-
342
- /**
343
- * Styles for licenses page
344
- */
345
- private function licenses_style() {
346
- ?>
347
- <style type="text/css">
348
- .appsero-license-section {
349
- width: 100%;
350
- max-width: 1100px;
351
- min-height: 1px;
352
- box-sizing: border-box;
353
- }
354
- .appsero-license-settings {
355
- background-color: #fff;
356
- box-shadow: 0px 3px 10px rgba(16, 16, 16, 0.05);
357
- }
358
- .appsero-license-settings * {
359
- box-sizing: border-box;
360
- }
361
- .appsero-license-title {
362
- background-color: #F8FAFB;
363
- border-bottom: 2px solid #EAEAEA;
364
- display: flex;
365
- align-items: center;
366
- padding: 10px 20px;
367
- }
368
- .appsero-license-title svg {
369
- width: 30px;
370
- height: 30px;
371
- fill: #0082BF;
372
- }
373
- .appsero-license-title span {
374
- font-size: 17px;
375
- color: #444444;
376
- margin-left: 10px;
377
- }
378
- .appsero-license-details {
379
- padding: 20px;
380
- }
381
- .appsero-license-details p {
382
- font-size: 15px;
383
- margin: 0 0 20px 0;
384
- }
385
- .license-input-key {
386
- position: relative;
387
- flex: 0 0 72%;
388
- max-width: 72%;
389
- }
390
- .license-input-key input {
391
- background-color: #F9F9F9;
392
- padding: 10px 15px 10px 48px;
393
- border: 1px solid #E8E5E5;
394
- border-radius: 3px;
395
- height: 45px;
396
- font-size: 16px;
397
- color: #71777D;
398
- width: 100%;
399
- box-shadow: 0 0 0 transparent;
400
- }
401
- .license-input-key input:focus {
402
- outline: 0 none;
403
- border: 1px solid #E8E5E5;
404
- box-shadow: 0 0 0 transparent;
405
- }
406
- .license-input-key svg {
407
- width: 22px;
408
- height: 22px;
409
- fill: #0082BF;
410
- position: absolute;
411
- left: 14px;
412
- top: 13px;
413
- }
414
- .license-input-fields {
415
- display: flex;
416
- justify-content: space-between;
417
- margin-bottom: 30px;
418
- max-width: 850px;
419
- width: 100%;
420
- }
421
- .license-input-fields button {
422
- color: #fff;
423
- font-size: 17px;
424
- padding: 8px;
425
- height: 46px;
426
- background-color: #0082BF;
427
- border-radius: 3px;
428
- cursor: pointer;
429
- flex: 0 0 25%;
430
- max-width: 25%;
431
- border: 1px solid #0082BF;
432
- }
433
- .license-input-fields button.deactive-button {
434
- background-color: #E40055;
435
- border-color: #E40055;
436
- }
437
- .license-input-fields button:focus {
438
- outline: 0 none;
439
- }
440
- .active-license-info {
441
- display: flex;
442
- }
443
- .single-license-info {
444
- min-width: 220px;
445
- flex: 0 0 30%;
446
- }
447
- .single-license-info h3 {
448
- font-size: 18px;
449
- margin: 0 0 12px 0;
450
- }
451
- .single-license-info p {
452
- margin: 0;
453
- color: #00C000;
454
- }
455
- .single-license-info p.occupied {
456
- color: #E40055;
457
- }
458
- </style>
459
- <?php
460
- }
461
-
462
- /**
463
- * Show active license information
464
- */
465
- private function show_active_license_info( $license ) {
466
- ?>
467
- <div class="active-license-info">
468
- <div class="single-license-info">
469
- <h3>Activation Remaining</h3>
470
- <?php if ( empty( $license['activation_limit'] ) ): ?>
471
- <p>Unlimited</p>
472
- <?php else: ?>
473
- <p class="<?php echo $license['remaining'] ? '' : 'occupied'; ?>">
474
- <?php echo $license['remaining']; ?> out of <?php echo $license['activation_limit']; ?>
475
- </p>
476
- <?php endif; ?>
477
- </div>
478
- <div class="single-license-info">
479
- <h3>Expires in</h3>
480
- <?php
481
- if ( $license['recurring'] && false !== $license['expiry_days'] ) {
482
- $occupied = $license['expiry_days'] > 10 ? '' : 'occupied';
483
- echo '<p class="' . $occupied . '">' . $license['expiry_days'] . ' days</p>';
484
- } else {
485
- echo '<p>Never</p>';
486
- }
487
- ?>
488
- </div>
489
- </div>
490
- <?php
491
- }
492
-
493
- /**
494
- * Show license settings page notices
495
- */
496
- private function show_license_page_notices() {
497
- if ( ! empty( $this->error ) ) :
498
- ?>
499
- <div class="notice notice-error is-dismissible appsero-license-section">
500
- <p><?php echo $this->error; ?></p>
501
- </div>
502
- <?php
503
- endif;
504
- if ( ! empty( $this->success ) ) :
505
- ?>
506
- <div class="notice notice-success is-dismissible appsero-license-section">
507
- <p><?php echo $this->success; ?></p>
508
- </div>
509
- <?php
510
- endif;
511
- echo '<br />';
512
- }
513
-
514
- /**
515
- * Card header
516
- */
517
- private function show_license_page_card_header() {
518
- ?>
519
- <div class="appsero-license-title">
520
- <svg enable-background="new 0 0 299.995 299.995" version="1.1" viewBox="0 0 300 300" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
521
- <path d="m150 161.48c-8.613 0-15.598 6.982-15.598 15.598 0 5.776 3.149 10.807 7.817 13.505v17.341h15.562v-17.341c4.668-2.697 7.817-7.729 7.817-13.505 0-8.616-6.984-15.598-15.598-15.598z"/>
522
- <path d="m150 85.849c-13.111 0-23.775 10.665-23.775 23.775v25.319h47.548v-25.319c-1e-3 -13.108-10.665-23.775-23.773-23.775z"/>
523
- <path d="m150 1e-3c-82.839 0-150 67.158-150 150 0 82.837 67.156 150 150 150s150-67.161 150-150c0-82.839-67.161-150-150-150zm46.09 227.12h-92.173c-9.734 0-17.626-7.892-17.626-17.629v-56.919c0-8.491 6.007-15.582 14.003-17.25v-25.697c0-27.409 22.3-49.711 49.711-49.711 27.409 0 49.709 22.3 49.709 49.711v25.697c7.993 1.673 14 8.759 14 17.25v56.919h2e-3c0 9.736-7.892 17.629-17.626 17.629z"/>
524
- </svg>
525
- <span>Activate License</span>
526
- </div>
527
- <?php
528
- }
529
-
530
- /**
531
- * Active client license
532
- */
533
- private function active_client_license( $form ) {
534
- if ( empty( $form['license_key'] ) ) {
535
- $this->error = 'The license key field is required.';
536
- return;
537
- }
538
-
539
- $license_key = sanitize_text_field( $form['license_key'] );
540
- $response = $this->activate( $license_key );
541
-
542
- if ( ! $response['success'] ) {
543
- $this->error = $response['error'] ? $response['error'] : 'Unknown error occurred.';
544
- return;
545
- }
546
-
547
- $data = array(
548
- 'key' => $license_key,
549
- 'status' => 'activate',
550
- 'remaining' => $response['remaining'],
551
- 'activation_limit' => $response['activation_limit'],
552
- 'expiry_days' => $response['expiry_days'],
553
- 'title' => $response['title'],
554
- 'source_id' => $response['source_identifier'],
555
- 'recurring' => $response['recurring'],
556
- );
557
-
558
- update_option( $this->option_key, $data, false );
559
-
560
- $this->success = 'License activated successfully.';
561
- }
562
-
563
- /**
564
- * Deactive client license
565
- */
566
- private function deactive_client_license( $form ) {
567
- $license = get_option( $this->option_key, null );
568
-
569
- if ( empty( $license['key'] ) ) {
570
- $this->error = 'License key not found.';
571
- return;
572
- }
573
-
574
- $response = $this->deactivate( $license['key'] );
575
-
576
- $data = array(
577
- 'key' => '',
578
- 'status' => 'deactivate',
579
- );
580
-
581
- update_option( $this->option_key, $data, false );
582
-
583
- if ( ! $response['success'] ) {
584
- $this->error = $response['error'] ? $response['error'] : 'Unknown error occurred.';
585
- return;
586
- }
587
-
588
- $this->success = 'License deactivated successfully.';
589
- }
590
-
591
- /**
592
- * Add license menu page
593
- */
594
- private function add_menu_page() {
595
- add_menu_page(
596
- $this->menu_args['page_title'],
597
- $this->menu_args['menu_title'],
598
- $this->menu_args['capability'],
599
- $this->menu_args['menu_slug'],
600
- array( $this, 'menu_output' ),
601
- $this->menu_args['icon_url'],
602
- $this->menu_args['position']
603
- );
604
- }
605
-
606
- /**
607
- * Add submenu page
608
- */
609
- private function add_submenu_page() {
610
- add_submenu_page(
611
- $this->menu_args['parent_slug'],
612
- $this->menu_args['page_title'],
613
- $this->menu_args['menu_title'],
614
- $this->menu_args['capability'],
615
- $this->menu_args['menu_slug'],
616
- array( $this, 'menu_output' ),
617
- $this->menu_args['position']
618
- );
619
- }
620
-
621
- /**
622
- * Add submenu page
623
- */
624
- private function add_options_page() {
625
- add_options_page(
626
- $this->menu_args['page_title'],
627
- $this->menu_args['menu_title'],
628
- $this->menu_args['capability'],
629
- $this->menu_args['menu_slug'],
630
- array( $this, 'menu_output' ),
631
- $this->menu_args['position']
632
- );
633
- }
634
-
635
- /**
636
- * Schedule daily sicense checker event
637
- */
638
- public function schedule_cron_event() {
639
- if ( ! wp_next_scheduled( $this->schedule_hook ) ) {
640
- wp_schedule_event( time(), 'daily', $this->schedule_hook );
641
-
642
- wp_schedule_single_event( time() + 20, $this->schedule_hook );
643
- }
644
- }
645
-
646
- /**
647
- * Clear any scheduled hook
648
- */
649
- public function clear_scheduler() {
650
- wp_clear_scheduled_hook( $this->schedule_hook );
651
- }
652
-
653
- /**
654
- * Enable/Disable schedule
655
- */
656
- private function run_schedule() {
657
- switch ( $this->client->type ) {
658
- case 'plugin':
659
- register_activation_hook( $this->client->file, array( $this, 'schedule_cron_event' ) );
660
- register_deactivation_hook( $this->client->file, array( $this, 'clear_scheduler' ) );
661
- break;
662
-
663
- case 'theme':
664
- add_action( 'after_switch_theme', array( $this, 'schedule_cron_event' ) );
665
- add_action( 'switch_theme', array( $this, 'clear_scheduler' ) );
666
- break;
667
- }
668
- }
669
-
670
- /**
671
- * Form action URL
672
- */
673
- private function formActionUrl() {
674
- echo add_query_arg(
675
- array( 'page' => $_GET['page'] ),
676
- admin_url( basename( $_SERVER['SCRIPT_NAME'] ) )
677
- );
678
- }
679
-
680
- /**
681
- * Get input license key
682
- * @param $action
683
- * @return $license
684
- */
685
- private function get_input_license_value( $action, $license ) {
686
- if ( 'active' == $action ) {
687
- return isset( $license['key'] ) ? $license['key'] : '';
688
- }
689
-
690
- if ( 'deactive' == $action ) {
691
- $key_length = strlen( $license['key'] );
692
-
693
- return str_pad(
694
- substr( $license['key'], 0, $key_length / 2 ), $key_length, '*'
695
- );
696
- }
697
-
698
- return '';
699
- }
700
-
701
- }
 
 
 
 
1
+ <?php
2
+ namespace Happy_Addons\Appsero;
3
+
4
+ /**
5
+ * Appsero License Checker
6
+ *
7
+ * This class will check, active and deactive license
8
+ */
9
+ class License {
10
+
11
+ /**
12
+ * AppSero\Client
13
+ *
14
+ * @var object
15
+ */
16
+ protected $client;
17
+
18
+ /**
19
+ * Arguments of create menu
20
+ *
21
+ * @var array
22
+ */
23
+ protected $menu_args;
24
+
25
+ /**
26
+ * `option_name` of `wp_options` table
27
+ *
28
+ * @var string
29
+ */
30
+ protected $option_key;
31
+
32
+ /**
33
+ * Error message of HTTP request
34
+ *
35
+ * @var string
36
+ */
37
+ public $error;
38
+
39
+ /**
40
+ * Success message on form submit
41
+ *
42
+ * @var string
43
+ */
44
+ public $success;
45
+
46
+ /**
47
+ * Corn schedule hook name
48
+ *
49
+ * @var string
50
+ */
51
+ protected $schedule_hook;
52
+
53
+ /**
54
+ * Set value for valid licnese
55
+ *
56
+ * @var boolean
57
+ */
58
+ private $is_valid_licnese = null;
59
+
60
+ /**
61
+ * Initialize the class
62
+ *
63
+ * @param Happy_Addons\Appsero\Client
64
+ */
65
+ public function __construct( Client $client ) {
66
+ $this->client = $client;
67
+
68
+ $this->option_key = 'appsero_' . md5( $this->client->slug ) . '_manage_license';
69
+
70
+ $this->schedule_hook = $this->client->slug . '_license_check_event';
71
+
72
+ // Run hook to check license status daily
73
+ add_action( $this->schedule_hook, array( $this, 'check_license_status' ) );
74
+
75
+ // Active/Deactive corn schedule
76
+ $this->run_schedule();
77
+ }
78
+
79
+ /**
80
+ * Check license
81
+ *
82
+ * @return boolean
83
+ */
84
+ public function check( $license_key ) {
85
+ $route = 'public/license/' . $this->client->hash . '/check';
86
+
87
+ return $this->send_request( $license_key, $route );
88
+ }
89
+
90
+ /**
91
+ * Active a license
92
+ *
93
+ * @return boolean
94
+ */
95
+ public function activate( $license_key ) {
96
+ $route = 'public/license/' . $this->client->hash . '/activate';
97
+
98
+ return $this->send_request( $license_key, $route );
99
+ }
100
+
101
+ /**
102
+ * Deactivate a license
103
+ *
104
+ * @return boolean
105
+ */
106
+ public function deactivate( $license_key ) {
107
+ $route = 'public/license/' . $this->client->hash . '/deactivate';
108
+
109
+ return $this->send_request( $license_key, $route );
110
+ }
111
+
112
+ /**
113
+ * Send common request
114
+ *
115
+ * @param $license_key
116
+ * @param $route
117
+ *
118
+ * @return array
119
+ */
120
+ protected function send_request( $license_key, $route ) {
121
+ $params = array(
122
+ 'license_key' => $license_key,
123
+ 'url' => esc_url( home_url() ),
124
+ 'is_local' => $this->client->is_local_server(),
125
+ );
126
+
127
+ $response = $this->client->send_request( $params, $route, true );
128
+
129
+ if ( is_wp_error( $response ) ) {
130
+ return array(
131
+ 'success' => false,
132
+ 'error' => $response->get_error_message()
133
+ );
134
+ }
135
+
136
+ $response = json_decode( wp_remote_retrieve_body( $response ), true );
137
+
138
+ if ( empty( $response ) || isset( $response['exception'] )) {
139
+ return array(
140
+ 'success' => false,
141
+ 'error' => 'Unknown error occurred, Please try again.'
142
+ );
143
+ }
144
+
145
+ if ( isset( $response['errors'] ) && isset( $response['errors']['license_key'] ) ) {
146
+ $response = array(
147
+ 'success' => false,
148
+ 'error' => $response['errors']['license_key'][0]
149
+ );
150
+ }
151
+
152
+ return $response;
153
+ }
154
+
155
+ /**
156
+ * Add settings page for license
157
+ *
158
+ * @param array $args
159
+ *
160
+ * @return void
161
+ */
162
+ public function add_settings_page( $args = array() ) {
163
+ $defaults = array(
164
+ 'type' => 'menu', // Can be: menu, options, submenu
165
+ 'page_title' => 'Manage License',
166
+ 'menu_title' => 'Manage License',
167
+ 'capability' => 'manage_options',
168
+ 'menu_slug' => $this->client->slug . '-manage-license',
169
+ 'icon_url' => '',
170
+ 'position' => null,
171
+ 'parent_slug' => '',
172
+ );
173
+
174
+ $this->menu_args = wp_parse_args( $args, $defaults );
175
+
176
+ add_action( 'admin_menu', array( $this, 'admin_menu' ), 99 );
177
+ }
178
+
179
+ /**
180
+ * Admin Menu hook
181
+ *
182
+ * @return void
183
+ */
184
+ public function admin_menu() {
185
+ switch ( $this->menu_args['type'] ) {
186
+ case 'menu':
187
+ $this->create_menu_page();
188
+ break;
189
+
190
+ case 'submenu':
191
+ $this->create_submenu_page();
192
+ break;
193
+
194
+ case 'options':
195
+ $this->create_options_page();
196
+ break;
197
+ }
198
+ }
199
+
200
+ /**
201
+ * License menu output
202
+ */
203
+ public function menu_output() {
204
+
205
+ if ( isset( $_POST['submit'] ) ) {
206
+ $this->license_form_submit( $_POST );
207
+ }
208
+
209
+ $license = get_option( $this->option_key, null );
210
+ $action = ( $license && isset( $license['status'] ) && 'activate' == $license['status'] ) ? 'deactive' : 'active';
211
+ $this->licenses_style();
212
+ ?>
213
+
214
+ <div class="wrap appsero-license-settings-wrapper">
215
+ <h1>License Settings</h1>
216
+
217
+ <?php
218
+ $this->show_license_page_notices();
219
+ do_action( 'before_appsero_license_section' );
220
+ ?>
221
+
222
+ <div class="appsero-license-settings appsero-license-section">
223
+ <?php $this->show_license_page_card_header(); ?>
224
+
225
+ <div class="appsero-license-details">
226
+ <p>Activate <strong><?php echo $this->client->name; ?></strong> by your license key to get professional support and automatic update from your WordPress dashboard.</p>
227
+ <form method="post" action="<?php $this->formActionUrl(); ?>" novalidate="novalidate" spellcheck="false">
228
+ <input type="hidden" name="_action" value="<?php echo $action; ?>">
229
+ <input type="hidden" name="_nonce" value="<?php echo wp_create_nonce( $this->client->name ); ?>">
230
+ <div class="license-input-fields">
231
+ <div class="license-input-key">
232
+ <svg enable-background="new 0 0 512 512" version="1.1" viewBox="0 0 512 512" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
233
+ <path d="m463.75 48.251c-64.336-64.336-169.01-64.335-233.35 1e-3 -43.945 43.945-59.209 108.71-40.181 167.46l-185.82 185.82c-2.813 2.813-4.395 6.621-4.395 10.606v84.858c0 8.291 6.709 15 15 15h84.858c3.984 0 7.793-1.582 10.605-4.395l21.211-21.226c3.237-3.237 4.819-7.778 4.292-12.334l-2.637-22.793 31.582-2.974c7.178-0.674 12.847-6.343 13.521-13.521l2.974-31.582 22.793 2.651c4.233 0.571 8.496-0.85 11.704-3.691 3.193-2.856 5.024-6.929 5.024-11.206v-27.929h27.422c3.984 0 7.793-1.582 10.605-4.395l38.467-37.958c58.74 19.043 122.38 4.929 166.33-39.046 64.336-64.335 64.336-169.01 0-233.35zm-42.435 106.07c-17.549 17.549-46.084 17.549-63.633 0s-17.549-46.084 0-63.633 46.084-17.549 63.633 0 17.548 46.084 0 63.633z"/>
234
+ </svg>
235
+ <input type="text" value="<?php echo $this->get_input_license_value( $action, $license ); ?>"
236
+ placeholder="Enter your license key to activate" name="license_key"
237
+ <?php echo ( 'deactive' == $action ) ? 'readonly="readonly"' : ''; ?>
238
+ />
239
+ </div>
240
+ <button type="submit" name="submit" class="<?php echo 'deactive' == $action ? 'deactive-button' : ''; ?>">
241
+ <?php echo $action == 'active' ? 'Activate License' : 'Deactivate License' ; ?>
242
+ </button>
243
+ </div>
244
+ </form>
245
+
246
+ <?php
247
+ if ( 'deactive' == $action && isset( $license['remaining'] ) ) {
248
+ $this->show_active_license_info( $license );
249
+ }
250
+ ?>
251
+ </div>
252
+ </div> <!-- /.appsero-license-settings -->
253
+
254
+ <?php do_action( 'after_appsero_license_section' ); ?>
255
+ </div>
256
+ <?php
257
+ }
258
+
259
+ /**
260
+ * License form submit
261
+ */
262
+ public function license_form_submit( $form ) {
263
+ if ( ! isset( $form['_nonce'], $form['_action'] ) ) {
264
+ $this->error = "Please add all information";
265
+ return;
266
+ }
267
+
268
+ if ( ! wp_verify_nonce( $form['_nonce'], $this->client->name ) ) {
269
+ $this->error = "You don't have permission to manage license.";
270
+ return;
271
+ }
272
+
273
+ switch ( $form['_action'] ) {
274
+ case 'active':
275
+ $this->active_client_license( $form );
276
+ break;
277
+
278
+ case 'deactive':
279
+ $this->deactive_client_license( $form );
280
+ break;
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Check license status on schedule
286
+ */
287
+ public function check_license_status() {
288
+ $license = get_option( $this->option_key, null );
289
+
290
+ if ( isset( $license['key'] ) && ! empty( $license['key'] ) ) {
291
+ $response = $this->check( $license['key'] );
292
+
293
+ if ( isset( $response['success'] ) && $response['success'] ) {
294
+ $license['status'] = 'activate';
295
+ $license['remaining'] = $response['remaining'];
296
+ $license['activation_limit'] = $response['activation_limit'];
297
+ $license['expiry_days'] = $response['expiry_days'];
298
+ $license['title'] = $response['title'];
299
+ $license['source_id'] = $response['source_identifier'];
300
+ $license['recurring'] = $response['recurring'];
301
+ } else {
302
+ $license['status'] = 'deactivate';
303
+ $license['expiry_days'] = 0;
304
+ }
305
+
306
+ update_option( $this->option_key, $license, false );
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Check this is a valid license
312
+ */
313
+ public function is_valid() {
314
+ if ( null !== $this->is_valid_licnese ) {
315
+ return $this->is_valid_licnese;
316
+ }
317
+
318
+ $license = get_option( $this->option_key, null );
319
+ if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] == 'activate' ) {
320
+ $this->is_valid_licnese = true;
321
+ } else {
322
+ $this->is_valid_licnese = false;
323
+ }
324
+
325
+ return $this->is_valid_licnese;
326
+ }
327
+
328
+ /**
329
+ * Check this is a valid license
330
+ */
331
+ public function is_valid_by( $option, $value ) {
332
+ $license = get_option( $this->option_key, null );
333
+
334
+ if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] == 'activate' ) {
335
+ if ( isset( $license[ $option ] ) && $license[ $option ] == $value ) {
336
+ return true;
337
+ }
338
+ }
339
+
340
+ return false;
341
+ }
342
+
343
+ /**
344
+ * Styles for licenses page
345
+ */
346
+ private function licenses_style() {
347
+ ?>
348
+ <style type="text/css">
349
+ .appsero-license-section {
350
+ width: 100%;
351
+ max-width: 1100px;
352
+ min-height: 1px;
353
+ box-sizing: border-box;
354
+ }
355
+ .appsero-license-settings {
356
+ background-color: #fff;
357
+ box-shadow: 0px 3px 10px rgba(16, 16, 16, 0.05);
358
+ }
359
+ .appsero-license-settings * {
360
+ box-sizing: border-box;
361
+ }
362
+ .appsero-license-title {
363
+ background-color: #F8FAFB;
364
+ border-bottom: 2px solid #EAEAEA;
365
+ display: flex;
366
+ align-items: center;
367
+ padding: 10px 20px;
368
+ }
369
+ .appsero-license-title svg {
370
+ width: 30px;
371
+ height: 30px;
372
+ fill: #0082BF;
373
+ }
374
+ .appsero-license-title span {
375
+ font-size: 17px;
376
+ color: #444444;
377
+ margin-left: 10px;
378
+ }
379
+ .appsero-license-details {
380
+ padding: 20px;
381
+ }
382
+ .appsero-license-details p {
383
+ font-size: 15px;
384
+ margin: 0 0 20px 0;
385
+ }
386
+ .license-input-key {
387
+ position: relative;
388
+ flex: 0 0 72%;
389
+ max-width: 72%;
390
+ }
391
+ .license-input-key input {
392
+ background-color: #F9F9F9;
393
+ padding: 10px 15px 10px 48px;
394
+ border: 1px solid #E8E5E5;
395
+ border-radius: 3px;
396
+ height: 45px;
397
+ font-size: 16px;
398
+ color: #71777D;
399
+ width: 100%;
400
+ box-shadow: 0 0 0 transparent;
401
+ }
402
+ .license-input-key input:focus {
403
+ outline: 0 none;
404
+ border: 1px solid #E8E5E5;
405
+ box-shadow: 0 0 0 transparent;
406
+ }
407
+ .license-input-key svg {
408
+ width: 22px;
409
+ height: 22px;
410
+ fill: #0082BF;
411
+ position: absolute;
412
+ left: 14px;
413
+ top: 13px;
414
+ }
415
+ .license-input-fields {
416
+ display: flex;
417
+ justify-content: space-between;
418
+ margin-bottom: 30px;
419
+ max-width: 850px;
420
+ width: 100%;
421
+ }
422
+ .license-input-fields button {
423
+ color: #fff;
424
+ font-size: 17px;
425
+ padding: 8px;
426
+ height: 46px;
427
+ background-color: #0082BF;
428
+ border-radius: 3px;
429
+ cursor: pointer;
430
+ flex: 0 0 25%;
431
+ max-width: 25%;
432
+ border: 1px solid #0082BF;
433
+ }
434
+ .license-input-fields button.deactive-button {
435
+ background-color: #E40055;
436
+ border-color: #E40055;
437
+ }
438
+ .license-input-fields button:focus {
439
+ outline: 0 none;
440
+ }
441
+ .active-license-info {
442
+ display: flex;
443
+ }
444
+ .single-license-info {
445
+ min-width: 220px;
446
+ flex: 0 0 30%;
447
+ }
448
+ .single-license-info h3 {
449
+ font-size: 18px;
450
+ margin: 0 0 12px 0;
451
+ }
452
+ .single-license-info p {
453
+ margin: 0;
454
+ color: #00C000;
455
+ }
456
+ .single-license-info p.occupied {
457
+ color: #E40055;
458
+ }
459
+ </style>
460
+ <?php
461
+ }
462
+
463
+ /**
464
+ * Show active license information
465
+ */
466
+ private function show_active_license_info( $license ) {
467
+ ?>
468
+ <div class="active-license-info">
469
+ <div class="single-license-info">
470
+ <h3>Activation Remaining</h3>
471
+ <?php if ( empty( $license['activation_limit'] ) ): ?>
472
+ <p>Unlimited</p>
473
+ <?php else: ?>
474
+ <p class="<?php echo $license['remaining'] ? '' : 'occupied'; ?>">
475
+ <?php echo $license['remaining']; ?> out of <?php echo $license['activation_limit']; ?>
476
+ </p>
477
+ <?php endif; ?>
478
+ </div>
479
+ <div class="single-license-info">
480
+ <h3>Expires in</h3>
481
+ <?php
482
+ if ( $license['recurring'] && false !== $license['expiry_days'] ) {
483
+ $occupied = $license['expiry_days'] > 10 ? '' : 'occupied';
484
+ echo '<p class="' . $occupied . '">' . $license['expiry_days'] . ' days</p>';
485
+ } else {
486
+ echo '<p>Never</p>';
487
+ }
488
+ ?>
489
+ </div>
490
+ </div>
491
+ <?php
492
+ }
493
+
494
+ /**
495
+ * Show license settings page notices
496
+ */
497
+ private function show_license_page_notices() {
498
+ if ( ! empty( $this->error ) ) :
499
+ ?>
500
+ <div class="notice notice-error is-dismissible appsero-license-section">
501
+ <p><?php echo $this->error; ?></p>
502
+ </div>
503
+ <?php
504
+ endif;
505
+ if ( ! empty( $this->success ) ) :
506
+ ?>
507
+ <div class="notice notice-success is-dismissible appsero-license-section">
508
+ <p><?php echo $this->success; ?></p>
509
+ </div>
510
+ <?php
511
+ endif;
512
+ echo '<br />';
513
+ }
514
+
515
+ /**
516
+ * Card header
517
+ */
518
+ private function show_license_page_card_header() {
519
+ ?>
520
+ <div class="appsero-license-title">
521
+ <svg enable-background="new 0 0 299.995 299.995" version="1.1" viewBox="0 0 300 300" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
522
+ <path d="m150 161.48c-8.613 0-15.598 6.982-15.598 15.598 0 5.776 3.149 10.807 7.817 13.505v17.341h15.562v-17.341c4.668-2.697 7.817-7.729 7.817-13.505 0-8.616-6.984-15.598-15.598-15.598z"/>
523
+ <path d="m150 85.849c-13.111 0-23.775 10.665-23.775 23.775v25.319h47.548v-25.319c-1e-3 -13.108-10.665-23.775-23.773-23.775z"/>
524
+ <path d="m150 1e-3c-82.839 0-150 67.158-150 150 0 82.837 67.156 150 150 150s150-67.161 150-150c0-82.839-67.161-150-150-150zm46.09 227.12h-92.173c-9.734 0-17.626-7.892-17.626-17.629v-56.919c0-8.491 6.007-15.582 14.003-17.25v-25.697c0-27.409 22.3-49.711 49.711-49.711 27.409 0 49.709 22.3 49.709 49.711v25.697c7.993 1.673 14 8.759 14 17.25v56.919h2e-3c0 9.736-7.892 17.629-17.626 17.629z"/>
525
+ </svg>
526
+ <span>Activate License</span>
527
+ </div>
528
+ <?php
529
+ }
530
+
531
+ /**
532
+ * Active client license
533
+ */
534
+ private function active_client_license( $form ) {
535
+ if ( empty( $form['license_key'] ) ) {
536
+ $this->error = 'The license key field is required.';
537
+ return;
538
+ }
539
+
540
+ $license_key = sanitize_text_field( $form['license_key'] );
541
+ $response = $this->activate( $license_key );
542
+
543
+ if ( ! $response['success'] ) {
544
+ $this->error = $response['error'] ? $response['error'] : 'Unknown error occurred.';
545
+ return;
546
+ }
547
+
548
+ $data = array(
549
+ 'key' => $license_key,
550
+ 'status' => 'activate',
551
+ 'remaining' => $response['remaining'],
552
+ 'activation_limit' => $response['activation_limit'],
553
+ 'expiry_days' => $response['expiry_days'],
554
+ 'title' => $response['title'],
555
+ 'source_id' => $response['source_identifier'],
556
+ 'recurring' => $response['recurring'],
557
+ );
558
+
559
+ update_option( $this->option_key, $data, false );
560
+
561
+ $this->success = 'License activated successfully.';
562
+ }
563
+
564
+ /**
565
+ * Deactive client license
566
+ */
567
+ private function deactive_client_license( $form ) {
568
+ $license = get_option( $this->option_key, null );
569
+
570
+ if ( empty( $license['key'] ) ) {
571
+ $this->error = 'License key not found.';
572
+ return;
573
+ }
574
+
575
+ $response = $this->deactivate( $license['key'] );
576
+
577
+ $data = array(
578
+ 'key' => '',
579
+ 'status' => 'deactivate',
580
+ );
581
+
582
+ update_option( $this->option_key, $data, false );
583
+
584
+ if ( ! $response['success'] ) {
585
+ $this->error = $response['error'] ? $response['error'] : 'Unknown error occurred.';
586
+ return;
587
+ }
588
+
589
+ $this->success = 'License deactivated successfully.';
590
+ }
591
+
592
+ /**
593
+ * Add license menu page
594
+ */
595
+ private function create_menu_page() {
596
+ call_user_func(
597
+ 'add_' . 'menu' . '_page',
598
+ $this->menu_args['page_title'],
599
+ $this->menu_args['menu_title'],
600
+ $this->menu_args['capability'],
601
+ $this->menu_args['menu_slug'],
602
+ array( $this, 'menu_output' ),
603
+ $this->menu_args['icon_url'],
604
+ $this->menu_args['position']
605
+ );
606
+ }
607
+
608
+ /**
609
+ * Add submenu page
610
+ */
611
+ private function create_submenu_page() {
612
+ call_user_func(
613
+ 'add_' . 'submenu' . '_page',
614
+ $this->menu_args['parent_slug'],
615
+ $this->menu_args['page_title'],
616
+ $this->menu_args['menu_title'],
617
+ $this->menu_args['capability'],
618
+ $this->menu_args['menu_slug'],
619
+ array( $this, 'menu_output' ),
620
+ $this->menu_args['position']
621
+ );
622
+ }
623
+
624
+ /**
625
+ * Add submenu page
626
+ */
627
+ private function create_options_page() {
628
+ call_user_func(
629
+ 'add_' . 'options' . '_page',
630
+ $this->menu_args['page_title'],
631
+ $this->menu_args['menu_title'],
632
+ $this->menu_args['capability'],
633
+ $this->menu_args['menu_slug'],
634
+ array( $this, 'menu_output' ),
635
+ $this->menu_args['position']
636
+ );
637
+ }
638
+
639
+ /**
640
+ * Schedule daily sicense checker event
641
+ */
642
+ public function schedule_cron_event() {
643
+ if ( ! wp_next_scheduled( $this->schedule_hook ) ) {
644
+ wp_schedule_event( time(), 'daily', $this->schedule_hook );
645
+
646
+ wp_schedule_single_event( time() + 20, $this->schedule_hook );
647
+ }
648
+ }
649
+
650
+ /**
651
+ * Clear any scheduled hook
652
+ */
653
+ public function clear_scheduler() {
654
+ wp_clear_scheduled_hook( $this->schedule_hook );
655
+ }
656
+
657
+ /**
658
+ * Enable/Disable schedule
659
+ */
660
+ private function run_schedule() {
661
+ switch ( $this->client->type ) {
662
+ case 'plugin':
663
+ register_activation_hook( $this->client->file, array( $this, 'schedule_cron_event' ) );
664
+ register_deactivation_hook( $this->client->file, array( $this, 'clear_scheduler' ) );
665
+ break;
666
+
667
+ case 'theme':
668
+ add_action( 'after_switch_theme', array( $this, 'schedule_cron_event' ) );
669
+ add_action( 'switch_theme', array( $this, 'clear_scheduler' ) );
670
+ break;
671
+ }
672
+ }
673
+
674
+ /**
675
+ * Form action URL
676
+ */
677
+ private function formActionUrl() {
678
+ echo add_query_arg(
679
+ array( 'page' => $_GET['page'] ),
680
+ admin_url( basename( $_SERVER['SCRIPT_NAME'] ) )
681
+ );
682
+ }
683
+
684
+ /**
685
+ * Get input license key
686
+ * @param $action
687
+ * @return $license
688
+ */
689
+ private function get_input_license_value( $action, $license ) {
690
+ if ( 'active' == $action ) {
691
+ return isset( $license['key'] ) ? $license['key'] : '';
692
+ }
693
+
694
+ if ( 'deactive' == $action ) {
695
+ $key_length = strlen( $license['key'] );
696
+
697
+ return str_pad(
698
+ substr( $license['key'], 0, $key_length / 2 ), $key_length, '*'
699
+ );
700
+ }
701
+
702
+ return '';
703
+ }
704
+
705
+ }
vendor/appsero/src/Updater.php CHANGED
@@ -1,247 +1,259 @@
1
- <?php
2
- namespace Happy_Addons\Appsero;
3
-
4
- /**
5
- * Appsero Updater
6
- *
7
- * This class will show new updates project
8
- */
9
- class Updater {
10
-
11
- /**
12
- * Appsero\Client
13
- *
14
- * @var object
15
- */
16
- protected $client;
17
-
18
- /**
19
- * Initialize the class
20
- *
21
- * @param Happy_Addons\Appsero\Client
22
- */
23
- public function __construct( Client $client ) {
24
-
25
- $this->client = $client;
26
- $this->cache_key = 'appsero_' . md5( $this->client->slug ) . '_version_info';
27
-
28
- // Run hooks.
29
- if ( $this->client->type == 'plugin' ) {
30
- $this->run_plugin_hooks();
31
- } elseif ( $this->client->type == 'theme' ) {
32
- $this->run_theme_hooks();
33
- }
34
- }
35
-
36
- /**
37
- * Set up WordPress filter to hooks to get update.
38
- *
39
- * @return void
40
- */
41
- public function run_plugin_hooks() {
42
- add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_plugin_update' ) );
43
- add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
44
- }
45
-
46
- /**
47
- * Set up WordPress filter to hooks to get update.
48
- *
49
- * @return void
50
- */
51
- public function run_theme_hooks() {
52
- add_filter( 'pre_set_site_transient_update_themes', array( $this, 'check_theme_update' ) );
53
- }
54
-
55
- /**
56
- * Check for Update for this specific project
57
- */
58
- public function check_plugin_update( $transient_data ) {
59
- global $pagenow;
60
-
61
- if ( ! is_object( $transient_data ) ) {
62
- $transient_data = new \stdClass;
63
- }
64
-
65
- if ( 'plugins.php' == $pagenow && is_multisite() ) {
66
- return $transient_data;
67
- }
68
-
69
- if ( ! empty( $transient_data->response ) && ! empty( $transient_data->response[ $this->client->basename ] ) ) {
70
- return $transient_data;
71
- }
72
-
73
- $version_info = $this->get_cached_version_info();
74
-
75
- if ( false === $version_info ) {
76
- $version_info = $this->get_project_latest_version();
77
- $this->set_cached_version_info( $version_info );
78
- }
79
-
80
- if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
81
-
82
- if ( version_compare( $this->client->project_version, $version_info->new_version, '<' ) ) {
83
- unset( $version_info->sections );
84
- $transient_data->response[ $this->client->basename ] = $version_info;
85
- }
86
-
87
- $transient_data->last_checked = time();
88
- $transient_data->checked[ $this->client->basename ] = $this->client->project_version;
89
- }
90
-
91
- return $transient_data;
92
- }
93
-
94
- /**
95
- * Get version info from database
96
- *
97
- * @return Object or Boolean
98
- */
99
- private function get_cached_version_info() {
100
-
101
- $value = get_transient( $this->cache_key );
102
-
103
- if( ! $value && ! isset( $value->name ) ) {
104
- return false; // Cache is expired
105
- }
106
-
107
- // We need to turn the icons into an array
108
- if ( isset( $value->icons ) ) {
109
- $value->icons = (array) $value->icons;
110
- }
111
-
112
- // We need to turn the banners into an array
113
- if ( isset( $value->banners ) ) {
114
- $value->banners = (array) $value->banners;
115
- }
116
-
117
- if ( isset( $value->sections ) ) {
118
- $value->sections = (array) $value->sections;
119
- }
120
-
121
- return $value;
122
- }
123
-
124
- /**
125
- * Set version info to database
126
- */
127
- private function set_cached_version_info( $value ) {
128
- if ( ! $value ) {
129
- return;
130
- }
131
-
132
- set_transient( $this->cache_key, $value, 3 * HOUR_IN_SECONDS );
133
- }
134
-
135
- /**
136
- * Get plugin info from Appsero
137
- */
138
- private function get_project_latest_version() {
139
-
140
- $license_option_key = 'appsero_' . md5( $this->client->slug ) . '_manage_license';
141
- $license = get_option( $license_option_key, null );
142
-
143
- $params = array(
144
- 'version' => $this->client->project_version,
145
- 'name' => $this->client->name,
146
- 'slug' => $this->client->slug,
147
- 'basename' => $this->client->basename,
148
- 'license_key' => ! empty( $license ) && isset( $license['key'] ) ? $license['key'] : '',
149
- );
150
-
151
- $route = 'update/' . $this->client->hash . '/check';
152
-
153
- $response = $this->client->send_request( $params, $route, true );
154
-
155
- if ( is_wp_error( $response ) ) {
156
- return false;
157
- }
158
-
159
- $response = json_decode( wp_remote_retrieve_body( $response ) );
160
-
161
- if ( ! isset( $response->slug ) ) {
162
- return false;
163
- }
164
-
165
- if ( isset( $response->icons ) ) {
166
- $response->icons = (array) $response->icons;
167
- }
168
-
169
- if ( isset( $response->banners ) ) {
170
- $response->banners = (array) $response->banners;
171
- }
172
-
173
- if ( isset( $response->sections ) ) {
174
- $response->sections = (array) $response->sections;
175
- }
176
-
177
- return $response;
178
- }
179
-
180
- /**
181
- * Updates information on the "View version x.x details" page with custom data.
182
- *
183
- * @param mixed $data
184
- * @param string $action
185
- * @param object $args
186
- *
187
- * @return object $data
188
- */
189
- public function plugins_api_filter( $data, $action = '', $args = null ) {
190
-
191
- if ( $action != 'plugin_information' ) {
192
- return $data;
193
- }
194
-
195
- if ( ! isset( $args->slug ) || ( $args->slug != $this->client->slug ) ) {
196
- return $data;
197
- }
198
-
199
- $version_info = $this->get_cached_version_info();
200
-
201
- if ( false === $version_info ) {
202
- $version_info = $this->get_project_latest_version();
203
- $this->set_cached_version_info( $version_info );
204
- }
205
-
206
- return $version_info;
207
- }
208
-
209
- /**
210
- * Check theme upate
211
- */
212
- public function check_theme_update( $transient_data ) {
213
- global $pagenow;
214
-
215
- if ( ! is_object( $transient_data ) ) {
216
- $transient_data = new \stdClass;
217
- }
218
-
219
- if ( 'themes.php' == $pagenow && is_multisite() ) {
220
- return $transient_data;
221
- }
222
-
223
- if ( ! empty( $transient_data->response ) && ! empty( $transient_data->response[ $this->client->slug ] ) ) {
224
- return $transient_data;
225
- }
226
-
227
- $version_info = $this->get_cached_version_info();
228
-
229
- if ( false === $version_info ) {
230
- $version_info = $this->get_project_latest_version();
231
- $this->set_cached_version_info( $version_info );
232
- }
233
-
234
- if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
235
-
236
- if ( version_compare( $this->client->project_version, $version_info->new_version, '<' ) ) {
237
- $transient_data->response[ $this->client->slug ] = (array) $version_info;
238
- }
239
-
240
- $transient_data->last_checked = time();
241
- $transient_data->checked[ $this->client->slug ] = $this->client->project_version;
242
- }
243
-
244
- return $transient_data;
245
- }
246
-
247
- }
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Happy_Addons\Appsero;
3
+
4
+ /**
5
+ * Appsero Updater
6
+ *
7
+ * This class will show new updates project
8
+ */
9
+ class Updater {
10
+
11
+ /**
12
+ * Appsero\Client
13
+ *
14
+ * @var object
15
+ */
16
+ protected $client;
17
+
18
+ /**
19
+ * Initialize the class
20
+ *
21
+ * @param Happy_Addons\Appsero\Client
22
+ */
23
+ public function __construct( Client $client ) {
24
+
25
+ $this->client = $client;
26
+ $this->cache_key = 'appsero_' . md5( $this->client->slug ) . '_version_info';
27
+
28
+ // Run hooks.
29
+ if ( $this->client->type == 'plugin' ) {
30
+ $this->run_plugin_hooks();
31
+ } elseif ( $this->client->type == 'theme' ) {
32
+ $this->run_theme_hooks();
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Set up WordPress filter to hooks to get update.
38
+ *
39
+ * @return void
40
+ */
41
+ public function run_plugin_hooks() {
42
+ add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_plugin_update' ) );
43
+ add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
44
+ }
45
+
46
+ /**
47
+ * Set up WordPress filter to hooks to get update.
48
+ *
49
+ * @return void
50
+ */
51
+ public function run_theme_hooks() {
52
+ add_filter( 'pre_set_site_transient_update_themes', array( $this, 'check_theme_update' ) );
53
+ }
54
+
55
+ /**
56
+ * Check for Update for this specific project
57
+ */
58
+ public function check_plugin_update( $transient_data ) {
59
+ global $pagenow;
60
+
61
+ if ( ! is_object( $transient_data ) ) {
62
+ $transient_data = new \stdClass;
63
+ }
64
+
65
+ if ( 'plugins.php' == $pagenow && is_multisite() ) {
66
+ return $transient_data;
67
+ }
68
+
69
+ if ( ! empty( $transient_data->response ) && ! empty( $transient_data->response[ $this->client->basename ] ) ) {
70
+ return $transient_data;
71
+ }
72
+
73
+ $version_info = $this->get_version_info();
74
+
75
+ if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
76
+
77
+ unset( $version_info->sections );
78
+
79
+ // If new version available then set to `response`
80
+ if ( version_compare( $this->client->project_version, $version_info->new_version, '<' ) ) {
81
+ $transient_data->response[ $this->client->basename ] = $version_info;
82
+ } else {
83
+ // If new version is not available then set to `no_update`
84
+ $transient_data->no_update[ $this->client->basename ] = $version_info;
85
+ }
86
+
87
+ $transient_data->last_checked = time();
88
+ $transient_data->checked[ $this->client->basename ] = $this->client->project_version;
89
+ }
90
+
91
+ return $transient_data;
92
+ }
93
+
94
+ /**
95
+ * Get version info from database
96
+ *
97
+ * @return Object or Boolean
98
+ */
99
+ private function get_cached_version_info() {
100
+ global $pagenow;
101
+
102
+ // If updater page then fetch from API now
103
+ if ( 'update-core.php' == $pagenow ) {
104
+ return false; // Force to fetch data
105
+ }
106
+
107
+ $value = get_transient( $this->cache_key );
108
+
109
+ if( ! $value && ! isset( $value->name ) ) {
110
+ return false; // Cache is expired
111
+ }
112
+
113
+ // We need to turn the icons into an array
114
+ if ( isset( $value->icons ) ) {
115
+ $value->icons = (array) $value->icons;
116
+ }
117
+
118
+ // We need to turn the banners into an array
119
+ if ( isset( $value->banners ) ) {
120
+ $value->banners = (array) $value->banners;
121
+ }
122
+
123
+ if ( isset( $value->sections ) ) {
124
+ $value->sections = (array) $value->sections;
125
+ }
126
+
127
+ return $value;
128
+ }
129
+
130
+ /**
131
+ * Set version info to database
132
+ */
133
+ private function set_cached_version_info( $value ) {
134
+ if ( ! $value ) {
135
+ return;
136
+ }
137
+
138
+ set_transient( $this->cache_key, $value, 3 * HOUR_IN_SECONDS );
139
+ }
140
+
141
+ /**
142
+ * Get plugin info from Appsero
143
+ */
144
+ private function get_project_latest_version() {
145
+
146
+ $license_option_key = 'appsero_' . md5( $this->client->slug ) . '_manage_license';
147
+ $license = get_option( $license_option_key, null );
148
+
149
+ $params = array(
150
+ 'version' => $this->client->project_version,
151
+ 'name' => $this->client->name,
152
+ 'slug' => $this->client->slug,
153
+ 'basename' => $this->client->basename,
154
+ 'license_key' => ! empty( $license ) && isset( $license['key'] ) ? $license['key'] : '',
155
+ );
156
+
157
+ $route = 'update/' . $this->client->hash . '/check';
158
+
159
+ $response = $this->client->send_request( $params, $route, true );
160
+
161
+ if ( is_wp_error( $response ) ) {
162
+ return false;
163
+ }
164
+
165
+ $response = json_decode( wp_remote_retrieve_body( $response ) );
166
+
167
+ if ( ! isset( $response->slug ) ) {
168
+ return false;
169
+ }
170
+
171
+ if ( isset( $response->icons ) ) {
172
+ $response->icons = (array) $response->icons;
173
+ }
174
+
175
+ if ( isset( $response->banners ) ) {
176
+ $response->banners = (array) $response->banners;
177
+ }
178
+
179
+ if ( isset( $response->sections ) ) {
180
+ $response->sections = (array) $response->sections;
181
+ }
182
+
183
+ return $response;
184
+ }
185
+
186
+ /**
187
+ * Updates information on the "View version x.x details" page with custom data.
188
+ *
189
+ * @param mixed $data
190
+ * @param string $action
191
+ * @param object $args
192
+ *
193
+ * @return object $data
194
+ */
195
+ public function plugins_api_filter( $data, $action = '', $args = null ) {
196
+
197
+ if ( $action != 'plugin_information' ) {
198
+ return $data;
199
+ }
200
+
201
+ if ( ! isset( $args->slug ) || ( $args->slug != $this->client->slug ) ) {
202
+ return $data;
203
+ }
204
+
205
+ return $this->get_version_info();
206
+ }
207
+
208
+ /**
209
+ * Check theme upate
210
+ */
211
+ public function check_theme_update( $transient_data ) {
212
+ global $pagenow;
213
+
214
+ if ( ! is_object( $transient_data ) ) {
215
+ $transient_data = new \stdClass;
216
+ }
217
+
218
+ if ( 'themes.php' == $pagenow && is_multisite() ) {
219
+ return $transient_data;
220
+ }
221
+
222
+ if ( ! empty( $transient_data->response ) && ! empty( $transient_data->response[ $this->client->slug ] ) ) {
223
+ return $transient_data;
224
+ }
225
+
226
+ $version_info = $this->get_version_info();
227
+
228
+ if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
229
+
230
+ // If new version available then set to `response`
231
+ if ( version_compare( $this->client->project_version, $version_info->new_version, '<' ) ) {
232
+ $transient_data->response[ $this->client->slug ] = (array) $version_info;
233
+ } else {
234
+ // If new version is not available then set to `no_update`
235
+ $transient_data->no_update[ $this->client->slug ] = (array) $version_info;
236
+ }
237
+
238
+ $transient_data->last_checked = time();
239
+ $transient_data->checked[ $this->client->slug ] = $this->client->project_version;
240
+ }
241
+
242
+ return $transient_data;
243
+ }
244
+
245
+ /**
246
+ * Get version information
247
+ */
248
+ private function get_version_info() {
249
+ $version_info = $this->get_cached_version_info();
250
+
251
+ if ( false === $version_info ) {
252
+ $version_info = $this->get_project_latest_version();
253
+ $this->set_cached_version_info( $version_info );
254
+ }
255
+
256
+ return $version_info;
257
+ }
258
+
259
+ }
widgets/calendly/widget.php CHANGED
@@ -1,184 +1,197 @@
1
- <?php
2
- /**
3
- * Calendly widget class
4
- *
5
- * @package Happy_Addons
6
- */
7
-
8
- namespace Happy_Addons\Elementor\Widget;
9
-
10
- use Elementor\Controls_Manager;
11
-
12
-
13
- defined( 'ABSPATH' ) || die();
14
-
15
- class Calendly extends Base {
16
-
17
- /**
18
- * Get widget title.
19
- *
20
- * @return string Widget title.
21
- * @since 1.0.0
22
- * @access public
23
- *
24
- */
25
- public function get_title() {
26
- return __( 'Calendly', 'happy-elementor-addons' );
27
- }
28
-
29
- public function get_custom_help_url() {
30
- return 'https://happyaddons.com/docs/happy-addons-for-elementor/widgets/calendly/';
31
- }
32
-
33
- /**
34
- * Get widget icon.
35
- *
36
- * @return string Widget icon.
37
- * @since 1.0.0
38
- * @access public
39
- *
40
- */
41
- public function get_icon() {
42
- return 'hm hm-calendar';
43
- }
44
-
45
- public function get_keywords() {
46
- return [ 'info', 'blurb', 'box', 'text', 'content' ];
47
- }
48
-
49
- /**
50
- * Register content related controls
51
- */
52
- protected function register_content_controls() {
53
- $this->start_controls_section(
54
- '_section_calendly',
55
- [
56
- 'label' => __( 'Calendly', 'happy-elementor-addons' ),
57
- 'tab' => Controls_Manager::TAB_CONTENT,
58
- ]
59
- );
60
-
61
- $this->add_control(
62
- 'calendly_username',
63
- [
64
- 'label' => __( 'Username', 'happy-elementor-addons' ),
65
- 'type' => Controls_Manager::TEXT,
66
- 'default' => __( '', 'happy-elementor-addons' ),
67
- 'placeholder' => __( 'Type calendly username here', 'happy-elementor-addons' ),
68
- ]
69
- );
70
-
71
- $this->add_control(
72
- 'calendly_time',
73
- [
74
- 'label' => __( 'Time Slot', 'happy-elementor-addons' ),
75
- 'type' => Controls_Manager::SELECT,
76
- 'options' => [
77
- '15min' => __( '15 Minutes', 'happy-elementor-addons' ),
78
- '30min' => __( '30 Minutes', 'happy-elementor-addons' ),
79
- '60min' => __( '60 Minutes', 'happy-elementor-addons' ),
80
- '' => __( 'All', 'happy-elementor-addons' ),
81
- ],
82
- 'default' => '15min'
83
- ]
84
- );
85
-
86
- $this->add_control(
87
- 'event_type_details',
88
- [
89
- 'label' => __( 'Hide Event Type Details', 'happy-elementor-addons' ),
90
- 'type' => Controls_Manager::SWITCHER,
91
- 'label_on' => __( 'yes', 'happy-elementor-addons' ),
92
- 'label_off' => __( 'no', 'happy-elementor-addons' ),
93
- 'return_value' => 'yes',
94
- 'default' => '',
95
- ]
96
- );
97
-
98
- $this->add_responsive_control(
99
- 'height',
100
- [
101
- 'label' => __( 'Height', 'happy-elementor-addons' ),
102
- 'type' => Controls_Manager::SLIDER,
103
- 'size_units' => [ 'px', '%' ],
104
- 'range' => [
105
- 'px' => [
106
- 'min' => 10,
107
- 'max' => 1000,
108
- 'step' => 5,
109
- ],
110
- '%' => [
111
- 'min' => 5,
112
- 'max' => 100,
113
- ],
114
- ],
115
- 'default' => [
116
- 'unit' => 'px',
117
- 'size' => '630',
118
- ],
119
- 'selectors' => [
120
- '{{WRAPPER}} .calendly-inline-widget' => 'height: {{SIZE}}{{UNIT}};',
121
- '{{WRAPPER}} .calendly-wrapper' => 'height: {{SIZE}}{{UNIT}};',
122
- ],
123
- ]
124
- );
125
-
126
- $this->end_controls_section();
127
- }
128
-
129
- /**
130
- * Register styles related controls
131
- */
132
- protected function register_style_controls() {
133
- $this->start_controls_section(
134
- '_section_style_calendly',
135
- [
136
- 'label' => __( 'Calendly', 'happy-elementor-addons' ),
137
- 'tab' => Controls_Manager::TAB_STYLE,
138
- ]
139
- );
140
-
141
- $this->add_control(
142
- 'text_color',
143
- [
144
- 'label' => __( 'Text Color', 'happy-elementor-addons' ),
145
- 'type' => Controls_Manager::COLOR,
146
- 'alpha' => false,
147
- ]
148
- );
149
-
150
- $this->add_control(
151
- 'button_link_color',
152
- [
153
- 'label' => __( 'Button & Link Color', 'happy-elementor-addons' ),
154
- 'type' => Controls_Manager::COLOR,
155
- ]
156
- );
157
-
158
- $this->add_control(
159
- 'background_color',
160
- [
161
- 'label' => __( 'Background Color', 'happy-elementor-addons' ),
162
- 'type' => Controls_Manager::COLOR,
163
- ]
164
- );
165
-
166
- $this->end_controls_section();
167
- }
168
-
169
- protected function render() {
170
- $settings = $this->get_settings_for_display();
171
- $calendly_time = $settings['calendly_time']!=''?"/{$settings['calendly_time']}":'';
172
- ?>
173
- <?php if ( $settings['calendly_username'] ): ?>
174
- <div class="calendly-inline-widget"
175
- data-url="https://calendly.com/<?php echo esc_attr( $settings['calendly_username'] ); ?><?php echo esc_attr( $calendly_time ); ?>/?<?php if ( 'yes' === $settings['event_type_details'] ): echo 'hide_event_type_details=1'; endif; ?><?php if ( $settings['text_color'] ): echo "&text_color=" . str_replace( '#', '', $settings['text_color'] ); endif; ?><?php if ( $settings['button_link_color'] ): echo "&primary_color=" . str_replace( '#', '', $settings['button_link_color'] ); endif; ?><?php if ( $settings['background_color'] ): echo "&background_color=" . str_replace( '#', '', $settings['background_color'] ); endif; ?>"
176
- style="min-width:320px;"></div>
177
- <script type="text/javascript" src="https://assets.calendly.com/assets/external/widget.js"></script>
178
- <?php if ( \Elementor\Plugin::$instance->editor->is_edit_mode() ) : ?>
179
- <div class="calendly-wrapper" style="width:100%; position:absolute; top:0; left:0; z-index:100;"></div>
180
- <?php endif; ?>
181
- <?php endif; ?>
182
- <?php
183
- }
184
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Calendly widget class
4
+ *
5
+ * @package Happy_Addons
6
+ */
7
+
8
+ namespace Happy_Addons\Elementor\Widget;
9
+
10
+ use Elementor\Controls_Manager;
11
+
12
+
13
+ defined( 'ABSPATH' ) || die();
14
+
15
+ class Calendly extends Base {
16
+
17
+ /**
18
+ * Get widget title.
19
+ *
20
+ * @return string Widget title.
21
+ * @since 1.0.0
22
+ * @access public
23
+ *
24
+ */
25
+ public function get_title() {
26
+ return __( 'Calendly', 'happy-elementor-addons' );
27
+ }
28
+
29
+ public function get_custom_help_url() {
30
+ return 'https://happyaddons.com/docs/happy-addons-for-elementor/widgets/calendly/';
31
+ }
32
+
33
+ /**
34
+ * Get widget icon.
35
+ *
36
+ * @return string Widget icon.
37
+ * @since 1.0.0
38
+ * @access public
39
+ *
40
+ */
41
+ public function get_icon() {
42
+ return 'hm hm-calendar';
43
+ }
44
+
45
+ public function get_keywords() {
46
+ return [ 'info', 'blurb', 'box', 'text', 'content' ];
47
+ }
48
+
49
+ /**
50
+ * Register content related controls
51
+ */
52
+ protected function register_content_controls() {
53
+ $this->start_controls_section(
54
+ '_section_calendly',
55
+ [
56
+ 'label' => __( 'Calendly', 'happy-elementor-addons' ),
57
+ 'tab' => Controls_Manager::TAB_CONTENT,
58
+ ]
59
+ );
60
+
61
+ $this->add_control(
62
+ 'calendly_username',
63
+ [
64
+ 'label' => __( 'Username', 'happy-elementor-addons' ),
65
+ 'type' => Controls_Manager::TEXT,
66
+ 'default' => 'happyaddons',
67
+ 'placeholder' => __( 'Type calendly username here', 'happy-elementor-addons' ),
68
+ ]
69
+ );
70
+
71
+ $this->add_control(
72
+ 'calendly_time',
73
+ [
74
+ 'label' => __( 'Time Slot', 'happy-elementor-addons' ),
75
+ 'type' => Controls_Manager::SELECT,
76
+ 'options' => [
77
+ '15min' => __( '15 Minutes', 'happy-elementor-addons' ),
78
+ '30min' => __( '30 Minutes', 'happy-elementor-addons' ),
79
+ '60min' => __( '60 Minutes', 'happy-elementor-addons' ),
80
+ '' => __( 'All', 'happy-elementor-addons' ),
81
+ ],
82
+ 'default' => '15min'
83
+ ]
84
+ );
85
+
86
+ $this->add_control(
87
+ 'event_type_details',
88
+ [
89
+ 'label' => __( 'Hide Event Type Details', 'happy-elementor-addons' ),
90
+ 'type' => Controls_Manager::SWITCHER,
91
+ 'label_on' => __( 'yes', 'happy-elementor-addons' ),
92
+ 'label_off' => __( 'no', 'happy-elementor-addons' ),
93
+ 'return_value' => 'yes',
94
+ 'default' => '',
95
+ ]
96
+ );
97
+
98
+ $this->add_responsive_control(
99
+ 'height',
100
+ [
101
+ 'label' => __( 'Height', 'happy-elementor-addons' ),
102
+ 'type' => Controls_Manager::SLIDER,
103
+ 'size_units' => [ 'px', '%' ],
104
+ 'range' => [
105
+ 'px' => [
106
+ 'min' => 10,
107
+ 'max' => 1000,
108
+ 'step' => 5,
109
+ ],
110
+ '%' => [
111
+ 'min' => 5,
112
+ 'max' => 100,
113
+ ],
114
+ ],
115
+ 'default' => [
116
+ 'unit' => 'px',
117
+ 'size' => '630',
118
+ ],
119
+ 'selectors' => [
120
+ '{{WRAPPER}} .calendly-inline-widget' => 'height: {{SIZE}}{{UNIT}};',
121
+ '{{WRAPPER}} .calendly-wrapper' => 'height: {{SIZE}}{{UNIT}};',
122
+ ],
123
+ ]
124
+ );
125
+
126
+ $this->end_controls_section();
127
+ }
128
+
129
+ /**
130
+ * Register styles related controls
131
+ */
132
+ protected function register_style_controls() {
133
+ $this->start_controls_section(
134
+ '_section_style_calendly',
135
+ [
136
+ 'label' => __( 'Calendly', 'happy-elementor-addons' ),
137
+ 'tab' => Controls_Manager::TAB_STYLE,
138
+ ]
139
+ );
140
+
141
+ $this->add_control(
142
+ '_calendly_pro_notice',
143
+ [
144
+ 'type' => Controls_Manager::RAW_HTML,
145
+ 'raw' => sprintf(
146
+ __( 'The following color customization controls only work with %s. Basic and Premium plan users cannot customize colors as per Calendy pricing plan. For more information please %s.', 'happy-elementor-addons' ),
147
+ '<a href="https://calendly.com/pages/pricing" target="_blank">Calendly Pro plan</a>',
148
+ '<a href="https://calendly.com/pages/pricing" target="_blank">click here</a>'
149
+ ),
150
+ 'content_classes' => 'elementor-panel-alert elementor-panel-alert-info',
151
+ ]
152
+ );
153
+
154
+ $this->add_control(
155
+ 'text_color',
156
+ [
157
+ 'label' => __( 'Text Color', 'happy-elementor-addons' ),
158
+ 'type' => Controls_Manager::COLOR,
159
+ 'alpha' => false,
160
+ ]
161
+ );
162
+
163
+ $this->add_control(
164
+ 'button_link_color',
165
+ [
166
+ 'label' => __( 'Button & Link Color', 'happy-elementor-addons' ),
167
+ 'type' => Controls_Manager::COLOR,
168
+ ]
169
+ );
170
+
171
+ $this->add_control(
172
+ 'background_color',
173
+ [
174
+ 'label' => __( 'Background Color', 'happy-elementor-addons' ),
175
+ 'type' => Controls_Manager::COLOR,
176
+ ]
177
+ );
178
+
179
+ $this->end_controls_section();
180
+ }
181
+
182
+ protected function render() {
183
+ $settings = $this->get_settings_for_display();
184
+ $calendly_time = $settings['calendly_time']!=''?"/{$settings['calendly_time']}":'';
185
+ ?>
186
+ <?php if ( $settings['calendly_username'] ): ?>
187
+ <div class="calendly-inline-widget"
188
+ data-url="https://calendly.com/<?php echo esc_attr( $settings['calendly_username'] ); ?><?php echo esc_attr( $calendly_time ); ?>/?<?php if ( 'yes' === $settings['event_type_details'] ): echo 'hide_event_type_details=1'; endif; ?><?php if ( $settings['text_color'] ): echo "&text_color=" . str_replace( '#', '', $settings['text_color'] ); endif; ?><?php if ( $settings['button_link_color'] ): echo "&primary_color=" . str_replace( '#', '', $settings['button_link_color'] ); endif; ?><?php if ( $settings['background_color'] ): echo "&background_color=" . str_replace( '#', '', $settings['background_color'] ); endif; ?>"
189
+ style="min-width:320px;"></div>
190
+ <script type="text/javascript" src="https://assets.calendly.com/assets/external/widget.js"></script>
191
+ <?php if ( \Elementor\Plugin::$instance->editor->is_edit_mode() ) : ?>
192
+ <div class="calendly-wrapper" style="width:100%; position:absolute; top:0; left:0; z-index:100;"></div>
193
+ <?php endif; ?>
194
+ <?php endif; ?>
195
+ <?php
196
+ }
197
+ }
widgets/card/widget.php CHANGED
@@ -1105,7 +1105,7 @@ class Card extends Base {
1105
  <figure class="ha-card-figure">
1106
  <?php echo Group_Control_Image_Size::get_attachment_image_html( $settings, 'thumbnail', 'image' ); ?>
1107
  <?php if ( $settings['badge_text'] ) : ?>
1108
- <span <?php echo $this->get_render_attribute_string( 'badge_text' ); ?>><?php echo esc_html( $settings['badge_text'] ); ?></span>
1109
  <?php endif; ?>
1110
  </figure>
1111
  <?php endif; ?>
@@ -1162,7 +1162,7 @@ class Card extends Base {
1162
  <figure class="ha-card-figure">
1163
  <img class="elementor-animation-{{settings.hover_animation}}" src="{{ image_url }}">
1164
  <# if (settings.badge_text) { #>
1165
- <span {{{ view.getRenderAttributeString( 'badge_text' ) }}}>{{ settings.badge_text }}</span>
1166
  <# } #>
1167
  </figure>
1168
  <# } #>
1105
  <figure class="ha-card-figure">
1106
  <?php echo Group_Control_Image_Size::get_attachment_image_html( $settings, 'thumbnail', 'image' ); ?>
1107
  <?php if ( $settings['badge_text'] ) : ?>
1108
+ <div <?php echo $this->get_render_attribute_string( 'badge_text' ); ?>><?php echo ha_kses_intermediate( $settings['badge_text'] ); ?></div>
1109
  <?php endif; ?>
1110
  </figure>
1111
  <?php endif; ?>
1162
  <figure class="ha-card-figure">
1163
  <img class="elementor-animation-{{settings.hover_animation}}" src="{{ image_url }}">
1164
  <# if (settings.badge_text) { #>
1165
+ <div {{{ view.getRenderAttributeString( 'badge_text' ) }}}>{{{ settings.badge_text }}}</div>
1166
  <# } #>
1167
  </figure>
1168
  <# } #>
widgets/logo-grid/widget.php CHANGED
@@ -1,571 +1,644 @@
1
- <?php
2
- /**
3
- * Logo grid widget class
4
- *
5
- * @package Happy_Addons
6
- */
7
- namespace Happy_Addons\Elementor\Widget;
8
-
9
- use Elementor\Group_Control_Css_Filter;
10
- use Elementor\Repeater;
11
- use Elementor\Controls_Manager;
12
- use Elementor\Group_Control_Box_Shadow;
13
- use Elementor\Group_Control_Image_Size;
14
- use Elementor\Utils;
15
-
16
- defined( 'ABSPATH' ) || die();
17
-
18
- class Logo_Grid extends Base {
19
-
20
- /**
21
- * Get widget title.
22
- *
23
- * @since 1.0.0
24
- * @access public
25
- *
26
- * @return string Widget title.
27
- */
28
- public function get_title() {
29
- return __('Logo Grid', 'happy-elementor-addons');
30
- }
31
-
32
- public function get_custom_help_url() {
33
- return 'https://happyaddons.com/docs/happy-addons-for-elementor/widgets/logo-grid/';
34
- }
35
-
36
- /**
37
- * Get widget icon.
38
- *
39
- * @since 1.0.0
40
- * @access public
41
- *
42
- * @return string Widget icon.
43
- */
44
- public function get_icon() {
45
- return 'hm hm-logo-grid';
46
- }
47
-
48
- public function get_keywords() {
49
- return ['logo', 'grid', 'brand', 'client'];
50
- }
51
-
52
- protected function register_content_controls() {
53
- $this->start_controls_section(
54
- '_section_logo',
55
- [
56
- 'label' => __( 'Logo Grid', 'happy-elementor-addons' ),
57
- 'tab' => Controls_Manager::TAB_CONTENT,
58
- ]
59
- );
60
-
61
- $repeater = new Repeater();
62
-
63
- $repeater->add_control(
64
- 'image',
65
- [
66
- 'label' => __('Logo', 'happy-elementor-addons'),
67
- 'type' => Controls_Manager::MEDIA,
68
- 'default' => [
69
- 'url' => Utils::get_placeholder_image_src(),
70
- ],
71
- 'dynamic' => [
72
- 'active' => true,
73
- ]
74
- ]
75
- );
76
-
77
- $repeater->add_control(
78
- 'link',
79
- [
80
- 'label' => __('Website Url', 'happy-elementor-addons'),
81
- 'type' => Controls_Manager::URL,
82
- 'show_external' => false,
83
- 'label_block' => false,
84
- 'dynamic' => [
85
- 'active' => true,
86
- ]
87
- ]
88
- );
89
-
90
- $repeater->add_control(
91
- 'name',
92
- [
93
- 'label' => __('Brand Name', 'happy-elementor-addons'),
94
- 'type' => Controls_Manager::TEXT,
95
- 'default' => __('Brand Name', 'happy-elementor-addons'),
96
- ]
97
- );
98
-
99
- $this->add_control(
100
- 'logo_list',
101
- [
102
- 'show_label' => false,
103
- 'type' => Controls_Manager::REPEATER,
104
- 'fields' => $repeater->get_controls(),
105
- 'title_field' => '{{{ name }}}',
106
- 'default' => [
107
- ['image' => ['url' => Utils::get_placeholder_image_src()]],
108
- ['image' => ['url' => Utils::get_placeholder_image_src()]],
109
- ['image' => ['url' => Utils::get_placeholder_image_src()]],
110
- ['image' => ['url' => Utils::get_placeholder_image_src()]],
111
- ['image' => ['url' => Utils::get_placeholder_image_src()]],
112
- ['image' => ['url' => Utils::get_placeholder_image_src()]],
113
- ['image' => ['url' => Utils::get_placeholder_image_src()]],
114
- ['image' => ['url' => Utils::get_placeholder_image_src()]],
115
- ]
116
- ]
117
- );
118
-
119
- $this->end_controls_section();
120
-
121
- $this->start_controls_section(
122
- '_section_settings',
123
- [
124
- 'label' => __( 'Settings', 'happy-elementor-addons' ),
125
- 'tab' => Controls_Manager::TAB_CONTENT,
126
- ]
127
- );
128
-
129
- $this->add_group_control(
130
- Group_Control_Image_Size::get_type(),
131
- [
132
- 'name' => 'thumbnail',
133
- 'default' => 'large',
134
- 'separator' => 'before',
135
- 'exclude' => [
136
- 'custom'
137
- ]
138
- ]
139
- );
140
-
141
- $this->add_control(
142
- 'layout',
143
- [
144
- 'label' => __( 'Grid Layout', 'happy-elementor-addons' ),
145
- 'type' => Controls_Manager::SELECT,
146
- 'options' => [
147
- 'box' => __( 'Box', 'happy-elementor-addons' ),
148
- 'border' => __( 'Border', 'happy-elementor-addons' ),
149
- 'tictactoe' => __( 'Tic Tac Toe', 'happy-elementor-addons' ),
150
- ],
151
- 'default' => 'box',
152
- 'prefix_class' => 'ha-logo-grid--',
153
- 'style_transfer' => true,
154
- ]
155
- );
156
-
157
- $this->add_responsive_control(
158
- 'columns',
159
- [
160
- 'label' => __( 'Columns', 'happy-elementor-addons' ),
161
- 'type' => Controls_Manager::SELECT,
162
- 'options' => [
163
- 2 => __( '2 Columns', 'happy-elementor-addons' ),
164
- 3 => __( '3 Columns', 'happy-elementor-addons' ),
165
- 4 => __( '4 Columns', 'happy-elementor-addons' ),
166
- 5 => __( '5 Columns', 'happy-elementor-addons' ),
167
- 6 => __( '6 Columns', 'happy-elementor-addons' ),
168
- ],
169
- 'desktop_default' => 4,
170
- 'tablet_default' => 2,
171
- 'mobile_default' => 2,
172
- 'prefix_class' => 'ha-logo-grid--col-%s',
173
- 'style_transfer' => true,
174
- ]
175
- );
176
-
177
- $this->end_controls_section();
178
- }
179
-
180
- protected function register_style_controls() {
181
- $this->start_controls_section(
182
- '_section_style_grid',
183
- [
184
- 'label' => __( 'Grid', 'happy-elementor-addons' ),
185
- 'tab' => Controls_Manager::TAB_STYLE,
186
- ]
187
- );
188
-
189
- $this->add_responsive_control(
190
- 'padding',
191
- [
192
- 'label' => __( 'Padding', 'happy-elementor-addons' ),
193
- 'type' => Controls_Manager::DIMENSIONS,
194
- 'size_units' => [ 'px', 'em', '%' ],
195
- 'selectors' => [
196
- '{{WRAPPER}} .ha-logo-grid-figure' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
197
- ],
198
- ]
199
- );
200
-
201
- $this->add_responsive_control(
202
- 'height',
203
- [
204
- 'label' => __( 'Height', 'happy-elementor-addons' ),
205
- 'type' => Controls_Manager::SLIDER,
206
- 'size_units' => ['px'],
207
- 'range' => [
208
- 'px' => [
209
- 'max' => 500,
210
- 'min' => 100,
211
- ]
212
- ],
213
- 'selectors' => [
214
- '{{WRAPPER}} .ha-logo-grid-item' => 'height: {{SIZE}}{{UNIT}};'
215
- ],
216
- ]
217
- );
218
-
219
- $this->add_control(
220
- 'grid_border_type',
221
- [
222
- 'label' => __( 'Border Type', 'happy-elementor-addons' ),
223
- 'type' => Controls_Manager::SELECT,
224
- 'options' => [
225
- 'none' => __( 'None', 'happy-elementor-addons' ),
226
- 'solid' => __( 'Solid', 'happy-elementor-addons' ),
227
- 'double' => __( 'Double', 'happy-elementor-addons' ),
228
- 'dotted' => __( 'Dotted', 'happy-elementor-addons' ),
229
- 'dashed' => __( 'Dashed', 'happy-elementor-addons' ),
230
- 'groove' => __( 'Groove', 'happy-elementor-addons' ),
231
- ],
232
- 'default' => 'solid',
233
- 'selectors' => [
234
- '{{WRAPPER}} .ha-logo-grid-item' => 'border-style: {{VALUE}};',
235
- ],
236
- ]
237
- );
238
-
239
- $this->add_responsive_control(
240
- 'grid_border_width',
241
- [
242
- 'label' => __( 'Border Width', 'happy-elementor-addons' ),
243
- 'type' => Controls_Manager::SLIDER,
244
- 'size_units' => ['px'],
245
- 'selectors' => [
246
- '(desktop+){{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-item' => 'border-right-width: {{grid_border_width.SIZE}}{{UNIT}}; border-bottom-width: {{grid_border_width.SIZE}}{{UNIT}};',
247
- '(tablet){{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-item' => 'border-right-width: {{grid_border_width_tablet.SIZE}}{{UNIT}}; border-bottom-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
248
- '(mobile){{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-item' => 'border-right-width: {{grid_border_width_mobile.SIZE}}{{UNIT}}; border-bottom-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
249
-
250
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-2 .ha-logo-grid-item:nth-child(2n+1)' => 'border-left-width: {{grid_border_width.SIZE}}{{UNIT}};',
251
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-3 .ha-logo-grid-item:nth-child(3n+1)' => 'border-left-width: {{grid_border_width.SIZE}}{{UNIT}};',
252
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-4 .ha-logo-grid-item:nth-child(4n+1)' => 'border-left-width: {{grid_border_width.SIZE}}{{UNIT}};',
253
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-5 .ha-logo-grid-item:nth-child(5n+1)' => 'border-left-width: {{grid_border_width.SIZE}}{{UNIT}};',
254
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-6 .ha-logo-grid-item:nth-child(6n+1)' => 'border-left-width: {{grid_border_width.SIZE}}{{UNIT}};',
255
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-2 .ha-logo-grid-item:nth-child(-n+2)' => 'border-top-width: {{grid_border_width.SIZE}}{{UNIT}};',
256
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-3 .ha-logo-grid-item:nth-child(-n+3)' => 'border-top-width: {{grid_border_width.SIZE}}{{UNIT}};',
257
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-4 .ha-logo-grid-item:nth-child(-n+4)' => 'border-top-width: {{grid_border_width.SIZE}}{{UNIT}};',
258
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-5 .ha-logo-grid-item:nth-child(-n+5)' => 'border-top-width: {{grid_border_width.SIZE}}{{UNIT}};',
259
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-6 .ha-logo-grid-item:nth-child(-n+6)' => 'border-top-width: {{grid_border_width.SIZE}}{{UNIT}};',
260
-
261
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-child(2n+1)' => 'border-left-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
262
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-child(3n+1)' => 'border-left-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
263
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-child(4n+1)' => 'border-left-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
264
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-child(5n+1)' => 'border-left-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
265
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-child(6n+1)' => 'border-left-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
266
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-child(-n+2)' => 'border-top-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
267
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-child(-n+3)' => 'border-top-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
268
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-child(-n+4)' => 'border-top-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
269
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-child(-n+5)' => 'border-top-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
270
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-child(-n+6)' => 'border-top-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
271
-
272
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-child(2n+1)' => 'border-left-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
273
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-child(3n+1)' => 'border-left-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
274
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-child(4n+1)' => 'border-left-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
275
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-child(5n+1)' => 'border-left-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
276
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-child(6n+1)' => 'border-left-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
277
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-child(-n+2)' => 'border-top-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
278
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-child(-n+3)' => 'border-top-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
279
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-child(-n+4)' => 'border-top-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
280
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-child(-n+5)' => 'border-top-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
281
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-child(-n+6)' => 'border-top-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
282
-
283
- '{{WRAPPER}}.ha-logo-grid--tictactoe .ha-logo-grid-item' => 'border-top-width: {{SIZE}}{{UNIT}}; border-right-width: {{SIZE}}{{UNIT}};',
284
-
285
- '{{WRAPPER}}.ha-logo-grid--box .ha-logo-grid-item' => 'border-width: {{SIZE}}{{UNIT}};',
286
- ],
287
- 'condition' => [
288
- 'grid_border_type!' => 'none',
289
- ]
290
- ]
291
- );
292
-
293
- $this->add_control(
294
- 'grid_border_color',
295
- [
296
- 'label' => __( 'Border Color', 'happy-elementor-addons' ),
297
- 'type' => Controls_Manager::COLOR,
298
- 'selectors' => [
299
- '{{WRAPPER}} .ha-logo-grid-item' => 'border-color: {{VALUE}};',
300
- ],
301
- 'condition' => [
302
- 'grid_border_type!' => 'none',
303
- ]
304
- ]
305
- );
306
-
307
- $this->add_control(
308
- 'grid_bg_color',
309
- [
310
- 'label' => __( 'Background Color', 'happy-elementor-addons' ),
311
- 'type' => Controls_Manager::COLOR,
312
- 'selectors' => [
313
- '{{WRAPPER}} .ha-logo-grid-figure' => 'background-color: {{VALUE}};',
314
- ],
315
- ]
316
- );
317
-
318
- $this->add_responsive_control(
319
- 'grid_border_radius',
320
- [
321
- 'label' => __( 'Border Radius', 'happy-elementor-addons' ),
322
- 'type' => Controls_Manager::DIMENSIONS,
323
- 'size_units' => ['px', '%'],
324
- 'selectors' => [
325
- '{{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-wrapper, {{WRAPPER}}.ha-logo-grid--box .ha-logo-grid-item' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
326
- '{{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-item:first-child' => 'border-top-left-radius: {{TOP}}{{UNIT}};',
327
- '{{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-item:last-child' => 'border-bottom-right-radius: {{BOTTOM}}{{UNIT}};',
328
-
329
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
330
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
331
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
332
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
333
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
334
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
335
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
336
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
337
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
338
- '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
339
-
340
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
341
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
342
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
343
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
344
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
345
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
346
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
347
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
348
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
349
- '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
350
-
351
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
352
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
353
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
354
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
355
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
356
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
357
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
358
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
359
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
360
- '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
361
-
362
- // Tictactoe
363
- '{{WRAPPER}}.ha-logo-grid--tictactoe .ha-logo-grid-wrapper' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
364
- '{{WRAPPER}}.ha-logo-grid--tictactoe .ha-logo-grid-item:first-child' => 'border-top-left-radius: {{TOP}}{{UNIT}};',
365
- '{{WRAPPER}}.ha-logo-grid--tictactoe .ha-logo-grid-item:last-child' => 'border-bottom-right-radius: {{BOTTOM}}{{UNIT}};',
366
-
367
- '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
368
- '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
369
- '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
370
- '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
371
- '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
372
- '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
373
- '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
374
- '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
375
- '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
376
- '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
377
-
378
- '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
379
- '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
380
- '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
381
- '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
382
- '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
383
- '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
384
- '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
385
- '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
386
- '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
387
- '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
388
-
389
- '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
390
- '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
391
- '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
392
- '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
393
- '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
394
- '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
395
- '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
396
- '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
397
- '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
398
- '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
399
- ],
400
- ]
401
- );
402
-
403
- $this->add_group_control(
404
- Group_Control_Box_Shadow::get_type(),
405
- [
406
- 'name' => 'grid_box_shadow',
407
- 'exclude' => [
408
- 'box_shadow_position',
409
- ],
410
- 'selector' => '{{WRAPPER}}.ha-logo-grid--tictactoe .ha-logo-grid-wrapper, {{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-wrapper, {{WRAPPER}}.ha-logo-grid--box .ha-logo-grid-item'
411
- ]
412
- );
413
-
414
-
415
- $this->start_controls_tabs(
416
- '_tabs_image_effects',
417
- [
418
- 'separator' => 'before'
419
- ]
420
- );
421
-
422
- $this->start_controls_tab(
423
- '_tab_image_effects_normal',
424
- [
425
- 'label' => __( 'Normal', 'happy-elementor-addons' ),
426
- ]
427
- );
428
-
429
- $this->add_control(
430
- 'image_opacity',
431
- [
432
- 'label' => __( 'Opacity', 'happy-elementor-addons' ),
433
- 'type' => Controls_Manager::SLIDER,
434
- 'range' => [
435
- 'px' => [
436
- 'max' => 1,
437
- 'min' => 0.10,
438
- 'step' => 0.01,
439
- ],
440
- ],
441
- 'selectors' => [
442
- '{{WRAPPER}} .ha-logo-grid-figure img' => 'opacity: {{SIZE}};',
443
- ],
444
- ]
445
- );
446
-
447
- $this->add_group_control(
448
- Group_Control_Css_Filter::get_type(),
449
- [
450
- 'name' => 'image_css_filters',
451
- 'selector' => '{{WRAPPER}} .ha-logo-grid-figure img',
452
- ]
453
- );
454
-
455
- $this->end_controls_tab();
456
-
457
- $this->start_controls_tab( 'hover',
458
- [
459
- 'label' => __( 'Hover', 'happy-elementor-addons' ),
460
- ]
461
- );
462
-
463
- $this->add_control(
464
- 'image_opacity_hover',
465
- [
466
- 'label' => __( 'Opacity', 'happy-elementor-addons' ),
467
- 'type' => Controls_Manager::SLIDER,
468
- 'range' => [
469
- 'px' => [
470
- 'max' => 1,
471
- 'min' => 0.10,
472
- 'step' => 0.01,
473
- ],
474
- ],
475
- 'selectors' => [
476
- '{{WRAPPER}} .ha-logo-grid-figure:hover img' => 'opacity: {{SIZE}};',
477
- ],
478
- ]
479
- );
480
-
481
- $this->add_group_control(
482
- Group_Control_Css_Filter::get_type(),
483
- [
484
- 'name' => 'image_css_filters_hover',
485
- 'selector' => '{{WRAPPER}} .ha-logo-grid-figure:hover img',
486
- ]
487
- );
488
-
489
- $this->add_control(
490
- 'image_bg_hover_transition',
491
- [
492
- 'label' => __( 'Transition Duration', 'happy-elementor-addons' ),
493
- 'type' => Controls_Manager::SLIDER,
494
- 'range' => [
495
- 'px' => [
496
- 'max' => 3,
497
- 'step' => 0.1,
498
- ],
499
- ],
500
- 'selectors' => [
501
- '{{WRAPPER}} .ha-logo-grid-figure:hover img' => 'transition-duration: {{SIZE}}s;',
502
- ],
503
- ]
504
- );
505
-
506
- $this->add_control(
507
- 'hover_animation',
508
- [
509
- 'label' => __( 'Hover Animation', 'happy-elementor-addons' ),
510
- 'type' => Controls_Manager::HOVER_ANIMATION,
511
- 'label_block' => true,
512
- ]
513
- );
514
-
515
- $this->end_controls_tab();
516
- $this->end_controls_tabs();
517
-
518
- $this->end_controls_section();
519
- }
520
-
521
- protected function render() {
522
- $settings = $this->get_settings_for_display();
523
-
524
- if ( empty($settings['logo_list'] ) ) {
525
- return;
526
- }
527
- ?>
528
-
529
- <div class="ha-logo-grid-wrapper">
530
- <?php
531
- foreach ( $settings['logo_list'] as $index => $item ) :
532
- $image = wp_get_attachment_image_url( $item['image']['id'], $settings['thumbnail_size'] );
533
- $repeater_key = 'grid_item' . $index;
534
- $tag = 'div';
535
- $this->add_render_attribute( $repeater_key, 'class', 'ha-logo-grid-item' );
536
-
537
- if ( $item['link']['url'] ) {
538
- $tag = 'a';
539
- $this->add_render_attribute( $repeater_key, 'class', 'ha-logo-grid-link' );
540
-
541
- $this->add_render_attribute( $repeater_key, 'target', '_blank' );
542
- $this->add_render_attribute( $repeater_key, 'rel', 'noopener' );
543
- $this->add_render_attribute( $repeater_key, 'href', $item['link']['url'] );
544
- }
545
- ?>
546
- <<?php echo $tag; ?> <?php $this->print_render_attribute_string( $repeater_key ); ?>>
547
- <figure class="ha-logo-grid-figure">
548
- <?php if ( $image ) :
549
- echo wp_get_attachment_image(
550
- $item['image']['id'],
551
- $settings['thumbnail_size'],
552
- false,
553
- [
554
- 'class' => 'ha-logo-grid-img elementor-animation-' . esc_attr( $settings['hover_animation'] )
555
- ]
556
- );
557
- else :
558
- printf( '<img class="ha-logo-grid-img elementor-animation-%s" src="%s" alt="%s">',
559
- esc_attr( $settings['hover_animation'] ),
560
- Utils::get_placeholder_image_src(),
561
- esc_attr( $item['name'] )
562
- );
563
- endif; ?>
564
- </figure>
565
- </<?php echo $tag; ?>>
566
- <?php endforeach; ?>
567
- </div>
568
-
569
- <?php
570
- }
571
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Logo grid widget class
4
+ *
5
+ * @package Happy_Addons
6
+ */
7
+ namespace Happy_Addons\Elementor\Widget;
8
+
9
+ use Elementor\Group_Control_Css_Filter;
10
+ use Elementor\Repeater;
11
+ use Elementor\Controls_Manager;
12
+ use Elementor\Group_Control_Box_Shadow;
13
+ use Elementor\Group_Control_Image_Size;
14
+ use Elementor\Utils;
15
+
16
+ defined( 'ABSPATH' ) || die();
17
+
18
+ class Logo_Grid extends Base {
19
+
20
+ /**
21
+ * Get widget title.
22
+ *
23
+ * @since 1.0.0
24
+ * @access public
25
+ *
26
+ * @return string Widget title.
27
+ */
28
+ public function get_title() {
29
+ return __('Logo Grid', 'happy-elementor-addons');
30
+ }
31
+
32
+ public function get_custom_help_url() {
33
+ return 'https://happyaddons.com/docs/happy-addons-for-elementor/widgets/logo-grid/';
34
+ }
35
+
36
+ /**
37
+ * Get widget icon.
38
+ *
39
+ * @since 1.0.0
40
+ * @access public
41
+ *
42
+ * @return string Widget icon.
43
+ */
44
+ public function get_icon() {
45
+ return 'hm hm-logo-grid';
46
+ }
47
+
48
+ public function get_keywords() {
49
+ return ['logo', 'grid', 'brand', 'client'];
50
+ }
51
+
52
+ protected function register_content_controls() {
53
+ $this->start_controls_section(
54
+ '_section_logo',
55
+ [
56
+ 'label' => __( 'Logo Grid', 'happy-elementor-addons' ),
57
+ 'tab' => Controls_Manager::TAB_CONTENT,
58
+ ]
59
+ );
60
+
61
+ $repeater = new Repeater();
62
+
63
+ $repeater->add_control(
64
+ 'image',
65
+ [
66
+ 'label' => __( 'Logo', 'happy-elementor-addons' ),
67
+ 'type' => Controls_Manager::MEDIA,
68
+ 'default' => [
69
+ 'url' => Utils::get_placeholder_image_src(),
70
+ ],
71
+ 'dynamic' => [
72
+ 'active' => true,
73
+ ]
74
+ ]
75
+ );
76
+
77
+ $repeater->add_control(
78
+ 'link',
79
+ [
80
+ 'label' => __( 'Website Url', 'happy-elementor-addons' ),
81
+ 'type' => Controls_Manager::URL,
82
+ 'label_block' => true,
83
+ 'dynamic' => [
84
+ 'active' => true,
85
+ ],
86
+ 'default' => [
87
+ 'url' => '#',
88
+ 'is_external' => true,
89
+ 'nofollow' => true,
90
+ ]
91
+ ]
92
+ );
93
+
94
+ $repeater->add_control(
95
+ 'name',
96
+ [
97
+ 'label' => __( 'Brand Name', 'happy-elementor-addons' ),
98
+ 'type' => Controls_Manager::TEXT,
99
+ 'default' => __( 'Brand Name', 'happy-elementor-addons' ),
100
+ ]
101
+ );
102
+
103
+ $this->add_control(
104
+ 'logo_list',
105
+ [
106
+ 'show_label' => false,
107
+ 'type' => Controls_Manager::REPEATER,
108
+ 'fields' => $repeater->get_controls(),
109
+ 'title_field' => '{{{ name }}}',
110
+ 'default' => [
111
+ [
112
+ 'image' => [
113
+ 'url' => Utils::get_placeholder_image_src()
114
+ ],
115
+ 'link' => [
116
+ 'url' => '#',
117
+ 'is_external' => true,
118
+ 'nofollow' => true,
119
+ ],
120
+ ],
121
+ [
122
+ 'image' => [
123
+ 'url' => Utils::get_placeholder_image_src()
124
+ ],
125
+ 'link' => [
126
+ 'url' => '#',
127
+ 'is_external' => true,
128
+ 'nofollow' => true,
129
+ ],
130
+ ],
131
+ [
132
+ 'image' => [
133
+ 'url' => Utils::get_placeholder_image_src()
134
+ ],
135
+ 'link' => [
136
+ 'url' => '#',
137
+ 'is_external' => true,
138
+ 'nofollow' => true,
139
+ ],
140
+ ],
141
+ [
142
+ 'image' => [
143
+ 'url' => Utils::get_placeholder_image_src()
144
+ ],
145
+ 'link' => [
146
+ 'url' => '#',
147
+ 'is_external' => true,
148
+ 'nofollow' => true,
149
+ ],
150
+ ],
151
+ [
152
+ 'image' => [
153
+ 'url' => Utils::get_placeholder_image_src()
154
+ ],
155
+ 'link' => [
156
+ 'url' => '#',
157
+ 'is_external' => true,
158
+ 'nofollow' => true,
159
+ ],
160
+ ],
161
+ [
162
+ 'image' => [
163
+ 'url' => Utils::get_placeholder_image_src()
164
+ ],
165
+ 'link' => [
166
+ 'url' => '#',
167
+ 'is_external' => true,
168
+ 'nofollow' => true,
169
+ ],
170
+ ],
171
+ [
172
+ 'image' => [
173
+ 'url' => Utils::get_placeholder_image_src()
174
+ ],
175
+ 'link' => [
176
+ 'url' => '#',
177
+ 'is_external' => true,
178
+ 'nofollow' => true,
179
+ ],
180
+ ],
181
+ [
182
+ 'image' => [
183
+ 'url' => Utils::get_placeholder_image_src()
184
+ ],
185
+ 'link' => [
186
+ 'url' => '#',
187
+ 'is_external' => true,
188
+ 'nofollow' => true,
189
+ ],
190
+ ],
191
+ ]
192
+ ]
193
+ );
194
+
195
+ $this->end_controls_section();
196
+
197
+ $this->start_controls_section(
198
+ '_section_settings',
199
+ [
200
+ 'label' => __( 'Settings', 'happy-elementor-addons' ),
201
+ 'tab' => Controls_Manager::TAB_CONTENT,
202
+ ]
203
+ );
204
+
205
+ $this->add_group_control(
206
+ Group_Control_Image_Size::get_type(),
207
+ [
208
+ 'name' => 'thumbnail',
209
+ 'default' => 'large',
210
+ 'separator' => 'before',
211
+ 'exclude' => [
212
+ 'custom'
213
+ ]
214
+ ]
215
+ );
216
+
217
+ $this->add_control(
218
+ 'layout',
219
+ [
220
+ 'label' => __( 'Grid Layout', 'happy-elementor-addons' ),
221
+ 'type' => Controls_Manager::SELECT,
222
+ 'options' => [
223
+ 'box' => __( 'Box', 'happy-elementor-addons' ),
224
+ 'border' => __( 'Border', 'happy-elementor-addons' ),
225
+ 'tictactoe' => __( 'Tic Tac Toe', 'happy-elementor-addons' ),
226
+ ],
227
+ 'default' => 'box',
228
+ 'prefix_class' => 'ha-logo-grid--',
229
+ 'style_transfer' => true,
230
+ ]
231
+ );
232
+
233
+ $this->add_responsive_control(
234
+ 'columns',
235
+ [
236
+ 'label' => __( 'Columns', 'happy-elementor-addons' ),
237
+ 'type' => Controls_Manager::SELECT,
238
+ 'options' => [
239
+ 2 => __( '2 Columns', 'happy-elementor-addons' ),
240
+ 3 => __( '3 Columns', 'happy-elementor-addons' ),
241
+ 4 => __( '4 Columns', 'happy-elementor-addons' ),
242
+ 5 => __( '5 Columns', 'happy-elementor-addons' ),
243
+ 6 => __( '6 Columns', 'happy-elementor-addons' ),
244
+ ],
245
+ 'desktop_default' => 4,
246
+ 'tablet_default' => 2,
247
+ 'mobile_default' => 2,
248
+ 'prefix_class' => 'ha-logo-grid--col-%s',
249
+ 'style_transfer' => true,
250
+ ]
251
+ );
252
+
253
+ $this->end_controls_section();
254
+ }
255
+
256
+ protected function register_style_controls() {
257
+ $this->start_controls_section(
258
+ '_section_style_grid',
259
+ [
260
+ 'label' => __( 'Grid', 'happy-elementor-addons' ),
261
+ 'tab' => Controls_Manager::TAB_STYLE,
262
+ ]
263
+ );
264
+
265
+ $this->add_responsive_control(
266
+ 'padding',
267
+ [
268
+ 'label' => __( 'Padding', 'happy-elementor-addons' ),
269
+ 'type' => Controls_Manager::DIMENSIONS,
270
+ 'size_units' => [ 'px', 'em', '%' ],
271
+ 'selectors' => [
272
+ '{{WRAPPER}} .ha-logo-grid-figure' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
273
+ ],
274
+ ]
275
+ );
276
+
277
+ $this->add_responsive_control(
278
+ 'height',
279
+ [
280
+ 'label' => __( 'Height', 'happy-elementor-addons' ),
281
+ 'type' => Controls_Manager::SLIDER,
282
+ 'size_units' => ['px'],
283
+ 'range' => [
284
+ 'px' => [
285
+ 'max' => 500,
286
+ 'min' => 100,
287
+ ]
288
+ ],
289
+ 'selectors' => [
290
+ '{{WRAPPER}} .ha-logo-grid-item' => 'height: {{SIZE}}{{UNIT}};'
291
+ ],
292
+ ]
293
+ );
294
+
295
+ $this->add_control(
296
+ 'grid_border_type',
297
+ [
298
+ 'label' => __( 'Border Type', 'happy-elementor-addons' ),
299
+ 'type' => Controls_Manager::SELECT,
300
+ 'options' => [
301
+ 'none' => __( 'None', 'happy-elementor-addons' ),
302
+ 'solid' => __( 'Solid', 'happy-elementor-addons' ),
303
+ 'double' => __( 'Double', 'happy-elementor-addons' ),
304
+ 'dotted' => __( 'Dotted', 'happy-elementor-addons' ),
305
+ 'dashed' => __( 'Dashed', 'happy-elementor-addons' ),
306
+ 'groove' => __( 'Groove', 'happy-elementor-addons' ),
307
+ ],
308
+ 'default' => 'solid',
309
+ 'selectors' => [
310
+ '{{WRAPPER}} .ha-logo-grid-item' => 'border-style: {{VALUE}};',
311
+ ],
312
+ ]
313
+ );
314
+
315
+ $this->add_responsive_control(
316
+ 'grid_border_width',
317
+ [
318
+ 'label' => __( 'Border Width', 'happy-elementor-addons' ),
319
+ 'type' => Controls_Manager::SLIDER,
320
+ 'size_units' => ['px'],
321
+ 'selectors' => [
322
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-item' => 'border-right-width: {{grid_border_width.SIZE}}{{UNIT}}; border-bottom-width: {{grid_border_width.SIZE}}{{UNIT}};',
323
+ '(tablet){{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-item' => 'border-right-width: {{grid_border_width_tablet.SIZE}}{{UNIT}}; border-bottom-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
324
+ '(mobile){{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-item' => 'border-right-width: {{grid_border_width_mobile.SIZE}}{{UNIT}}; border-bottom-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
325
+
326
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-2 .ha-logo-grid-item:nth-child(2n+1)' => 'border-left-width: {{grid_border_width.SIZE}}{{UNIT}};',
327
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-3 .ha-logo-grid-item:nth-child(3n+1)' => 'border-left-width: {{grid_border_width.SIZE}}{{UNIT}};',
328
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-4 .ha-logo-grid-item:nth-child(4n+1)' => 'border-left-width: {{grid_border_width.SIZE}}{{UNIT}};',
329
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-5 .ha-logo-grid-item:nth-child(5n+1)' => 'border-left-width: {{grid_border_width.SIZE}}{{UNIT}};',
330
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-6 .ha-logo-grid-item:nth-child(6n+1)' => 'border-left-width: {{grid_border_width.SIZE}}{{UNIT}};',
331
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-2 .ha-logo-grid-item:nth-child(-n+2)' => 'border-top-width: {{grid_border_width.SIZE}}{{UNIT}};',
332
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-3 .ha-logo-grid-item:nth-child(-n+3)' => 'border-top-width: {{grid_border_width.SIZE}}{{UNIT}};',
333
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-4 .ha-logo-grid-item:nth-child(-n+4)' => 'border-top-width: {{grid_border_width.SIZE}}{{UNIT}};',
334
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-5 .ha-logo-grid-item:nth-child(-n+5)' => 'border-top-width: {{grid_border_width.SIZE}}{{UNIT}};',
335
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-6 .ha-logo-grid-item:nth-child(-n+6)' => 'border-top-width: {{grid_border_width.SIZE}}{{UNIT}};',
336
+
337
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-child(2n+1)' => 'border-left-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
338
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-child(3n+1)' => 'border-left-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
339
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-child(4n+1)' => 'border-left-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
340
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-child(5n+1)' => 'border-left-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
341
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-child(6n+1)' => 'border-left-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
342
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-child(-n+2)' => 'border-top-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
343
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-child(-n+3)' => 'border-top-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
344
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-child(-n+4)' => 'border-top-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
345
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-child(-n+5)' => 'border-top-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
346
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-child(-n+6)' => 'border-top-width: {{grid_border_width_tablet.SIZE}}{{UNIT}};',
347
+
348
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-child(2n+1)' => 'border-left-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
349
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-child(3n+1)' => 'border-left-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
350
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-child(4n+1)' => 'border-left-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
351
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-child(5n+1)' => 'border-left-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
352
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-child(6n+1)' => 'border-left-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
353
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-child(-n+2)' => 'border-top-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
354
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-child(-n+3)' => 'border-top-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
355
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-child(-n+4)' => 'border-top-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
356
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-child(-n+5)' => 'border-top-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
357
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-child(-n+6)' => 'border-top-width: {{grid_border_width_mobile.SIZE}}{{UNIT}};',
358
+
359
+ '{{WRAPPER}}.ha-logo-grid--tictactoe .ha-logo-grid-item' => 'border-top-width: {{SIZE}}{{UNIT}}; border-right-width: {{SIZE}}{{UNIT}};',
360
+
361
+ '{{WRAPPER}}.ha-logo-grid--box .ha-logo-grid-item' => 'border-width: {{SIZE}}{{UNIT}};',
362
+ ],
363
+ 'condition' => [
364
+ 'grid_border_type!' => 'none',
365
+ ]
366
+ ]
367
+ );
368
+
369
+ $this->add_control(
370
+ 'grid_border_color',
371
+ [
372
+ 'label' => __( 'Border Color', 'happy-elementor-addons' ),
373
+ 'type' => Controls_Manager::COLOR,
374
+ 'selectors' => [
375
+ '{{WRAPPER}} .ha-logo-grid-item' => 'border-color: {{VALUE}};',
376
+ ],
377
+ 'condition' => [
378
+ 'grid_border_type!' => 'none',
379
+ ]
380
+ ]
381
+ );
382
+
383
+ $this->add_control(
384
+ 'grid_bg_color',
385
+ [
386
+ 'label' => __( 'Background Color', 'happy-elementor-addons' ),
387
+ 'type' => Controls_Manager::COLOR,
388
+ 'selectors' => [
389
+ '{{WRAPPER}} .ha-logo-grid-figure' => 'background-color: {{VALUE}};',
390
+ ],
391
+ ]
392
+ );
393
+
394
+ $this->add_responsive_control(
395
+ 'grid_border_radius',
396
+ [
397
+ 'label' => __( 'Border Radius', 'happy-elementor-addons' ),
398
+ 'type' => Controls_Manager::DIMENSIONS,
399
+ 'size_units' => ['px', '%'],
400
+ 'selectors' => [
401
+ '{{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-wrapper, {{WRAPPER}}.ha-logo-grid--box .ha-logo-grid-item' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
402
+ '{{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-item:first-child' => 'border-top-left-radius: {{TOP}}{{UNIT}};',
403
+ '{{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-item:last-child' => 'border-bottom-right-radius: {{BOTTOM}}{{UNIT}};',
404
+
405
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
406
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
407
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
408
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
409
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
410
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
411
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
412
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
413
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
414
+ '(desktop+){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col-6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
415
+
416
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
417
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
418
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
419
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
420
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
421
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
422
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
423
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
424
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
425
+ '(tablet){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
426
+
427
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
428
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
429
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
430
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
431
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
432
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
433
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
434
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
435
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
436
+ '(mobile){{WRAPPER}}.ha-logo-grid--border.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
437
+
438
+ // Tictactoe
439
+ '{{WRAPPER}}.ha-logo-grid--tictactoe .ha-logo-grid-wrapper' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
440
+ '{{WRAPPER}}.ha-logo-grid--tictactoe .ha-logo-grid-item:first-child' => 'border-top-left-radius: {{TOP}}{{UNIT}};',
441
+ '{{WRAPPER}}.ha-logo-grid--tictactoe .ha-logo-grid-item:last-child' => 'border-bottom-right-radius: {{BOTTOM}}{{UNIT}};',
442
+
443
+ '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
444
+ '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
445
+ '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
446
+ '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
447
+ '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
448
+ '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
449
+ '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
450
+ '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
451
+ '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius.RIGHT}}{{UNIT}};',
452
+ '(desktop+){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col-6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius.LEFT}}{{UNIT}};',
453
+
454
+ '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
455
+ '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
456
+ '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
457
+ '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
458
+ '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
459
+ '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
460
+ '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
461
+ '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
462
+ '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius_tablet.RIGHT}}{{UNIT}};',
463
+ '(tablet){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--tablet6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius_tablet.LEFT}}{{UNIT}};',
464
+
465
+ '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-child(2)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
466
+ '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile2 .ha-logo-grid-item:nth-last-child(2)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
467
+ '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-child(3)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
468
+ '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile3 .ha-logo-grid-item:nth-last-child(3)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
469
+ '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-child(4)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
470
+ '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile4 .ha-logo-grid-item:nth-last-child(4)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
471
+ '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-child(5)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
472
+ '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile5 .ha-logo-grid-item:nth-last-child(5)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
473
+ '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-child(6)' => 'border-top-right-radius: {{grid_border_radius_mobile.RIGHT}}{{UNIT}};',
474
+ '(mobile){{WRAPPER}}.ha-logo-grid--tictactoe.ha-logo-grid--col--mobile6 .ha-logo-grid-item:nth-last-child(6)' => 'border-bottom-left-radius: {{grid_border_radius_mobile.LEFT}}{{UNIT}};',
475
+ ],
476
+ ]
477
+ );
478
+
479
+ $this->add_group_control(
480
+ Group_Control_Box_Shadow::get_type(),
481
+ [
482
+ 'name' => 'grid_box_shadow',
483
+ 'exclude' => [
484
+ 'box_shadow_position',
485
+ ],
486
+ 'selector' => '{{WRAPPER}}.ha-logo-grid--tictactoe .ha-logo-grid-wrapper, {{WRAPPER}}.ha-logo-grid--border .ha-logo-grid-wrapper, {{WRAPPER}}.ha-logo-grid--box .ha-logo-grid-item'
487
+ ]
488
+ );
489
+
490
+
491
+ $this->start_controls_tabs(
492
+ '_tabs_image_effects',
493
+ [
494
+ 'separator' => 'before'
495
+ ]
496
+ );
497
+
498
+ $this->start_controls_tab(
499
+ '_tab_image_effects_normal',
500
+ [
501
+ 'label' => __( 'Normal', 'happy-elementor-addons' ),
502
+ ]
503
+ );
504
+
505
+ $this->add_control(
506
+ 'image_opacity',
507
+ [
508
+ 'label' => __( 'Opacity', 'happy-elementor-addons' ),
509
+ 'type' => Controls_Manager::SLIDER,
510
+ 'range' => [
511
+ 'px' => [
512
+ 'max' => 1,
513
+ 'min' => 0.10,
514
+ 'step' => 0.01,
515
+ ],
516
+ ],
517
+ 'selectors' => [
518
+ '{{WRAPPER}} .ha-logo-grid-figure img' => 'opacity: {{SIZE}};',
519
+ ],
520
+ ]
521
+ );
522
+
523
+ $this->add_group_control(
524
+ Group_Control_Css_Filter::get_type(),
525
+ [
526
+ 'name' => 'image_css_filters',
527
+ 'selector' => '{{WRAPPER}} .ha-logo-grid-figure img',
528
+ ]
529
+ );
530
+
531
+ $this->end_controls_tab();
532
+
533
+ $this->start_controls_tab( 'hover',
534
+ [
535
+ 'label' => __( 'Hover', 'happy-elementor-addons' ),
536
+ ]
537
+ );
538
+
539
+ $this->add_control(
540
+ 'image_opacity_hover',
541
+ [
542
+ 'label' => __( 'Opacity', 'happy-elementor-addons' ),
543
+ 'type' => Controls_Manager::SLIDER,
544
+ 'range' => [
545
+ 'px' => [
546
+ 'max' => 1,
547
+ 'min' => 0.10,
548
+ 'step' => 0.01,
549
+ ],
550
+ ],
551
+ 'selectors' => [
552
+ '{{WRAPPER}} .ha-logo-grid-figure:hover img' => 'opacity: {{SIZE}};',
553
+ ],
554
+ ]
555
+ );
556
+
557
+ $this->add_group_control(
558
+ Group_Control_Css_Filter::get_type(),
559
+ [
560
+ 'name' => 'image_css_filters_hover',
561
+ 'selector' => '{{WRAPPER}} .ha-logo-grid-figure:hover img',
562
+ ]
563
+ );
564
+
565
+ $this->add_control(
566
+ 'image_bg_hover_transition',
567
+ [
568
+ 'label' => __( 'Transition Duration', 'happy-elementor-addons' ),
569
+ 'type' => Controls_Manager::SLIDER,
570
+ 'range' => [
571
+ 'px' => [
572
+ 'max' => 3,
573
+ 'step' => 0.1,
574
+ ],
575
+ ],
576
+ 'selectors' => [
577
+ '{{WRAPPER}} .ha-logo-grid-figure:hover img' => 'transition-duration: {{SIZE}}s;',
578
+ ],
579
+ ]
580
+ );
581
+
582
+ $this->add_control(
583
+ 'hover_animation',
584
+ [
585
+ 'label' => __( 'Hover Animation', 'happy-elementor-addons' ),
586
+ 'type' => Controls_Manager::HOVER_ANIMATION,
587
+ 'label_block' => true,
588
+ ]
589
+ );
590
+
591
+ $this->end_controls_tab();
592
+ $this->end_controls_tabs();
593
+
594
+ $this->end_controls_section();
595
+ }
596
+
597
+ protected function render() {
598
+ $settings = $this->get_settings_for_display();
599
+
600
+ if ( empty($settings['logo_list'] ) ) {
601
+ return;
602
+ }
603
+ ?>
604
+
605
+ <div class="ha-logo-grid-wrapper">
606
+ <?php
607
+ foreach ( $settings['logo_list'] as $index => $item ) :
608
+ $image = wp_get_attachment_image_url( $item['image']['id'], $settings['thumbnail_size'] );
609
+ $repeater_key = 'grid_item' . $index;
610
+ $tag = 'div';
611
+ $this->add_render_attribute( $repeater_key, 'class', 'ha-logo-grid-item' );
612
+
613
+ if ( $item['link']['url'] ) {
614
+ $tag = 'a';
615
+ $this->add_render_attribute( $repeater_key, 'class', 'ha-logo-grid-link' );
616
+ $this->add_link_attributes( $repeater_key, $item['link'] );
617
+ }
618
+ ?>
619
+ <<?php echo $tag; ?> <?php $this->print_render_attribute_string( $repeater_key ); ?>>
620
+ <figure class="ha-logo-grid-figure">
621
+ <?php if ( $image ) :
622
+ echo wp_get_attachment_image(
623
+ $item['image']['id'],
624
+ $settings['thumbnail_size'],
625
+ false,
626
+ [
627
+ 'class' => 'ha-logo-grid-img elementor-animation-' . esc_attr( $settings['hover_animation'] )
628
+ ]
629
+ );
630
+ else :
631
+ printf( '<img class="ha-logo-grid-img elementor-animation-%s" src="%s" alt="%s">',
632
+ esc_attr( $settings['hover_animation'] ),
633
+ Utils::get_placeholder_image_src(),
634
+ esc_attr( $item['name'] )
635
+ );
636
+ endif; ?>
637
+ </figure>
638
+ </<?php echo $tag; ?>>
639
+ <?php endforeach; ?>
640
+ </div>
641
+
642
+ <?php
643
+ }
644
+ }
widgets/member/widget.php CHANGED
@@ -1,1336 +1,1338 @@
1
- <?php
2
- /**
3
- * Member widget class
4
- *
5
- * @package Happy_Addons
6
- */
7
- namespace Happy_Addons\Elementor\Widget;
8
-
9
- use Elementor\Group_Control_Text_Shadow;
10
- use Elementor\Repeater;
11
- use Elementor\Scheme_Typography;
12
- use Elementor\Utils;
13
- use Elementor\Control_Media;
14
- use Elementor\Controls_Manager;
15
- use Elementor\Group_Control_Border;
16
- use Elementor\Group_Control_Box_Shadow;
17
- use Elementor\Group_Control_Image_Size;
18
- use Elementor\Group_Control_Typography;
19
- use Happy_Addons\Elementor\Traits\Button_Renderer;
20
-
21
- defined( 'ABSPATH' ) || die();
22
-
23
- class Member extends Base {
24
-
25
- use Button_Renderer;
26
-
27
- /**
28
- * Get widget title.
29
- *
30
- * @since 1.0.0
31
- * @access public
32
- *
33
- * @return string Widget title.
34
- */
35
- public function get_title() {
36
- return __( 'Team Member', 'happy-elementor-addons' );
37
- }
38
-
39
- public function get_custom_help_url() {
40
- return 'https://happyaddons.com/docs/happy-addons-for-elementor/widgets/team-member/';
41
- }
42
-
43
- /**
44
- * Get widget icon.
45
- *
46
- * @since 1.0.0
47
- * @access public
48
- *
49
- * @return string Widget icon.
50
- */
51
- public function get_icon() {
52
- return 'hm hm-team-member';
53
- }
54
-
55
- public function get_keywords() {
56
- return [ 'team', 'member', 'crew', 'staff', 'person' ];
57
- }
58
-
59
- public function get_style_depends() {
60
- return [
61
- 'elementor-icons-fa-solid',
62
- 'elementor-icons-fa-brands',
63
- ];
64
- }
65
-
66
- protected static function get_profile_names() {
67
- return [
68
- '500px' => __( '500px', 'happy-elementor-addons' ),
69
- 'apple' => __( 'Apple', 'happy-elementor-addons' ),
70
- 'behance' => __( 'Behance', 'happy-elementor-addons' ),
71
- 'bitbucket' => __( 'BitBucket', 'happy-elementor-addons' ),
72
- 'codepen' => __( 'CodePen', 'happy-elementor-addons' ),
73
- 'delicious' => __( 'Delicious', 'happy-elementor-addons' ),
74
- 'deviantart' => __( 'DeviantArt', 'happy-elementor-addons' ),
75
- 'digg' => __( 'Digg', 'happy-elementor-addons' ),
76
- 'dribbble' => __( 'Dribbble', 'happy-elementor-addons' ),
77
- 'email' => __( 'Email', 'happy-elementor-addons' ),
78
- 'facebook' => __( 'Facebook', 'happy-elementor-addons' ),
79
- 'flickr' => __( 'Flicker', 'happy-elementor-addons' ),
80
- 'foursquare' => __( 'FourSquare', 'happy-elementor-addons' ),
81
- 'github' => __( 'Github', 'happy-elementor-addons' ),
82
- 'houzz' => __( 'Houzz', 'happy-elementor-addons' ),
83
- 'instagram' => __( 'Instagram', 'happy-elementor-addons' ),
84
- 'jsfiddle' => __( 'JS Fiddle', 'happy-elementor-addons' ),
85
- 'linkedin' => __( 'LinkedIn', 'happy-elementor-addons' ),
86
- 'medium' => __( 'Medium', 'happy-elementor-addons' ),
87
- 'pinterest' => __( 'Pinterest', 'happy-elementor-addons' ),
88
- 'product-hunt' => __( 'Product Hunt', 'happy-elementor-addons' ),
89
- 'reddit' => __( 'Reddit', 'happy-elementor-addons' ),
90
- 'slideshare' => __( 'Slide Share', 'happy-elementor-addons' ),
91
- 'snapchat' => __( 'Snapchat', 'happy-elementor-addons' ),
92
- 'soundcloud' => __( 'SoundCloud', 'happy-elementor-addons' ),
93
- 'spotify' => __( 'Spotify', 'happy-elementor-addons' ),
94
- 'stack-overflow' => __( 'StackOverflow', 'happy-elementor-addons' ),
95
- 'tripadvisor' => __( 'TripAdvisor', 'happy-elementor-addons' ),
96
- 'tumblr' => __( 'Tumblr', 'happy-elementor-addons' ),
97
- 'twitch' => __( 'Twitch', 'happy-elementor-addons' ),
98
- 'twitter' => __( 'Twitter', 'happy-elementor-addons' ),
99
- 'vimeo' => __( 'Vimeo', 'happy-elementor-addons' ),
100
- 'vk' => __( 'VK', 'happy-elementor-addons' ),
101
- 'website' => __( 'Website', 'happy-elementor-addons' ),
102
- 'whatsapp' => __( 'WhatsApp', 'happy-elementor-addons' ),
103
- 'wordpress' => __( 'WordPress', 'happy-elementor-addons' ),
104
- 'xing' => __( 'Xing', 'happy-elementor-addons' ),
105
- 'yelp' => __( 'Yelp', 'happy-elementor-addons' ),
106
- 'youtube' => __( 'YouTube', 'happy-elementor-addons' ),
107
- ];
108
- }
109
-
110
- /**
111
- * Register content related controls
112
- */
113
- protected function register_content_controls() {
114
- $this->start_controls_section(
115
- '_section_info',
116
- [
117
- 'label' => __( 'Information', 'happy-elementor-addons' ),
118
- 'tab' => Controls_Manager::TAB_CONTENT,
119
- ]
120
- );
121
-
122
- $this->add_control(
123
- 'image',
124
- [
125
- 'label' => __( 'Photo', 'happy-elementor-addons' ),
126
- 'type' => Controls_Manager::MEDIA,
127
- 'default' => [
128
- 'url' => Utils::get_placeholder_image_src(),
129
- ],
130
- 'dynamic' => [
131
- 'active' => true,
132
- ]
133
- ]
134
- );
135
-
136
- $this->add_group_control(
137
- Group_Control_Image_Size::get_type(),
138
- [
139
- 'name' => 'thumbnail',
140
- 'default' => 'large',
141
- 'separator' => 'none',
142
- ]
143
- );
144
-
145
- $this->add_control(
146
- 'title',
147
- [
148
- 'label' => __( 'Name', 'happy-elementor-addons' ),
149
- 'label_block' => true,
150
- 'type' => Controls_Manager::TEXT,
151
- 'default' => 'Happy Member Name',
152
- 'placeholder' => __( 'Type Member Name', 'happy-elementor-addons' ),
153
- 'separator' => 'before',
154
- 'dynamic' => [
155
- 'active' => true,
156
- ]
157
- ]
158
- );
159
-
160
- $this->add_control(
161
- 'job_title',
162
- [
163
- 'label' => __( 'Job Title', 'happy-elementor-addons' ),
164
- 'label_block' => true,
165
- 'type' => Controls_Manager::TEXT,
166
- 'default' => __( 'Happy Officer', 'happy-elementor-addons' ),
167
- 'placeholder' => __( 'Type Member Job Title', 'happy-elementor-addons' ),
168
- 'dynamic' => [
169
- 'active' => true,
170
- ]
171
- ]
172
- );
173
-
174
- $this->add_control(
175
- 'bio',
176
- [
177
- 'label' => __( 'Short Bio', 'happy-elementor-addons' ),
178
- 'description' => ha_get_allowed_html_desc( 'intermediate' ),
179
- 'type' => Controls_Manager::TEXTAREA,
180
- 'placeholder' => __( 'Write something amazing about the happy member', 'happy-elementor-addons' ),
181
- 'rows' => 5,
182
- 'dynamic' => [
183
- 'active' => true,
184
- ]
185
- ]
186
- );
187
-
188
- $this->add_control(
189
- 'title_tag',
190
- [
191
- 'label' => __( 'Title HTML Tag', 'happy-elementor-addons' ),
192
- 'type' => Controls_Manager::CHOOSE,
193
- 'options' => [
194
- 'h1' => [
195
- 'title' => __( 'H1', 'happy-elementor-addons' ),
196
- 'icon' => 'eicon-editor-h1'
197
- ],
198
- 'h2' => [
199
- 'title' => __( 'H2', 'happy-elementor-addons' ),
200
- 'icon' => 'eicon-editor-h2'
201
- ],
202
- 'h3' => [
203
- 'title' => __( 'H3', 'happy-elementor-addons' ),
204
- 'icon' => 'eicon-editor-h3'
205
- ],
206
- 'h4' => [
207
- 'title' => __( 'H4', 'happy-elementor-addons' ),
208
- 'icon' => 'eicon-editor-h4'
209
- ],
210
- 'h5' => [
211
- 'title' => __( 'H5', 'happy-elementor-addons' ),
212
- 'icon' => 'eicon-editor-h5'
213
- ],
214
- 'h6' => [
215
- 'title' => __( 'H6', 'happy-elementor-addons' ),
216
- 'icon' => 'eicon-editor-h6'
217
- ]
218
- ],
219
- 'default' => 'h2',
220
- 'toggle' => false,
221
- 'separator' => 'before',
222
- ]
223
- );
224
-
225
- $this->add_responsive_control(
226
- 'align',
227
- [
228
- 'label' => __( 'Alignment', 'happy-elementor-addons' ),
229
- 'type' => Controls_Manager::CHOOSE,
230
- 'options' => [
231
- 'left' => [
232
- 'title' => __( 'Left', 'happy-elementor-addons' ),
233
- 'icon' => 'eicon-text-align-left',
234
- ],
235
- 'center' => [
236
- 'title' => __( 'Center', 'happy-elementor-addons' ),
237
- 'icon' => 'eicon-text-align-center',
238
- ],
239
- 'right' => [
240
- 'title' => __( 'Right', 'happy-elementor-addons' ),
241
- 'icon' => 'eicon-text-align-right',
242
- ],
243
- 'justify' => [
244
- 'title' => __( 'Justify', 'happy-elementor-addons' ),
245
- 'icon' => 'eicon-text-align-justify',
246
- ],
247
- ],
248
- 'toggle' => true,
249
- 'selectors' => [
250
- '{{WRAPPER}}' => 'text-align: {{VALUE}};'
251
- ]
252
- ]
253
- );
254
-
255
- $this->end_controls_section();
256
-
257
- $this->start_controls_section(
258
- '_section_social',
259
- [
260
- 'label' => __( 'Social Profiles', 'happy-elementor-addons' ),
261
- 'tab' => Controls_Manager::TAB_CONTENT,
262
- ]
263
- );
264
-
265
- $repeater = new Repeater();
266
-
267
- $repeater->add_control(
268
- 'name',
269
- [
270
- 'label' => __( 'Profile Name', 'happy-elementor-addons' ),
271
- 'type' => Controls_Manager::SELECT2,
272
- 'label_block' => true,
273
- 'select2options' => [
274
- 'allowClear' => false,
275
- ],
276
- 'options' => self::get_profile_names()
277
- ]
278
- );
279
-
280
- $repeater->add_control(
281
- 'link', [
282
- 'label' => __( 'Profile Link', 'happy-elementor-addons' ),
283
- 'placeholder' => __( 'Add your profile link', 'happy-elementor-addons' ),
284
- 'type' => Controls_Manager::URL,
285
- 'label_block' => true,
286
- 'autocomplete' => false,
287
- 'show_external' => false,
288
- 'condition' => [
289
- 'name!' => 'email'
290
- ],
291
- 'dynamic' => [
292
- 'active' => true,
293
- ]
294
- ]
295
- );
296
-
297
- $repeater->add_control(
298
- 'email', [
299
- 'label' => __( 'Email Address', 'happy-elementor-addons' ),
300
- 'placeholder' => __( 'Add your email address', 'happy-elementor-addons' ),
301
- 'type' => Controls_Manager::TEXT,
302
- 'label_block' => false,
303
- 'input_type' => 'email',
304
- 'condition' => [
305
- 'name' => 'email'
306
- ],
307
- 'dynamic' => [
308
- 'active' => true,
309
- ]
310
- ]
311
- );
312
-
313
- $repeater->add_control(
314
- 'customize',
315
- [
316
- 'label' => __( 'Want To Customize?', 'happy-elementor-addons' ),
317
- 'type' => Controls_Manager::SWITCHER,
318
- 'label_on' => __( 'Yes', 'happy-elementor-addons' ),
319
- 'label_off' => __( 'No', 'happy-elementor-addons' ),
320
- 'return_value' => 'yes',
321
- 'style_transfer' => true,
322
- ]
323
- );
324
-
325
- $repeater->start_controls_tabs(
326
- '_tab_icon_colors',
327
- [
328
- 'condition' => ['customize' => 'yes']
329
- ]
330
- );
331
- $repeater->start_controls_tab(
332
- '_tab_icon_normal',
333
- [
334
- 'label' => __( 'Normal', 'happy-elementor-addons' ),
335
- ]
336
- );
337
-
338
- $repeater->add_control(
339
- 'color',
340
- [
341
- 'label' => __( 'Text Color', 'happy-elementor-addons' ),
342
- 'type' => Controls_Manager::COLOR,
343
- 'selectors' => [
344
- '{{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}' => 'color: {{VALUE}}',
345
- ],
346
- 'condition' => ['customize' => 'yes'],
347
- 'style_transfer' => true,
348
- ]
349
- );
350
-
351
- $repeater->add_control(
352
- 'bg_color',
353
- [
354
- 'label' => __( 'Background Color', 'happy-elementor-addons' ),
355
- 'type' => Controls_Manager::COLOR,
356
- 'selectors' => [
357
- '{{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}' => 'background-color: {{VALUE}}',
358
- ],
359
- 'condition' => ['customize' => 'yes'],
360
- 'style_transfer' => true,
361
- ]
362
- );
363
-
364
- $repeater->end_controls_tab();
365
- $repeater->start_controls_tab(
366
- '_tab_icon_hover',
367
- [
368
- 'label' => __( 'Hover', 'happy-elementor-addons' ),
369
- ]
370
- );
371
-
372
- $repeater->add_control(
373
- 'hover_color',
374
- [
375
- 'label' => __( 'Text Color', 'happy-elementor-addons' ),
376
- 'type' => Controls_Manager::COLOR,
377
- 'selectors' => [
378
- '{{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:hover, {{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:focus' => 'color: {{VALUE}}',
379
- ],
380
- 'condition' => ['customize' => 'yes'],
381
- 'style_transfer' => true,
382
- ]
383
- );
384
-
385
- $repeater->add_control(
386
- 'hover_bg_color',
387
- [
388
- 'label' => __( 'Background Color', 'happy-elementor-addons' ),
389
- 'type' => Controls_Manager::COLOR,
390
- 'selectors' => [
391
- '{{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:hover, {{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:focus' => 'background-color: {{VALUE}}',
392
- ],
393
- 'condition' => ['customize' => 'yes'],
394
- 'style_transfer' => true,
395
- ]
396
- );
397
-
398
- $repeater->add_control(
399
- 'hover_border_color',
400
- [
401
- 'label' => __( 'Border Color', 'happy-elementor-addons' ),
402
- 'type' => Controls_Manager::COLOR,
403
- 'selectors' => [
404
- '{{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:hover, {{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:focus' => 'border-color: {{VALUE}}',
405
- ],
406
- 'condition' => ['customize' => 'yes'],
407
- 'style_transfer' => true,
408
- ]
409
- );
410
-
411
- $repeater->end_controls_tab();
412
- $repeater->end_controls_tabs();
413
-
414
- $this->add_control(
415
- 'profiles',
416
- [
417
- 'show_label' => false,
418
- 'type' => Controls_Manager::REPEATER,
419
- 'fields' => $repeater->get_controls(),
420
- 'title_field' => '<# print(name.slice(0,1).toUpperCase() + name.slice(1)) #>',
421
- 'default' => [
422
- [
423
- 'link' => ['url' => 'https://facebook.com/'],
424
- 'name' => 'facebook'
425
- ],
426
- [
427
- 'link' => ['url' => 'https://twitter.com/'],
428
- 'name' => 'twitter'
429
- ],
430
- [
431
- 'link' => ['url' => 'https://linkedin.com/'],
432
- 'name' => 'linkedin'
433
- ]
434
- ],
435
- ]
436
- );
437
-
438
- $this->add_control(
439
- 'show_profiles',
440
- [
441
- 'label' => __( 'Show Profiles', 'happy-elementor-addons' ),
442
- 'type' => Controls_Manager::SWITCHER,
443
- 'label_on' => __( 'Show', 'happy-elementor-addons' ),
444
- 'label_off' => __( 'Hide', 'happy-elementor-addons' ),
445
- 'return_value' => 'yes',
446
- 'default' => 'yes',
447
- 'separator' => 'before',
448
- 'style_transfer' => true,
449
- ]
450
- );
451
-
452
- $this->end_controls_section();
453
-
454
- $this->start_controls_section(
455
- '_section_button',
456
- [
457
- 'label' => __( 'Details Button', 'happy-elementor-addons' ),
458
- 'tab' => Controls_Manager::TAB_CONTENT,
459
- ]
460
- );
461
-
462
- $this->add_control(
463
- 'show_details_button',
464
- [
465
- 'label' => __( 'Show Button', 'happy-elementor-addons' ),
466
- 'type' => Controls_Manager::SWITCHER,
467
- 'label_on' => __( 'Show', 'happy-elementor-addons' ),
468
- 'label_off' => __( 'Hide', 'happy-elementor-addons' ),
469
- 'return_value' => 'yes',
470
- 'default' => '',
471
- 'style_transfer' => true,
472
- ]
473
- );
474
-
475
- $this->add_control(
476
- 'button_position',
477
- [
478
- 'label' => __( 'Position', 'happy-elementor-addons' ),
479
- 'type' => Controls_Manager::SELECT,
480
- 'default' => 'after',
481
- 'style_transfer' => true,
482
- 'options' => [
483
- 'before' => __( 'Before Social Icons', 'happy-elementor-addons' ),
484
- 'after' => __( 'After Social Icons', 'happy-elementor-addons' ),
485
- ],
486
- 'condition' => [
487
- 'show_details_button' => 'yes',
488
- ]
489
- ]
490
- );
491
-
492
- $this->add_control(
493
- 'button_text',
494
- [
495
- 'label' => __( 'Text', 'happy-elementor-addons' ),
496
- 'type' => Controls_Manager::TEXT,
497
- 'default' => __( 'Show Details', 'happy-elementor-addons' ),
498
- 'placeholder' => __( 'Type button text here', 'happy-elementor-addons' ),
499
- 'label_block' => true,
500
- 'dynamic' => [
501
- 'active' => true,
502
- ],
503
- 'condition' => [
504
- 'show_details_button' => 'yes',
505
- ]
506
- ]
507
- );
508
-
509
- $this->add_control(
510
- 'button_link',
511
- [
512
- 'label' => __( 'Link', 'happy-elementor-addons' ),
513
- 'type' => Controls_Manager::URL,
514
- 'placeholder' => 'https://example.com',
515
- 'dynamic' => [
516
- 'active' => true,
517
- ],
518
- 'condition' => [
519
- 'show_details_button' => 'yes',
520
- ],
521
- 'default' => [
522
- 'url' => '#',
523
- ]
524
- ]
525
- );
526
-
527
- $this->add_control(
528
- 'button_icon',
529
- [
530
- 'type' => Controls_Manager::ICONS,
531
- 'label_block' => true,
532
- 'show_label' => false,
533
- 'condition' => [
534
- 'show_details_button' => 'yes',
535
- ]
536
- ]
537
- );
538
-
539
- $this->add_control(
540
- 'button_icon_position',
541
- [
542
- 'label' => __( 'Icon Position', 'happy-elementor-addons' ),
543
- 'type' => Controls_Manager::CHOOSE,
544
- 'label_block' => false,
545
- 'options' => [
546
- 'before' => [
547
- 'title' => __( 'Before', 'happy-elementor-addons' ),
548
- 'icon' => 'eicon-h-align-left',
549
- ],
550
- 'after' => [
551
- 'title' => __( 'After', 'happy-elementor-addons' ),
552
- 'icon' => 'eicon-h-align-right',
553
- ],
554
- ],
555
- 'default' => 'after',
556
- 'toggle' => false,
557
- 'style_transfer' => true,
558
- 'condition' => [
559
- 'show_details_button' => 'yes',
560
- 'button_icon[value]!' => ''
561
- ]
562
- ]
563
- );
564
-
565
- $this->add_control(
566
- 'button_icon_spacing',
567
- [
568
- 'label' => __( 'Icon Spacing', 'happy-elementor-addons' ),
569
- 'type' => Controls_Manager::SLIDER,
570
- 'default' => [
571
- 'size' => 10
572
- ],
573
- 'condition' => [
574
- 'show_details_button' => 'yes',
575
- 'button_icon[value]!' => ''
576
- ],
577
- 'selectors' => [
578
- '{{WRAPPER}} .ha-btn--icon-before .ha-btn-icon' => 'margin-right: {{SIZE}}{{UNIT}};',
579
- '{{WRAPPER}} .ha-btn--icon-after .ha-btn-icon' => 'margin-left: {{SIZE}}{{UNIT}};',
580
- ],
581
- ]
582
- );
583
-
584
- $this->end_controls_section();
585
- }
586
-
587
- /**
588
- * Register styles related controls
589
- */
590
- protected function register_style_controls() {
591
- $this->start_controls_section(
592
- '_section_style_image',
593
- [
594
- 'label' => __( 'Photo', 'happy-elementor-addons' ),
595
- 'tab' => Controls_Manager::TAB_STYLE,
596
- ]
597
- );
598
-
599
- $this->add_responsive_control(
600
- 'image_width',
601
- [
602
- 'label' => __( 'Width', 'happy-elementor-addons' ),
603
- 'type' => Controls_Manager::SLIDER,
604
- 'size_units' => [ 'px', '%'],
605
- 'range' => [
606
- '%' => [
607
- 'min' => 20,
608
- 'max' => 100,
609
- ],
610
- 'px' => [
611
- 'min' => 100,
612
- 'max' => 700,
613
- ],
614
- ],
615
- 'selectors' => [
616
- '{{WRAPPER}} .ha-member-figure' => 'width: {{SIZE}}{{UNIT}};',
617
- ],
618
- ]
619
- );
620
-
621
- $this->add_responsive_control(
622
- 'image_height',
623
- [
624
- 'label' => __( 'Height', 'happy-elementor-addons' ),
625
- 'type' => Controls_Manager::SLIDER,
626
- 'size_units' => [ 'px' ],
627
- 'range' => [
628
- 'px' => [
629
- 'min' => 100,
630
- 'max' => 700,
631
- ],
632
- ],
633
- 'selectors' => [
634
- '{{WRAPPER}} .ha-member-figure' => 'height: {{SIZE}}{{UNIT}};',
635
- ],
636
- ]
637
- );
638
-
639
- $this->add_responsive_control(
640
- 'image_spacing',
641
- [
642
- 'label' => __( 'Bottom Spacing', 'happy-elementor-addons' ),
643
- 'type' => Controls_Manager::SLIDER,
644
- 'size_units' => ['px'],
645
- 'selectors' => [
646
- '{{WRAPPER}} .ha-member-figure' => 'margin-bottom: {{SIZE}}{{UNIT}} !important;',
647
- ],
648
- ]
649
- );
650
-
651
- $this->add_responsive_control(
652
- 'image_padding',
653
- [
654
- 'label' => __( 'Padding', 'happy-elementor-addons' ),
655
- 'type' => Controls_Manager::DIMENSIONS,
656
- 'size_units' => [ 'px', 'em', '%' ],
657
- 'selectors' => [
658
- '{{WRAPPER}} .ha-member-figure img' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
659
- ],
660
- ]
661
- );
662
-
663
- $this->add_group_control(
664
- Group_Control_Border::get_type(),
665
- [
666
- 'name' => 'image_border',
667
- 'selector' => '{{WRAPPER}} .ha-member-figure img'
668
- ]
669
- );
670
-
671
- $this->add_responsive_control(
672
- 'image_border_radius',
673
- [
674
- 'label' => __( 'Border Radius', 'happy-elementor-addons' ),
675
- 'type' => Controls_Manager::DIMENSIONS,
676
- 'size_units' => [ 'px', '%' ],
677
- 'selectors' => [
678
- '{{WRAPPER}} .ha-member-figure img' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
679
- ],
680
- ]
681
- );
682
-
683
- $this->add_group_control(
684
- Group_Control_Box_Shadow::get_type(),
685
- [
686
- 'name' => 'image_box_shadow',
687
- 'exclude' => [
688
- 'box_shadow_position',
689
- ],
690
- 'selector' => '{{WRAPPER}} .ha-member-figure img'
691
- ]
692
- );
693
-
694
- $this->add_control(
695
- 'image_bg_color',
696
- [
697
- 'label' => __( 'Background Color', 'happy-elementor-addons' ),
698
- 'type' => Controls_Manager::COLOR,
699
- 'selectors' => [
700
- '{{WRAPPER}} .ha-member-figure img' => 'background-color: {{VALUE}};',
701
- ],
702
- ]
703
- );
704
-
705
- $this->end_controls_section();
706
-
707
- $this->start_controls_section(
708
- '_section_style_content',
709
- [
710
- 'label' => __( 'Name, Job Title & Bio', 'happy-elementor-addons' ),
711
- 'tab' => Controls_Manager::TAB_STYLE,
712
- ]
713
- );
714
-
715
- $this->add_responsive_control(
716
- 'content_padding',
717
- [
718
- 'label' => __( 'Content Padding', 'happy-elementor-addons' ),
719
- 'type' => Controls_Manager::DIMENSIONS,
720
- 'size_units' => [ 'px', 'em', '%' ],
721
- 'selectors' => [
722
- '{{WRAPPER}} .ha-member-body' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
723
- ],
724
- ]
725
- );
726
-
727
- $this->add_control(
728
- '_heading_title',
729
- [
730
- 'type' => Controls_Manager::HEADING,
731
- 'label' => __( 'Name', 'happy-elementor-addons' ),
732
- 'separator' => 'before',
733
- ]
734
- );
735
-
736
- $this->add_responsive_control(
737
- 'title_spacing',
738
- [
739
- 'label' => __( 'Bottom Spacing', 'happy-elementor-addons' ),
740
- 'type' => Controls_Manager::SLIDER,
741
- 'size_units' => ['px'],
742
- 'selectors' => [
743
- '{{WRAPPER}} .ha-member-name' => 'margin-bottom: {{SIZE}}{{UNIT}};',
744
- ],
745
- ]
746
- );
747
-
748
- $this->add_control(
749
- 'title_color',
750
- [
751
- 'label' => __( 'Text Color', 'happy-elementor-addons' ),
752
- 'type' => Controls_Manager::COLOR,
753
- 'selectors' => [
754
- '{{WRAPPER}} .ha-member-name' => 'color: {{VALUE}}',
755
- ],
756
- ]
757
- );
758
-
759
- $this->add_group_control(
760
- Group_Control_Typography::get_type(),
761
- [
762
- 'name' => 'title_typography',
763
- 'selector' => '{{WRAPPER}} .ha-member-name',
764
- 'scheme' => Scheme_Typography::TYPOGRAPHY_2,
765
- ]
766
- );
767
-
768
- $this->add_group_control(
769
- Group_Control_Text_Shadow::get_type(),
770
- [
771
- 'name' => 'title_text_shadow',
772
- 'selector' => '{{WRAPPER}} .ha-member-name',
773
- ]
774
- );
775
-
776
- $this->add_control(
777
- '_heading_job_title',
778
- [
779
- 'type' => Controls_Manager::HEADING,
780
- 'label' => __( 'Job Title', 'happy-elementor-addons' ),
781
- 'separator' => 'before'
782
- ]
783
- );
784
-
785
- $this->add_responsive_control(
786
- 'job_title_spacing',
787
- [
788
- 'label' => __( 'Bottom Spacing', 'happy-elementor-addons' ),
789
- 'type' => Controls_Manager::SLIDER,
790
- 'size_units' => ['px'],
791
- 'selectors' => [
792
- '{{WRAPPER}} .ha-member-position' => 'margin-bottom: {{SIZE}}{{UNIT}};',
793
- ],
794
- ]
795
- );
796
-
797
- $this->add_control(
798
- 'job_title_color',
799
- [
800
- 'label' => __( 'Text Color', 'happy-elementor-addons' ),
801
- 'type' => Controls_Manager::COLOR,
802
- 'selectors' => [
803
- '{{WRAPPER}} .ha-member-position' => 'color: {{VALUE}}',
804
- ],
805
- ]
806
- );
807
-
808
- $this->add_group_control(
809
- Group_Control_Typography::get_type(),
810
- [
811
- 'name' => 'job_title_typography',
812
- 'selector' => '{{WRAPPER}} .ha-member-position',
813
- 'scheme' => Scheme_Typography::TYPOGRAPHY_3,
814
- ]
815
- );
816
-
817
- $this->add_group_control(
818
- Group_Control_Text_Shadow::get_type(),
819
- [
820
- 'name' => 'job_title_text_shadow',
821
- 'selector' => '{{WRAPPER}} .ha-member-position',
822
- ]
823
- );
824
-
825
- $this->add_control(
826
- '_heading_bio',
827
- [
828
- 'type' => Controls_Manager::HEADING,
829
- 'label' => __( 'Short Bio', 'happy-elementor-addons' ),
830
- 'separator' => 'before'
831
- ]
832
- );
833
-
834
- $this->add_responsive_control(
835
- 'bio_spacing',
836
- [
837
- 'label' => __( 'Bottom Spacing', 'happy-elementor-addons' ),
838
- 'type' => Controls_Manager::SLIDER,
839
- 'size_units' => ['px'],
840
- 'selectors' => [
841
- '{{WRAPPER}} .ha-member-bio' => 'margin-bottom: {{SIZE}}{{UNIT}};',
842
- ],
843
- ]
844
- );
845
-
846
- $this->add_control(
847
- 'bio_color',
848
- [
849
- 'label' => __( 'Text Color', 'happy-elementor-addons' ),
850
- 'type' => Controls_Manager::COLOR,
851
- 'selectors' => [
852
- '{{WRAPPER}} .ha-member-bio' => 'color: {{VALUE}};',
853
- ],
854
- ]
855
- );
856
-
857
- $this->add_group_control(
858
- Group_Control_Typography::get_type(),
859
- [
860
- 'name' => 'bio_typography',
861
- 'selector' => '{{WRAPPER}} .ha-member-bio',
862
- 'scheme' => Scheme_Typography::TYPOGRAPHY_3,
863
- ]
864
- );
865
-
866
- $this->add_group_control(
867
- Group_Control_Text_Shadow::get_type(),
868
- [
869
- 'name' => 'bio_text_shadow',
870
- 'selector' => '{{WRAPPER}} .ha-member-bio',
871
- ]
872
- );
873
-
874
- $this->end_controls_section();
875
-
876
- $this->start_controls_section(
877
- '_section_style_social',
878
- [
879
- 'label' => __( 'Social Icons', 'happy-elementor-addons' ),
880
- 'tab' => Controls_Manager::TAB_STYLE,
881
- ]
882
- );
883
-
884
- $this->add_responsive_control(
885
- 'links_spacing',
886
- [
887
- 'label' => __( 'Right Spacing', 'happy-elementor-addons' ),
888
- 'type' => Controls_Manager::SLIDER,
889
- 'size_units' => ['px'],
890
- 'selectors' => [
891
- '{{WRAPPER}} .ha-member-links > a:not(:last-child)' => 'margin-right: {{SIZE}}{{UNIT}};',
892
- ],
893
- ]
894
- );
895
-
896
- $this->add_responsive_control(
897
- 'links_padding',
898
- [
899
- 'label' => __( 'Padding', 'happy-elementor-addons' ),
900
- 'type' => Controls_Manager::SLIDER,
901
- 'size_units' => ['px'],
902
- 'selectors' => [
903
- '{{WRAPPER}} .ha-member-links > a' => 'padding: {{SIZE}}{{UNIT}};',
904
- ],
905
- ]
906
- );
907
-
908
- $this->add_responsive_control(
909
- 'links_icon_size',
910
- [
911
- 'label' => __( 'Icon Size', 'happy-elementor-addons' ),
912
- 'type' => Controls_Manager::SLIDER,
913
- 'size_units' => ['px'],
914
- 'selectors' => [
915
- '{{WRAPPER}} .ha-member-links > a' => 'font-size: {{SIZE}}{{UNIT}};',
916
- ],
917
- ]
918
- );
919
-
920
- $this->add_group_control(
921
- Group_Control_Border::get_type(),
922
- [
923
- 'name' => 'links_border',
924
- 'selector' => '{{WRAPPER}} .ha-member-links > a'
925
- ]
926
- );
927
-
928
- $this->add_responsive_control(
929
- 'links_border_radius',
930
- [
931
- 'label' => __( 'Border Radius', 'happy-elementor-addons' ),
932
- 'type' => Controls_Manager::DIMENSIONS,
933
- 'size_units' => [ 'px', '%' ],
934
- 'selectors' => [
935
- '{{WRAPPER}} .ha-member-links > a' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
936
- ],
937
- ]
938
- );
939
-
940
- $this->start_controls_tabs( '_tab_links_colors' );
941
- $this->start_controls_tab(
942
- '_tab_links_normal',
943
- [
944
- 'label' => __( 'Normal', 'happy-elementor-addons' ),
945
- ]
946
- );
947
-
948
- $this->add_control(
949
- 'links_color',
950
- [
951
- 'label' => __( 'Text Color', 'happy-elementor-addons' ),
952
- 'type' => Controls_Manager::COLOR,
953
- 'selectors' => [
954
- '{{WRAPPER}} .ha-member-links > a' => 'color: {{VALUE}};',
955
- ],
956
- ]
957
- );
958
-
959
- $this->add_control(
960
- 'links_bg_color',
961
- [
962
- 'label' => __( 'Background Color', 'happy-elementor-addons' ),
963
- 'type' => Controls_Manager::COLOR,
964
- 'selectors' => [
965
- '{{WRAPPER}} .ha-member-links > a' => 'background-color: {{VALUE}};',
966
- ],
967
- ]
968
- );
969
-
970
- $this->end_controls_tab();
971
- $this->start_controls_tab(
972
- '_tab_links_hover',
973
- [
974
- 'label' => __( 'Hover', 'happy-elementor-addons' ),
975
- ]
976
- );
977
-
978
- $this->add_control(
979
- 'links_hover_color',
980
- [
981
- 'label' => __( 'Text Color', 'happy-elementor-addons' ),
982
- 'type' => Controls_Manager::COLOR,
983
- 'selectors' => [
984
- '{{WRAPPER}} .ha-member-links > a:hover, {{WRAPPER}} .ha-member-links > a:focus' => 'color: {{VALUE}}',
985
- ],
986
- ]
987
- );
988
-
989
- $this->add_control(
990
- 'links_hover_bg_color',
991
- [
992
- 'label' => __( 'Background Color', 'happy-elementor-addons' ),
993
- 'type' => Controls_Manager::COLOR,
994
- 'selectors' => [
995
- '{{WRAPPER}} .ha-member-links > a:hover, {{WRAPPER}} .ha-member-links > a:focus' => 'background-color: {{VALUE}}',
996
- ],
997
- ]
998
- );
999
-
1000
- $this->add_control(
1001
- 'links_hover_border_color',
1002
- [
1003
- 'label' => __( 'Border Color', 'happy-elementor-addons' ),
1004
- 'type' => Controls_Manager::COLOR,
1005
- 'selectors' => [
1006
- '{{WRAPPER}} .ha-member-links > a:hover, {{WRAPPER}} .ha-member-links > a:focus' => 'border-color: {{VALUE}};',
1007
- ],
1008
- 'condition' => [
1009
- 'links_border_border!' => '',
1010
- ]
1011
- ]
1012
- );
1013
-
1014
- $this->end_controls_tab();
1015
- $this->end_controls_tabs();
1016
-
1017
- $this->end_controls_section();
1018
-
1019
- $this->start_controls_section(
1020
- '_section_style_button',
1021
- [
1022
- 'label' => __( 'Details Button', 'happy-elementor-addons' ),
1023
- 'tab' => Controls_Manager::TAB_STYLE,
1024
- ]
1025
- );
1026
-
1027
- $this->add_responsive_control(
1028
- 'button_margin',
1029
- [
1030
- 'label' => __( 'Margin', 'happy-elementor-addons' ),
1031
- 'type' => Controls_Manager::DIMENSIONS,
1032
- 'size_units' => [ 'px', '%' ],
1033
- 'selectors' => [
1034
- '{{WRAPPER}} .ha-btn' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1035
- ],
1036
- ]
1037
- );
1038
-
1039
- $this->add_responsive_control(
1040
- 'button_padding',
1041
- [
1042
- 'label' => __( 'Padding', 'happy-elementor-addons' ),
1043
- 'type' => Controls_Manager::DIMENSIONS,
1044
- 'size_units' => [ 'px', 'em', '%' ],
1045
- 'selectors' => [
1046
- '{{WRAPPER}} .ha-btn' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1047
- ],
1048
- ]
1049
- );
1050
-
1051
- $this->add_group_control(
1052
- Group_Control_Typography::get_type(),
1053
- [
1054
- 'name' => 'button_typography',
1055
- 'selector' => '{{WRAPPER}} .ha-btn',
1056
- 'scheme' => Scheme_Typography::TYPOGRAPHY_4,
1057
- ]
1058
- );
1059
-
1060
- $this->add_group_control(
1061
- Group_Control_Border::get_type(),
1062
- [
1063
- 'name' => 'button_border',
1064
- 'selector' => '{{WRAPPER}} .ha-btn',
1065
- ]
1066
- );
1067
-
1068
- $this->add_control(
1069
- 'button_border_radius',
1070
- [
1071
- 'label' => __( 'Border Radius', 'happy-elementor-addons' ),
1072
- 'type' => Controls_Manager::DIMENSIONS,
1073
- 'size_units' => [ 'px', '%' ],
1074
- 'selectors' => [
1075
- '{{WRAPPER}} .ha-btn' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1076
- ],
1077
- ]
1078
- );
1079
-
1080
- $this->add_group_control(
1081
- Group_Control_Box_Shadow::get_type(),
1082
- [
1083
- 'name' => 'button_box_shadow',
1084
- 'selector' => '{{WRAPPER}} .ha-btn',
1085
- ]
1086
- );
1087
-
1088
- $this->add_control(
1089
- 'hr',
1090
- [
1091
- 'type' => Controls_Manager::DIVIDER,
1092
- 'style' => 'thick',
1093
- ]
1094
- );
1095
-
1096
- $this->start_controls_tabs( '_tabs_button' );
1097
-
1098
- $this->start_controls_tab(
1099
- '_tab_button_normal',
1100
- [
1101
- 'label' => __( 'Normal', 'happy-elementor-addons' ),
1102
- ]
1103
- );
1104
-
1105
- $this->add_control(
1106
- 'button_color',
1107
- [
1108
- 'label' => __( 'Text Color', 'happy-elementor-addons' ),
1109
- 'type' => Controls_Manager::COLOR,
1110
- 'default' => '',
1111
- 'selectors' => [
1112
- '{{WRAPPER}} .ha-btn' => 'color: {{VALUE}};',
1113
- ],
1114
- ]
1115
- );
1116
-
1117
- $this->add_control(
1118
- 'button_bg_color',
1119
- [
1120
- 'label' => __( 'Background Color', 'happy-elementor-addons' ),
1121
- 'type' => Controls_Manager::COLOR,
1122
- 'selectors' => [
1123
- '{{WRAPPER}} .ha-btn' => 'background-color: {{VALUE}};',
1124
- ],
1125
- ]
1126
- );
1127
-
1128
- $this->end_controls_tab();
1129
-
1130
- $this->start_controls_tab(
1131
- '_tab_button_hover',
1132
- [
1133
- 'label' => __( 'Hover', 'happy-elementor-addons' ),
1134
- ]
1135
- );
1136
-
1137
- $this->add_control(
1138
- 'button_hover_color',
1139
- [
1140
- 'label' => __( 'Text Color', 'happy-elementor-addons' ),
1141
- 'type' => Controls_Manager::COLOR,
1142
- 'selectors' => [
1143
- '{{WRAPPER}} .ha-btn:hover, {{WRAPPER}} .ha-btn:focus' => 'color: {{VALUE}};',
1144
- ],
1145
- ]
1146
- );
1147
-
1148
- $this->add_control(
1149
- 'button_hover_bg_color',
1150
- [
1151
- 'label' => __( 'Background Color', 'happy-elementor-addons' ),
1152
- 'type' => Controls_Manager::COLOR,
1153
- 'selectors' => [
1154
- '{{WRAPPER}} .ha-btn:hover, {{WRAPPER}} .ha-btn:focus' => 'background-color: {{VALUE}};',
1155
- ],
1156
- ]
1157
- );
1158
-
1159
- $this->add_control(
1160
- 'button_hover_border_color',
1161
- [
1162
- 'label' => __( 'Border Color', 'happy-elementor-addons' ),
1163
- 'type' => Controls_Manager::COLOR,
1164
- 'condition' => [
1165
- 'button_border_border!' => '',
1166
- ],
1167
- 'selectors' => [
1168
- '{{WRAPPER}} .ha-btn:hover, {{WRAPPER}} .ha-btn:focus' => 'border-color: {{VALUE}};',
1169
- ],
1170
- ]
1171
- );
1172
-
1173
- $this->end_controls_tab();
1174
- $this->end_controls_tabs();
1175
-
1176
- $this->end_controls_section();
1177
- }
1178
-
1179
- protected function render() {
1180
- $settings = $this->get_settings_for_display();
1181
-
1182
- $button_position = ! empty( $settings['button_position'] ) ? $settings['button_position'] : 'after';
1183
-
1184
- $show_button = false;
1185
- if ( ! empty( $settings['show_details_button'] ) && $settings['show_details_button'] === 'yes' ) {
1186
- $show_button = true;
1187
- }
1188
-
1189
- $this->add_inline_editing_attributes( 'title', 'basic' );
1190
- $this->add_render_attribute( 'title', 'class', 'ha-member-name' );
1191
-
1192
- $this->add_inline_editing_attributes( 'job_title', 'basic' );
1193
- $this->add_render_attribute( 'job_title', 'class', 'ha-member-position' );
1194
-
1195
- $this->add_inline_editing_attributes( 'bio', 'intermediate' );
1196
- $this->add_render_attribute( 'bio', 'class', 'ha-member-bio' );
1197
- ?>
1198
-
1199
- <?php if ( $settings['image']['url'] || $settings['image']['id'] ) :
1200
- $settings['hover_animation'] = 'disable-animation'; // hack to prevent image hover animation
1201
- ?>
1202
- <figure class="ha-member-figure">
1203
- <?php echo Group_Control_Image_Size::get_attachment_image_html( $settings, 'thumbnail', 'image' ); ?>
1204
- </figure>
1205
- <?php endif; ?>
1206
-
1207
- <div class="ha-member-body">
1208
- <?php if ( $settings['title'] ) :
1209
- printf( '<%1$s %2$s>%3$s</%1$s>',
1210
- tag_escape( $settings['title_tag'] ),
1211
- $this->get_render_attribute_string( 'title' ),
1212
- ha_kses_basic( $settings['title'] )
1213
- );
1214
- endif; ?>
1215
-
1216
- <?php if ( $settings['job_title' ] ) : ?>
1217
- <div <?php $this->print_render_attribute_string( 'job_title' ); ?>><?php echo ha_kses_basic( $settings['job_title' ] ); ?></div>
1218
- <?php endif; ?>
1219
-
1220
- <?php if ( $settings['bio'] ) : ?>
1221
- <div <?php $this->print_render_attribute_string( 'bio' ); ?>>
1222
- <p><?php echo ha_kses_intermediate( $settings['bio'] ); ?></p>
1223
- </div>
1224
- <?php endif; ?>
1225
-
1226
- <?php
1227
- if ( $show_button && $button_position === 'before' ) {
1228
- $this->render_icon_button( [ 'new_icon' => 'button_icon', 'old_icon' => '' ] );
1229
- }
1230
- ?>
1231
-
1232
- <?php if ( $settings['show_profiles' ] && is_array( $settings['profiles' ] ) ) : ?>
1233
- <div class="ha-member-links">
1234
- <?php
1235
- foreach ( $settings['profiles'] as $profile ) :
1236
- $icon = $profile['name'];
1237
- $url = $profile['link']['url'];
1238
-
1239
- if ($profile['name'] === 'website') {
1240
- $icon = 'globe';
1241
- } elseif ($profile['name'] === 'email') {
1242
- $icon = 'envelope';
1243
- $url = 'mailto:' . antispambot( $profile['email'] );
1244
- }
1245
-
1246
- printf( '<a target="_blank" rel="noopener" href="%s" class="elementor-repeater-item-%s"><i class="fa fab fa-%s" aria-hidden="true"></i></a>',
1247
- $url,
1248
- esc_attr( $profile['_id'] ),
1249
- esc_attr( $icon )
1250
- );
1251
- endforeach; ?>
1252
- </div>
1253
- <?php endif; ?>
1254
-
1255
- <?php
1256
- if ( $show_button && $button_position === 'after' ) {
1257
- $this->render_icon_button( [ 'new_icon' => 'button_icon', 'old_icon' => '' ] );
1258
- }
1259
- ?>
1260
- </div>
1261
- <?php
1262
- }
1263
-
1264
- public function _content_template() {
1265
- return '';
1266
- ?>
1267
- <#
1268
- view.addInlineEditingAttributes( 'title', 'basic' );
1269
- view.addRenderAttribute( 'title', 'class', 'ha-member-name' );
1270
-
1271
- view.addInlineEditingAttributes( 'job_title', 'basic' );
1272
- view.addRenderAttribute( 'job_title', 'class', 'ha-member-position' );
1273
-
1274
- view.addInlineEditingAttributes( 'bio', 'intermediate' );
1275
- view.addRenderAttribute( 'bio', 'class', 'ha-member-bio' );
1276
-
1277
- if ( settings.image.url || settings.image.id ) {
1278
- var image = {
1279
- id: settings.image.id,
1280
- url: settings.image.url,
1281
- size: settings.thumbnail_size,
1282
- dimension: settings.thumbnail_custom_dimension,
1283
- model: view.getEditModel()
1284
- };
1285
-
1286
- var image_url = elementor.imagesManager.getImageUrl( image );
1287
- #>
1288
- <figure class="ha-member-figure">
1289
- <img src="{{ image_url }}">
1290
- </figure>
1291
- <# } #>
1292
- <div class="ha-member-body">
1293
- <# if (settings.title) { #>
1294
- <{{ settings.title_tag }} {{{ view.getRenderAttributeString( 'title' ) }}}>{{ settings.title }}</{{ settings.title_tag }}>
1295
- <# } #>
1296
- <# if (settings.job_title) { #>
1297
- <div {{{ view.getRenderAttributeString( 'job_title' ) }}}>{{ settings.job_title }}</div>
1298
- <# } #>
1299
- <# if (settings.bio) { #>
1300
- <div {{{ view.getRenderAttributeString( 'bio' ) }}}>
1301
- <p>{{{ settings.bio }}}</p>
1302
- </div>
1303
- <# } #>
1304
-
1305
- <# if ( !_.isUndefined( settings['button_position'] ) && settings['button_position'] === 'before' ) {
1306
- print( ha.getButtonWithIcon( view, {newIcon: 'button_icon', oldIcon: ''} ) );
1307
- } #>
1308
-
1309
- <# if (settings.show_profiles && _.isArray(settings.profiles)) { #>
1310
- <div class="ha-member-links">
1311
- <# _.each(settings.profiles, function(profile, index) {
1312
- var icon = profile.name,
1313
- url = profile.link.url,
1314
- linkKey = view.getRepeaterSettingKey( 'profile', 'profiles', index);
1315
-
1316
- if (profile.name === 'website') {
1317
- icon = 'globe';
1318
- } else if (profile.name === 'email') {
1319
- icon = 'envelope'
1320
- url = 'mailto:' + profile.email;
1321
- }
1322
-
1323
- view.addRenderAttribute( linkKey, 'class', 'elementor-repeater-item-' + profile._id );
1324
- view.addRenderAttribute( linkKey, 'href', url ); #>
1325
- <a {{{view.getRenderAttributeString( linkKey )}}}><i class="fa fab fa-{{{icon}}}"></i></a>
1326
- <# }); #>
1327
- </div>
1328
- <# } #>
1329
-
1330
- <# if ( !_.isUndefined( settings['button_position'] ) && settings['button_position'] === 'after' ) {
1331
- print( ha.getButtonWithIcon( view, {newIcon: 'button_icon', oldIcon: ''} ) );
1332
- } #>
1333
- </div>
1334
- <?php
1335
- }
1336
- }
 
 
1
+ <?php
2
+ /**
3
+ * Member widget class
4
+ *
5
+ * @package Happy_Addons
6
+ */
7
+ namespace Happy_Addons\Elementor\Widget;
8
+
9
+ use Elementor\Group_Control_Text_Shadow;
10
+ use Elementor\Repeater;
11
+ use Elementor\Scheme_Typography;
12
+ use Elementor\Utils;
13
+ use Elementor\Control_Media;
14
+ use Elementor\Controls_Manager;
15
+ use Elementor\Group_Control_Border;
16
+ use Elementor\Group_Control_Box_Shadow;
17
+ use Elementor\Group_Control_Image_Size;
18
+ use Elementor\Group_Control_Typography;
19
+ use Happy_Addons\Elementor\Traits\Button_Renderer;
20
+
21
+ defined( 'ABSPATH' ) || die();
22
+
23
+ class Member extends Base {
24
+
25
+ use Button_Renderer;
26
+
27
+ /**
28
+ * Get widget title.
29
+ *
30
+ * @since 1.0.0
31
+ * @access public
32
+ *
33
+ * @return string Widget title.
34
+ */
35
+ public function get_title() {
36
+ return __( 'Team Member', 'happy-elementor-addons' );
37
+ }
38
+
39
+ public function get_custom_help_url() {
40
+ return 'https://happyaddons.com/docs/happy-addons-for-elementor/widgets/team-member/';
41
+ }
42
+
43
+ /**
44
+ * Get widget icon.
45
+ *
46
+ * @since 1.0.0
47
+ * @access public
48
+ *
49
+ * @return string Widget icon.
50
+ */
51
+ public function get_icon() {
52
+ return 'hm hm-team-member';
53
+ }
54
+
55
+ public function get_keywords() {
56
+ return [ 'team', 'member', 'crew', 'staff', 'person' ];
57
+ }
58
+
59
+ public function get_style_depends() {
60
+ return [
61
+ 'elementor-icons-fa-solid',
62
+ 'elementor-icons-fa-brands',
63
+ ];
64
+ }
65
+
66
+ protected static function get_profile_names() {
67
+ return [
68
+ '500px' => __( '500px', 'happy-elementor-addons' ),
69
+ 'apple' => __( 'Apple', 'happy-elementor-addons' ),
70
+ 'behance' => __( 'Behance', 'happy-elementor-addons' ),
71
+ 'bitbucket' => __( 'BitBucket', 'happy-elementor-addons' ),
72
+ 'codepen' => __( 'CodePen', 'happy-elementor-addons' ),
73
+ 'delicious' => __( 'Delicious', 'happy-elementor-addons' ),
74
+ 'deviantart' => __( 'DeviantArt', 'happy-elementor-addons' ),
75
+ 'digg' => __( 'Digg', 'happy-elementor-addons' ),
76
+ 'dribbble' => __( 'Dribbble', 'happy-elementor-addons' ),
77
+ 'email' => __( 'Email', 'happy-elementor-addons' ),
78
+ 'facebook' => __( 'Facebook', 'happy-elementor-addons' ),
79
+ 'flickr' => __( 'Flicker', 'happy-elementor-addons' ),
80
+ 'foursquare' => __( 'FourSquare', 'happy-elementor-addons' ),
81
+ 'github' => __( 'Github', 'happy-elementor-addons' ),
82
+ 'houzz' => __( 'Houzz', 'happy-elementor-addons' ),
83
+ 'instagram' => __( 'Instagram', 'happy-elementor-addons' ),
84
+ 'jsfiddle' => __( 'JS Fiddle', 'happy-elementor-addons' ),
85
+ 'linkedin' => __( 'LinkedIn', 'happy-elementor-addons' ),
86
+ 'medium' => __( 'Medium', 'happy-elementor-addons' ),
87
+ 'pinterest' => __( 'Pinterest', 'happy-elementor-addons' ),
88
+ 'product-hunt' => __( 'Product Hunt', 'happy-elementor-addons' ),
89
+ 'reddit' => __( 'Reddit', 'happy-elementor-addons' ),
90
+ 'slideshare' => __( 'Slide Share', 'happy-elementor-addons' ),
91
+ 'snapchat' => __( 'Snapchat', 'happy-elementor-addons' ),
92
+ 'soundcloud' => __( 'SoundCloud', 'happy-elementor-addons' ),
93
+ 'spotify' => __( 'Spotify', 'happy-elementor-addons' ),
94
+ 'stack-overflow' => __( 'StackOverflow', 'happy-elementor-addons' ),
95
+ 'tripadvisor' => __( 'TripAdvisor', 'happy-elementor-addons' ),
96
+ 'tumblr' => __( 'Tumblr', 'happy-elementor-addons' ),
97
+ 'twitch' => __( 'Twitch', 'happy-elementor-addons' ),
98
+ 'twitter' => __( 'Twitter', 'happy-elementor-addons' ),
99
+ 'vimeo' => __( 'Vimeo', 'happy-elementor-addons' ),
100
+ 'vk' => __( 'VK', 'happy-elementor-addons' ),
101
+ 'website' => __( 'Website', 'happy-elementor-addons' ),
102
+ 'whatsapp' => __( 'WhatsApp', 'happy-elementor-addons' ),
103
+ 'wordpress' => __( 'WordPress', 'happy-elementor-addons' ),
104
+ 'xing' => __( 'Xing', 'happy-elementor-addons' ),
105
+ 'yelp' => __( 'Yelp', 'happy-elementor-addons' ),
106
+ 'youtube' => __( 'YouTube', 'happy-elementor-addons' ),
107
+ ];
108
+ }
109
+
110
+ /**
111
+ * Register content related controls
112
+ */
113
+ protected function register_content_controls() {
114
+ $this->start_controls_section(
115
+ '_section_info',
116
+ [
117
+ 'label' => __( 'Information', 'happy-elementor-addons' ),
118
+ 'tab' => Controls_Manager::TAB_CONTENT,
119
+ ]
120
+ );
121
+
122
+ $this->add_control(
123
+ 'image',
124
+ [
125
+ 'label' => __( 'Photo', 'happy-elementor-addons' ),
126
+ 'type' => Controls_Manager::MEDIA,
127
+ 'default' => [
128
+ 'url' => Utils::get_placeholder_image_src(),
129
+ ],
130
+ 'dynamic' => [
131
+ 'active' => true,
132
+ ]
133
+ ]
134
+ );
135
+
136
+ $this->add_group_control(
137
+ Group_Control_Image_Size::get_type(),
138
+ [
139
+ 'name' => 'thumbnail',
140
+ 'default' => 'large',
141
+ 'separator' => 'none',
142
+ ]
143
+ );
144
+
145
+ $this->add_control(
146
+ 'title',
147
+ [
148
+ 'label' => __( 'Name', 'happy-elementor-addons' ),
149
+ 'label_block' => true,
150
+ 'type' => Controls_Manager::TEXT,
151
+ 'default' => 'Happy Member Name',
152
+ 'placeholder' => __( 'Type Member Name', 'happy-elementor-addons' ),
153
+ 'separator' => 'before',
154
+ 'dynamic' => [
155
+ 'active' => true,
156
+ ]
157
+ ]
158
+ );
159
+
160
+ $this->add_control(
161
+ 'job_title',
162
+ [
163
+ 'label' => __( 'Job Title', 'happy-elementor-addons' ),
164
+ 'label_block' => true,
165
+ 'type' => Controls_Manager::TEXT,
166
+ 'default' => __( 'Happy Officer', 'happy-elementor-addons' ),
167
+ 'placeholder' => __( 'Type Member Job Title', 'happy-elementor-addons' ),
168
+ 'dynamic' => [
169
+ 'active' => true,
170
+ ]
171
+ ]
172
+ );
173
+
174
+ $this->add_control(
175
+ 'bio',
176
+ [
177
+ 'label' => __( 'Short Bio', 'happy-elementor-addons' ),
178
+ 'description' => ha_get_allowed_html_desc( 'intermediate' ),
179
+ 'type' => Controls_Manager::TEXTAREA,
180
+ 'placeholder' => __( 'Write something amazing about the happy member', 'happy-elementor-addons' ),
181
+ 'rows' => 5,
182
+ 'dynamic' => [
183
+ 'active' => true,
184
+ ]
185
+ ]
186
+ );
187
+
188
+ $this->add_control(
189
+ 'title_tag',
190
+ [
191
+ 'label' => __( 'Title HTML Tag', 'happy-elementor-addons' ),
192
+ 'type' => Controls_Manager::CHOOSE,
193
+ 'options' => [
194
+ 'h1' => [
195
+ 'title' => __( 'H1', 'happy-elementor-addons' ),
196
+ 'icon' => 'eicon-editor-h1'
197
+ ],
198
+ 'h2' => [
199
+ 'title' => __( 'H2', 'happy-elementor-addons' ),
200
+ 'icon' => 'eicon-editor-h2'
201
+ ],
202
+ 'h3' => [
203
+ 'title' => __( 'H3', 'happy-elementor-addons' ),
204
+ 'icon' => 'eicon-editor-h3'
205
+ ],
206
+ 'h4' => [
207
+ 'title' => __( 'H4', 'happy-elementor-addons' ),
208
+ 'icon' => 'eicon-editor-h4'
209
+ ],
210
+ 'h5' => [
211
+ 'title' => __( 'H5', 'happy-elementor-addons' ),
212
+ 'icon' => 'eicon-editor-h5'
213
+ ],
214
+ 'h6' => [
215
+ 'title' => __( 'H6', 'happy-elementor-addons' ),
216
+ 'icon' => 'eicon-editor-h6'
217
+ ]
218
+ ],
219
+ 'default' => 'h2',
220
+ 'toggle' => false,
221
+ 'separator' => 'before',
222
+ ]
223
+ );
224
+
225
+ $this->add_responsive_control(
226
+ 'align',
227
+ [
228
+ 'label' => __( 'Alignment', 'happy-elementor-addons' ),
229
+ 'type' => Controls_Manager::CHOOSE,
230
+ 'options' => [
231
+ 'left' => [
232
+ 'title' => __( 'Left', 'happy-elementor-addons' ),
233
+ 'icon' => 'eicon-text-align-left',
234
+ ],
235
+ 'center' => [
236
+ 'title' => __( 'Center', 'happy-elementor-addons' ),
237
+ 'icon' => 'eicon-text-align-center',
238
+ ],
239
+ 'right' => [
240
+ 'title' => __( 'Right', 'happy-elementor-addons' ),
241
+ 'icon' => 'eicon-text-align-right',
242
+ ],
243
+ 'justify' => [
244
+ 'title' => __( 'Justify', 'happy-elementor-addons' ),
245
+ 'icon' => 'eicon-text-align-justify',
246
+ ],
247
+ ],
248
+ 'toggle' => true,
249
+ 'selectors' => [
250
+ '{{WRAPPER}}' => 'text-align: {{VALUE}};'
251
+ ]
252
+ ]
253
+ );
254
+
255
+ $this->end_controls_section();
256
+
257
+ $this->start_controls_section(
258
+ '_section_social',
259
+ [
260
+ 'label' => __( 'Social Profiles', 'happy-elementor-addons' ),
261
+ 'tab' => Controls_Manager::TAB_CONTENT,
262
+ ]
263
+ );
264
+
265
+ $repeater = new Repeater();
266
+
267
+ $repeater->add_control(
268
+ 'name',
269
+ [
270
+ 'label' => __( 'Profile Name', 'happy-elementor-addons' ),
271
+ 'type' => Controls_Manager::SELECT2,
272
+ 'label_block' => true,
273
+ 'select2options' => [
274
+ 'allowClear' => false,
275
+ ],
276
+ 'options' => self::get_profile_names()
277
+ ]
278
+ );
279
+
280
+ $repeater->add_control(
281
+ 'link', [
282
+ 'label' => __( 'Profile Link', 'happy-elementor-addons' ),
283
+ 'placeholder' => __( 'Add your profile link', 'happy-elementor-addons' ),
284
+ 'type' => Controls_Manager::URL,
285
+ 'label_block' => true,
286
+ 'autocomplete' => false,
287
+ 'show_external' => false,
288
+ 'condition' => [
289
+ 'name!' => 'email'
290
+ ],
291
+ 'dynamic' => [
292
+ 'active' => true,
293
+ ]
294
+ ]
295
+ );
296
+
297
+ $repeater->add_control(
298
+ 'email', [
299
+ 'label' => __( 'Email Address', 'happy-elementor-addons' ),
300
+ 'placeholder' => __( 'Add your email address', 'happy-elementor-addons' ),
301
+ 'type' => Controls_Manager::TEXT,
302
+ 'label_block' => false,
303
+ 'input_type' => 'email',
304
+ 'condition' => [
305
+ 'name' => 'email'
306
+ ],
307
+ 'dynamic' => [
308
+ 'active' => true,
309
+ ]
310
+ ]
311
+ );
312
+
313
+ $repeater->add_control(
314
+ 'customize',
315
+ [
316
+ 'label' => __( 'Want To Customize?', 'happy-elementor-addons' ),
317
+ 'type' => Controls_Manager::SWITCHER,
318
+ 'label_on' => __( 'Yes', 'happy-elementor-addons' ),
319
+ 'label_off' => __( 'No', 'happy-elementor-addons' ),
320
+ 'return_value' => 'yes',
321
+ 'style_transfer' => true,
322
+ ]
323
+ );
324
+
325
+ $repeater->start_controls_tabs(
326
+ '_tab_icon_colors',
327
+ [
328
+ 'condition' => ['customize' => 'yes']
329
+ ]
330
+ );
331
+ $repeater->start_controls_tab(
332
+ '_tab_icon_normal',
333
+ [
334
+ 'label' => __( 'Normal', 'happy-elementor-addons' ),
335
+ ]
336
+ );
337
+
338
+ $repeater->add_control(
339
+ 'color',
340
+ [
341
+ 'label' => __( 'Text Color', 'happy-elementor-addons' ),
342
+ 'type' => Controls_Manager::COLOR,
343
+ 'selectors' => [
344
+ '{{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}' => 'color: {{VALUE}}',
345
+ ],
346
+ 'condition' => ['customize' => 'yes'],
347
+ 'style_transfer' => true,
348
+ ]
349
+ );
350
+
351
+ $repeater->add_control(
352
+ 'bg_color',
353
+ [
354
+ 'label' => __( 'Background Color', 'happy-elementor-addons' ),
355
+ 'type' => Controls_Manager::COLOR,
356
+ 'selectors' => [
357
+ '{{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}' => 'background-color: {{VALUE}}',
358
+ ],
359
+ 'condition' => ['customize' => 'yes'],
360
+ 'style_transfer' => true,
361
+ ]
362
+ );
363
+
364
+ $repeater->end_controls_tab();
365
+ $repeater->start_controls_tab(
366
+ '_tab_icon_hover',
367
+ [
368
+ 'label' => __( 'Hover', 'happy-elementor-addons' ),
369
+ ]
370
+ );
371
+
372
+ $repeater->add_control(
373
+ 'hover_color',
374
+ [
375
+ 'label' => __( 'Text Color', 'happy-elementor-addons' ),
376
+ 'type' => Controls_Manager::COLOR,
377
+ 'selectors' => [
378
+ '{{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:hover, {{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:focus' => 'color: {{VALUE}}',
379
+ ],
380
+ 'condition' => ['customize' => 'yes'],
381
+ 'style_transfer' => true,
382
+ ]
383
+ );
384
+
385
+ $repeater->add_control(
386
+ 'hover_bg_color',
387
+ [
388
+ 'label' => __( 'Background Color', 'happy-elementor-addons' ),
389
+ 'type' => Controls_Manager::COLOR,
390
+ 'selectors' => [
391
+ '{{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:hover, {{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:focus' => 'background-color: {{VALUE}}',
392
+ ],
393
+ 'condition' => ['customize' => 'yes'],
394
+ 'style_transfer' => true,
395
+ ]
396
+ );
397
+
398
+ $repeater->add_control(
399
+ 'hover_border_color',
400
+ [
401
+ 'label' => __( 'Border Color', 'happy-elementor-addons' ),
402
+ 'type' => Controls_Manager::COLOR,
403
+ 'selectors' => [
404
+ '{{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:hover, {{WRAPPER}} .ha-member-links > {{CURRENT_ITEM}}:focus' => 'border-color: {{VALUE}}',
405
+ ],
406
+ 'condition' => ['customize' => 'yes'],
407
+ 'style_transfer' => true,
408
+ ]
409
+ );
410
+
411
+ $repeater->end_controls_tab();
412
+ $repeater->end_controls_tabs();
413
+
414
+ $this->add_control(
415
+ 'profiles',
416
+ [
417
+ 'show_label' => false,
418
+ 'type' => Controls_Manager::REPEATER,
419
+ 'fields' => $repeater->get_controls(),
420
+ 'title_field' => '<# print(name.slice(0,1).toUpperCase() + name.slice(1)) #>',
421
+ 'default' => [
422
+ [
423
+ 'link' => ['url' => 'https://facebook.com/'],
424
+ 'name' => 'facebook'
425
+ ],
426
+ [
427
+ 'link' => ['url' => 'https://twitter.com/'],
428
+ 'name' => 'twitter'
429
+ ],
430
+ [
431
+ 'link' => ['url' => 'https://linkedin.com/'],
432
+ 'name' => 'linkedin'
433
+ ]
434
+ ],
435
+ ]
436
+ );
437
+
438
+ $this->add_control(
439
+ 'show_profiles',
440
+ [
441
+ 'label' => __( 'Show Profiles', 'happy-elementor-addons' ),
442
+ 'type' => Controls_Manager::SWITCHER,
443
+ 'label_on' => __( 'Show', 'happy-elementor-addons' ),
444
+ 'label_off' => __( 'Hide', 'happy-elementor-addons' ),
445
+ 'return_value' => 'yes',
446
+ 'default' => 'yes',
447
+ 'separator' => 'before',
448
+ 'style_transfer' => true,
449
+ ]
450
+ );
451
+
452
+ $this->end_controls_section();
453
+
454
+ $this->start_controls_section(
455
+ '_section_button',
456
+ [
457
+ 'label' => __( 'Details Button', 'happy-elementor-addons' ),
458
+ 'tab' => Controls_Manager::TAB_CONTENT,
459
+ ]
460
+ );
461
+
462
+ $this->add_control(
463
+ 'show_details_button',
464
+ [
465
+ 'label' => __( 'Show Button', 'happy-elementor-addons' ),
466
+ 'type' => Controls_Manager::SWITCHER,
467
+ 'label_on' => __( 'Show', 'happy-elementor-addons' ),
468
+ 'label_off' => __( 'Hide', 'happy-elementor-addons' ),
469
+ 'return_value' => 'yes',
470
+ 'default' => '',
471
+ 'style_transfer' => true,
472
+ ]
473
+ );
474
+
475
+ $this->add_control(
476
+ 'button_position',
477
+ [
478
+ 'label' => __( 'Position', 'happy-elementor-addons' ),
479
+ 'type' => Controls_Manager::SELECT,
480
+ 'default' => 'after',
481
+ 'style_transfer' => true,
482
+ 'options' => [
483
+ 'before' => __( 'Before Social Icons', 'happy-elementor-addons' ),
484
+ 'after' => __( 'After Social Icons', 'happy-elementor-addons' ),
485
+ ],
486
+ 'condition' => [
487
+ 'show_details_button' => 'yes',
488
+ ]
489
+ ]
490
+ );
491
+
492
+ $this->add_control(
493
+ 'button_text',
494
+ [
495
+ 'label' => __( 'Text', 'happy-elementor-addons' ),
496
+ 'type' => Controls_Manager::TEXT,
497
+ 'default' => __( 'Show Details', 'happy-elementor-addons' ),
498
+ 'placeholder' => __( 'Type button text here', 'happy-elementor-addons' ),
499
+ 'label_block' => true,
500
+ 'dynamic' => [
501
+ 'active' => true,
502
+ ],
503
+ 'condition' => [
504
+ 'show_details_button' => 'yes',
505
+ ]
506
+ ]
507
+ );
508
+
509
+ $this->add_control(
510
+ 'button_link',
511
+ [
512
+ 'label' => __( 'Link', 'happy-elementor-addons' ),
513
+ 'type' => Controls_Manager::URL,
514
+ 'placeholder' => 'https://example.com',
515
+ 'dynamic' => [
516
+ 'active' => true,
517
+ ],
518
+ 'condition' => [
519
+ 'show_details_button' => 'yes',
520
+ ],
521
+ 'default' => [
522
+ 'url' => '#',
523
+ ]
524
+ ]
525
+ );
526
+
527
+ $this->add_control(
528
+ 'button_icon',
529
+ [
530
+ 'type' => Controls_Manager::ICONS,
531
+ 'label_block' => true,
532
+ 'show_label' => false,
533
+ 'condition' => [
534
+ 'show_details_button' => 'yes',
535
+ ]
536
+ ]
537
+ );
538
+
539
+ $this->add_control(
540
+ 'button_icon_position',
541
+ [
542
+ 'label' => __( 'Icon Position', 'happy-elementor-addons' ),
543
+ 'type' => Controls_Manager::CHOOSE,
544
+ 'label_block' => false,
545
+ 'options' => [
546
+ 'before' => [
547
+ 'title' => __( 'Before', 'happy-elementor-addons' ),
548
+ 'icon' => 'eicon-h-align-left',
549
+ ],
550
+ 'after' => [
551
+ 'title' => __( 'After', 'happy-elementor-addons' ),
552
+ 'icon' => 'eicon-h-align-right',
553
+ ],
554
+ ],
555
+ 'default' => 'after',
556
+ 'toggle' => false,
557
+ 'style_transfer' => true,
558
+ 'condition' => [
559
+ 'show_details_button' => 'yes',
560
+ 'button_icon[value]!' => ''
561
+ ]
562
+ ]
563
+ );
564
+
565
+ $this->add_control(
566
+ 'button_icon_spacing',
567
+ [
568
+ 'label' => __( 'Icon Spacing', 'happy-elementor-addons' ),
569
+ 'type' => Controls_Manager::SLIDER,
570
+ 'default' => [
571
+ 'size' => 10
572
+ ],
573
+ 'condition' => [
574
+ 'show_details_button' => 'yes',
575
+ 'button_icon[value]!' => ''
576
+ ],
577
+ 'selectors' => [
578
+ '{{WRAPPER}} .ha-btn--icon-before .ha-btn-icon' => 'margin-right: {{SIZE}}{{UNIT}};',
579
+ '{{WRAPPER}} .ha-btn--icon-after .ha-btn-icon' => 'margin-left: {{SIZE}}{{UNIT}};',
580
+ ],
581
+ ]
582
+ );
583
+
584
+ $this->end_controls_section();
585
+ }
586
+
587
+ /**
588
+ * Register styles related controls
589
+ */
590
+ protected function register_style_controls() {
591
+ $this->start_controls_section(
592
+ '_section_style_image',
593
+ [
594
+ 'label' => __( 'Photo', 'happy-elementor-addons' ),
595
+ 'tab' => Controls_Manager::TAB_STYLE,
596
+ ]
597
+ );
598
+
599
+ $this->add_responsive_control(
600
+ 'image_width',
601
+ [
602
+ 'label' => __( 'Width', 'happy-elementor-addons' ),
603
+ 'type' => Controls_Manager::SLIDER,
604
+ 'size_units' => [ 'px', '%'],
605
+ 'range' => [
606
+ '%' => [
607
+ 'min' => 20,
608
+ 'max' => 100,
609
+ ],
610
+ 'px' => [
611
+ 'min' => 100,
612
+ 'max' => 700,
613
+ ],
614
+ ],
615
+ 'selectors' => [
616
+ '{{WRAPPER}} .ha-member-figure' => 'width: {{SIZE}}{{UNIT}};',
617
+ ],
618
+ ]
619
+ );
620
+
621
+ $this->add_responsive_control(
622
+ 'image_height',
623
+ [
624
+ 'label' => __( 'Height', 'happy-elementor-addons' ),
625
+ 'type' => Controls_Manager::SLIDER,
626
+ 'size_units' => [ 'px' ],
627
+ 'range' => [
628
+ 'px' => [
629
+ 'min' => 100,
630
+ 'max' => 700,
631
+ ],
632
+ ],
633
+ 'selectors' => [
634
+ '{{WRAPPER}} .ha-member-figure' => 'height: {{SIZE}}{{UNIT}};',
635
+ ],
636
+ ]
637
+ );
638
+
639
+ $this->add_responsive_control(
640
+ 'image_spacing',
641
+ [
642
+ 'label' => __( 'Bottom Spacing', 'happy-elementor-addons' ),
643
+ 'type' => Controls_Manager::SLIDER,
644
+ 'size_units' => ['px'],
645
+ 'selectors' => [
646
+ '{{WRAPPER}} .ha-member-figure' => 'margin-bottom: {{SIZE}}{{UNIT}} !important;',
647
+ ],
648
+ ]
649
+ );
650
+
651
+ $this->add_responsive_control(
652
+ 'image_padding',
653
+ [
654
+ 'label' => __( 'Padding', 'happy-elementor-addons' ),
655
+ 'type' => Controls_Manager::DIMENSIONS,
656
+ 'size_units' => [ 'px', 'em', '%' ],
657
+ 'selectors' => [
658
+ '{{WRAPPER}} .ha-member-figure img' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
659
+ ],
660
+ ]
661
+ );
662
+
663
+ $this->add_group_control(
664
+ Group_Control_Border::get_type(),
665
+ [
666
+ 'name' => 'image_border',
667
+ 'selector' => '{{WRAPPER}} .ha-member-figure img'
668
+ ]
669
+ );
670
+
671
+ $this->add_responsive_control(
672
+ 'image_border_radius',
673
+ [
674
+ 'label' => __( 'Border Radius', 'happy-elementor-addons' ),
675
+ 'type' => Controls_Manager::DIMENSIONS,
676
+ 'size_units' => [ 'px', '%' ],
677
+ 'selectors' => [
678
+ '{{WRAPPER}} .ha-member-figure img' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
679
+ ],
680
+ ]
681
+ );
682
+
683
+ $this->add_group_control(
684
+ Group_Control_Box_Shadow::get_type(),
685
+ [
686
+ 'name' => 'image_box_shadow',
687
+ 'exclude' => [
688
+ 'box_shadow_position',
689
+ ],
690
+ 'selector' => '{{WRAPPER}} .ha-member-figure img'
691
+ ]
692
+ );
693
+
694
+ $this->add_control(
695
+ 'image_bg_color',
696
+ [
697
+ 'label' => __( 'Background Color', 'happy-elementor-addons' ),
698
+ 'type' => Controls_Manager::COLOR,
699
+ 'selectors' => [
700
+ '{{WRAPPER}} .ha-member-figure img' => 'background-color: {{VALUE}};',
701
+ ],
702
+ ]
703
+ );
704
+
705
+ $this->end_controls_section();
706
+
707
+ $this->start_controls_section(
708
+ '_section_style_content',
709
+ [
710
+ 'label' => __( 'Name, Job Title & Bio', 'happy-elementor-addons' ),
711
+ 'tab' => Controls_Manager::TAB_STYLE,
712
+ ]
713
+ );
714
+
715
+ $this->add_responsive_control(
716
+ 'content_padding',
717
+ [
718
+ 'label' => __( 'Content Padding', 'happy-elementor-addons' ),
719
+ 'type' => Controls_Manager::DIMENSIONS,
720
+ 'size_units' => [ 'px', 'em', '%' ],
721
+ 'selectors' => [
722
+ '{{WRAPPER}} .ha-member-body' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
723
+ ],
724
+ ]
725
+ );
726
+
727
+ $this->add_control(
728
+ '_heading_title',
729
+ [
730
+ 'type' => Controls_Manager::HEADING,
731
+ 'label' => __( 'Name', 'happy-elementor-addons' ),
732
+ 'separator' => 'before',
733
+ ]
734
+ );
735
+
736
+ $this->add_responsive_control(
737
+ 'title_spacing',
738
+ [
739
+ 'label' => __( 'Bottom Spacing', 'happy-elementor-addons' ),
740
+ 'type' => Controls_Manager::SLIDER,
741
+ 'size_units' => ['px'],
742
+ 'selectors' => [
743
+ '{{WRAPPER}} .ha-member-name' => 'margin-bottom: {{SIZE}}{{UNIT}};',
744
+ ],
745
+ ]
746
+ );
747
+
748
+ $this->add_control(
749
+ 'title_color',
750
+ [
751
+ 'label' => __( 'Text Color', 'happy-elementor-addons' ),
752
+ 'type' => Controls_Manager::COLOR,
753
+ 'selectors' => [
754
+ '{{WRAPPER}} .ha-member-name' => 'color: {{VALUE}}',
755
+ ],
756
+ ]
757
+ );
758
+
759
+ $this->add_group_control(
760
+ Group_Control_Typography::get_type(),
761
+ [
762
+ 'name' => 'title_typography',
763
+ 'selector' => '{{WRAPPER}} .ha-member-name',
764
+ 'scheme' => Scheme_Typography::TYPOGRAPHY_2,
765
+ ]
766
+ );
767
+
768
+ $this->add_group_control(
769
+ Group_Control_Text_Shadow::get_type(),
770
+ [
771
+ 'name' => 'title_text_shadow',
772
+ 'selector' => '{{WRAPPER}} .ha-member-name',
773
+ ]
774
+ );
775
+
776
+ $this->add_control(
777
+ '_heading_job_title',
778
+ [
779
+ 'type' => Controls_Manager::HEADING,
780
+ 'label' => __( 'Job Title', 'happy-elementor-addons' ),
781
+ 'separator' => 'before'
782
+ ]
783
+ );
784
+
785
+ $this->add_responsive_control(
786
+ 'job_title_spacing',
787
+ [
788
+ 'label' => __( 'Bottom Spacing', 'happy-elementor-addons' ),
789
+ 'type' => Controls_Manager::SLIDER,
790
+ 'size_units' => ['px'],
791
+ 'selectors' => [
792
+ '{{WRAPPER}} .ha-member-position' => 'margin-bottom: {{SIZE}}{{UNIT}};',
793
+ ],
794
+ ]
795
+ );
796
+
797
+ $this->add_control(
798
+ 'job_title_color',
799
+ [
800
+ 'label' => __( 'Text Color', 'happy-elementor-addons' ),
801
+ 'type' => Controls_Manager::COLOR,
802
+ 'selectors' => [
803
+ '{{WRAPPER}} .ha-member-position' => 'color: {{VALUE}}',
804
+ ],
805
+ ]
806
+ );
807
+
808
+ $this->add_group_control(
809
+ Group_Control_Typography::get_type(),
810
+ [
811
+ 'name' => 'job_title_typography',
812
+ 'selector' => '{{WRAPPER}} .ha-member-position',
813
+ 'scheme' => Scheme_Typography::TYPOGRAPHY_3,
814
+ ]
815
+ );
816
+
817
+ $this->add_group_control(
818
+ Group_Control_Text_Shadow::get_type(),
819
+ [
820
+ 'name' => 'job_title_text_shadow',
821
+ 'selector' => '{{WRAPPER}} .ha-member-position',
822
+ ]
823
+ );
824
+
825
+ $this->add_control(
826
+ '_heading_bio',
827
+ [
828
+ 'type' => Controls_Manager::HEADING,
829
+ 'label' => __( 'Short Bio', 'happy-elementor-addons' ),
830
+ 'separator' => 'before'
831
+ ]
832
+ );
833
+
834
+ $this->add_responsive_control(
835
+ 'bio_spacing',
836
+ [
837
+ 'label' => __( 'Bottom Spacing', 'happy-elementor-addons' ),
838
+ 'type' => Controls_Manager::SLIDER,
839
+ 'size_units' => ['px'],
840
+ 'selectors' => [
841
+ '{{WRAPPER}} .ha-member-bio' => 'margin-bottom: {{SIZE}}{{UNIT}};',
842
+ ],
843
+ ]
844
+ );
845
+
846
+ $this->add_control(
847
+ 'bio_color',
848
+ [
849
+ 'label' => __( 'Text Color', 'happy-elementor-addons' ),
850
+ 'type' => Controls_Manager::COLOR,
851
+ 'selectors' => [
852
+ '{{WRAPPER}} .ha-member-bio' => 'color: {{VALUE}};',
853
+ ],
854
+ ]
855
+ );
856
+
857
+ $this->add_group_control(
858
+ Group_Control_Typography::get_type(),
859
+ [
860
+ 'name' => 'bio_typography',
861
+ 'selector' => '{{WRAPPER}} .ha-member-bio',
862
+ 'scheme' => Scheme_Typography::TYPOGRAPHY_3,
863
+ ]
864
+ );
865
+
866
+ $this->add_group_control(
867
+ Group_Control_Text_Shadow::get_type(),
868
+ [
869
+ 'name' => 'bio_text_shadow',
870
+ 'selector' => '{{WRAPPER}} .ha-member-bio',
871
+ ]
872
+ );
873
+
874
+ $this->end_controls_section();
875
+
876
+ $this->start_controls_section(
877
+ '_section_style_social',
878
+ [
879
+ 'label' => __( 'Social Icons', 'happy-elementor-addons' ),
880
+ 'tab' => Controls_Manager::TAB_STYLE,
881
+ ]
882
+ );
883
+
884
+ $this->add_responsive_control(
885
+ 'links_spacing',
886
+ [
887
+ 'label' => __( 'Right Spacing', 'happy-elementor-addons' ),
888
+ 'type' => Controls_Manager::SLIDER,
889
+ 'size_units' => ['px'],
890
+ 'selectors' => [
891
+ '{{WRAPPER}} .ha-member-links > a:not(:last-child)' => 'margin-right: {{SIZE}}{{UNIT}};',
892
+ ],
893
+ ]
894
+ );
895
+
896
+ $this->add_responsive_control(
897
+ 'links_padding',
898
+ [
899
+ 'label' => __( 'Padding', 'happy-elementor-addons' ),
900
+ 'type' => Controls_Manager::SLIDER,
901
+ 'size_units' => ['px'],
902
+ 'selectors' => [
903
+ '{{WRAPPER}} .ha-member-links > a' => 'padding: {{SIZE}}{{UNIT}};',
904
+ ],
905
+ ]
906
+ );
907
+
908
+ $this->add_responsive_control(
909
+ 'links_icon_size',
910
+ [
911
+ 'label' => __( 'Icon Size', 'happy-elementor-addons' ),
912
+ 'type' => Controls_Manager::SLIDER,
913
+ 'size_units' => ['px'],
914
+ 'selectors' => [
915
+ '{{WRAPPER}} .ha-member-links > a' => 'font-size: {{SIZE}}{{UNIT}};',
916
+ ],
917
+ ]
918
+ );
919
+
920
+ $this->add_group_control(
921
+ Group_Control_Border::get_type(),
922
+ [
923
+ 'name' => 'links_border',
924
+ 'selector' => '{{WRAPPER}} .ha-member-links > a'
925
+ ]
926
+ );
927
+
928
+ $this->add_responsive_control(
929
+ 'links_border_radius',
930
+ [
931
+ 'label' => __( 'Border Radius', 'happy-elementor-addons' ),
932
+ 'type' => Controls_Manager::DIMENSIONS,
933
+ 'size_units' => [ 'px', '%' ],
934
+ 'selectors' => [
935
+ '{{WRAPPER}} .ha-member-links > a' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
936
+ ],
937
+ ]
938
+ );
939
+
940
+ $this->start_controls_tabs( '_tab_links_colors' );
941
+ $this->start_controls_tab(
942
+ '_tab_links_normal',
943
+ [
944
+ 'label' => __( 'Normal', 'happy-elementor-addons' ),
945
+ ]
946
+ );
947
+
948
+ $this->add_control(
949
+ 'links_color',
950
+ [
951
+ 'label' => __( 'Text Color', 'happy-elementor-addons' ),
952
+ 'type' => Controls_Manager::COLOR,
953
+ 'selectors' => [
954
+ '{{WRAPPER}} .ha-member-links > a' => 'color: {{VALUE}};',
955
+ ],
956
+ ]
957
+ );
958
+
959
+ $this->add_control(
960
+ 'links_bg_color',
961
+ [
962
+ 'label' => __( 'Background Color', 'happy-elementor-addons' ),
963
+ 'type' => Controls_Manager::COLOR,
964
+ 'selectors' => [
965
+ '{{WRAPPER}} .ha-member-links > a' => 'background-color: {{VALUE}};',
966
+ ],
967
+ ]
968
+ );
969
+
970
+ $this->end_controls_tab();
971
+ $this->start_controls_tab(
972
+ '_tab_links_hover',
973
+ [
974
+ 'label' => __( 'Hover', 'happy-elementor-addons' ),
975
+ ]
976
+ );
977
+
978
+ $this->add_control(
979
+ 'links_hover_color',
980
+ [
981
+ 'label' => __( 'Text Color', 'happy-elementor-addons' ),
982
+ 'type' => Controls_Manager::COLOR,
983
+ 'selectors' => [
984
+ '{{WRAPPER}} .ha-member-links > a:hover, {{WRAPPER}} .ha-member-links > a:focus' => 'color: {{VALUE}}',
985
+ ],
986
+ ]
987
+ );
988
+
989
+ $this->add_control(
990
+ 'links_hover_bg_color',
991
+ [
992
+ 'label' => __( 'Background Color', 'happy-elementor-addons' ),
993
+ 'type' => Controls_Manager::COLOR,
994
+ 'selectors' => [
995
+ '{{WRAPPER}} .ha-member-links > a:hover, {{WRAPPER}} .ha-member-links > a:focus' => 'background-color: {{VALUE}}',
996
+ ],
997
+ ]
998
+ );
999
+
1000
+ $this->add_control(
1001
+ 'links_hover_border_color',
1002
+ [
1003
+ 'label' => __( 'Border Color', 'happy-elementor-addons' ),
1004
+ 'type' => Controls_Manager::COLOR,
1005
+ 'selectors' => [
1006
+ '{{WRAPPER}} .ha-member-links > a:hover, {{WRAPPER}} .ha-member-links > a:focus' => 'border-color: {{VALUE}};',
1007
+ ],
1008
+ 'condition' => [
1009
+ 'links_border_border!' => '',
1010
+ ]
1011
+ ]
1012
+ );
1013
+
1014
+ $this->end_controls_tab();
1015
+ $this->end_controls_tabs();
1016
+
1017
+ $this->end_controls_section();
1018
+
1019
+ $this->start_controls_section(
1020
+ '_section_style_button',
1021
+ [
1022
+ 'label' => __( 'Details Button', 'happy-elementor-addons' ),
1023
+ 'tab' => Controls_Manager::TAB_STYLE,
1024
+ ]
1025
+ );
1026
+
1027
+ $this->add_responsive_control(
1028
+ 'button_margin',
1029
+ [
1030
+ 'label' => __( 'Margin', 'happy-elementor-addons' ),
1031
+ 'type' => Controls_Manager::DIMENSIONS,
1032
+ 'size_units' => [ 'px', '%' ],
1033
+ 'selectors' => [
1034
+ '{{WRAPPER}} .ha-btn' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1035
+ ],
1036
+ ]
1037
+ );
1038
+
1039
+ $this->add_responsive_control(
1040
+ 'button_padding',
1041
+ [
1042
+ 'label' => __( 'Padding', 'happy-elementor-addons' ),
1043
+ 'type' => Controls_Manager::DIMENSIONS,
1044
+ 'size_units' => [ 'px', 'em', '%' ],
1045
+ 'selectors' => [
1046
+ '{{WRAPPER}} .ha-btn' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1047
+ ],
1048
+ ]
1049
+ );
1050
+
1051
+ $this->add_group_control(
1052
+ Group_Control_Typography::get_type(),
1053
+ [
1054
+ 'name' => 'button_typography',
1055
+ 'selector' => '{{WRAPPER}} .ha-btn',
1056
+ 'scheme' => Scheme_Typography::TYPOGRAPHY_4,
1057
+ ]
1058
+ );
1059
+
1060
+ $this->add_group_control(
1061
+ Group_Control_Border::get_type(),
1062
+ [
1063
+ 'name' => 'button_border',
1064
+ 'selector' => '{{WRAPPER}} .ha-btn',
1065
+ ]
1066
+ );
1067
+
1068
+ $this->add_control(
1069
+ 'button_border_radius',
1070
+ [
1071
+ 'label' => __( 'Border Radius', 'happy-elementor-addons' ),
1072
+ 'type' => Controls_Manager::DIMENSIONS,
1073
+ 'size_units' => [ 'px', '%' ],
1074
+ 'selectors' => [
1075
+ '{{WRAPPER}} .ha-btn' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1076
+ ],
1077
+ ]
1078
+ );
1079
+
1080
+ $this->add_group_control(
1081
+ Group_Control_Box_Shadow::get_type(),
1082
+ [
1083
+ 'name' => 'button_box_shadow',
1084
+ 'selector' => '{{WRAPPER}} .ha-btn',
1085
+ ]
1086
+ );
1087
+
1088
+ $this->add_control(
1089
+ 'hr',
1090
+ [
1091
+ 'type' => Controls_Manager::DIVIDER,
1092
+ 'style' => 'thick',
1093
+ ]
1094
+ );
1095
+
1096
+ $this->start_controls_tabs( '_tabs_button' );
1097
+
1098
+ $this->start_controls_tab(
1099
+ '_tab_button_normal',
1100
+ [
1101
+ 'label' => __( 'Normal', 'happy-elementor-addons' ),
1102
+ ]
1103
+ );
1104
+
1105
+ $this->add_control(
1106
+ 'button_color',
1107
+ [
1108
+ 'label' => __( 'Text Color', 'happy-elementor-addons' ),
1109
+ 'type' => Controls_Manager::COLOR,
1110
+ 'default' => '',
1111
+ 'selectors' => [
1112
+ '{{WRAPPER}} .ha-btn' => 'color: {{VALUE}};',
1113
+ ],
1114
+ ]
1115
+ );
1116
+
1117
+ $this->add_control(
1118
+ 'button_bg_color',
1119
+ [
1120
+ 'label' => __( 'Background Color', 'happy-elementor-addons' ),
1121
+ 'type' => Controls_Manager::COLOR,
1122
+ 'selectors' => [
1123
+ '{{WRAPPER}} .ha-btn' => 'background-color: {{VALUE}};',
1124
+ ],
1125
+ ]
1126
+ );
1127
+
1128
+ $this->end_controls_tab();
1129
+
1130
+ $this->start_controls_tab(
1131
+ '_tab_button_hover',
1132
+ [
1133
+ 'label' => __( 'Hover', 'happy-elementor-addons' ),
1134
+ ]
1135
+ );
1136
+
1137
+ $this->add_control(
1138
+ 'button_hover_color',
1139
+ [
1140
+ 'label' => __( 'Text Color', 'happy-elementor-addons' ),
1141
+ 'type' => Controls_Manager::COLOR,
1142
+ 'selectors' => [
1143
+ '{{WRAPPER}} .ha-btn:hover, {{WRAPPER}} .ha-btn:focus' => 'color: {{VALUE}};',
1144
+ ],
1145
+ ]
1146
+ );
1147
+
1148
+ $this->add_control(
1149
+ 'button_hover_bg_color',
1150
+ [
1151
+ 'label' => __( 'Background Color', 'happy-elementor-addons' ),
1152
+ 'type' => Controls_Manager::COLOR,
1153
+ 'selectors' => [
1154
+ '{{WRAPPER}} .ha-btn:hover, {{WRAPPER}} .ha-btn:focus' => 'background-color: {{VALUE}};',
1155
+ ],
1156
+ ]
1157
+ );
1158
+
1159
+ $this->add_control(
1160
+ 'button_hover_border_color',
1161
+ [
1162
+ 'label' => __( 'Border Color', 'happy-elementor-addons' ),
1163
+ 'type' => Controls_Manager::COLOR,
1164
+ 'condition' => [
1165
+ 'button_border_border!' => '',
1166
+ ],
1167
+ 'selectors' => [
1168
+ '{{WRAPPER}} .ha-btn:hover, {{WRAPPER}} .ha-btn:focus' => 'border-color: {{VALUE}};',
1169
+ ],
1170
+ ]
1171
+ );
1172
+
1173
+ $this->end_controls_tab();
1174
+ $this->end_controls_tabs();
1175
+
1176
+ $this->end_controls_section();
1177
+ }
1178
+
1179
+ protected function render() {
1180
+ $settings = $this->get_settings_for_display();
1181
+
1182
+ $button_position = ! empty( $settings['button_position'] ) ? $settings['button_position'] : 'after';
1183
+
1184
+ $show_button = false;
1185
+ if ( ! empty( $settings['show_details_button'] ) && $settings['show_details_button'] === 'yes' ) {
1186
+ $show_button = true;
1187
+ }
1188
+
1189
+ $this->add_inline_editing_attributes( 'title', 'basic' );
1190
+ $this->add_render_attribute( 'title', 'class', 'ha-member-name' );
1191
+
1192
+ $this->add_inline_editing_attributes( 'job_title', 'basic' );
1193
+ $this->add_render_attribute( 'job_title', 'class', 'ha-member-position' );
1194
+
1195
+ $this->add_inline_editing_attributes( 'bio', 'intermediate' );
1196
+ $this->add_render_attribute( 'bio', 'class', 'ha-member-bio' );
1197
+ ?>
1198
+
1199
+ <?php if ( $settings['image']['url'] || $settings['image']['id'] ) :
1200
+ $settings['hover_animation'] = 'disable-animation'; // hack to prevent image hover animation
1201
+ ?>
1202
+ <figure class="ha-member-figure">
1203
+ <?php echo Group_Control_Image_Size::get_attachment_image_html( $settings, 'thumbnail', 'image' ); ?>
1204
+ </figure>
1205
+ <?php endif; ?>
1206
+
1207
+ <div class="ha-member-body">
1208
+ <?php if ( $settings['title'] ) :
1209
+ printf( '<%1$s %2$s>%3$s</%1$s>',
1210
+ tag_escape( $settings['title_tag'] ),
1211
+ $this->get_render_attribute_string( 'title' ),
1212
+ ha_kses_basic( $settings['title'] )
1213
+ );
1214
+ endif; ?>
1215
+
1216
+ <?php if ( $settings['job_title' ] ) : ?>
1217
+ <div <?php $this->print_render_attribute_string( 'job_title' ); ?>><?php echo ha_kses_basic( $settings['job_title' ] ); ?></div>
1218
+ <?php endif; ?>
1219
+
1220
+ <?php if ( $settings['bio'] ) : ?>
1221
+ <div <?php $this->print_render_attribute_string( 'bio' ); ?>>
1222
+ <p><?php echo ha_kses_intermediate( $settings['bio'] ); ?></p>
1223
+ </div>
1224
+ <?php endif; ?>
1225
+
1226
+ <?php
1227
+ if ( $show_button && $button_position === 'before' ) {
1228
+ $this->render_icon_button( [ 'new_icon' => 'button_icon', 'old_icon' => '' ] );
1229
+ }
1230
+ ?>
1231
+
1232
+ <?php if ( $settings['show_profiles' ] && is_array( $settings['profiles' ] ) ) : ?>
1233
+ <div class="ha-member-links">
1234
+ <?php
1235
+ foreach ( $settings['profiles'] as $profile ) :
1236
+ $icon = $profile['name'];
1237
+ $url = $profile['link']['url'];
1238
+
1239
+ if ( $profile['name'] === 'website' ) {
1240
+ $icon = 'globe far';
1241
+ } elseif ( $profile['name'] === 'email' ) {
1242
+ $icon = 'envelope far';
1243
+ $url = 'mailto:' . antispambot( $profile['email'] );
1244
+ } else {
1245
+ $icon .= ' fab';
1246
+ }
1247
+
1248
+ printf( '<a target="_blank" rel="noopener" href="%s" class="elementor-repeater-item-%s"><i class="fa fa-%s" aria-hidden="true"></i></a>',
1249
+ $url,
1250
+ esc_attr( $profile['_id'] ),
1251
+ esc_attr( $icon )
1252
+ );
1253
+ endforeach; ?>
1254
+ </div>
1255
+ <?php endif; ?>
1256
+
1257
+ <?php
1258
+ if ( $show_button && $button_position === 'after' ) {
1259
+ $this->render_icon_button( [ 'new_icon' => 'button_icon', 'old_icon' => '' ] );
1260
+ }
1261
+ ?>
1262
+ </div>
1263
+ <?php
1264
+ }
1265
+
1266
+ public function _content_template() {
1267
+ return '';
1268
+ ?>
1269
+ <#
1270
+ view.addInlineEditingAttributes( 'title', 'basic' );
1271
+ view.addRenderAttribute( 'title', 'class', 'ha-member-name' );
1272
+
1273
+ view.addInlineEditingAttributes( 'job_title', 'basic' );
1274
+ view.addRenderAttribute( 'job_title', 'class', 'ha-member-position' );
1275
+
1276
+ view.addInlineEditingAttributes( 'bio', 'intermediate' );
1277
+ view.addRenderAttribute( 'bio', 'class', 'ha-member-bio' );
1278
+
1279
+ if ( settings.image.url || settings.image.id ) {
1280
+ var image = {
1281
+ id: settings.image.id,
1282
+ url: settings.image.url,
1283
+ size: settings.thumbnail_size,
1284
+ dimension: settings.thumbnail_custom_dimension,
1285
+ model: view.getEditModel()
1286
+ };
1287
+
1288
+ var image_url = elementor.imagesManager.getImageUrl( image );
1289
+ #>
1290
+ <figure class="ha-member-figure">
1291
+ <img src="{{ image_url }}">
1292
+ </figure>
1293
+ <# } #>
1294
+ <div class="ha-member-body">
1295
+ <# if (settings.title) { #>
1296
+ <{{ settings.title_tag }} {{{ view.getRenderAttributeString( 'title' ) }}}>{{ settings.title }}</{{ settings.title_tag }}>
1297
+ <# } #>
1298
+ <# if (settings.job_title) { #>
1299
+ <div {{{ view.getRenderAttributeString( 'job_title' ) }}}>{{ settings.job_title }}</div>
1300
+ <# } #>
1301
+ <# if (settings.bio) { #>
1302
+ <div {{{ view.getRenderAttributeString( 'bio' ) }}}>
1303
+ <p>{{{ settings.bio }}}</p>
1304
+ </div>
1305
+ <# } #>
1306
+
1307
+ <# if ( !_.isUndefined( settings['button_position'] ) && settings['button_position'] === 'before' ) {
1308
+ print( ha.getButtonWithIcon( view, {newIcon: 'button_icon', oldIcon: ''} ) );
1309
+ } #>
1310
+
1311
+ <# if (settings.show_profiles && _.isArray(settings.profiles)) { #>
1312
+ <div class="ha-member-links">
1313
+ <# _.each(settings.profiles, function(profile, index) {
1314
+ var icon = profile.name,
1315
+ url = profile.link.url,
1316
+ linkKey = view.getRepeaterSettingKey( 'profile', 'profiles', index);
1317
+
1318
+ if (profile.name === 'website') {
1319
+ icon = 'globe';
1320
+ } else if (profile.name === 'email') {
1321
+ icon = 'envelope'
1322
+ url = 'mailto:' + profile.email;
1323
+ }
1324
+
1325
+ view.addRenderAttribute( linkKey, 'class', 'elementor-repeater-item-' + profile._id );
1326
+ view.addRenderAttribute( linkKey, 'href', url ); #>
1327
+ <a {{{view.getRenderAttributeString( linkKey )}}}><i class="fa fab fa-{{{icon}}}"></i></a>
1328
+ <# }); #>
1329
+ </div>
1330
+ <# } #>
1331
+
1332
+ <# if ( !_.isUndefined( settings['button_position'] ) && settings['button_position'] === 'after' ) {
1333
+ print( ha.getButtonWithIcon( view, {newIcon: 'button_icon', oldIcon: ''} ) );
1334
+ } #>
1335
+ </div>
1336
+ <?php
1337
+ }
1338
+ }
widgets/review/widget.php CHANGED
@@ -132,16 +132,6 @@ class Review extends Base {
132
  ]
133
  );
134
 
135
- $this->add_control(
136
- 'review_for',
137
- [
138
- 'label' => __( 'Review For', 'happy-elementor-addons' ),
139
- 'type' => Controls_Manager::TEXT,
140
- 'placeholder' => __( 'Movie, Games, Software name etc.', 'happy-elementor-addons' ),
141
- 'description' => __( '[This field is only for structured data (schema.org) purpose] Obviously this review belongs to something like Movie, Games, Software or Service. So type the name of that thing.', 'happy-elementor-addons' ),
142
- ]
143
- );
144
-
145
  $this->end_controls_section();
146
 
147
  $this->start_controls_section(
@@ -688,35 +678,23 @@ class Review extends Base {
688
  protected function render() {
689
  $settings = $this->get_settings_for_display();
690
 
691
- $this->add_render_attribute( '_wrapper', 'itemscope' );
692
- $this->add_render_attribute( '_wrapper', 'itemtype', 'https://schema.org/Review' );
693
-
694
  $this->add_inline_editing_attributes( 'title', 'basic' );
695
  $this->add_render_attribute( 'title', 'class', 'ha-review-reviewer' );
696
- $this->add_render_attribute( 'title', 'itemprop', 'author' );
697
- $this->add_render_attribute( 'title', 'itemscope', '' );
698
- $this->add_render_attribute( 'title', 'itemtype', 'https://schema.org/Person' );
699
 
700
  $this->add_inline_editing_attributes( 'job_title', 'basic' );
701
  $this->add_render_attribute( 'job_title', 'class', 'ha-review-position' );
702
 
703
  $this->add_inline_editing_attributes( 'review', 'intermediate' );
704
  $this->add_render_attribute( 'review', 'class', 'ha-review-desc' );
705
- $this->add_render_attribute( 'review', 'itemprop', 'reviewBody' );
706
 
707
  $this->add_render_attribute( 'ratting', 'class', [
708
- 'ha-review-ratting',
709
- 'ha-review-ratting--' . $settings['ratting_style']
710
- ] );
711
-
712
- $this->add_render_attribute( 'ratting', 'itemprop', 'reviewRating' );
713
- $this->add_render_attribute( 'ratting', 'itemscope' );
714
- $this->add_render_attribute( 'ratting', 'itemtype', 'https://schema.org/Rating' );
715
 
716
  $ratting = max( 0, $settings['ratting']['size'] );
717
- ?>
718
 
719
- <?php if ( $settings['image']['url'] || $settings['image']['id'] ) :
720
  $settings['hover_animation'] = 'disable-animation'; // hack to prevent image hover animation
721
  ?>
722
  <figure class="ha-review-figure">
@@ -745,8 +723,6 @@ class Review extends Base {
745
  <?php endif; ?>
746
 
747
  <div <?php $this->print_render_attribute_string( 'ratting' ); ?>>
748
- <meta itemprop="ratingValue" content="<?php echo esc_attr( $ratting ); ?>">
749
-
750
  <?php if ( $settings['ratting_style'] === 'num' ) : ?>
751
  <?php echo esc_html( $ratting ); ?> <i class="fas fa-star" aria-hidden="true"></i>
752
  <?php else :
@@ -767,10 +743,6 @@ class Review extends Base {
767
  </div>
768
  <?php endif; ?>
769
  </div>
770
-
771
- <span class="ha-screen-reader-text" itemprop="itemReviewed" itemscope itemtype="https://schema.org/Thing">
772
- <span itemprop="name"><?php echo esc_html( $settings['review_for'] ); ?></span>
773
- </span>
774
  <?php
775
  }
776
 
132
  ]
133
  );
134
 
 
 
 
 
 
 
 
 
 
 
135
  $this->end_controls_section();
136
 
137
  $this->start_controls_section(
678
  protected function render() {
679
  $settings = $this->get_settings_for_display();
680
 
 
 
 
681
  $this->add_inline_editing_attributes( 'title', 'basic' );
682
  $this->add_render_attribute( 'title', 'class', 'ha-review-reviewer' );
 
 
 
683
 
684
  $this->add_inline_editing_attributes( 'job_title', 'basic' );
685
  $this->add_render_attribute( 'job_title', 'class', 'ha-review-position' );
686
 
687
  $this->add_inline_editing_attributes( 'review', 'intermediate' );
688
  $this->add_render_attribute( 'review', 'class', 'ha-review-desc' );
 
689
 
690
  $this->add_render_attribute( 'ratting', 'class', [
691
+ 'ha-review-ratting',
692
+ 'ha-review-ratting--' . $settings['ratting_style']
693
+ ] );
 
 
 
 
694
 
695
  $ratting = max( 0, $settings['ratting']['size'] );
 
696
 
697
+ if ( $settings['image']['url'] || $settings['image']['id'] ) :
698
  $settings['hover_animation'] = 'disable-animation'; // hack to prevent image hover animation
699
  ?>
700
  <figure class="ha-review-figure">
723
  <?php endif; ?>
724
 
725
  <div <?php $this->print_render_attribute_string( 'ratting' ); ?>>
 
 
726
  <?php if ( $settings['ratting_style'] === 'num' ) : ?>
727
  <?php echo esc_html( $ratting ); ?> <i class="fas fa-star" aria-hidden="true"></i>
728
  <?php else :
743
  </div>
744
  <?php endif; ?>
745
  </div>
 
 
 
 
746
  <?php
747
  }
748