diff --git a/assets/css/admin/users.css b/assets/css/admin/users.css index bb7b01fc..f4d527c3 100644 --- a/assets/css/admin/users.css +++ b/assets/css/admin/users.css @@ -1,3 +1,36 @@ +.um-admin.users-php .um_account_status { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: stretch; + flex-wrap: nowrap; +} +.um-admin.users-php .um_account_status span { + margin: 0 0 2px 0; + padding: 0; +} +.um-admin.users-php .um_account_status ul { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: baseline; + flex-wrap: wrap; + column-gap: 4px; + row-gap: 0; + margin: 0 0 4px 0; + padding: 0; +} +.um-admin.users-php .um_account_status ul li { + margin: 0; + padding: 0; +} +.um-admin.users-php .um_account_status ul li a.um-set-status-rejected, .um-admin.users-php .um_account_status ul li a.um-deactivate-user { + color: #b32d2e; +} +.um-admin.users-php .um_account_status ul li a.um-set-status-rejected:active, .um-admin.users-php .um_account_status ul li a.um-set-status-rejected:hover, .um-admin.users-php .um_account_status ul li a.um-deactivate-user:active, .um-admin.users-php .um_account_status ul li a.um-deactivate-user:hover { + color: #b32d2e; +} + .um-admin.users-php .subsubsub li.subsep { display: block; visibility: hidden; diff --git a/assets/css/admin/users.min.css b/assets/css/admin/users.min.css index eb6d1dc7..1efe0289 100644 --- a/assets/css/admin/users.min.css +++ b/assets/css/admin/users.min.css @@ -1 +1 @@ -.um-admin.users-php .subsubsub li.subsep{display:block;visibility:hidden;height:0}.um-admin-modal .um-admin-infobox label{font-weight:700;display:block;color:#333;cursor:default}.um-admin-modal .um-admin-infobox p{color:#666;padding-top:15px}.um-admin-modal .um-admin-infobox>p:not(:first-child){border-top:1px solid #e5e5e5}.um-admin-modal .um-admin-infobox>p:first-child{margin-top:0;padding-top:0}.um-admin-modal .um-admin-infobox>.um-row>p{border-top:1px solid #e5e5e5}.um-admin-modal .um-admin-infobox>.um-row>p:last-child{margin-bottom:0}#UM_preview_registration .um-admin-modal-foot{display:none} \ No newline at end of file +.um-admin.users-php .um_account_status{display:flex;flex-direction:column;justify-content:flex-start;align-items:stretch;flex-wrap:nowrap}.um-admin.users-php .um_account_status span{margin:0 0 2px 0;padding:0}.um-admin.users-php .um_account_status ul{display:flex;flex-direction:row;justify-content:flex-start;align-items:baseline;flex-wrap:wrap;column-gap:4px;row-gap:0;margin:0 0 4px 0;padding:0}.um-admin.users-php .um_account_status ul li{margin:0;padding:0}.um-admin.users-php .um_account_status ul li a.um-deactivate-user,.um-admin.users-php .um_account_status ul li a.um-set-status-rejected{color:#b32d2e}.um-admin.users-php .um_account_status ul li a.um-deactivate-user:active,.um-admin.users-php .um_account_status ul li a.um-deactivate-user:hover,.um-admin.users-php .um_account_status ul li a.um-set-status-rejected:active,.um-admin.users-php .um_account_status ul li a.um-set-status-rejected:hover{color:#b32d2e}.um-admin.users-php .subsubsub li.subsep{display:block;visibility:hidden;height:0}.um-admin-modal .um-admin-infobox label{font-weight:700;display:block;color:#333;cursor:default}.um-admin-modal .um-admin-infobox p{color:#666;padding-top:15px}.um-admin-modal .um-admin-infobox>p:not(:first-child){border-top:1px solid #e5e5e5}.um-admin-modal .um-admin-infobox>p:first-child{margin-top:0;padding-top:0}.um-admin-modal .um-admin-infobox>.um-row>p{border-top:1px solid #e5e5e5}.um-admin-modal .um-admin-infobox>.um-row>p:last-child{margin-bottom:0}#UM_preview_registration .um-admin-modal-foot{display:none} \ No newline at end of file diff --git a/assets/css/admin/users.sass b/assets/css/admin/users.sass index fe61d28f..09b3756e 100644 --- a/assets/css/admin/users.sass +++ b/assets/css/admin/users.sass @@ -1,5 +1,28 @@ @import "selectors" +@import "mixins" +.#{$prefix}admin.users-php + .um_account_status + +flex( column, flex-start, stretch, nowrap ) + span + margin: 0 0 2px 0 + padding: 0 + ul + +flex( row, flex-start, baseline, wrap ) + column-gap: 4px + row-gap: 0 + margin: 0 0 4px 0 + padding: 0 + li + margin: 0 + padding: 0 + a + &.um-set-status-rejected, + &.um-deactivate-user + color: #b32d2e + &:active, + &:hover + color: #b32d2e .#{$prefix}admin.users-php .subsubsub li.subsep diff --git a/assets/js/admin/block-restrictions.min.js b/assets/js/admin/block-restrictions.min.js index 50daef62..203ca795 100644 --- a/assets/js/admin/block-restrictions.min.js +++ b/assets/js/admin/block-restrictions.min.js @@ -1 +1 @@ -"use strict";var um_components=wp.components,umSelectControl=um_components.SelectControl,umTextareaControl=um_components.TextareaControl;function um_admin_blocks_custom_fields(e,t){return wp.hooks.applyFilters("um_admin_blocks_custom_fields",[],e,t)}var um_block_restriction=wp.compose.createHigherOrderComponent(function(s){var _={um_who_access:"um_block_settings_hide",um_roles_access:"um_block_settings_hide",um_message_type:"um_block_settings_hide",um_message_content:"um_block_settings_hide"},_=wp.hooks.applyFilters("um_admin_blocks_condition_fields_default",_);return function(t){var e=void 0!==t.attributes.um_is_restrict&&t.attributes.um_is_restrict;return!0!==t.attributes.um_is_restrict?(_.um_who_access="um_block_settings_hide",_.um_roles_access="um_block_settings_hide",_.um_message_type="um_block_settings_hide",_.um_message_content="um_block_settings_hide"):(_.um_who_access="",0===parseInt(t.attributes.um_who_access)||void 0===t.attributes.um_who_access?(_.um_roles_access="um_block_settings_hide",_.um_message_type="um_block_settings_hide",_.um_message_content="um_block_settings_hide"):(1===parseInt(t.attributes.um_who_access)&&(_.um_roles_access=""),_.um_message_type="",2===parseInt(t.attributes.um_message_type)?_.um_message_content="":_.um_message_content="um_block_settings_hide")),_=wp.hooks.applyFilters("um_admin_blocks_condition_fields",_,t),wp.element.createElement(wp.element.Fragment,{},wp.element.createElement(s,t),wp.element.createElement(wp.blockEditor.InspectorControls,{},wp.element.createElement(wp.components.PanelBody,{title:wp.i18n.__("Ultimate Member: Content Restriction","ultimate-member"),className:"um_block_settings"},wp.element.createElement(wp.components.ToggleControl,{label:wp.i18n.__("Restrict access?","ultimate-member"),checked:e,onChange:function(e){t.setAttributes({um_is_restrict:e}),!1===e?(_.um_who_access="um_block_settings_hide",_.um_roles_access="um_block_settings_hide",_.um_message_type="um_block_settings_hide",_.um_message_content="um_block_settings_hide"):_.um_who_access="",_=wp.hooks.applyFilters("um_admin_blocks_condition_fields_on_change",_,"um_is_restrict",e)}}),wp.element.createElement(umSelectControl,{type:"number",className:_.um_who_access,label:wp.i18n.__("Who can access this block?","ultimate-member"),value:t.attributes.um_who_access,options:[{label:wp.i18n.__("Everyone","ultimate-member"),value:0},{label:wp.i18n.__("Logged in users","ultimate-member"),value:1},{label:wp.i18n.__("Logged out users","ultimate-member"),value:2}],onChange:function(e){t.setAttributes({um_who_access:e}),0===parseInt(e)?(_.um_message_type="um_block_settings_hide",_.um_message_content="um_block_settings_hide",_.um_roles_access="um_block_settings_hide"):1===parseInt(e)?(_.um_message_type="",_.um_roles_access=""):(_.um_message_type="",_.um_roles_access="um_block_settings_hide"),_=wp.hooks.applyFilters("um_admin_blocks_condition_fields_on_change",_,"um_who_access",e)}}),wp.element.createElement(umSelectControl,{multiple:!0,className:_.um_roles_access,label:wp.i18n.__("What roles can access this block?","ultimate-member"),value:t.attributes.um_roles_access,options:um_restrict_roles,onChange:function(e){t.setAttributes({um_roles_access:e})}}),wp.element.createElement(umSelectControl,{type:"number",className:_.um_message_type,label:wp.i18n.__("Restriction action","ultimate-member"),value:t.attributes.um_message_type,options:[{label:wp.i18n.__("Hide block","ultimate-member"),value:0},{label:wp.i18n.__("Show global default message","ultimate-member"),value:1},{label:wp.i18n.__("Show custom message","ultimate-member"),value:2}],onChange:function(e){t.setAttributes({um_message_type:e}),2===parseInt(e)?_.um_message_content="":_.um_message_content="um_block_settings_hide"}}),wp.element.createElement(umTextareaControl,{type:"number",className:_.um_message_content,label:wp.i18n.__("Custom restricted access message","ultimate-member"),value:t.attributes.um_message_content,onChange:function(e){t.setAttributes({um_message_content:e})}}),um_admin_blocks_custom_fields(_,t))))}},"um_block_restriction");wp.hooks.addFilter("editor.BlockEdit","um-block/um_block_restriction",um_block_restriction); \ No newline at end of file +var um_components=wp.components,umSelectControl=um_components.SelectControl,umTextareaControl=um_components.TextareaControl;function um_admin_blocks_custom_fields(e,t){return wp.hooks.applyFilters("um_admin_blocks_custom_fields",[],e,t)}var um_block_restriction=wp.compose.createHigherOrderComponent(function(s){var _={um_who_access:"um_block_settings_hide",um_roles_access:"um_block_settings_hide",um_message_type:"um_block_settings_hide",um_message_content:"um_block_settings_hide"},_=wp.hooks.applyFilters("um_admin_blocks_condition_fields_default",_);return function(t){var e=void 0!==t.attributes.um_is_restrict&&t.attributes.um_is_restrict;return!0!==t.attributes.um_is_restrict?(_.um_who_access="um_block_settings_hide",_.um_roles_access="um_block_settings_hide",_.um_message_type="um_block_settings_hide",_.um_message_content="um_block_settings_hide"):(_.um_who_access="",0===parseInt(t.attributes.um_who_access)||void 0===t.attributes.um_who_access?(_.um_roles_access="um_block_settings_hide",_.um_message_type="um_block_settings_hide",_.um_message_content="um_block_settings_hide"):(1===parseInt(t.attributes.um_who_access)&&(_.um_roles_access=""),_.um_message_type="",2===parseInt(t.attributes.um_message_type)?_.um_message_content="":_.um_message_content="um_block_settings_hide")),_=wp.hooks.applyFilters("um_admin_blocks_condition_fields",_,t),wp.element.createElement(wp.element.Fragment,{},wp.element.createElement(s,t),wp.element.createElement(wp.blockEditor.InspectorControls,{},wp.element.createElement(wp.components.PanelBody,{title:wp.i18n.__("Ultimate Member: Content Restriction","ultimate-member"),className:"um_block_settings"},wp.element.createElement(wp.components.ToggleControl,{label:wp.i18n.__("Restrict access?","ultimate-member"),checked:e,onChange:function(e){t.setAttributes({um_is_restrict:e}),!1===e?(_.um_who_access="um_block_settings_hide",_.um_roles_access="um_block_settings_hide",_.um_message_type="um_block_settings_hide",_.um_message_content="um_block_settings_hide"):_.um_who_access="",_=wp.hooks.applyFilters("um_admin_blocks_condition_fields_on_change",_,"um_is_restrict",e)}}),wp.element.createElement(umSelectControl,{type:"number",className:_.um_who_access,label:wp.i18n.__("Who can access this block?","ultimate-member"),value:t.attributes.um_who_access,options:[{label:wp.i18n.__("Everyone","ultimate-member"),value:0},{label:wp.i18n.__("Logged in users","ultimate-member"),value:1},{label:wp.i18n.__("Logged out users","ultimate-member"),value:2}],onChange:function(e){t.setAttributes({um_who_access:e}),0===parseInt(e)?(_.um_message_type="um_block_settings_hide",_.um_message_content="um_block_settings_hide",_.um_roles_access="um_block_settings_hide"):1===parseInt(e)?(_.um_message_type="",_.um_roles_access=""):(_.um_message_type="",_.um_roles_access="um_block_settings_hide"),_=wp.hooks.applyFilters("um_admin_blocks_condition_fields_on_change",_,"um_who_access",e)}}),wp.element.createElement(umSelectControl,{multiple:!0,className:_.um_roles_access,label:wp.i18n.__("What roles can access this block?","ultimate-member"),value:t.attributes.um_roles_access,options:um_restrict_roles,onChange:function(e){t.setAttributes({um_roles_access:e})}}),wp.element.createElement(umSelectControl,{type:"number",className:_.um_message_type,label:wp.i18n.__("Restriction action","ultimate-member"),value:t.attributes.um_message_type,options:[{label:wp.i18n.__("Hide block","ultimate-member"),value:0},{label:wp.i18n.__("Show global default message","ultimate-member"),value:1},{label:wp.i18n.__("Show custom message","ultimate-member"),value:2}],onChange:function(e){t.setAttributes({um_message_type:e}),2===parseInt(e)?_.um_message_content="":_.um_message_content="um_block_settings_hide"}}),wp.element.createElement(umTextareaControl,{type:"number",className:_.um_message_content,label:wp.i18n.__("Custom restricted access message","ultimate-member"),value:t.attributes.um_message_content,onChange:function(e){t.setAttributes({um_message_content:e})}}),um_admin_blocks_custom_fields(_,t))))}},"um_block_restriction");wp.hooks.addFilter("editor.BlockEdit","um-block/um_block_restriction",um_block_restriction); \ No newline at end of file diff --git a/assets/js/admin/security.min.js b/assets/js/admin/security.min.js index 680722e6..1fc8d38c 100644 --- a/assets/js/admin/security.min.js +++ b/assets/js/admin/security.min.js @@ -1 +1 @@ -jQuery(document).ready(function(){const n=jQuery(".um-secure-scan-results"),t=jQuery(".um-secure-scan-content"),e=jQuery("input[data-field_id^='banned_capabilities']");var c={init:function(){n.css({"margin-top":"10px",padding:"10px","padding-bottom":"10px","background-color":"#fff",display:"block","max-height":"200px",height:"500px","overflow-y":"scroll"}),t.on("click",function(e){c.effect(),e.preventDefault(),jQuery(this).prop("disabled",!0),n.empty(),c.log(wp.i18n.__("Scanning site..","ultimate-member")),c.ajax("")}),e.on("change",function(){t.after(' '+wp.i18n.__("You can start the scan now but you must save the settings to apply the selected capabilities after the scan is complete.","ultimate-member")+""),e.off("change")})},ajax:function(e){let a=[];n.parents(".um-form-table").find('input[type="checkbox"][data-field_id^="banned_capabilities_"]:checked').each(function(){a.push(jQuery(this).data("field_id").replace("banned_capabilities_",""))});e={nonce:um_admin_scripts.nonce,capabilities:a,last_scanned_capability:e};wp.ajax.send("um_secure_scan_affected_users",{data:e,success:function(e){e.completed?e.completed&&(n.empty(),c.log(e.recommendations),n.find(".current").removeClass("current"),t.prop("disabled",!1)):(c.ajax(e.last_scanned_capability),c.log(e.message))}})},log:function(e){n.find(".current").removeClass("current"),n.append(''+e+"
")},effect:function(){setInterval(function(){n.find(".current").fadeTo(100,.1).fadeTo(200,1)},1e3)}};c.init()}); \ No newline at end of file +jQuery(document).ready(function(){let t=jQuery(".um-secure-scan-results"),n=jQuery(".um-secure-scan-content"),e=jQuery("input[data-field_id^='banned_capabilities']");var c={init:function(){t.css({"margin-top":"10px",padding:"10px","padding-bottom":"10px","background-color":"#fff",display:"block","max-height":"200px",height:"500px","overflow-y":"scroll"}),n.on("click",function(e){c.effect(),e.preventDefault(),jQuery(this).prop("disabled",!0),t.empty(),c.log(wp.i18n.__("Scanning site..","ultimate-member")),c.ajax("")}),e.on("change",function(){n.after(' '+wp.i18n.__("You can start the scan now but you must save the settings to apply the selected capabilities after the scan is complete.","ultimate-member")+""),e.off("change")})},ajax:function(e){let a=[];t.parents(".um-form-table").find('input[type="checkbox"][data-field_id^="banned_capabilities_"]:checked').each(function(){a.push(jQuery(this).data("field_id").replace("banned_capabilities_",""))});e={nonce:um_admin_scripts.nonce,capabilities:a,last_scanned_capability:e};wp.ajax.send("um_secure_scan_affected_users",{data:e,success:function(e){e.completed?e.completed&&(t.empty(),c.log(e.recommendations),t.find(".current").removeClass("current"),n.prop("disabled",!1)):(c.ajax(e.last_scanned_capability),c.log(e.message))}})},log:function(e){t.find(".current").removeClass("current"),t.append(''+e+"
")},effect:function(){setInterval(function(){t.find(".current").fadeTo(100,.1).fadeTo(200,1)},1e3)}};c.init()}); \ No newline at end of file diff --git a/assets/js/um-gdpr.min.js b/assets/js/um-gdpr.min.js index 98f5ff88..76470131 100644 --- a/assets/js/um-gdpr.min.js +++ b/assets/js/um-gdpr.min.js @@ -1 +1 @@ -!function(){"use strict";jQuery(document).on("click","a.um-toggle-gdpr",function(e){var e=jQuery(e.currentTarget),t=e.closest(".um-field-area"),g=t.find(".um-gdpr-content");g.is(":visible")?(t.find("a.um-toggle-gdpr").text(e.data("toggle-show")),g.hide().find("a.um-toggle-gdpr").remove(),e.length&&e.get(0).scrollIntoView()):(t.find("a.um-toggle-gdpr").text(e.data("toggle-hide")),g.show().prepend(e.clone()))})}(); \ No newline at end of file +jQuery(document).on("click","a.um-toggle-gdpr",function(e){var e=jQuery(e.currentTarget),t=e.closest(".um-field-area"),g=t.find(".um-gdpr-content");g.is(":visible")?(t.find("a.um-toggle-gdpr").text(e.data("toggle-show")),g.hide().find("a.um-toggle-gdpr").remove(),e.length&&e.get(0).scrollIntoView()):(t.find("a.um-toggle-gdpr").text(e.data("toggle-hide")),g.show().prepend(e.clone()))}); \ No newline at end of file diff --git a/assets/js/um-scripts.js b/assets/js/um-scripts.js index a14ddb83..0e005ffe 100644 --- a/assets/js/um-scripts.js +++ b/assets/js/um-scripts.js @@ -417,7 +417,7 @@ jQuery(document).ready(function() { e.preventDefault(); var hook = jQuery(this).data('hook'); var user_id = jQuery(this).data('user_id'); - var arguments = jQuery(this).data('arguments'); + var args = jQuery(this).data('args'); if ( jQuery(this).data('js-remove') ){ jQuery(this).parents('.'+jQuery(this).data('js-remove')).fadeOut('fast'); @@ -430,7 +430,7 @@ jQuery(document).ready(function() { action: 'um_muted_action', hook: hook, user_id: user_id, - arguments: arguments, + arguments: args, nonce: um_scripts.nonce }, success: function(data){ diff --git a/assets/js/um-scripts.min.js b/assets/js/um-scripts.min.js index 40e412d4..087cfa13 100644 --- a/assets/js/um-scripts.min.js +++ b/assets/js/um-scripts.min.js @@ -1 +1 @@ -function um_sanitize_value(e,t){var a=document.createElement("div"),e=(a.innerText=e,a.innerHTML);return t&&jQuery(t).val(e),e}function um_unsanitize_value(e){var t=document.createElement("textarea");return t.innerHTML=e,0===t.childNodes.length?"":t.childNodes[0].nodeValue}jQuery(document).ready(function(){function n(e){var a=jQuery(e.currentTarget),e=a.find(":selected");1'),a.find(".um-single-image-preview").removeAttr("style").hide(),a.find(".ajax-upload-dragdrop").show(),a.find(".um-modal-btn.um-finish-upload").addClass("disabled"),um_modal_responsive()}}):(a=jQuery(this).parents(".um-field"),n=a.data("mode"),i=a.find(".um-single-image-preview img").attr("src"),e=a.find('input[type="hidden"]#'+a.data("key")+"-"+jQuery(this).parents("form").find('input[type="hidden"][name="form_id"]').val()).val(),r={data:{mode:n,filename:e,src:i,nonce:um_scripts.nonce},success:function(){a.find(".um-single-image-preview img").replaceWith(''),a.find(".um-single-image-preview").removeAttr("style").hide(),a.find(".um-btn-auto-width").html(a.data("upload-label")),a.find('input[type="hidden"]').val("empty_file")}},"register"!==n&&(r.data.user_id=jQuery(this).parents("form").find("#user_id").val())),wp.ajax.send("um_remove_file",r)}),jQuery(document.body).on("click",".um-single-file-preview a.cancel",function(e){e.preventDefault();let t=!1;0'),a.find(".um-single-image-preview").removeAttr("style").hide(),a.find(".ajax-upload-dragdrop").show(),a.find(".um-modal-btn.um-finish-upload").addClass("disabled"),um_modal_responsive()}}):(a=jQuery(this).parents(".um-field"),n=a.data("mode"),i=a.find(".um-single-image-preview img").attr("src"),e=a.find('input[type="hidden"]#'+a.data("key")+"-"+jQuery(this).parents("form").find('input[type="hidden"][name="form_id"]').val()).val(),r={data:{mode:n,filename:e,src:i,nonce:um_scripts.nonce},success:function(){a.find(".um-single-image-preview img").replaceWith(''),a.find(".um-single-image-preview").removeAttr("style").hide(),a.find(".um-btn-auto-width").html(a.data("upload-label")),a.find('input[type="hidden"]').val("empty_file")}},"register"!==n&&(r.data.user_id=jQuery(this).parents("form").find("#user_id").val())),wp.ajax.send("um_remove_file",r)}),jQuery(document.body).on("click",".um-single-file-preview a.cancel",function(e){e.preventDefault();let t=!1;0",{name:this.opt.scoreName,type:"hidden"}).appendTo(this)},_createCancel:function(){var t=this.opt.path+this.opt.cancelOff,e=i("<"+this.opt.starType+" />",{title:this.opt.cancelHint,class:this.opt.cancelClass});"img"===this.opt.starType?e.attr({src:t,alt:"x"}):e.attr("data-alt","x").addClass(t),"left"===this.opt.cancelPlace?this.self.prepend(" ").prepend(e):this.self.append(" ").append(e),this.cancel=e},_createScore:function(){var t=i(this.opt.targetScore);this.score=t.length?t:r._buildScoreField.call(this)},_createStars:function(){for(var t=1;t<=this.opt.number;t++){var e=r._nameForIndex.call(this,t),e={alt:t,src:this.opt.path+this.opt[e]};(e="img"!==this.opt.starType?{"data-alt":t,class:e.src}:e).title=r._getHint.call(this,t),i("<"+this.opt.starType+" />",e).appendTo(this),this.opt.space&&this.self.append(te?(s=this.opt.iconRange[e],i=r._getRangeIcon.call(this,s,n),a<=s.range&&r._setIcon.call(this,o,i),a===s.range&&e++):(i=this.opt[n?"starOn":"starOff"],r._setIcon.call(this,o,i))}},_getRangeIcon:function(t,e){return e?t.on||this.opt.starOn:t.off||this.opt.starOff},_getScoreByPosition:function(t,e){var a,s=parseInt(e.alt||e.getAttribute("data-alt"),10);return this.opt.half&&(a=r._getSize.call(this),t=parseFloat((t.pageX-i(e).offset().left)/a),s=this.opt.precision?s-1+t:s-1+(.5=t?"starOn":"starOff"},_roundStars:function(t){var e,a=(t%1).toFixed(2);a>this.opt.round.down&&(e="starOn",this.opt.halfShow&&a=e.number&&(t=e.number-1,a=10);e=r._getSize.call(this)/10,t=i(this.stars[t]),e=t.offset().left+e*parseInt(a,10),a=i.Event("mousemove",{pageX:e});t.trigger(a)})},readOnly:function(e){return this.each(function(){var t=i(this);t.data("readonly")!==e&&((e?(t.off(".um_raty").children("img").off(".um_raty"),r._lock):(r._binds.call(this),r._unlock)).call(this),t.data("readonly",e))})},reload:function(){return r.set.call(this,{})},score:function(){var t=i(this);return arguments.length?r.setScore.apply(t,arguments):r.getScore.call(t)},set:function(a){return this.each(function(){var t=i(this),e=t.data("options"),e=i.extend({},e,a);t.um_raty(e)})},setScore:function(t){return this.each(function(){!0!==i(this).data("readonly")&&(r._apply.call(this,t),r._target.call(this,t))})}};i.fn.um_raty=function(t){return r[t]?r[t].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof t&&t?void i.error("Method "+t+" does not exist!"):r.init.apply(this,arguments)},i.fn.um_raty.defaults={cancel:!1,cancelClass:"raty-cancel",cancelHint:wp.i18n.__("Cancel this rating!","ultimate-member"),cancelOff:"cancel-off.png",cancelOn:"cancel-on.png",cancelPlace:"left",click:void 0,half:!1,halfShow:!0,hints:["bad","poor","regular","good","gorgeous"],iconRange:void 0,mouseout:void 0,mouseover:void 0,noRatedMsg:wp.i18n.__("Not rated yet!","ultimate-member"),number:5,numberMax:20,path:void 0,precision:!1,readOnly:!1,round:{down:.25,full:.6,up:.76},score:void 0,scoreName:"score",single:!1,space:!0,starHalf:"star-half.png",starOff:"star-off.png",starOn:"star-on.png",starType:"img",target:void 0,targetFormat:"{score}",targetKeep:!1,targetScore:void 0,targetText:"",targetType:"hint"}}(jQuery); \ No newline at end of file +!function(i){var r={init:function(t){return this.each(function(){this.self=i(this),r.destroy.call(this.self),this.opt=i.extend(!0,{},i.fn.um_raty.defaults,t),r._adjustCallback.call(this),r._adjustNumber.call(this),"img"!==this.opt.starType&&r._adjustStarType.call(this),r._adjustPath.call(this),r._createStars.call(this),this.opt.cancel&&r._createCancel.call(this),this.opt.precision&&r._adjustPrecision.call(this),r._createScore.call(this),r._apply.call(this,this.opt.score),r._target.call(this,this.opt.score),(this.opt.readOnly?r._lock:(this.style.cursor="pointer",r._binds)).call(this),this.self.data("options",this.opt)})},_adjustCallback:function(){for(var t=["number","readOnly","score","scoreName","target"],e=0;e",{name:this.opt.scoreName,type:"hidden"}).appendTo(this)},_createCancel:function(){var t=this.opt.path+this.opt.cancelOff,e=i("<"+this.opt.starType+" />",{title:this.opt.cancelHint,class:this.opt.cancelClass});"img"===this.opt.starType?e.attr({src:t,alt:"x"}):e.attr("data-alt","x").addClass(t),"left"===this.opt.cancelPlace?this.self.prepend(" ").prepend(e):this.self.append(" ").append(e),this.cancel=e},_createScore:function(){var t=i(this.opt.targetScore);this.score=t.length?t:r._buildScoreField.call(this)},_createStars:function(){for(var t=1;t<=this.opt.number;t++){var e=r._nameForIndex.call(this,t),e={alt:t,src:this.opt.path+this.opt[e]};(e="img"!==this.opt.starType?{"data-alt":t,class:e.src}:e).title=r._getHint.call(this,t),i("<"+this.opt.starType+" />",e).appendTo(this),this.opt.space&&this.self.append(te?(s=this.opt.iconRange[e],i=r._getRangeIcon.call(this,s,n),a<=s.range&&r._setIcon.call(this,o,i),a===s.range&&e++):(i=this.opt[n?"starOn":"starOff"],r._setIcon.call(this,o,i))}},_getRangeIcon:function(t,e){return e?t.on||this.opt.starOn:t.off||this.opt.starOff},_getScoreByPosition:function(t,e){var a,s=parseInt(e.alt||e.getAttribute("data-alt"),10);return this.opt.half&&(a=r._getSize.call(this),t=parseFloat((t.pageX-i(e).offset().left)/a),s=this.opt.precision?s-1+t:s-1+(.5=t?"starOn":"starOff"},_roundStars:function(t){var e,a=(t%1).toFixed(2);a>this.opt.round.down&&(e="starOn",this.opt.halfShow&&a=e.number&&(t=e.number-1,a=10);e=r._getSize.call(this)/10,t=i(this.stars[t]),e=t.offset().left+e*parseInt(a,10),a=i.Event("mousemove",{pageX:e});t.trigger(a)})},readOnly:function(e){return this.each(function(){var t=i(this);t.data("readonly")!==e&&((e?(t.off(".um_raty").children("img").off(".um_raty"),r._lock):(r._binds.call(this),r._unlock)).call(this),t.data("readonly",e))})},reload:function(){return r.set.call(this,{})},score:function(){var t=i(this);return arguments.length?r.setScore.apply(t,arguments):r.getScore.call(t)},set:function(a){return this.each(function(){var t=i(this),e=t.data("options"),e=i.extend({},e,a);t.um_raty(e)})},setScore:function(t){return this.each(function(){!0!==i(this).data("readonly")&&(r._apply.call(this,t),r._target.call(this,t))})}};i.fn.um_raty=function(t){return r[t]?r[t].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof t&&t?void i.error("Method "+t+" does not exist!"):r.init.apply(this,arguments)},i.fn.um_raty.defaults={cancel:!1,cancelClass:"raty-cancel",cancelHint:wp.i18n.__("Cancel this rating!","ultimate-member"),cancelOff:"cancel-off.png",cancelOn:"cancel-on.png",cancelPlace:"left",click:void 0,half:!1,halfShow:!0,hints:["bad","poor","regular","good","gorgeous"],iconRange:void 0,mouseout:void 0,mouseover:void 0,noRatedMsg:wp.i18n.__("Not rated yet!","ultimate-member"),number:5,numberMax:20,path:void 0,precision:!1,readOnly:!1,round:{down:.25,full:.6,up:.76},score:void 0,scoreName:"score",single:!1,space:!0,starHalf:"star-half.png",starOff:"star-off.png",starOn:"star-on.png",starType:"img",target:void 0,targetFormat:"{score}",targetKeep:!1,targetScore:void 0,targetText:"",targetType:"hint"}}(jQuery); \ No newline at end of file diff --git a/includes/admin/class-actions-listener.php b/includes/admin/class-actions-listener.php new file mode 100644 index 00000000..81442364 --- /dev/null +++ b/includes/admin/class-actions-listener.php @@ -0,0 +1,160 @@ +common()->users()->can_current_user_edit_user( $user_id ) ) { + $result = UM()->common()->users()->approve( $user_id ); + if ( $result ) { + $redirect = add_query_arg( array( 'update' => 'um_approved', 'approved_count' => 1 ), $redirect ); + } + } + + wp_safe_redirect( $redirect ); + exit; + case 'reactivate_user': + if ( empty( $_REQUEST['uid'] ) || ! is_numeric( $_REQUEST['uid'] ) ) { + die( esc_html__( 'Invalid user ID', 'ultimate-member' ) ); + } + + $user_id = absint( $_REQUEST['uid'] ); + + check_admin_referer( "reactivate_user{$user_id}" ); + + $redirect = wp_get_referer(); + if ( UM()->common()->users()->can_current_user_edit_user( $user_id ) ) { + $result = UM()->common()->users()->reactivate( $user_id ); + if ( $result ) { + $redirect = add_query_arg( array( 'update' => 'um_reactivated', 'reactivated_count' => 1 ), $redirect ); + } + } + wp_safe_redirect( $redirect ); + exit; + case 'put_user_as_pending': + if ( empty( $_REQUEST['uid'] ) || ! is_numeric( $_REQUEST['uid'] ) ) { + die( esc_html__( 'Invalid user ID', 'ultimate-member' ) ); + } + + $user_id = absint( $_REQUEST['uid'] ); + + check_admin_referer( "put_user_as_pending{$user_id}" ); + + $redirect = wp_get_referer(); + if ( UM()->common()->users()->can_current_user_edit_user( $user_id ) ) { + $result = UM()->common()->users()->set_as_pending( $user_id ); + if ( $result ) { + $redirect = add_query_arg( array( 'update' => 'um_pending', 'pending_count' => 1 ), $redirect ); + } + } + wp_safe_redirect( $redirect ); + exit; + case 'resend_user_activation': + if ( empty( $_REQUEST['uid'] ) || ! is_numeric( $_REQUEST['uid'] ) ) { + die( esc_html__( 'Invalid user ID', 'ultimate-member' ) ); + } + + $user_id = absint( $_REQUEST['uid'] ); + + check_admin_referer( "resend_user_activation{$user_id}" ); + + $redirect = wp_get_referer(); + if ( UM()->common()->users()->can_current_user_edit_user( $user_id ) ) { + $result = UM()->common()->users()->send_activation( $user_id ); + if ( $result ) { + $redirect = add_query_arg( array( 'update' => 'um_resend_activation', 'resend_activation_count' => 1 ), $redirect ); + } + } + wp_safe_redirect( $redirect ); + exit; + case 'reject_user': + if ( empty( $_REQUEST['uid'] ) || ! is_numeric( $_REQUEST['uid'] ) ) { + die( esc_html__( 'Invalid user ID', 'ultimate-member' ) ); + } + + $user_id = absint( $_REQUEST['uid'] ); + + check_admin_referer( "reject_user{$user_id}" ); + + $redirect = wp_get_referer(); + if ( UM()->common()->users()->can_current_user_edit_user( $user_id ) ) { + $result = UM()->common()->users()->reject( $user_id ); + if ( $result ) { + $redirect = add_query_arg( array( 'update' => 'um_rejected', 'rejected_count' => 1 ), $redirect ); + } + } + wp_safe_redirect( $redirect ); + exit; + case 'deactivate_user': + if ( empty( $_REQUEST['uid'] ) || ! is_numeric( $_REQUEST['uid'] ) ) { + die( esc_html__( 'Invalid user ID', 'ultimate-member' ) ); + } + + $user_id = absint( $_REQUEST['uid'] ); + + check_admin_referer( "deactivate_user{$user_id}" ); + + $redirect = wp_get_referer(); + if ( UM()->common()->users()->can_current_user_edit_user( $user_id ) ) { + $result = UM()->common()->users()->deactivate( $user_id ); + if ( $result ) { + $redirect = add_query_arg( array( 'update' => 'um_deactivate', 'deactivated_count' => 1 ), $redirect ); + } + } + wp_safe_redirect( $redirect ); + exit; + } + } + } + + public function extends_individual_nonce_actions( $actions ) { + $actions[] = 'approve_user'; + $actions[] = 'reactivate_user'; + $actions[] = 'put_user_as_pending'; + $actions[] = 'resend_user_activation'; + $actions[] = 'reject_user'; + $actions[] = 'deactivate_user'; + return $actions; + } + } +} diff --git a/includes/admin/class-admin.php b/includes/admin/class-admin.php index 0afb0a04..c34d913c 100644 --- a/includes/admin/class-admin.php +++ b/includes/admin/class-admin.php @@ -67,7 +67,6 @@ if ( ! class_exists( 'um\admin\Admin' ) ) { add_action( 'um_admin_do_action__purge_temp', array( &$this, 'purge_temp' ) ); add_action( 'um_admin_do_action__manual_upgrades_request', array( &$this, 'manual_upgrades_request' ) ); add_action( 'um_admin_do_action__duplicate_form', array( &$this, 'duplicate_form' ) ); - add_action( 'um_admin_do_action__user_action', array( &$this, 'user_action' ) ); add_action( 'um_admin_do_action__check_templates_version', array( &$this, 'check_templates_version' ) ); add_action( 'um_admin_do_action__install_core_pages', array( &$this, 'install_core_pages' ) ); @@ -79,10 +78,12 @@ if ( ! class_exists( 'um\admin\Admin' ) ) { } public function includes() { + $this->actions_listener(); $this->enqueue(); $this->notices(); $this->secure(); $this->site_health(); + $this->users_columns(); } public function init_variables() { @@ -1840,69 +1841,6 @@ if ( ! class_exists( 'um\admin\Admin' ) ) { exit; } - /** - * Various user actions. - */ - public function user_action() { - if ( ! current_user_can( 'edit_users' ) ) { - die(); - } - if ( ! isset( $_REQUEST['sub'] ) ) { - die(); - } - if ( ! isset( $_REQUEST['user_id'] ) ) { - die(); - } - - um_fetch_user( absint( $_REQUEST['user_id'] ) ); - - $subaction = sanitize_key( $_REQUEST['sub'] ); - - /** - * UM hook - * - * @type action - * @title um_admin_user_action_hook - * @description Action on bulk user subaction - * @input_vars - * [{"var":"$subaction","type":"string","desc":"Bulk Subaction"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_admin_user_action_hook', 'function_name', 10, 1 ); - * @example - * - */ - do_action( 'um_admin_user_action_hook', $subaction ); - /** - * UM hook - * - * @type action - * @title um_admin_user_action_{$subaction}_hook - * @description Action on bulk user subaction - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_admin_user_action_{$subaction}_hook', 'function_name', 10 ); - * @example - * - */ - do_action( "um_admin_user_action_{$subaction}_hook" ); - - um_reset_user(); - - wp_safe_redirect( add_query_arg( 'update', 'um_user_updated', admin_url( '?page=ultimatemember' ) ) ); - exit; - } - /** * Manual check templates versions. */ @@ -1946,7 +1884,6 @@ if ( ! class_exists( 'um\admin\Admin' ) ) { $action = sanitize_key( $_REQUEST['um_adm_action'] ); $individual_nonce_actions = array( - 'user_action', 'duplicate_form', ); $individual_nonce_actions = apply_filters( 'um_adm_action_individual_nonce_actions', $individual_nonce_actions ); @@ -2071,6 +2008,18 @@ if ( ! class_exists( 'um\admin\Admin' ) ) { return $parent_file; } + /** + * @since 2.8.7 + * + * @return Actions_Listener + */ + public function actions_listener() { + if ( empty( UM()->classes['um\admin\actions_listener'] ) ) { + UM()->classes['um\admin\actions_listener'] = new Actions_Listener(); + } + return UM()->classes['um\admin\actions_listener']; + } + /** * @since 2.7.0 * @@ -2130,5 +2079,17 @@ if ( ! class_exists( 'um\admin\Admin' ) ) { } return UM()->classes['um\admin\site_health']; } + + /** + * @since 2.8.7 + * + * @return Users_Columns + */ + public function users_columns() { + if ( empty( UM()->classes['um\admin\users_columns'] ) ) { + UM()->classes['um\admin\users_columns'] = new Users_Columns(); + } + return UM()->classes['um\admin\users_columns']; + } } } diff --git a/includes/admin/class-secure.php b/includes/admin/class-secure.php index 30bb4ff2..772891ec 100644 --- a/includes/admin/class-secure.php +++ b/includes/admin/class-secure.php @@ -150,7 +150,8 @@ if ( ! class_exists( 'um\admin\Secure' ) ) { } // Restore Account Status. if ( isset( $metadata['account_status'] ) ) { - UM()->user()->set_status( $metadata['account_status'] ); + // UM()->user()->set_status( $metadata['account_status'] ); + UM()->common()->users()->set_status( $user_id, $metadata['account_status'] ); } // Delete blocked meta. diff --git a/includes/admin/class-users-columns.php b/includes/admin/class-users-columns.php new file mode 100644 index 00000000..76989262 --- /dev/null +++ b/includes/admin/class-users-columns.php @@ -0,0 +1,633 @@ +common()->users()->get_status( $user_id, 'formatted' ); + + $status = apply_filters( 'um_users_column_account_status', $status, $user_id ); + + $value = '' . esc_html( $status ) . ''; + + if ( get_current_user_id() === $user_id ) { + return $value; + } + + $row_actions = array(); + if ( UM()->common()->users()->can_be_approved( $user_id ) ) { + $url = add_query_arg( + array( + 'um_adm_action' => 'approve_user', + 'uid' => $user_id, + '_wpnonce' => wp_create_nonce( 'approve_user' . $user_id ), + ), + admin_url( 'users.php' ) + ); + $row_actions[] = '' . esc_html__( 'Approve', 'ultimate-member' ) . ''; + } + if ( UM()->common()->users()->can_be_reactivated( $user_id ) ) { + $url = add_query_arg( + array( + 'um_adm_action' => 'reactivate_user', + 'uid' => $user_id, + '_wpnonce' => wp_create_nonce( 'reactivate_user' . $user_id ), + ), + admin_url( 'users.php' ) + ); + $row_actions[] = '' . esc_html__( 'Reactivate', 'ultimate-member' ) . ''; + } + if ( UM()->common()->users()->can_be_set_as_pending( $user_id ) ) { + $url = add_query_arg( + array( + 'um_adm_action' => 'put_user_as_pending', + 'uid' => $user_id, + '_wpnonce' => wp_create_nonce( 'put_user_as_pending' . $user_id ), + ), + admin_url( 'users.php' ) + ); + $row_actions[] = '' . esc_html__( 'Put as pending', 'ultimate-member' ) . ''; + } + if ( UM()->common()->users()->can_activation_send( $user_id ) ) { + $url = add_query_arg( + array( + 'um_adm_action' => 'resend_user_activation', + 'uid' => $user_id, + '_wpnonce' => wp_create_nonce( 'resend_user_activation' . $user_id ), + ), + admin_url( 'users.php' ) + ); + $row_actions[] = '' . esc_html__( 'Resend activation email', 'ultimate-member' ) . ''; + } + if ( UM()->common()->users()->can_be_rejected( $user_id ) ) { + $url = add_query_arg( + array( + 'um_adm_action' => 'reject_user', + 'uid' => $user_id, + '_wpnonce' => wp_create_nonce( 'reject_user' . $user_id ), + ), + admin_url( 'users.php' ) + ); + $row_actions[] = '' . esc_html__( 'Reject', 'ultimate-member' ) . ''; + } + if ( UM()->common()->users()->can_be_deactivated( $user_id ) ) { + $url = add_query_arg( + array( + 'um_adm_action' => 'deactivate_user', + 'uid' => $user_id, + '_wpnonce' => wp_create_nonce( 'deactivate_user' . $user_id ), + ), + admin_url( 'users.php' ) + ); + $row_actions[] = '' . esc_html__( 'Deactivate', 'ultimate-member' ) . ''; + } + + $row_actions = apply_filters( 'um_users_column_account_status_row_actions', $row_actions, $user_id ); + if ( ! empty( $row_actions ) ) { + $value .= '
  • ' . implode( '
  • |
  • ', $row_actions ) . '
'; + } + return $value; + } + + /** + * Change default sorting at WP Users list table + * + * @param WP_User_Query $query Current instance of WP_User_Query (passed by reference). + */ + public function sort_by_newest( $query ) { + global $pagenow; + + // phpcs:ignore WordPress.Security.NonceVerification -- situated in WP native query and just checking sorting + if ( 'users.php' === $pagenow && ! isset( $_REQUEST['orderby'] ) && is_admin() ) { + $query->query_vars['order'] = 'desc'; + $query->query_orderby = ' ORDER BY user_registered DESC'; + } + } + + /** + * Hide users who are hidden by role access for not Administrator user + * + * @param array $args Arguments passed to WP_User_Query to retrieve items for the current + * users list table + * + * @return array + */ + public function hide_by_caps( $args ) { + if ( current_user_can( 'manage_options' ) ) { + return $args; + } + + // @todo avoid um_user() function using + // @todo check another restrictions not only the role settings. We need to exclude users per user ID. + $can_view_roles = um_user( 'can_view_roles' ); + if ( ! empty( $can_view_roles ) && um_user( 'can_view_all' ) ) { + $args['role__in'] = $can_view_roles; + } + + return $args; + } + + /** + * Hide role filters with not accessible roles + * + * @param array $views + * @return array + */ + public function restrict_role_links( $views ) { + if ( current_user_can( 'manage_options' ) ) { + return $views; + } + + $can_view_roles = um_user( 'can_view_roles' ); + if ( ! empty( $can_view_roles ) && um_user( 'can_view_all' ) ) { + $wp_roles = wp_roles(); + foreach ( $wp_roles->get_names() as $this_role => $name ) { + if ( ! in_array( $this_role, $can_view_roles, true ) ) { + unset( $views[ $this_role ] ); + } + } + } + + return $views; + } + + /** + * Custom row actions for users page + * + * @param array $actions + * @param WP_User $user_object + * + * @return array + */ + public function user_row_actions( $actions, $user_object ) { + $user_id = $user_object->ID; + + // Link to Ultimate Member Profile. + $actions['frontend_profile'] = '' . esc_html__( 'View profile', 'ultimate-member' ) . ''; + + // The link for open popup with the registration data submitted through Ultimate Member Registration form. + $submitted = get_user_meta( $user_id, 'submitted', true ); + if ( ! empty( $submitted ) ) { + $actions['view_info'] = '' . esc_html__( 'Info', 'ultimate-member' ) . ''; + // For new modal below. + // $actions['view_info'] = '' . esc_html__( 'Info', 'ultimate-member' ) . ''; + } + + // Remove row actions for now Administrator role and who cannot view profiles of row's user. + if ( ! current_user_can( 'manage_options' ) && ! um_can_view_profile( $user_id ) ) { + unset( $actions['frontend_profile'], $actions['view_info'], $actions['view'] ); + } + + /** + * Filters the rows actions for the user in wp-admin > Users List Table screen. + * + * Note: Row actions format is 'key' => 'action_link_html' + * + * @since 1.3.x + * @hook um_admin_user_row_actions + * + * @param {array} $actions User's row actions. + * @param {int} $user_id Row's user ID. + * + * @return {array} User's row actions. + */ + return apply_filters( 'um_admin_user_row_actions', $actions, $user_id ); + } + + /** + * Get the list with the bulk actions. + * + * @return array + */ + private function get_user_bulk_actions() { + $um_actions = array( + 'um_approve_membership' => __( 'Approve Membership', 'ultimate-member' ), + 'um_reject_membership' => __( 'Reject Membership', 'ultimate-member' ), + 'um_put_as_pending' => __( 'Put as Pending Review', 'ultimate-member' ), + 'um_resend_activation' => __( 'Resend Activation E-mail', 'ultimate-member' ), + 'um_deactivate' => __( 'Deactivate', 'ultimate-member' ), + 'um_reactivate' => __( 'Reactivate', 'ultimate-member' ), // um_reenable + ); + /** + * Filters wp-admin > Users List Table bulk actions. + * + * @since 1.3.x + * @since 2.8.7 changed format from `$action_slug => array( 'label' => $action_title )` to `$action_slug => $action_title` + * @hook um_admin_bulk_user_actions_hook + * + * @param {array} $um_actions Users admin actions. + * + * @return {array} Users admin actions. + * + * @example Add `$action_title` to Users List Table bulk actions. + * function um_custom_admin_bulk_user_actions_hook( $um_actions ) { + * $um_actions[ $action_slug ] = $action_title; + * return $um_actions; + * } + * add_filter( 'um_admin_bulk_user_actions_hook', 'um_custom_admin_bulk_user_actions_hook' ); + */ + return apply_filters( 'um_admin_bulk_user_actions_hook', $um_actions ); + } + + /** + * @param array $actions + * + * @return array + */ + public function add_bulk_actions( $actions ) { + $rolename = UM()->roles()->get_priority_user_role( get_current_user_id() ); + $role = get_role( $rolename ); + + if ( null === $role ) { + return $actions; + } + + // Add Ultimate Member bulk actions only when the current user has 'edit_users' capability. + if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { + return $actions; + } + + $actions[ esc_html__( 'Ultimate Member', 'ultimate-member' ) ] = $this->get_user_bulk_actions(); + return $actions; + } + + private function get_statuses_filter_options() { + $statuses = UM()->common()->users()->statuses_list(); + /** + * Filters the user statuses added via Ultimate Member plugin. + * + * Note: Statuses format is 'key' => 'title' + * + * @since 2.8.7 + * @hook um_user_statuses_admin_filter_options + * + * @param {array} $statuses User statuses in Ultimate Member environment. + * + * @return {array} User statuses. + */ + return apply_filters( 'um_user_statuses_admin_filter_options', $statuses ); + } + + /** + * Adds HTML with the filter by the Ultimate Member status. + * + * @param string $which Where the callback's hook fired. + */ + public function add_status_filter( $which ) { + if ( 'top' !== $which ) { + return; + } + + // Set default statuses if not already done. + UM()->setup()->set_default_user_status(); + + $id = 'um_user_status'; + + // need to add there additional nonce field because WordPress native _wpnonce field isn't visible on the users.php screen then custom actions + wp_nonce_field( 'um-bulk-users', '_um_wpnonce', false ); + + $statuses = $this->get_statuses_filter_options(); + ?> +
+ + + +
+ get_user_bulk_actions(); + + if ( ! array_key_exists( $current_action, $um_actions ) ) { + return $sendback; + } + + // need to handle there additional nonce field because WordPress native _wpnonce field isn't visible on the users.php screen then custom actions + check_admin_referer( 'um-bulk-users', '_um_wpnonce' ); + + $rolename = UM()->roles()->get_priority_user_role( get_current_user_id() ); + $role = get_role( $rolename ); + + if ( null === $role ) { + return $sendback; + } + + // Make Ultimate Member bulk actions only when the current user has 'edit_users' capability. + if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { + wp_die( esc_html__( 'You do not have enough permissions to do that.', 'ultimate-member' ) ); + } + + $users = array_map( 'absint', $userids ); + $users = array_diff( $users, array( get_current_user_id() ) ); // cannot make any action related to himself. + + switch ( $current_action ) { + case 'um_approve_membership': + $approved_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->users()->approve( $user_id ); + if ( $res ) { + ++$approved_count; + } + } + + $sendback = add_query_arg( + array( + 'approved_count' => $approved_count, + 'update' => 'um_approved', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + + case 'um_reactivate': + $reactivated_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->users()->reactivate( $user_id ); + if ( $res ) { + ++$reactivated_count; + } + } + + $sendback = add_query_arg( + array( + 'reactivated_count' => $reactivated_count, + 'update' => 'um_reactivated', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + + case 'um_reject_membership': + $rejected_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->users()->reject( $user_id ); + if ( $res ) { + ++$rejected_count; + } + } + + $sendback = add_query_arg( + array( + 'rejected_count' => $rejected_count, + 'update' => 'um_rejected', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + + case 'um_deactivate': + $deactivated_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->users()->deactivate( $user_id ); + if ( $res ) { + ++$deactivated_count; + } + } + + $sendback = add_query_arg( + array( + 'deactivated_count' => $deactivated_count, + 'update' => 'um_deactivate', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + + case 'um_put_as_pending': + $pending_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->users()->set_as_pending( $user_id ); + if ( $res ) { + ++$pending_count; + } + } + + $sendback = add_query_arg( + array( + 'pending_count' => $pending_count, + 'update' => 'um_pending', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + + case 'um_resend_activation': + $email_pending_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->users()->send_activation( $user_id ); + if ( $res ) { + ++$email_pending_count; + } + } + + $sendback = add_query_arg( + array( + 'resend_activation_count' => $email_pending_count, + 'update' => 'um_resend_activation', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + + default: + /** + * Fires when a custom Ultimate Member bulk action for wp-admin > Users list table should be handled. + * + * The redirect link should be modified with success or failure feedback + * from the action to be used to display feedback to the user. + * + * The dynamic portion of the hook name, `$current_action`, refers to the current bulk action. + * Use together with custom actions added via `um_admin_bulk_user_actions_hook` hook. + * + * @param {string} $sendback The redirect URL. + * @param {array} $userids Selected users in bulk action. + * + * @return {string} The redirect URL. + * + * @since 2.8.7 + * @hook um_handle_bulk_actions-users-{$current_action} + * + * @example Handle custom-action and set redirect after it. + * function um_custom_bulk_actions_users( $sendback, $userids ) { + * foreach ( $userids as $user_id ) { + * // make some action here + * } + * return add_query_arg( 'action_counter', 'completed action count', $sendback ); + * } + * add_filter( 'um_handle_bulk_actions-users-custom-action', 'um_custom_bulk_actions_users' ); + */ + $sendback = apply_filters( "um_handle_bulk_actions-users-{$current_action}", $sendback, $userids ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores + break; + } + + return $sendback; + } + + /** + * Filter WP users by UM Status + * + * WP_User_Query $query Current instance of WP_User_Query (passed by reference). + */ + public function filter_users_by_status( $query ) { + global $wpdb, $pagenow; + + if ( 'users.php' !== $pagenow || ! is_admin() ) { + return; + } + + if ( empty( $_REQUEST['um_user_status'] ) ) { + return; + } + + $status = sanitize_key( $_REQUEST['um_user_status'] ); + + /** + * Filters the marker to disable Ultimate Member default filter by user status. + * + * @since 2.8.7 + * @hook um_skip_filter_users_by_status + * + * @param {bool} $skip Marker to skip Ultimate Member core user filter handler. + * @param {string} $status User Status + * + * @return {array} User's row actions. + */ + $skip_status_filter = apply_filters( 'um_skip_filter_users_by_status', false, $status ); + if ( false !== $skip_status_filter ) { + return; + } + + $query->query_where = str_replace( + 'WHERE 1=1', + $wpdb->prepare( + "WHERE 1=1 AND + {$wpdb->users}.ID IN ( + SELECT {$wpdb->usermeta}.user_id + FROM $wpdb->usermeta + WHERE {$wpdb->usermeta}.meta_key = 'account_status' AND + {$wpdb->usermeta}.meta_value = %s + )", + $status + ), + $query->query_where + ); + } + + /** + * Sets redirect URI after bulk action + * + * @param string $uri + * @return string + */ + public function set_redirect_uri( $uri ) { + if ( ! empty( $_REQUEST['s'] ) ) { + $uri = add_query_arg( 's', sanitize_text_field( $_REQUEST['s'] ), $uri ); + } + + if ( ! empty( $_REQUEST['um_user_status'] ) ) { + $uri = add_query_arg( 'um_user_status', sanitize_key( $_REQUEST['um_user_status'] ), $uri ); + } + + return $uri; + } + + /** + * Add query args to list of query variable names to remove. + * + * @param array $removable_query_args An array of query variable names to remove from a URL + * + * @return array + */ + public function add_removable_query_args( $removable_query_args ) { + $removable_query_args[] = '_um_wpnonce'; // need to add there additional nonce field because WordPress native _wpnonce field isn't visible on the users.php screen then custom actions + $removable_query_args[] = 'approved_count'; + $removable_query_args[] = 'rejected_count'; + $removable_query_args[] = 'reactivated_count'; + $removable_query_args[] = 'deactivated_count'; + $removable_query_args[] = 'pending_count'; + $removable_query_args[] = 'resend_activation_count'; + return $removable_query_args; + } + } +} diff --git a/includes/admin/core/class-admin-ajax-hooks.php b/includes/admin/core/class-admin-ajax-hooks.php index 23e27f06..2342a2cd 100644 --- a/includes/admin/core/class-admin-ajax-hooks.php +++ b/includes/admin/core/class-admin-ajax-hooks.php @@ -30,8 +30,6 @@ if ( ! class_exists( 'um\admin\core\Admin_Ajax_Hooks' ) ) { add_action( 'wp_ajax_um_member_directory_default_filter_settings', array( UM()->member_directory(), 'default_filter_settings' ) ); add_action( 'wp_ajax_um_same_page_update', array( UM()->admin_settings(), 'same_page_update_ajax' ) ); - - add_action( 'wp_ajax_um_get_users', array( UM()->users(), 'get_users' ) ); } } diff --git a/includes/admin/core/class-admin-columns.php b/includes/admin/core/class-admin-columns.php index 9baa4527..2b689bec 100644 --- a/includes/admin/core/class-admin-columns.php +++ b/includes/admin/core/class-admin-columns.php @@ -33,42 +33,6 @@ if ( ! class_exists( 'um\admin\core\Admin_Columns' ) ) { add_filter( 'display_post_states', array( &$this, 'add_display_post_states' ), 10, 2 ); add_filter( 'post_row_actions', array( &$this, 'remove_bulk_actions_um_form_inline' ), 10, 2 ); - - add_filter( 'manage_users_columns', array( &$this, 'manage_users_columns' ) ); - - add_filter( 'manage_users_custom_column', array( &$this, 'manage_users_custom_column' ), 10, 3 ); - } - - /** - * Filter: Add column 'Status' - * - * @param array $columns - * - * @return array - */ - public function manage_users_columns( $columns ) { - $columns['account_status'] = __( 'Status', 'ultimate-member' ); - return $columns; - } - - - /** - * Filter: Show column 'Status' - * - * @param string $val - * @param string $column_name - * @param int $user_id - * - * @return string - */ - public function manage_users_custom_column( $val, $column_name, $user_id ) { - if ( $column_name == 'account_status' ) { - um_fetch_user( $user_id ); - $value = um_user( 'account_status_name' ); - um_reset_user(); - return $value; - } - return $val; } /** diff --git a/includes/admin/core/class-admin-notices.php b/includes/admin/core/class-admin-notices.php index 8ea72173..94641895 100644 --- a/includes/admin/core/class-admin-notices.php +++ b/includes/admin/core/class-admin-notices.php @@ -490,9 +490,6 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) { case 'um_settings_updated': $messages[0]['content'] = __( 'Settings have been saved successfully.', 'ultimate-member' ); break; - case 'um_user_updated': - $messages[0]['content'] = __( 'User has been updated.', 'ultimate-member' ); - break; case 'um_users_updated': $messages[0]['content'] = __( 'Users have been updated.', 'ultimate-member' ); break; @@ -502,6 +499,36 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) { case 'um_secure_restore': $messages[0]['content'] = __( 'Account has been successfully restored.', 'ultimate-member' ); break; + case 'um_approved': + $approved_count = isset( $_REQUEST['approved_count'] ) ? absint( $_REQUEST['approved_count'] ) : 0; + + $messages[0]['content'] = sprintf( _n( '%s user has been approved.', '%s users have been approved.', $approved_count, 'ultimate-member' ), $approved_count ); + break; + case 'um_reactivated': + $reactivated_count = isset( $_REQUEST['reactivated_count'] ) ? absint( $_REQUEST['reactivated_count'] ) : 0; + + $messages[0]['content'] = sprintf( _n( '%s user has been reactivated.', '%s users have been reactivated.', $reactivated_count, 'ultimate-member' ), $reactivated_count ); + break; + case 'um_rejected': + $rejected_count = isset( $_REQUEST['rejected_count'] ) ? absint( $_REQUEST['rejected_count'] ) : 0; + + $messages[0]['content'] = sprintf( _n( '%s user has been rejected.', '%s users have been rejected.', $rejected_count, 'ultimate-member' ), $rejected_count ); + break; + case 'um_deactivate': + $deactivated_count = isset( $_REQUEST['deactivated_count'] ) ? absint( $_REQUEST['deactivated_count'] ) : 0; + + $messages[0]['content'] = sprintf( _n( '%s user has been deactivated.', '%s users have been deactivated.', $deactivated_count, 'ultimate-member' ), $deactivated_count ); + break; + case 'um_pending': + $pending_count = isset( $_REQUEST['pending_count'] ) ? absint( $_REQUEST['pending_count'] ) : 0; + + $messages[0]['content'] = sprintf( _n( '%s user has been set as pending admin review.', '%s users have been set as pending admin review.', $pending_count, 'ultimate-member' ), $pending_count ); + break; + case 'um_resend_activation': + $resend_activation_count = isset( $_REQUEST['resend_activation_count'] ) ? absint( $_REQUEST['resend_activation_count'] ) : 0; + + $messages[0]['content'] = sprintf( _n( 'Activation email for %s user has been sent.', 'Activation emails for %s users have been sent.', $resend_activation_count, 'ultimate-member' ), $resend_activation_count ); + break; default: /** * Filters the custom admin notice after um_adm_action. diff --git a/includes/admin/core/class-admin-users.php b/includes/admin/core/class-admin-users.php deleted file mode 100644 index 6db6d889..00000000 --- a/includes/admin/core/class-admin-users.php +++ /dev/null @@ -1,576 +0,0 @@ -admin()->check_ajax_nonce(); - - $search_request = ! empty( $_REQUEST['search'] ) ? sanitize_text_field( $_REQUEST['search'] ) : ''; - $page = ! empty( $_REQUEST['page'] ) ? absint( $_REQUEST['page'] ) : 1; - $per_page = 20; - - $args = array( - 'fields' => array( 'ID', 'user_login' ), - 'paged' => $page, - 'number' => $per_page, - ); - - if ( ! empty( $search_request ) ) { - $args['search'] = '*' . $search_request . '*'; - } - - $args = apply_filters( 'um_get_users_list_ajax_args', $args ); - - $users_query = new \WP_User_Query( $args ); - $users = $users_query->get_results(); - $total_count = $users_query->get_total(); - - if ( ! empty( $_REQUEST['avatar'] ) ) { - foreach ( $users as $key => $user ) { - $url = get_avatar_url( $user->ID ); - $users[ $key ]->img = $url; - } - } - - wp_send_json_success( - array( - 'users' => $users, - 'total_count' => $total_count, - ) - ); - } - - /** - * Restrict the edit/delete users via wp-admin screen by the UM role capabilities - * - * @param $allcaps - * @param $cap - * @param $args - * @param $user - * - * @return mixed - */ - public function map_caps_by_role( $allcaps, $cap, $args, $user ) { - if ( isset( $cap[0] ) && $cap[0] == 'edit_users' ) { - if ( isset( $args[0] ) && isset( $args[1] ) && ! user_can( $args[1], 'administrator' ) && $args[0] == 'edit_user' ) { - if ( isset( $args[2] ) && ! UM()->roles()->um_current_user_can( 'edit', $args[2] ) ) { - $allcaps[ $cap[0] ] = false; - } - } - } elseif ( isset( $cap[0] ) && $cap[0] == 'delete_users' ) { - if ( isset( $args[0] ) && isset( $args[1] ) && ! user_can( $args[1], 'administrator' ) && $args[0] == 'delete_user' ) { - if ( isset( $args[2] ) && ! UM()->roles()->um_current_user_can( 'delete', $args[2] ) ) { - $allcaps[ $cap[0] ] = false; - } - } - } elseif ( isset( $cap[0] ) && $cap[0] == 'list_users' ) { - if ( isset( $args[0] ) && isset( $args[1] ) && ! user_can( $args[1], 'administrator' ) && $args[0] == 'list_users' ) { - if ( ! um_user( 'can_view_all' ) ) { - $allcaps[ $cap[0] ] = false; - } - } - } - - return $allcaps; - } - - /** - * Does an action to user asap - * - * @param string $action - */ - public function user_action_hook( $action ) { - switch ( $action ) { - default: - /** - * UM hook - * - * @type action - * @title um_admin_custom_hook_{$action} - * @description Integration hook on user action - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_admin_custom_hook_{$action}', 'function_name', 10, 1 ); - * @example - * - */ - do_action( "um_admin_custom_hook_{$action}", UM()->user()->id ); - break; - - case 'um_put_as_pending': - UM()->user()->pending(); - break; - - case 'um_approve_membership': - case 'um_reenable': - add_filter( 'um_template_tags_patterns_hook', array( UM()->password(), 'add_placeholder' ), 10, 1 ); - add_filter( 'um_template_tags_replaces_hook', array( UM()->password(), 'add_replace_placeholder' ), 10, 1 ); - - UM()->user()->approve(); - break; - - case 'um_reject_membership': - UM()->user()->reject(); - break; - - case 'um_resend_activation': - add_filter( 'um_template_tags_patterns_hook', array( UM()->user(), 'add_activation_placeholder' ), 10, 1 ); - add_filter( 'um_template_tags_replaces_hook', array( UM()->user(), 'add_activation_replace_placeholder' ), 10, 1 ); - - UM()->user()->email_pending(); - break; - - case 'um_deactivate': - UM()->user()->deactivate(); - break; - - case 'um_delete': - if ( is_admin() ) { - wp_die( esc_html__( 'This action is not allowed in backend.', 'ultimate-member' ) ); - } - UM()->user()->delete(); - break; - } - } - - /** - * Add UM Bulk actions to Users List Table - * - */ - public function restrict_manage_users() { - ?> -
- - - - - - - -
- - - - 'My Custom Bulk Action' - * ); - * return $actions; - * } - * ?> - */ - $actions = apply_filters( 'um_admin_bulk_user_actions_hook', array( - 'um_approve_membership' => array( - 'label' => __( 'Approve Membership', 'ultimate-member' ) - ), - 'um_reject_membership' => array( - 'label' => __( 'Reject Membership', 'ultimate-member' ) - ), - 'um_put_as_pending' => array( - 'label' => __( 'Put as Pending Review', 'ultimate-member' ) - ), - 'um_resend_activation' => array( - 'label' => __( 'Resend Activation Email', 'ultimate-member' ) - ), - 'um_deactivate' => array( - 'label' => __( 'Deactivate', 'ultimate-member' ) - ), - 'um_reenable' => array( - 'label' => __( 'Reactivate', 'ultimate-member' ) - ) - ) ); - - $output = ''; - foreach ( $actions as $id => $action_data ) { - $output .= ''; - } - return $output; - } - - /** - * Custom row actions for users page - * - * @param array $actions - * @param $user_object \WP_User - * @return array - */ - public function user_row_actions( $actions, $user_object ) { - $user_id = $user_object->ID; - - $actions['frontend_profile'] = '' . __( 'View profile', 'ultimate-member' ) . ''; - - $submitted = get_user_meta( $user_id, 'submitted', true ); - if ( ! empty( $submitted ) ) { - $actions['view_info'] = '' . __( 'Info', 'ultimate-member' ) . ''; - } - - if ( ! current_user_can( 'administrator' ) ) { - if ( ! um_can_view_profile( $user_id ) ) { - unset( $actions['frontend_profile'] ); - unset( $actions['view_info'] ); - unset( $actions['view'] ); - } - } - - /** - * UM hook - * - * @type filter - * @title um_admin_user_row_actions - * @description Admin views array - * @input_vars - * [{"var":"$actions","type":"array","desc":"User List Table actions"}, - * {"var":"$user_id","type":"int","desc":"User ID"}] - * @change_log - * ["Since: 2.0"] - * @usage add_filter( 'um_admin_user_row_actions', 'function_name', 10, 2 ); - * @example - * - */ - $actions = apply_filters( 'um_admin_user_row_actions', $actions, $user_id ); - - return $actions; - } - - /** - * Change default sorting at WP Users list table - * - * @param array $args - * @return array - */ - public function hide_by_caps( $args ) { - if ( ! current_user_can( 'administrator' ) ) { - $can_view_roles = um_user( 'can_view_roles' ); - if ( um_user( 'can_view_all' ) && ! empty( $can_view_roles ) ) { - $args['role__in'] = $can_view_roles; - } - } - - return $args; - } - - /** - * Change default sorting at WP Users list table - * - * @param $query - * @return mixed - */ - public function sort_by_newest( $query ) { - global $pagenow; - - if ( is_admin() && 'users.php' === $pagenow ) { - if ( ! isset( $_REQUEST['orderby'] ) ) { - $query->query_vars['order'] = 'desc'; - $query->query_orderby = ' ORDER BY user_registered ' . ( 'desc' === $query->query_vars['order'] ? 'desc ' : 'asc ' ); //set sort order - } - } - - return $query; - } - - /** - * Filter WP users by UM Status - * - * @param $query - * @return mixed - */ - public function filter_users_by_status( $query ) { - global $wpdb, $pagenow; - if ( is_admin() && 'users.php' === $pagenow && ! empty( $_REQUEST['um_status'] ) ) { - - $status = sanitize_key( $_REQUEST['um_status'] ); - - if ( 'needs-verification' === $status ) { - $query->query_where = str_replace('WHERE 1=1', - "WHERE 1=1 AND {$wpdb->users}.ID IN ( - SELECT {$wpdb->usermeta}.user_id FROM $wpdb->usermeta - WHERE {$wpdb->usermeta}.meta_key = '_um_verified' - AND {$wpdb->usermeta}.meta_value = 'pending')", - $query->query_where - ); - } else { - $query->query_where = str_replace('WHERE 1=1', - "WHERE 1=1 AND {$wpdb->users}.ID IN ( - SELECT {$wpdb->usermeta}.user_id FROM $wpdb->usermeta - WHERE {$wpdb->usermeta}.meta_key = 'account_status' - AND {$wpdb->usermeta}.meta_value = '{$status}')", - $query->query_where - ); - } - } - - return $query; - } - - /** - * Add status links to WP Users List Table - * - * @param $views - * @return array - */ - public function add_status_links( $views ) { - remove_filter( 'pre_user_query', array( &$this, 'filter_users_by_status' ) ); - - $old_views = $views; - $views = array(); - - if ( ! isset( $_REQUEST['role'] ) && ! isset( $_REQUEST['um_status'] ) ) { - $views['all'] = '' . __( 'All', 'ultimate-member' ) . ' (' . UM()->query()->count_users() . ')'; - } else { - $views['all'] = '' . __( 'All', 'ultimate-member' ) . ' (' . UM()->query()->count_users() . ')'; - } - - $status = array( - 'approved' => __( 'Approved', 'ultimate-member' ), - 'awaiting_admin_review' => __( 'Pending review', 'ultimate-member' ), - 'awaiting_email_confirmation' => __( 'Waiting email confirmation', 'ultimate-member' ), - 'inactive' => __( 'Inactive', 'ultimate-member' ), - 'rejected' => __( 'Rejected', 'ultimate-member' ), - ); - - // set default statuses if not already done - UM()->setup()->set_default_user_status(); - - foreach ( $status as $k => $v ) { - if ( isset( $_REQUEST['um_status'] ) && sanitize_key( $_REQUEST['um_status'] ) === $k ) { - $current = 'class="current"'; - } else { - $current = ''; - } - - $views[ $k ] = '' . $v . ' (' . UM()->query()->count_users_by_status( $k ) . ')'; - } - - /** - * UM hook - * - * @type filter - * @title um_admin_views_users - * @description Admin views array - * @input_vars - * [{"var":"$views","type":"array","desc":"User Views"}] - * @change_log - * ["Since: 2.0"] - * @usage add_filter( 'um_admin_views_users', 'function_name', 10, 1 ); - * @example - * - */ - $views = apply_filters( 'um_admin_views_users', $views ); - - // remove all filters - unset( $old_views['all'] ); - - // add separator - $views['subsep'] = ''; - - // merge views - foreach ( $old_views as $key => $view ) { - $views[ $key ] = $view; - } - - // hide filters with not accessible roles - if ( ! current_user_can( 'administrator' ) ) { - $wp_roles = wp_roles(); - $can_view_roles = um_user( 'can_view_roles' ); - if ( ! empty( $can_view_roles ) ) { - foreach ( $wp_roles->get_names() as $this_role => $name ) { - if ( ! in_array( $this_role, $can_view_roles, true ) ) { - unset( $views[ $this_role ] ); - } - } - } - } - - return $views; - } - - /** - * Bulk user editing actions - */ - public function um_bulk_users_edit() { - // bulk edit users - if ( ! empty( $_REQUEST['users'] ) && ! empty( $_REQUEST['um_bulkedit'] ) && ! empty( $_REQUEST['um_bulk_action'] ) ) { - - $rolename = UM()->roles()->get_priority_user_role( get_current_user_id() ); - $role = get_role( $rolename ); - - if ( empty( $role ) ) { - wp_die( esc_html__( 'You do not have enough permissions to do that.', 'ultimate-member' ) ); - } - - if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { - wp_die( esc_html__( 'You do not have enough permissions to do that.', 'ultimate-member' ) ); - } - - check_admin_referer( 'bulk-users' ); - - $users = array_map( 'absint', (array) $_REQUEST['users'] ); - $bulk_action = current( array_filter( $_REQUEST['um_bulk_action'] ) ); - - foreach ( $users as $user_id ) { - UM()->user()->set( $user_id ); - - /** - * UM hook - * - * @type action - * @title um_admin_user_action_hook - * @description Action on bulk user action - * @input_vars - * [{"var":"$bulk_action","type":"string","desc":"Bulk Action"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_admin_user_action_hook{$action}', 'function_name', 10, 1 ); - * @example - * - */ - do_action( 'um_admin_user_action_hook', $bulk_action ); - - /** - * UM hook - * - * @type action - * @title um_admin_user_action_{$bulk_action}_hook - * @description Action on bulk user action - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_admin_user_action_{$bulk_action}_hook', 'function_name', 10 ); - * @example - * - */ - do_action( "um_admin_user_action_{$bulk_action}_hook" ); - } - - $uri = $this->set_redirect_uri( admin_url( 'users.php' ) ); - $uri = add_query_arg( 'update', 'um_users_updated', $uri ); - - wp_safe_redirect( $uri ); - exit; - } - - if ( ! empty( $_REQUEST['um_bulkedit'] ) ) { - $uri = $this->set_redirect_uri( admin_url( 'users.php' ) ); - wp_safe_redirect( $uri ); - exit; - } - } - - /** - * Sets redirect URI after bulk action - * - * @param string $uri - * @return string - */ - public function set_redirect_uri( $uri ) { - - if ( ! empty( $_REQUEST['s'] ) ) { - $uri = add_query_arg( 's', sanitize_text_field( $_REQUEST['s'] ), $uri ); - } - - if ( ! empty( $_REQUEST['um_status'] ) ) { - $uri = add_query_arg( 'um_status', sanitize_key( $_REQUEST['um_status'] ), $uri ); - } - - return $uri; - - } - } -} diff --git a/includes/ajax/class-init.php b/includes/ajax/class-init.php index 50645233..eeb2e7fc 100644 --- a/includes/ajax/class-init.php +++ b/includes/ajax/class-init.php @@ -23,6 +23,7 @@ if ( ! class_exists( 'um\ajax\Init' ) ) { $this->forms(); $this->pages(); $this->secure(); + $this->users(); } /** @@ -60,5 +61,17 @@ if ( ! class_exists( 'um\ajax\Init' ) ) { } return UM()->classes['um\ajax\secure']; } + + /** + * @since 2.8.7 + * + * @return Users + */ + public function users() { + if ( empty( UM()->classes['um\ajax\users'] ) ) { + UM()->classes['um\ajax\users'] = new Users(); + } + return UM()->classes['um\ajax\users']; + } } } diff --git a/includes/ajax/class-users.php b/includes/ajax/class-users.php new file mode 100644 index 00000000..bd44eaa5 --- /dev/null +++ b/includes/ajax/class-users.php @@ -0,0 +1,56 @@ +admin()->check_ajax_nonce(); + + $search_request = ! empty( $_REQUEST['search'] ) ? sanitize_text_field( $_REQUEST['search'] ) : ''; + $page = ! empty( $_REQUEST['page'] ) ? absint( $_REQUEST['page'] ) : 1; + $per_page = 20; + + $args = array( + 'fields' => array( 'ID', 'user_login' ), + 'paged' => $page, + 'number' => $per_page, + ); + + if ( ! empty( $search_request ) ) { + $args['search'] = '*' . $search_request . '*'; + } + + $args = apply_filters( 'um_get_users_list_ajax_args', $args ); + + $users_query = new \WP_User_Query( $args ); + $users = $users_query->get_results(); + $total_count = $users_query->get_total(); + + if ( ! empty( $_REQUEST['avatar'] ) ) { + foreach ( $users as $key => $user ) { + $url = get_avatar_url( $user->ID ); + $users[ $key ]->img = $url; + } + } + + wp_send_json_success( + array( + 'users' => $users, + 'total_count' => $total_count, + ) + ); + } +} diff --git a/includes/class-init.php b/includes/class-init.php index efa6cf07..9c8f811b 100644 --- a/includes/class-init.php +++ b/includes/class-init.php @@ -526,7 +526,6 @@ if ( ! class_exists( 'UM' ) ) { $this->admin_settings(); $this->columns(); $this->metabox(); - $this->users(); $this->dragdrop(); $this->admin_gdpr(); $this->admin_navmenu(); @@ -902,20 +901,6 @@ if ( ! class_exists( 'UM' ) ) { return $this->classes['admin_metabox']; } - - /** - * @since 2.0 - * - * @return um\admin\core\Admin_Users() - */ - function users() { - if ( empty( $this->classes['admin_users'] ) ) { - $this->classes['admin_users'] = new um\admin\core\Admin_Users(); - } - return $this->classes['admin_users']; - } - - /** * @since 2.0 * @@ -1466,7 +1451,7 @@ if ( ! class_exists( 'UM' ) ) { require_once 'core/um-actions-form.php'; require_once 'core/um-actions-access.php'; require_once 'core/um-actions-wpadmin.php'; - require_once 'core/um-actions-core.php'; +// require_once 'core/um-actions-core.php'; require_once 'core/um-actions-ajax.php'; require_once 'core/um-actions-login.php'; require_once 'core/um-actions-register.php'; diff --git a/includes/common/class-init.php b/includes/common/class-init.php index 1e9e74cd..41ad1b2a 100644 --- a/includes/common/class-init.php +++ b/includes/common/class-init.php @@ -25,6 +25,7 @@ if ( ! class_exists( 'um\common\Init' ) ) { $this->secure()->hooks(); $this->site_health(); $this->theme()->hooks(); + $this->users()->hooks(); } /** @@ -86,5 +87,17 @@ if ( ! class_exists( 'um\common\Init' ) ) { } return UM()->classes['um\common\theme']; } + + /** + * @since 2.8.7 + * + * @return Users + */ + public function users() { + if ( empty( UM()->classes['um\common\users'] ) ) { + UM()->classes['um\common\users'] = new Users(); + } + return UM()->classes['um\common\users']; + } } } diff --git a/includes/common/class-secure.php b/includes/common/class-secure.php index a0d01571..6fd084fa 100644 --- a/includes/common/class-secure.php +++ b/includes/common/class-secure.php @@ -229,9 +229,11 @@ if ( ! class_exists( 'um\common\Secure' ) ) { $user->update_user_level_from_caps(); if ( is_user_logged_in() ) { - UM()->user()->set_status( 'inactive' ); + //UM()->user()->set_status( 'inactive' ); + UM()->common()->users()->set_status( $user->ID, 'inactive' ); } else { - UM()->user()->set_status( 'rejected' ); + //UM()->user()->set_status( 'rejected' ); + UM()->common()->users()->set_status( $user->ID, 'rejected' ); } um_reset_user(); update_user_meta( $user->ID, 'um_user_blocked', 'suspicious_activity' ); diff --git a/includes/common/class-users.php b/includes/common/class-users.php new file mode 100644 index 00000000..f8a8b512 --- /dev/null +++ b/includes/common/class-users.php @@ -0,0 +1,811 @@ +roles()->um_current_user_can( 'edit', $args[2] ) ) { + $allcaps[ $caps[0] ] = false; + } + } elseif ( 'delete_users' === $caps[0] && 'delete_user' === $args[0] ) { + if ( isset( $args[2] ) && ! UM()->roles()->um_current_user_can( 'delete', $args[2] ) ) { + $allcaps[ $caps[0] ] = false; + } + } elseif ( 'list_users' === $caps[0] ) { + if ( 'list_users' === $args[0] && ! um_user( 'can_view_all' ) ) { + $allcaps[ $caps[0] ] = false; + } + } + + return $allcaps; + } + + /** + * Hide role filters with not accessible roles + * + * @param array $roles + * @return array + */ + public function restrict_roles( $roles ) { + if ( current_user_can( 'manage_options' ) ) { + return $roles; + } + + $can_view_roles = UM()->roles()->um_user_can( 'can_view_roles' ); + if ( UM()->roles()->um_user_can( 'can_view_all' ) && empty( $can_view_roles ) ) { + return $roles; + } + + if ( ! empty( $can_view_roles ) ) { + $wp_roles = wp_roles(); + foreach ( $wp_roles->get_names() as $this_role => $name ) { + if ( ! in_array( $this_role, $can_view_roles, true ) ) { + unset( $roles[ $this_role ] ); + } + } + } + + return $roles; + } + + /** + * Get the user statuses list. + * + * @return array + */ + public function statuses_list() { + $statuses = array( + 'approved' => __( 'Approved', 'ultimate-member' ), + 'awaiting_admin_review' => __( 'Pending administrator review', 'ultimate-member' ), + 'awaiting_email_confirmation' => __( 'Waiting email confirmation', 'ultimate-member' ), + 'inactive' => __( 'Membership inactive', 'ultimate-member' ), + 'rejected' => __( 'Membership rejected', 'ultimate-member' ), + ); + /** + * Filters the user statuses added via Ultimate Member plugin. + * + * Note: Statuses format is 'key' => 'title' + * + * @since 2.8.7 + * @hook um_user_statuses + * + * @param {array} $statuses User statuses in Ultimate Member environment. + * + * @return {array} User statuses. + */ + return apply_filters( 'um_user_statuses', $statuses ); + } + + /** + * Set user's account status. + * + * @param int $user_id User ID. + * @param string $status Status key. + * + * @return bool + */ + public function set_status( $user_id, $status ) { + $old_status = $this->get_status( $user_id ); + + /** + * Fires before User status is set. + * + * @since 2.8.7 + * @hook um_before_user_status_is_set + * + * @param {string} $status New status key. + * @param {int} $user_id User ID. + * @param {string} $old_status Old status key. + */ + do_action( 'um_before_user_status_is_set', $status, $user_id, $old_status ); + + $result = update_user_meta( $user_id, 'account_status', $status ); + + // false on failure or if the value passed to the function is the same as the one that is already in the database. + if ( false !== $result ) { + // backward compatibility. @todo maybe uncomment it after some testing. + // UM()->user()->profile['account_status'] = $status; + + // Reset cache. + $this->remove_cache( $user_id ); + + /** + * Fires just after User status is changed. + * + * @since 1.3.x + * @since 2.0 Added $user_id + * @since 2.8.7 Added $old_status + * + * @hook um_after_user_status_is_changed + * + * @param {string} $status Status key. + * @param {int} $user_id User ID. Since 2.0 + * @param {string} $old_status Old status key. Since 2.8.7 + */ + do_action( 'um_after_user_status_is_changed', $status, $user_id, $old_status ); + + return true; + } + + return false; + } + + /** + * Get user account status. + * + * @param int $user_id User ID + * + * @return string + */ + public function get_status( $user_id, $format = 'raw' ) { + $status = get_user_meta( $user_id, 'account_status', true ); + if ( 'raw' === $format ) { + return $status; + } + + $all_statuses = $this->statuses_list(); + if ( array_key_exists( $status, $all_statuses ) ) { + return $all_statuses[ $status ]; + } + + return __( 'Undefined', 'ultimate-member' ); + } + + /** + * Check if user has selected account status. + * + * @since 2.8.7 + * + * @param int $user_id User ID. + * @param string $status_control Status key. + * + * @return bool + */ + public function has_status( $user_id, $status_control ) { + $status = $this->get_status( $user_id ); + return $status === $status_control; + } + + /** + * Reset User cache + * + * @param int $user_id User ID. + */ + public function remove_cache( $user_id ) { + delete_option( "um_cache_userdata_{$user_id}" ); + } + + /** + * Reset Activation link hash. + * + * @param int $user_id User ID. + */ + public function reset_activation_link( $user_id ) { + delete_user_meta( $user_id, 'account_secret_hash' ); + delete_user_meta( $user_id, 'account_secret_hash_expiry' ); + } + + /** + * Set user's activation link hash + * + * @param int $user_id User ID. + */ + public function assign_secretkey( $user_id ) { + if ( ! $this->has_status( $user_id, 'awaiting_email_confirmation' ) ) { + return; + } + + /** + * Fires before user activation link hash is generated. + * + * @since 1.3.x + * @since 2.8.7 Added $user_id + * @hook um_before_user_hash_is_changed + * + * @param {int} $user_id User ID. Since 2.8.7 + */ + do_action( 'um_before_user_hash_is_changed', $user_id ); + + $hash = UM()->validation()->generate(); + update_user_meta( $user_id, 'account_secret_hash', $hash ); + // backward compatibility. @todo maybe uncomment it after some testing. + // UM()->user()->profile['account_secret_hash'] = $hash; + + $expiration = ''; + $expiry_time = UM()->options()->get( 'activation_link_expiry_time' ); + if ( ! empty( $expiry_time ) && is_numeric( $expiry_time ) ) { + $expiration = time() + $expiry_time * DAY_IN_SECONDS; + update_user_meta( $user_id, 'account_secret_hash_expiry', $expiration ); + // backward compatibility. @todo maybe uncomment it after some testing. + // UM()->user()->profile['account_secret_hash_expiry'] = $expiration; + } + + /** + * Fires after user activation link hash is changed. + * + * @since 1.3.x + * @since 2.8.7 Added $user_id, $hash, $expiration + * @hook um_before_user_hash_is_changed + * + * @param {int} $user_id User ID. Since 2.8.7. + * @param {string} $hash Activation link hash. Since 2.8.7. + * @param {int} $expiration Expiration timestamp. Since 2.8.7. + */ + do_action( 'um_after_user_hash_is_changed', $user_id, $hash, $expiration ); + } + + /** + * @param WP_User $userdata + * + * @return string|WP_Error + */ + public function maybe_generate_password_reset_key( $userdata ) { + return get_password_reset_key( $userdata ); + } + + public function can_current_user_edit_user( $user_id ) { + $current_user_id = get_current_user_id(); + if ( $current_user_id === $user_id ) { + return true; + } + + if ( ! self::user_exists( $user_id ) ) { + return false; + } + + $rolename = UM()->roles()->get_priority_user_role( $current_user_id ); + $role = get_role( $rolename ); + + if ( null === $role ) { + return false; + } + + // Make Ultimate Member bulk actions only when the current user has 'edit_users' capability. + if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { + return false; + } + + return true; + } + + public function can_activation_send( $user_id ) { + $current_user_id = get_current_user_id(); + if ( $current_user_id === $user_id || ! self::user_exists( $user_id ) ) { + return false; + } + +// $rolename = UM()->roles()->get_priority_user_role( $current_user_id ); +// $role = get_role( $rolename ); +// +// if ( null === $role ) { +// return false; +// } +// +// // Make Ultimate Member bulk actions only when the current user has 'edit_users' capability. +// if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { +// return false; +// } + + $status = $this->get_status( $user_id ); + return 'awaiting_admin_review' !== $status; + } + + public function send_activation( $user_id ) { + if ( ! $this->can_activation_send( $user_id ) ) { + return false; + } + + /** + * Fires before User has been set as pending email confirmation. + * + * @since 2.8.7 + * @hook um_before_user_is_set_as_awaiting_email_confirmation + * + * @param {int} $user_id User ID. + */ + do_action( 'um_before_user_is_set_as_awaiting_email_confirmation', $user_id ); + + $result = $this->set_status( $user_id, 'awaiting_email_confirmation' ); + + // It's `false` on failure or if the user already has rejected status. + if ( false !== $result ) { + //clear all sessions for email confirmation pending users + $user = WP_Session_Tokens::get_instance( $user_id ); + $user->destroy_all(); + + // Set activation link hash. + $this->assign_secretkey( $user_id ); + + $userdata = get_userdata( $user_id ); + + add_filter( 'um_template_tags_patterns_hook', array( UM()->user(), 'add_activation_placeholder' ) ); + add_filter( 'um_template_tags_replaces_hook', array( UM()->user(), 'add_activation_replace_placeholder' ) ); + + UM()->mail()->send( $userdata->user_email, 'checkmail_email' ); + + /** + * Fires after User has been set as pending email confirmation. + * + * @since 2.8.7 + * @hook um_after_user_is_set_as_awaiting_email_confirmation + * + * @param {int} $user_id User ID. + */ + do_action( 'um_after_user_is_set_as_awaiting_email_confirmation', $user_id ); + return true; + } + + return false; + } + + /** + * @param $user_id + * + * @return bool + */ + public function can_be_deactivated( $user_id ) { + $current_user_id = get_current_user_id(); + if ( $current_user_id === $user_id || ! self::user_exists( $user_id ) ) { + return false; + } + +// $rolename = UM()->roles()->get_priority_user_role( $current_user_id ); +// $role = get_role( $rolename ); +// +// if ( null === $role ) { +// return false; +// } +// +// // Make Ultimate Member bulk actions only when the current user has 'edit_users' capability. +// if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { +// return false; +// } + + $status = $this->get_status( $user_id ); + if ( 'inactive' === $status ) { + // Break if the user already approved + return false; + } + + if ( 'approved' !== $status ) { + // Break if the user already doesn't approved yet + return false; + } + + return true; + } + + /** + * @param $user_id + * + * @return bool + */ + public function deactivate( $user_id ) { + if ( ! $this->can_be_deactivated( $user_id ) ) { + return false; + } + + /** + * Fires before User has been deactivated. + * + * @since 2.8.7 + * @hook um_before_user_is_deactivated + * + * @param {int} $user_id User ID. + */ + do_action( 'um_before_user_is_deactivated', $user_id ); + + $result = $this->set_status( $user_id, 'inactive' ); + + // It's `false` on failure or if the user already has approved status. + if ( false !== $result ) { + // Clear all sessions for inactive users + $user = WP_Session_Tokens::get_instance( $user_id ); + $user->destroy_all(); + + $userdata = get_userdata( $user_id ); + UM()->mail()->send( $userdata->user_email, 'inactive_email' ); + + /** + * Fires after User has been deactivated. + * + * @since 1.3.x + * @hook um_after_user_is_inactive + * + * @param {int} $user_id User ID. + */ + do_action( 'um_after_user_is_inactive', $user_id ); + return true; + } + + return false; + } + + /** + * @param $user_id + * + * @return bool + */ + public function can_be_rejected( $user_id ) { + $current_user_id = get_current_user_id(); + if ( $current_user_id === $user_id || ! self::user_exists( $user_id ) ) { + return false; + } + +// $rolename = UM()->roles()->get_priority_user_role( $current_user_id ); +// $role = get_role( $rolename ); +// +// if ( null === $role ) { +// return false; +// } +// +// // Make Ultimate Member bulk actions only when the current user has 'edit_users' capability. +// if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { +// return false; +// } + + $status = $this->get_status( $user_id ); + if ( 'rejected' === $status ) { + // Break if the user already rejected + return false; + } + + if ( 'approved' !== $status ) { + // Break if the user already doesn't approved yet + return false; + } + + return true; + } + + /** + * @param $user_id + * + * @return bool + */ + public function reject( $user_id ) { + if ( ! $this->can_be_rejected( $user_id ) ) { + return false; + } + + /** + * Fires before User has been rejected. + * + * @since 2.8.7 + * @hook um_before_user_is_rejected + * + * @param {int} $user_id User ID. + */ + do_action( 'um_before_user_is_rejected', $user_id ); + + $result = $this->set_status( $user_id, 'rejected' ); + + // It's `false` on failure or if the user already has rejected status. + if ( false !== $result ) { + // Clear all sessions for rejected users + $user = WP_Session_Tokens::get_instance( $user_id ); + $user->destroy_all(); + + $userdata = get_userdata( $user_id ); + UM()->mail()->send( $userdata->user_email, 'rejected_email' ); + + /** + * Fires after User has been rejected. + * + * @since 2.8.7 + * @hook um_after_user_is_rejected + * + * @param {int} $user_id User ID. + */ + do_action( 'um_after_user_is_rejected', $user_id ); + return true; + } + + return false; + } + + /** + * @param int $user_id + * + * @return bool + */ + public function can_be_set_as_pending( $user_id ) { + $current_user_id = get_current_user_id(); + if ( $current_user_id === $user_id || ! self::user_exists( $user_id ) ) { + return false; + } + +// $rolename = UM()->roles()->get_priority_user_role( $current_user_id ); +// $role = get_role( $rolename ); +// +// if ( null === $role ) { +// return false; +// } +// +// // Make Ultimate Member bulk actions only when the current user has 'edit_users' capability. +// if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { +// return false; +// } + + $status = $this->get_status( $user_id ); + return 'awaiting_admin_review' !== $status; + } + + /** + * @param int $user_id + * + * @return bool + */ + public function set_as_pending( $user_id ) { + if ( ! $this->can_be_set_as_pending( $user_id ) ) { + return false; + } + + /** + * Fires before User has been set as pending admin review. + * + * @since 2.8.7 + * @hook um_before_user_is_set_as_pending + * + * @param {int} $user_id User ID. + */ + do_action( 'um_before_user_is_set_as_pending', $user_id ); + + $result = $this->set_status( $user_id, 'awaiting_admin_review' ); + + // It's `false` on failure or if the user already has rejected status. + if ( false !== $result ) { + // Clear all sessions for awaiting admin confirmation users + $user = WP_Session_Tokens::get_instance( $user_id ); + $user->destroy_all(); + + $userdata = get_userdata( $user_id ); + UM()->mail()->send( $userdata->user_email, 'pending_email' ); + + /** + * Fires after User has been set as pending admin review. + * + * @since 2.8.7 + * @hook um_after_user_is_set_as_pending + * + * @param {int} $user_id User ID. + */ + do_action( 'um_after_user_is_set_as_pending', $user_id ); + return true; + } + + return false; + } + + /** + * Check if the user can be approved. + * + * @param int $user_id User ID + * + * @return bool + */ + public function can_be_approved( $user_id ) { + $current_user_id = get_current_user_id(); + if ( $current_user_id === $user_id || ! self::user_exists( $user_id ) ) { + return false; + } + +// $rolename = UM()->roles()->get_priority_user_role( $current_user_id ); +// $role = get_role( $rolename ); +// +// if ( null === $role ) { +// return false; +// } +// +// // Make Ultimate Member bulk actions only when the current user has 'edit_users' capability. +// if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { +// return false; +// } + + $status = $this->get_status( $user_id ); + return 'approved' !== $status; + } + + /** + * @param int $user_id + * + * @return bool + */ + public static function user_exists( $user_id ) { + /** + * @var bool[] $search_results + */ + static $search_results = array(); + + if ( array_key_exists( $user_id, $search_results ) ) { + return $search_results[ $user_id ]; + } + + $user = get_userdata( $user_id ); + + $search_results[ $user_id ] = false !== $user; + return $search_results[ $user_id ]; + } + + /** + * Approve user. + * + * @param int $user_id User ID. + * + * @return bool `true` if the user has been approved + * `false` on failure or if the user already has approved status. + */ + public function approve( $user_id ) { + if ( ! $this->can_be_approved( $user_id ) ) { + return false; + } + + /** + * Fires before User has been approved. + * + * @since 2.8.7 + * @hook um_before_user_is_approved + * + * @param {int} $user_id User ID. + */ + do_action( 'um_before_user_is_approved', $user_id ); + + $old_status = $this->get_status( $user_id ); + + $result = $this->set_status( $user_id, 'approved' ); + + // It's `false` on failure or if the user already has approved status. + if ( false !== $result ) { + $userdata = get_userdata( $user_id ); + + $this->reset_activation_link( $user_id ); + + $email_slug = 'welcome_email'; + if ( 'awaiting_admin_review' === $old_status ) { + $email_slug = 'approved_email'; + $this->maybe_generate_password_reset_key( $userdata ); + } + + add_filter( 'um_template_tags_patterns_hook', array( UM()->password(), 'add_placeholder' ) ); + add_filter( 'um_template_tags_replaces_hook', array( UM()->password(), 'add_replace_placeholder' ) ); + + UM()->mail()->send( $userdata->user_email, $email_slug ); + + /** + * Fires after User has been approved. + * + * @since 1.3.x + * @hook um_after_user_is_approved + * + * @param {int} $user_id User ID. + */ + do_action( 'um_after_user_is_approved', $user_id ); + return true; + } + + return false; + } + + /** + * @param int $user_id + * + * @return bool + */ + public function can_be_reactivated( $user_id ) { + $current_user_id = get_current_user_id(); + if ( $current_user_id === $user_id || ! self::user_exists( $user_id ) ) { + return false; + } + +// $rolename = UM()->roles()->get_priority_user_role( $current_user_id ); +// $role = get_role( $rolename ); +// +// if ( null === $role ) { +// return false; +// } +// +// // Make Ultimate Member bulk actions only when the current user has 'edit_users' capability. +// if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { +// return false; +// } + + $status = $this->get_status( $user_id ); + return 'inactive' === $status; + } + + /** + * @param int $user_id + * + * @return bool + */ + public function reactivate( $user_id ) { + if ( ! $this->can_be_reactivated( $user_id ) ) { + return false; + } + + /** + * Fires before User has been reactivated. + * + * @since 2.8.7 + * @hook um_before_user_is_reactivated + * + * @param {int} $user_id User ID. + */ + do_action( 'um_before_user_is_reactivated', $user_id ); + + $result = $this->set_status( $user_id, 'approved' ); + + // It's `false` on failure or if the user already has approved status. + if ( false !== $result ) { + // Reset activation link hash. + $this->reset_activation_link( $user_id ); + + $userdata = get_userdata( $user_id ); + + add_filter( 'um_template_tags_patterns_hook', array( UM()->password(), 'add_placeholder' ) ); + add_filter( 'um_template_tags_replaces_hook', array( UM()->password(), 'add_replace_placeholder' ) ); + + UM()->mail()->send( $userdata->user_email, 'welcome_email' ); + + /** + * Fires after User has been reactivated. + * + * @since 2.8.7 + * @hook um_after_user_is_reactivated + * + * @param {int} $user_id User ID. + */ + do_action( 'um_after_user_is_reactivated', $user_id ); + return true; + } + + return false; + } +} diff --git a/includes/core/class-member-directory.php b/includes/core/class-member-directory.php index d9cdea0e..ea83dffa 100644 --- a/includes/core/class-member-directory.php +++ b/includes/core/class-member-directory.php @@ -2589,21 +2589,18 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) { return $pagination_data; } - /** * @param int $user_id * * @return array */ - function build_user_actions_list( $user_id ) { - + private function build_user_actions_list( $user_id ) { $actions = array(); if ( ! is_user_logged_in() ) { return $actions; } - if ( get_current_user_id() != $user_id ) { - + if ( get_current_user_id() !== $user_id ) { if ( UM()->roles()->um_current_user_can( 'edit', $user_id ) ) { $actions['um-editprofile'] = array( 'title' => esc_html__( 'Edit Profile', 'ultimate-member' ), @@ -2611,31 +2608,17 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) { ); } - /** - * UM hook - * - * @type filter - * @title um_admin_user_actions_hook - * @description Extend admin actions for each user - * @input_vars - * [{"var":"$actions","type":"array","desc":"Actions for user"}] - * @change_log - * ["Since: 2.0"] - * @usage - * - * @example - * - */ - $admin_actions = apply_filters( 'um_admin_user_actions_hook', array(), $user_id ); + $admin_actions = UM()->frontend()->users()->get_actions_list( $user_id ); if ( ! empty( $admin_actions ) ) { foreach ( $admin_actions as $id => $arr ) { - $url = add_query_arg( array( 'um_action' => $id, 'uid' => $user_id ), um_get_core_page( 'user' ) ); + $url = add_query_arg( + array( + 'um_action' => $id, + 'uid' => $user_id, + 'nonce' => wp_create_nonce( $id . $user_id ), + ), + um_user_profile_url( $user_id ) + ); $actions[ $id ] = array( 'title' => esc_html( $arr['label'] ), @@ -2645,9 +2628,7 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) { } $actions = apply_filters( 'um_member_directory_users_card_actions', $actions, $user_id ); - } else { - if ( empty( UM()->user()->cannot_edit ) ) { $actions['um-editprofile'] = array( 'title' => esc_html__( 'Edit Profile', 'ultimate-member' ), @@ -2671,15 +2652,13 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) { return $actions; } - /** * @param int $user_id * @param array $directory_data * * @return array */ - function build_user_card_data( $user_id, $directory_data ) { - + public function build_user_card_data( $user_id, $directory_data ) { um_fetch_user( $user_id ); $dropdown_actions = $this->build_user_actions_list( $user_id ); diff --git a/includes/core/class-permalinks.php b/includes/core/class-permalinks.php index b2714d45..3f04ffac 100644 --- a/includes/core/class-permalinks.php +++ b/includes/core/class-permalinks.php @@ -129,7 +129,7 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) { $set_password_required = get_user_meta( $user_id, 'um_set_password_required', true ); um_fetch_user( $user_id ); - UM()->user()->approve(); + UM()->common()->users()->approve( $user_id ); if ( ! empty( $set_password_required ) ) { $redirect = um_user( 'password_reset_link' ); } diff --git a/includes/core/class-rewrite.php b/includes/core/class-rewrite.php index 13578add..7d238716 100644 --- a/includes/core/class-rewrite.php +++ b/includes/core/class-rewrite.php @@ -234,8 +234,8 @@ if ( ! class_exists( 'um\core\Rewrite' ) ) { $user_id = $this->get_user_id_by_user_login_slug(); } - if ( 'user_id' === $permalink_base ) { - $user_id = UM()->user()->user_exists_by_id( um_queried_user() ); + if ( 'user_id' === $permalink_base && UM()->common()->users()::user_exists( um_queried_user() ) ) { + $user_id = um_queried_user(); } if ( 'hash' === $permalink_base ) { diff --git a/includes/core/class-user.php b/includes/core/class-user.php index 914a82b2..68f53dd9 100644 --- a/includes/core/class-user.php +++ b/includes/core/class-user.php @@ -130,7 +130,6 @@ if ( ! class_exists( 'um\core\User' ) ) { add_action( 'personal_options_update', array( &$this, 'remove_cache' ) ); //add_action('edit_user_profile_update', array(&$this, 'remove_cache') ); add_action( 'um_when_role_is_set', array( &$this, 'remove_cache' ) ); - add_action( 'um_when_status_is_set', array( &$this, 'remove_cache' ) ); add_action( 'show_user_profile', array( $this, 'profile_form_additional_section' ), 10 ); add_action( 'user_new_form', array( $this, 'profile_form_additional_section' ), 10 ); @@ -1504,134 +1503,23 @@ if ( ! class_exists( 'um\core\User' ) ) { /** * Set user's account status * - * @param $status + * @deprecated 2.8.7 + * + * @param string $status */ - function set_status( $status ) { - - /** - * UM hook - * - * @type action - * @title um_when_status_is_set - * @description Action on user status changed - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_when_status_is_set', 'function_name', 10, 1 ); - * @example - * - */ - do_action( 'um_when_status_is_set', um_user( 'ID' ) ); - - $this->profile['account_status'] = $status; - - $this->update_usermeta_info( 'account_status' ); - - /** - * UM hook - * - * @type action - * @title um_after_user_status_is_changed_hook - * @description Action after user status changed - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_after_user_status_is_changed_hook', 'function_name', 10 ); - * @example - * - */ - do_action( 'um_after_user_status_is_changed_hook', um_user( 'ID' ) ); - - /** - * UM hook - * - * @type action - * @title um_after_user_status_is_changed - * @description Action after user status changed - * @input_vars - * [{"var":"$status","type":"string","desc":"User Status"}, - * {"var":"$user_id","type":"integer","desc":"User ID"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_after_user_status_is_changed', 'function_name', 10, 1 ); - * @example - * - */ - do_action( 'um_after_user_status_is_changed', $status, um_user( 'ID' ) ); - + public function set_status( $status ) { + _deprecated_function( __METHOD__, '2.8.7', 'UM()->common()->users()->set_status()' ); + UM()->common()->users()->set_status( $status, um_user( 'ID' ) ); } - /** * Set user's hash */ - function assign_secretkey() { - /** - * UM hook - * - * @type action - * @title um_before_user_hash_is_changed - * @description Action before user hash is changed - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_before_user_hash_is_changed', 'function_name', 10 ); - * @example - * - */ - do_action( 'um_before_user_hash_is_changed' ); - - $this->profile['account_secret_hash'] = UM()->validation()->generate(); - $this->update_usermeta_info( 'account_secret_hash' ); - - $expiry_time = UM()->options()->get( 'activation_link_expiry_time' ); - if ( ! empty( $expiry_time ) && is_numeric( $expiry_time ) ) { - $this->profile['account_secret_hash_expiry'] = time() + $expiry_time * DAY_IN_SECONDS; - $this->update_usermeta_info( 'account_secret_hash_expiry' ); - } - - /** - * UM hook - * - * @type action - * @title um_after_user_hash_is_changed - * @description Action after user hash is changed - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_after_user_hash_is_changed', 'function_name', 10 ); - * @example - * - */ - do_action( 'um_after_user_hash_is_changed' ); + public function assign_secretkey() { + _deprecated_function( __METHOD__, '2.8.7', 'UM()->common()->users()->assign_secretkey()' ); + UM()->common()->users()->assign_secretkey( um_user( 'ID' ) ); } - /** * @param \WP_User $userdata * @@ -1677,186 +1565,53 @@ if ( ! class_exists( 'um\core\User' ) ) { /** * This method approves a user membership and sends them an optional welcome/approval email. - * - * @usage user()->approve(); ?> - * - * @example Approve a pending user and allow him to sign-in to your site. - - user()->approve(); - - ?> - * + * @param bool $repeat @deprecated + * @deprecated 2.8.7 */ - public function approve( $repeat = true ) { - $user_id = um_user( 'ID' ); - - if ( ! $repeat ) { - $status = get_user_meta( $user_id, 'account_status', true ); - if ( 'approved' === $status ) { - return; - } - } - - delete_option( "um_cache_userdata_{$user_id}" ); - - if ( 'awaiting_admin_review' === um_user( 'account_status' ) ) { - $userdata = get_userdata( $user_id ); - - $this->maybe_generate_password_reset_key( $userdata ); - - UM()->mail()->send( um_user( 'user_email' ), 'approved_email' ); - - } else { - //$userdata = get_userdata( $user_id ); - //get_password_reset_key( $userdata ); - UM()->mail()->send( um_user( 'user_email' ), 'welcome_email' ); - } - - $this->set_status( 'approved' ); - $this->delete_meta( 'account_secret_hash' ); - $this->delete_meta( 'account_secret_hash_expiry' ); - - /** - * UM hook - * - * @type action - * @title um_after_user_is_approved - * @description Action after user was approved - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_after_user_is_approved', 'function_name', 10, 1 ); - * @example - * - */ - do_action( 'um_after_user_is_approved', um_user( 'ID' ) ); + public function approve( $repeat = true ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- deprecated function + _deprecated_function( __METHOD__, '2.8.7', 'UM()->common()->users()->approve()' ); + UM()->common()->users()->approve( um_user( 'ID' ) ); } - /** * Pending email + * @deprecated 2.8.7 */ - function email_pending() { - $this->assign_secretkey(); - $this->set_status( 'awaiting_email_confirmation' ); - - //clear all sessions for email confirmation pending users - $user = \WP_Session_Tokens::get_instance( um_user( 'ID' ) ); - $user->destroy_all(); - - UM()->mail()->send( um_user( 'user_email' ), 'checkmail_email' ); + public function email_pending() { + _deprecated_function( __METHOD__, '2.8.7', 'UM()->common()->users()->send_activation()' ); + UM()->common()->users()->send_activation( um_user( 'ID' ) ); } - /** * This method puts a user under manual review by administrator and sends them an optional email. - * - * @usage user()->pending(); ?> - * - * @example An example of putting a user pending manual review - - user()->pending(); - - ?> - * + * @deprecated 2.8.7 + * @return void */ - function pending() { - $this->set_status( 'awaiting_admin_review' ); - - //clear all sessions for awaiting admin confirmation users - $user = \WP_Session_Tokens::get_instance( um_user( 'ID' ) ); - $user->destroy_all(); - - UM()->mail()->send( um_user( 'user_email' ), 'pending_email' ); + public function pending() { + _deprecated_function( __METHOD__, '2.8.7', 'UM()->common()->users()->set_as_pending()' ); + UM()->common()->users()->set_as_pending( um_user( 'ID' ) ); } - /** * This method rejects a user membership and sends them an optional email. - * - * @usage user()->reject(); ?> - * - * @example Reject a user membership example - - user()->reject(); - - ?> - - * + * @deprecated 2.8.7 + * @return void */ - function reject() { - $this->set_status( 'rejected' ); - - //clear all sessions for rejected users - $user = \WP_Session_Tokens::get_instance( um_user( 'ID' ) ); - $user->destroy_all(); - - UM()->mail()->send( um_user( 'user_email' ), 'rejected_email' ); + public function reject() { + _deprecated_function( __METHOD__, '2.8.7', 'UM()->common()->users()->reject()' ); + UM()->common()->users()->reject( um_user( 'ID' ) ); } - /** * This method deactivates a user membership and sends them an optional email. - * - * @usage user()->deactivate(); ?> - * - * @example Deactivate a user membership with the following example - - user->deactivate(); - - ?> - * + * @deprecated 2.8.7 + * @return void */ - function deactivate() { - $this->set_status( 'inactive' ); - - //clear all sessions for inactive users - $user = \WP_Session_Tokens::get_instance( um_user( 'ID' ) ); - $user->destroy_all(); - - /** - * UM hook - * - * @type action - * @title um_after_user_is_inactive - * @description Action after user was inactive - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_after_user_is_inactive', 'function_name', 10, 1 ); - * @example - * - */ - do_action( 'um_after_user_is_inactive', um_user( 'ID' ) ); - - UM()->mail()->send( um_user( 'user_email' ), 'inactive_email' ); + public function deactivate() { + _deprecated_function( __METHOD__, '2.8.7', 'UM()->common()->users()->deactivate()' ); + UM()->common()->users()->deactivate( um_user( 'ID' ) ); } - /** * Delete user * @@ -1970,28 +1725,7 @@ if ( ! class_exists( 'um\core\User' ) ) { function get_admin_actions() { $items = array(); - /** - * UM hook - * - * @type filter - * @title um_admin_user_actions_hook - * @description Extend admin actions for each user - * @input_vars - * [{"var":"$actions","type":"array","desc":"Actions for user"}] - * @change_log - * ["Since: 2.0"] - * @usage - * - * @example - * - */ - $actions = apply_filters( 'um_admin_user_actions_hook', array(), um_profile_id() ); + $actions = UM()->frontend()->users()->get_actions_list( um_profile_id() ); if ( empty( $actions ) ) { return $items; } @@ -2001,10 +1735,9 @@ if ( ! class_exists( 'um\core\User' ) ) { array( 'um_action' => $id, 'uid' => um_profile_id(), + 'nonce' => wp_create_nonce( $id . um_profile_id() ), ) ); - /*$url = add_query_arg( 'um_action', $id ); - $url = add_query_arg( 'uid', um_profile_id(), $url );*/ $items[] = '' . esc_html( $arr['label'] ) . ''; } return $items; @@ -2356,32 +2089,15 @@ if ( ! class_exists( 'um\core\User' ) ) { /** * This method checks if a user exists or not in your site based on the user ID. * - * @usage user()->user_exists_by_id( $user_id ); ?> + * @deprecated 2.8.7 * * @param int $user_id A user ID must be passed to check if the user exists * * @return bool|int - * - * @example Basic Usage - - user()->user_exists_by_id( 15 ); - if ( $boolean ) { - // That user exists - } - - ?> - - * */ public function user_exists_by_id( $user_id ) { - $aux = get_userdata( absint( $user_id ) ); - if ( $aux == false ) { - return false; - } else { - return $user_id; - } + _deprecated_function( __METHOD__, '2.8.7', 'UM()->common()->users()::user_exists' ); + return UM()->common()->users()::user_exists( $user_id ) ? $user_id : false; } /** @@ -2522,7 +2238,6 @@ if ( ! class_exists( 'um\core\User' ) ) { return $hash_email_address; } - /** * UM Placeholders for activation link in email * @@ -2530,12 +2245,11 @@ if ( ! class_exists( 'um\core\User' ) ) { * * @return array */ - function add_activation_placeholder( $placeholders ) { + public function add_activation_placeholder( $placeholders ) { $placeholders[] = '{account_activation_link}'; return $placeholders; } - /** * UM Replace Placeholders for activation link in email * @@ -2543,31 +2257,9 @@ if ( ! class_exists( 'um\core\User' ) ) { * * @return array */ - function add_activation_replace_placeholder( $replace_placeholders ) { + public function add_activation_replace_placeholder( $replace_placeholders ) { $replace_placeholders[] = um_user( 'account_activation_link' ); return $replace_placeholders; } - - - /** - * Get pending users (in queue) - * - * @deprecated 2.4.2 - */ - function get_pending_users_count() { - _deprecated_function( __METHOD__, '2.4.2', 'UM()->query()->get_pending_users_count()' ); - return UM()->query()->get_pending_users_count(); - } - - - /** - * Remove cached queue from Users backend - * - * @deprecated 2.4.2 - */ - function remove_cached_queue() { - _deprecated_function( __METHOD__, '2.4.2', '' ); - delete_option( 'um_cached_users_queue' ); - } } } diff --git a/includes/core/rest/class-api-v1.php b/includes/core/rest/class-api-v1.php index a3aee5c2..40a0df97 100644 --- a/includes/core/rest/class-api-v1.php +++ b/includes/core/rest/class-api-v1.php @@ -239,7 +239,8 @@ if ( ! class_exists( 'um\core\rest\API_v1' ) ) { switch ( $data ) { case 'status': - UM()->user()->set_status( $value ); + //UM()->user()->set_status( $value ); + UM()->common()->users()->set_status( $id, $value ); $response['success'] = __( 'User status has been changed.', 'ultimate-member' ); break; case 'role': diff --git a/includes/core/rest/class-api-v2.php b/includes/core/rest/class-api-v2.php index 3874b827..68cc382c 100644 --- a/includes/core/rest/class-api-v2.php +++ b/includes/core/rest/class-api-v2.php @@ -221,7 +221,8 @@ if ( ! class_exists( 'um\core\rest\API_v2' ) ) { switch ( $data ) { case 'status': - UM()->user()->set_status( $value ); + // UM()->user()->set_status( $value ); + UM()->common()->users()->set_status( $id, $value ); $response['success'] = __( 'User status has been changed.', 'ultimate-member' ); break; case 'role': diff --git a/includes/core/um-actions-core.php b/includes/core/um-actions-core.php deleted file mode 100644 index 8779fafc..00000000 --- a/includes/core/um-actions-core.php +++ /dev/null @@ -1,157 +0,0 @@ -user()->user_exists_by_id( $uid ) ) { - return; - } - - if ( ! empty( $uid ) && is_super_admin( $uid ) ) { - wp_die( esc_html__( 'Super administrators can not be modified.', 'ultimate-member' ) ); - } - - $role = get_role( UM()->roles()->get_priority_user_role( get_current_user_id() ) ); - $can_edit_users = current_user_can( 'edit_users' ) && $role->has_cap( 'edit_users' ); - - switch ( $action ) { - default: - /** - * UM hook - * - * @type action - * @title um_action_user_request_hook - * @description Integration for user actions - * @input_vars - * [{"var":"$action","type":"string","desc":"Action for user"}, - * {"var":"$user_id","type":"int","desc":"User ID"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_action_user_request_hook', 'function_name', 10, 2 ); - * @example - * - */ - do_action( 'um_action_user_request_hook', $action, $uid ); - break; - - case 'edit': - UM()->fields()->editing = true; - if ( ! um_is_myprofile() ) { - if ( ! UM()->roles()->um_current_user_can( 'edit', um_profile_id() ) ) { - exit( wp_redirect( UM()->permalinks()->get_current_url( true ) ) ); - } - } else { - if ( ! um_can_edit_my_profile() ) { - $url = um_edit_my_profile_cancel_uri(); - exit( wp_redirect( $url ) ); - } - } - break; - - case 'um_switch_user': - if ( ! current_user_can( 'manage_options' ) ) { - return; - } - UM()->user()->auto_login( $uid ); - exit( wp_redirect( UM()->permalinks()->get_current_url( true ) ) ); - break; - - case 'um_reject_membership': - if ( ! $can_edit_users ) { - wp_die( esc_html__( 'You do not have permission to make this action.', 'ultimate-member' ) ); - } - - um_fetch_user( $uid ); - UM()->user()->reject(); - exit( wp_redirect( UM()->permalinks()->get_current_url( true ) ) ); - break; - - case 'um_approve_membership': - case 'um_reenable': - if ( ! $can_edit_users ) { - wp_die( esc_html__( 'You do not have permission to make this action.', 'ultimate-member' ) ); - } - - um_fetch_user( $uid ); - - add_filter( 'um_template_tags_patterns_hook', array( UM()->password(), 'add_placeholder' ), 10, 1 ); - add_filter( 'um_template_tags_replaces_hook', array( UM()->password(), 'add_replace_placeholder' ), 10, 1 ); - - UM()->user()->approve(); - exit( wp_redirect( UM()->permalinks()->get_current_url( true ) ) ); - break; - - case 'um_put_as_pending': - if ( ! $can_edit_users ) { - wp_die( esc_html__( 'You do not have permission to make this action.', 'ultimate-member' ) ); - } - - um_fetch_user( $uid ); - UM()->user()->pending(); - exit( wp_redirect( UM()->permalinks()->get_current_url( true ) ) ); - break; - - case 'um_resend_activation': - if ( ! $can_edit_users ) { - wp_die( esc_html__( 'You do not have permission to make this action.', 'ultimate-member' ) ); - } - - add_filter( 'um_template_tags_patterns_hook', array( UM()->user(), 'add_activation_placeholder' ), 10, 1 ); - add_filter( 'um_template_tags_replaces_hook', array( UM()->user(), 'add_activation_replace_placeholder' ), 10, 1 ); - - um_fetch_user( $uid ); - UM()->user()->email_pending(); - exit( wp_redirect( UM()->permalinks()->get_current_url( true ) ) ); - break; - - case 'um_deactivate': - if ( ! $can_edit_users ) { - wp_die( esc_html__( 'You do not have permission to make this action.', 'ultimate-member' ) ); - } - - um_fetch_user( $uid ); - UM()->user()->deactivate(); - exit( wp_redirect( UM()->permalinks()->get_current_url( true ) ) ); - break; - - case 'um_delete': - if ( ! UM()->roles()->um_current_user_can( 'delete', $uid ) ) { - wp_die( esc_html__( 'You do not have permission to delete this user.', 'ultimate-member' ) ); - } - - um_fetch_user( $uid ); - UM()->user()->delete(); - exit( wp_redirect( UM()->permalinks()->get_current_url( true ) ) ); - break; - - } -} -add_action( 'template_redirect', 'um_action_request_process', 10000 ); diff --git a/includes/core/um-actions-register.php b/includes/core/um-actions-register.php index d79718c4..f2c65e92 100644 --- a/includes/core/um-actions-register.php +++ b/includes/core/um-actions-register.php @@ -11,7 +11,7 @@ if ( ! defined( 'ABSPATH' ) ) { function um_post_registration_approved_hook( $user_id ) { um_fetch_user( $user_id ); - UM()->user()->approve(); + UM()->common()->users()->approve( $user_id ); } add_action( 'um_post_registration_approved_hook', 'um_post_registration_approved_hook' ); @@ -23,7 +23,7 @@ add_action( 'um_post_registration_approved_hook', 'um_post_registration_approved function um_post_registration_checkmail_hook( $user_id ) { um_fetch_user( $user_id ); - UM()->user()->email_pending(); + UM()->common()->users()->send_activation( $user_id ); } add_action( 'um_post_registration_checkmail_hook', 'um_post_registration_checkmail_hook' ); @@ -35,7 +35,7 @@ add_action( 'um_post_registration_checkmail_hook', 'um_post_registration_checkma function um_post_registration_pending_hook( $user_id ) { um_fetch_user( $user_id ); - UM()->user()->pending(); + UM()->common()->users()->set_as_pending( $user_id ); } add_action( 'um_post_registration_pending_hook', 'um_post_registration_pending_hook' ); @@ -64,7 +64,8 @@ function um_after_insert_user( $user_id, $args, $form_data = null ) { um_fetch_user( $user_id ); $status = um_user( 'status' ); } - UM()->user()->set_status( $status ); + // UM()->user()->set_status( $status ); + UM()->common()->users()->set_status( $user_id, $status ); // Create user uploads directory. UM()->uploader()->get_upload_user_base_dir( $user_id, true ); diff --git a/includes/core/um-filters-user.php b/includes/core/um-filters-user.php index 2ff9e293..4d0eb375 100644 --- a/includes/core/um-filters-user.php +++ b/includes/core/um-filters-user.php @@ -3,61 +3,6 @@ if ( ! defined( 'ABSPATH' ) ) { exit; } -/** - * Main admin user actions. - * - * @param array $actions - * @param int $user_id - * - * @return array - */ -function um_admin_user_actions_hook( $actions, $user_id ) { - um_fetch_user( $user_id ); - - $role = get_role( UM()->roles()->get_priority_user_role( get_current_user_id() ) ); - - $can_edit_users = null !== $role && current_user_can( 'edit_users' ) && $role->has_cap( 'edit_users' ); - if ( $can_edit_users ) { - $account_status = um_user( 'account_status' ); - - if ( 'awaiting_admin_review' === $account_status ) { - $actions['um_approve_membership'] = array( 'label' => __( 'Approve Membership', 'ultimate-member' ) ); - $actions['um_reject_membership'] = array( 'label' => __( 'Reject Membership', 'ultimate-member' ) ); - } - - if ( 'rejected' === $account_status ) { - $actions['um_approve_membership'] = array( 'label' => __( 'Approve Membership', 'ultimate-member' ) ); - } - - if ( 'approved' === $account_status ) { - $actions['um_put_as_pending'] = array( 'label' => __( 'Put as Pending Review', 'ultimate-member' ) ); - } - - if ( 'awaiting_email_confirmation' === $account_status ) { - $actions['um_resend_activation'] = array( 'label' => __( 'Resend Activation Email', 'ultimate-member' ) ); - } - - if ( 'inactive' !== $account_status ) { - $actions['um_deactivate'] = array( 'label' => __( 'Deactivate this account', 'ultimate-member' ) ); - } - - if ( 'inactive' === $account_status ) { - $actions['um_reenable'] = array( 'label' => __( 'Reactivate this account', 'ultimate-member' ) ); - } - } - - if ( UM()->roles()->um_current_user_can( 'delete', $user_id ) ) { - $actions['um_delete'] = array( 'label' => __( 'Delete this user', 'ultimate-member' ) ); - } - - if ( current_user_can( 'manage_options' ) && ! is_super_admin( $user_id ) ) { - $actions['um_switch_user'] = array( 'label' => __( 'Login as this user', 'ultimate-member' ) ); - } - - return $actions; -} -add_filter( 'um_admin_user_actions_hook', 'um_admin_user_actions_hook', 10, 2 ); - /** * Filter user basename. * diff --git a/includes/frontend/class-actions-listener.php b/includes/frontend/class-actions-listener.php new file mode 100644 index 00000000..389f7a21 --- /dev/null +++ b/includes/frontend/class-actions-listener.php @@ -0,0 +1,206 @@ +common()->users()::user_exists( $user_id ) ) { + return; + } + + if ( get_current_user_id() === $user_id ) { + return; + } + + if ( ! empty( $user_id ) && is_super_admin( $user_id ) ) { + wp_die( esc_html__( 'Super administrators can not be modified.', 'ultimate-member' ) ); + } + + $action = sanitize_key( $_REQUEST['um_action'] ); + // phpcs:enable WordPress.Security.NonceVerification -- there is nonce verification below for each case + switch ( $action ) { + case 'approve_user': + if ( ! wp_verify_nonce( $_REQUEST['nonce'], "approve_user{$user_id}" ) ) { + wp_die( esc_html__( 'The link you followed has expired.', 'ultimate-member' ) ); + } + + if ( ! UM()->common()->users()->can_current_user_edit_user( $user_id ) ) { + wp_die( esc_html__( 'You do not have permission to edit this user.', 'ultimate-member' ) ); + } + + $result = UM()->common()->users()->approve( $user_id ); + if ( ! $result ) { + wp_die( esc_html__( 'Something went wrong.', 'ultimate-member' ) ); + } + + um_safe_redirect( UM()->permalinks()->get_current_url( true ) ); + exit; + case 'reactivate_user': + if ( ! wp_verify_nonce( $_REQUEST['nonce'], "reactivate_user{$user_id}" ) ) { + wp_die( esc_html__( 'The link you followed has expired.', 'ultimate-member' ) ); + } + + if ( ! UM()->common()->users()->can_current_user_edit_user( $user_id ) ) { + wp_die( esc_html__( 'You do not have permission to edit this user.', 'ultimate-member' ) ); + } + + $result = UM()->common()->users()->reactivate( $user_id ); + if ( ! $result ) { + wp_die( esc_html__( 'Something went wrong.', 'ultimate-member' ) ); + } + + um_safe_redirect( UM()->permalinks()->get_current_url( true ) ); + exit; + case 'put_user_as_pending': + if ( ! wp_verify_nonce( $_REQUEST['nonce'], "put_user_as_pending{$user_id}" ) ) { + wp_die( esc_html__( 'The link you followed has expired.', 'ultimate-member' ) ); + } + + if ( ! UM()->common()->users()->can_current_user_edit_user( $user_id ) ) { + wp_die( esc_html__( 'You do not have permission to edit this user.', 'ultimate-member' ) ); + } + + $result = UM()->common()->users()->set_as_pending( $user_id ); + if ( ! $result ) { + wp_die( esc_html__( 'Something went wrong.', 'ultimate-member' ) ); + } + + um_safe_redirect( UM()->permalinks()->get_current_url( true ) ); + exit; + case 'resend_user_activation': + if ( ! wp_verify_nonce( $_REQUEST['nonce'], "resend_user_activation{$user_id}" ) ) { + wp_die( esc_html__( 'The link you followed has expired.', 'ultimate-member' ) ); + } + + if ( ! UM()->common()->users()->can_current_user_edit_user( $user_id ) ) { + wp_die( esc_html__( 'You do not have permission to edit this user.', 'ultimate-member' ) ); + } + + $result = UM()->common()->users()->send_activation( $user_id ); + if ( ! $result ) { + wp_die( esc_html__( 'Something went wrong.', 'ultimate-member' ) ); + } + + um_safe_redirect( UM()->permalinks()->get_current_url( true ) ); + exit; + case 'reject_user': + if ( ! wp_verify_nonce( $_REQUEST['nonce'], "reject_user{$user_id}" ) ) { + wp_die( esc_html__( 'The link you followed has expired.', 'ultimate-member' ) ); + } + + if ( ! UM()->common()->users()->can_current_user_edit_user( $user_id ) ) { + wp_die( esc_html__( 'You do not have permission to edit this user.', 'ultimate-member' ) ); + } + + $result = UM()->common()->users()->reject( $user_id ); + if ( ! $result ) { + wp_die( esc_html__( 'Something went wrong.', 'ultimate-member' ) ); + } + + um_safe_redirect( UM()->permalinks()->get_current_url( true ) ); + exit; + case 'deactivate_user': + if ( ! wp_verify_nonce( $_REQUEST['nonce'], "deactivate_user{$user_id}" ) ) { + wp_die( esc_html__( 'The link you followed has expired.', 'ultimate-member' ) ); + } + + if ( ! UM()->common()->users()->can_current_user_edit_user( $user_id ) ) { + wp_die( esc_html__( 'You do not have permission to edit this user.', 'ultimate-member' ) ); + } + + $result = UM()->common()->users()->deactivate( $user_id ); + if ( ! $result ) { + wp_die( esc_html__( 'Something went wrong.', 'ultimate-member' ) ); + } + + um_safe_redirect( UM()->permalinks()->get_current_url( true ) ); + exit; + case 'switch_user': + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + + if ( ! wp_verify_nonce( $_REQUEST['nonce'], "switch_user{$user_id}" ) ) { + wp_die( esc_html__( 'The link you followed has expired.', 'ultimate-member' ) ); + } + + UM()->user()->auto_login( $user_id ); + + um_safe_redirect( UM()->permalinks()->get_current_url( true ) ); + exit; + case 'delete': + if ( ! wp_verify_nonce( $_REQUEST['nonce'], "delete{$user_id}" ) ) { + wp_die( esc_html__( 'The link you followed has expired.', 'ultimate-member' ) ); + } + + if ( ! UM()->roles()->um_current_user_can( 'delete', $user_id ) ) { + wp_die( esc_html__( 'You do not have permission to delete this user.', 'ultimate-member' ) ); + } + + um_fetch_user( $user_id ); + UM()->user()->delete(); + + um_safe_redirect( UM()->permalinks()->get_current_url( true ) ); + exit; + default: + /** + * Fires to handle 3rd-party user actions from User Profile. + * + * Note: Please verify nonce and redirect after action individually in 3rd-party handler. + * + * @since 1.3.x + * @hook um_action_user_request_hook + * + * @param {string} $action User action key. + * @param {int} $user_id User ID. + * + * @example Update `some_custom_meta` user meta on `my_custom_action`. + * function um_action_user_request_hook( $action, $user_id ) { + * if ( 'my_custom_action' === $action ) { + * update_user_meta( $user_id, 'some_custom_meta', true ); + * } + * } + * add_action( 'um_action_user_request_hook', 'um_action_user_request_hook', 10, 2 ); + */ + do_action( 'um_action_user_request_hook', $action, $user_id ); + break; + } + } + } +} diff --git a/includes/frontend/class-init.php b/includes/frontend/class-init.php index b34cd983..1d3d460f 100644 --- a/includes/frontend/class-init.php +++ b/includes/frontend/class-init.php @@ -20,9 +20,25 @@ if ( ! class_exists( 'um\frontend\Init' ) ) { * @used-by \UM::includes() */ public function includes() { + $this->actions_listener(); $this->enqueue(); $this->modal(); $this->secure(); + $this->user_profile(); + $this->users(); + } + + /** + * @since 2.8.7 + * + * @return Actions_Listener + */ + public function actions_listener() { + if ( empty( UM()->classes['um\frontend\actions_listener'] ) ) { + UM()->classes['um\frontend\actions_listener'] = new Actions_Listener(); + } + + return UM()->classes['um\frontend\actions_listener']; } /** @@ -62,5 +78,29 @@ if ( ! class_exists( 'um\frontend\Init' ) ) { } return UM()->classes['um\frontend\secure']; } + + /** + * @since 2.8.7 + * + * @return User_Profile + */ + public function user_profile() { + if ( empty( UM()->classes['um\frontend\user_profile'] ) ) { + UM()->classes['um\frontend\user_profile'] = new User_Profile(); + } + return UM()->classes['um\frontend\user_profile']; + } + + /** + * @since 2.8.7 + * + * @return Users + */ + public function users() { + if ( empty( UM()->classes['um\frontend\users'] ) ) { + UM()->classes['um\frontend\users'] = new Users(); + } + return UM()->classes['um\frontend\users']; + } } } diff --git a/includes/frontend/class-user-profile.php b/includes/frontend/class-user-profile.php new file mode 100644 index 00000000..f77cd3cc --- /dev/null +++ b/includes/frontend/class-user-profile.php @@ -0,0 +1,69 @@ +common()->users()::user_exists( $uid ) ) { + return; + } + + if ( ! empty( $uid ) && is_super_admin( $uid ) ) { + wp_die( esc_html__( 'Super administrators can not be modified.', 'ultimate-member' ) ); + } + + UM()->fields()->editing = true; + + if ( ! um_is_myprofile() && ! UM()->roles()->um_current_user_can( 'edit', um_profile_id() ) ) { + um_safe_redirect( UM()->permalinks()->get_current_url( true ) ); + exit; + } + + if ( ! um_can_edit_my_profile() ) { + um_safe_redirect( um_edit_my_profile_cancel_uri() ); + exit; + } + } + } +} diff --git a/includes/frontend/class-users.php b/includes/frontend/class-users.php new file mode 100644 index 00000000..585cbcd9 --- /dev/null +++ b/includes/frontend/class-users.php @@ -0,0 +1,81 @@ +roles()->get_priority_user_role( get_current_user_id() ); + $role = get_role( $priority_role ); + + $can_edit_users = null !== $role && current_user_can( 'edit_users' ) && $role->has_cap( 'edit_users' ); + if ( $can_edit_users ) { + if ( UM()->common()->users()->can_be_approved( $user_id ) ) { + $actions['approve_user'] = array( 'label' => __( 'Approve Membership', 'ultimate-member' ) ); + } + if ( UM()->common()->users()->can_be_reactivated( $user_id ) ) { + $actions['reactivate_user'] = array( 'label' => __( 'Reactivate this account', 'ultimate-member' ) ); + } + if ( UM()->common()->users()->can_be_set_as_pending( $user_id ) ) { + $actions['put_user_as_pending'] = array( 'label' => __( 'Put as Pending Review', 'ultimate-member' ) ); + } + if ( UM()->common()->users()->can_activation_send( $user_id ) ) { + $actions['resend_user_activation'] = array( 'label' => __( 'Resend Activation Email', 'ultimate-member' ) ); + } + if ( UM()->common()->users()->can_be_rejected( $user_id ) ) { + $actions['reject_user'] = array( 'label' => __( 'Reject Membership', 'ultimate-member' ) ); + } + if ( UM()->common()->users()->can_be_deactivated( $user_id ) ) { + $actions['deactivate_user'] = array( 'label' => __( 'Deactivate this account', 'ultimate-member' ) ); + } + } + + if ( UM()->roles()->um_current_user_can( 'delete', $user_id ) ) { + $actions['delete'] = array( 'label' => __( 'Delete this user', 'ultimate-member' ) ); + } + + if ( current_user_can( 'manage_options' ) && ! is_super_admin( $user_id ) ) { + $actions['switch_user'] = array( 'label' => __( 'Login as this user', 'ultimate-member' ) ); + } + + /** + * Filters users actions list in Ultimate Member frontend. + * + * @since 1.3.x + * @hook um_admin_user_actions_hook + * + * @param {array} $actions CPT keys. + * @param {int} $user_id User ID. + * + * @return {array} CPT keys. + * + * @example Add `um_custom_action` action to the users actions list on frontend. + * function um_custom_admin_user_actions_hook( $actions, $user_id ) { + * $actions['um_custom_action'] = array( 'label' => 'um_custom_action_label' ); + * return $actions; + * } + * add_filter( 'um_admin_user_actions_hook', 'um_custom_admin_user_actions_hook', 10, 2 ); + */ + return apply_filters( 'um_admin_user_actions_hook', $actions, $user_id ); + } +} diff --git a/includes/um-deprecated-hooks.php b/includes/um-deprecated-hooks.php index 86a01327..3231ab27 100644 --- a/includes/um-deprecated-hooks.php +++ b/includes/um-deprecated-hooks.php @@ -45,3 +45,53 @@ if ( ! defined( 'ABSPATH' ) ) { * } * add_filter( 'um_language_file', 'my_um_language_file' ); */ + +/** + * Fires after user status changed. + * + * @param {int} $user_id User ID. + * + * @since 1.3.x + * @depecated 2.8.7 use action hook `um_after_user_status_is_changed` instead. + * @hook um_after_user_status_is_changed_hook + */ + +/** + * Fires just before User status is changed. + * + * @since 1.3.x + * @depecated 2.8.7 use action hook `um_before_user_status_is_set` instead. + * @hook um_when_status_is_set + * + * @param {int} $user_id User ID. Since 2.0 + */ + +/** + * Fires for handle admin user_action scripts. + * + * @since 1.3.x + * @depecated 2.8.7 WordPress native `handle_bulk_actions-users` hook is used. Use action hook `um_handle_bulk_actions-users-{$current_action}` for custom user bulk actions instead. + * @hook um_admin_user_action_hook + * + * @param {string} $bulk_action Bulk action key + */ + +/** + * Fires for handle admin user_action scripts. + * Where $bulk_action is a bulk action key + * + * @since 1.3.x + * @depecated 2.8.7 WordPress native `handle_bulk_actions-users` hook is used. Use action hook `um_handle_bulk_actions-users-{$current_action}` for custom user bulk actions instead. + * @hook um_admin_user_action_{$bulk_action}_hook + */ + +/** + * Fires for handle custom admin user_action scripts. + * Where $action is a bulk action key + * + * @since 1.3.x + * @depecated 2.8.7 WordPress native `handle_bulk_actions-users` hook is used. Use action hook `um_handle_bulk_actions-users-{$current_action}` for custom user bulk actions instead. + * @hook um_admin_custom_hook_{$action} + * + * @param {int} $user_id User ID. + */ diff --git a/includes/um-short-functions.php b/includes/um-short-functions.php index b4179d30..280b3714 100644 --- a/includes/um-short-functions.php +++ b/includes/um-short-functions.php @@ -1579,7 +1579,7 @@ function um_can_view_field( $data ) { /** * Checks if user can view profile - * + * @todo make the function review. Maybe rewrite it. * @param int $user_id * * @return bool diff --git a/ultimate-member.php b/ultimate-member.php index ea2c7aa5..c24ef586 100644 --- a/ultimate-member.php +++ b/ultimate-member.php @@ -3,7 +3,7 @@ * Plugin Name: Ultimate Member * Plugin URI: http://ultimatemember.com/ * Description: The easiest way to create powerful online communities and beautiful user profiles with WordPress - * Version: 2.8.7-alpha + * Version: 2.8.7 * Author: Ultimate Member * Author URI: http://ultimatemember.com/ * Text Domain: ultimate-member