diff --git a/plugins/bcc-login/bcc-login.php b/plugins/bcc-login/bcc-login.php index 2ed5ac7..10984d8 100644 --- a/plugins/bcc-login/bcc-login.php +++ b/plugins/bcc-login/bcc-login.php @@ -70,7 +70,7 @@ private function __construct(){ $this->_feed = new BCC_Login_Feed( $this->_settings, $this->_client ); $this->_updater = new BCC_Login_Updater( $this->plugin, $this->plugin_slug, $this->plugin_version, $this->plugin_name ); - if (!empty($this->_settings->site_groups)) { + if (!empty($this->_settings->site_groups) || !empty($this->_settings->full_content_access_groups)) { $this->_coreapi->ensure_subscription_to_person_updates(); } diff --git a/plugins/bcc-login/includes/class-bcc-coreapi-client.php b/plugins/bcc-login/includes/class-bcc-coreapi-client.php index f2c267a..713cee2 100644 --- a/plugins/bcc-login/includes/class-bcc-coreapi-client.php +++ b/plugins/bcc-login/includes/class-bcc-coreapi-client.php @@ -13,7 +13,7 @@ function __construct(BCC_Login_Settings $login_settings, BCC_Storage $storage) } function get_site_groups() { - if(isset($this->_site_groups)) { + if (isset($this->_site_groups)) { return $this->_site_groups; } $group_uids = $this->_settings->site_groups; @@ -21,7 +21,7 @@ function get_site_groups() { $cache_key = 'coreapi_groups_' . implode($group_uids); $cached_response = get_transient($cache_key); - if($cached_response) { + if ($cached_response !== false) { return $cached_response; } @@ -65,7 +65,7 @@ function get_groups_for_user($user_uid) { $cache_key = 'coreapi_user_groups_'.$user_uid; $cached_response = get_transient($cache_key); - if($cached_response !== false) { + if ($cached_response !== false) { return $cached_response; } @@ -77,13 +77,12 @@ function get_groups_for_user($user_uid) { return $user_groups; } - function fetch_groups_for_user($user_uid) - { - if(empty( $this->_settings->site_groups)) return array(); + function fetch_groups_for_user($user_uid) { + if (empty($this->_settings->site_groups)) return array(); $token = $this->get_coreapi_token(); - $request_url = $this->_settings->coreapi_base_url . "/v2/persons/". $user_uid . "/checkGroupMemberships"; + $request_url = $this->_settings->coreapi_base_url . "/v2/persons/". $user_uid . "/checkGroupMemberships"; $request_body = array( "groupUids" => $this->_settings->site_groups ); @@ -95,9 +94,8 @@ function fetch_groups_for_user($user_uid) ) )); - - if ( is_wp_error( $response ) ) { - wp_die( $response->get_error_message() ); + if (is_wp_error($response)) { + wp_die($response->get_error_message()); } if ($response['response']['code'] != 200) { @@ -111,7 +109,7 @@ function fetch_groups_for_user($user_uid) } public function ensure_subscription_to_person_updates() { - if(str_contains(site_url(), "localhost")){ + if (str_contains(site_url(), "localhost") || str_contains(site_url(), ".local") ) { return; } diff --git a/plugins/bcc-login/includes/class-bcc-login-settings.php b/plugins/bcc-login/includes/class-bcc-login-settings.php index 25a21a3..4db189d 100644 --- a/plugins/bcc-login/includes/class-bcc-login-settings.php +++ b/plugins/bcc-login/includes/class-bcc-login-settings.php @@ -16,6 +16,7 @@ class BCC_Login_Settings { public $feed_key; public $show_protected_menu_items; public $site_groups = array(); + public $full_content_access_groups = array(); public $coreapi_audience; public $coreapi_base_url; } @@ -87,6 +88,11 @@ function __construct () { $settings->site_groups = explode(",", $site_groups_option); } + $full_content_access_groups_option = get_option('bcc_full_content_access_groups'); + if ($full_content_access_groups_option) { + $settings->full_content_access_groups = explode(",", $full_content_access_groups_option); + } + // Backwards compatibility with old plugin configuration. if ( ! isset( $settings->client_id ) ) { $old_oidc_settings = (array) get_option( 'openid_connect_generic_settings', array () ); @@ -138,6 +144,7 @@ function register_settings() { register_setting( $this->option_name, 'bcc_member_organization_name' ); register_setting( $this->option_name, 'bcc_feed_key' ); register_setting( $this->option_name, 'bcc_site_groups' ); + register_setting( $this->option_name, 'bcc_full_content_access_groups' ); register_setting( $this->option_name, 'show_protected_menu_items' ); add_settings_section( 'general', '', null, $this->options_page ); @@ -215,7 +222,7 @@ function register_settings() { ) ); - if(!empty($this->_settings->site_groups)|| BCC_Coreapi_Client::check_groups_access( + if (!empty($this->_settings->site_groups) || BCC_Coreapi_Client::check_groups_access( $this->_settings->token_endpoint, $this->_settings->client_id, $this->_settings->client_secret, @@ -230,12 +237,30 @@ function register_settings() { array( 'name' => 'bcc_site_groups', 'value' => join(",", $this->_settings->site_groups), - 'description' => 'Provide group uids for groups you\'re going to use (comma delimtied)' + 'description' => 'Provide group uids for groups you\'re going to use (comma delimited).' ) ); - } + if (!empty($this->_settings->full_content_access_groups) || BCC_Coreapi_Client::check_groups_access( + $this->_settings->token_endpoint, + $this->_settings->client_id, + $this->_settings->client_secret, + $this->_settings->coreapi_audience + )) { + add_settings_field( + 'bcc_full_content_access_groups', + 'Full Content Access Groups', + array( $this, 'render_text_field' ), + $this->options_page, + 'general', + array( + 'name' => 'bcc_full_content_access_groups', + 'value' => join(",", $this->_settings->full_content_access_groups), + 'description' => 'Groups that always can see published content regardless of group settings on content.' + ) + ); + } add_settings_field( 'show_protected_menu_items', diff --git a/plugins/bcc-login/includes/class-bcc-login-visibility.php b/plugins/bcc-login/includes/class-bcc-login-visibility.php index bf568c0..3d245fd 100644 --- a/plugins/bcc-login/includes/class-bcc-login-visibility.php +++ b/plugins/bcc-login/includes/class-bcc-login-visibility.php @@ -39,6 +39,7 @@ function __construct( BCC_Login_Settings $settings, BCC_Login_Client $client, BC add_action( 'updated_post_meta', array( $this, 'on_meta_saved' ), 10, 4 ); add_action( 'enqueue_block_editor_assets', array( $this, 'on_block_editor_assets' ) ); add_filter( 'pre_get_posts', array( $this, 'filter_pre_get_posts' ) ); + add_filter( 'pre_get_posts', array( $this, 'filter_by_selected_target_groups' ) ); add_filter( 'wp_get_nav_menu_items', array( $this, 'filter_menu_items' ), 20 ); add_filter( 'render_block', array( $this, 'on_render_block' ), 10, 2 ); @@ -47,7 +48,13 @@ function __construct( BCC_Login_Settings $settings, BCC_Login_Client $client, BC add_action( 'quick_edit_custom_box', array( $this, 'quick_edit_fields'), 10, 2 ); add_action( 'save_post', array( $this, 'bcc_quick_edit_save' ) ); + add_action( 'wp_enqueue_scripts', array( $this, 'bcc_enqueue_filtering_scripts' ) ); + add_action( 'admin_enqueue_scripts', array( $this, 'bcc_enqueue_visibility_scripts' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'bcc_enqueue_quick_edit_scripts' ) ); + + add_shortcode('bcc_groups_filtering', array($this, 'bcc_groups_filtering')); + add_shortcode('bcc_groups_filtered_tags', array($this, 'bcc_groups_filtered_tags')); + add_shortcode('get_bcc_group_name', array($this, 'get_bcc_group_name_by_id')); } /** @@ -151,23 +158,26 @@ function on_template_redirect() { } } - if(!empty($this->_settings->site_groups)){ - $post_groups = get_post_meta( $post->ID, 'bcc_groups', false ); + if ( !empty($this->_settings->site_groups) ) { + $post_groups = get_post_meta($post->ID, 'bcc_groups', false); if (!$post_groups) { return; } + $user_groups = $this->get_current_user_groups(); if (!$user_groups) { return $this->not_allowed_to_view_page(); } - if(count(array_intersect($post_groups, $user_groups)) == 0) { + + if (count(array_intersect($post_groups, $user_groups)) == 0 && + count(array_intersect($this->_settings->full_content_access_groups, $user_groups)) == 0) + { return $this->not_allowed_to_view_page(); } } - } - private function not_allowed_to_view_page(){ + private function not_allowed_to_view_page() { wp_die( sprintf( '%s
%s', @@ -225,7 +235,7 @@ function on_meta_saved( $mid, $post_id, $key, $value ) { function on_block_editor_assets() { $script_path = BCC_LOGIN_PATH . 'build/visibility.asset.php'; $script_url = BCC_LOGIN_URL . 'build/visibility.js'; - $scrcipt_handle = 'bcc-login-visibility'; + $script_handle = 'bcc-login-visibility'; if ( ! file_exists( $script_path ) ) { return; @@ -234,7 +244,7 @@ function on_block_editor_assets() { $script_asset = require $script_path; wp_enqueue_script( - $scrcipt_handle, + $script_handle, $script_url, $script_asset['dependencies'], $script_asset['version'], @@ -242,7 +252,7 @@ function on_block_editor_assets() { ); wp_add_inline_script( - $scrcipt_handle, + $script_handle, 'var bccLoginPostVisibility = ' . json_encode( array( 'localName' => $this->_settings->member_organization_name, 'defaultLevel' => self::VISIBILITY_DEFAULT, @@ -253,7 +263,7 @@ function on_block_editor_assets() { if (!empty($this->_settings->site_groups) ) { wp_add_inline_script( - $scrcipt_handle, + $script_handle, 'var siteGroups = ' . json_encode($this->_coreapi->get_site_groups()), 'before' ); @@ -279,7 +289,7 @@ function filter_pre_get_posts( $query ) { } // Allow feeds to be accessed using key - if ( $query->is_feed && ! empty($this->_settings->feed_key) && array_key_exists('id',$_GET) && $this->_settings->feed_key == $_GET['id'] ) { + if ( $query->is_feed && ! empty($this->_settings->feed_key) && array_key_exists('id', $_GET) && $this->_settings->feed_key == $_GET['id'] ) { return $query; } @@ -313,8 +323,12 @@ function filter_pre_get_posts( $query ) { ); } - if(!empty($this->_settings->site_groups)) { - $user_groups = $this->get_current_user_groups(); + $user_groups = $this->get_current_user_groups(); + + // Filter posts which user should have access to - except when user has full content access + if (count($user_groups) > 0 && + count(array_intersect($this->_settings->full_content_access_groups, $user_groups)) == 0 + ) { $group_rules = array(); if (empty($user_groups)) { @@ -335,9 +349,10 @@ function filter_pre_get_posts( $query ) { 'key' => 'bcc_groups', 'compare' => 'IN', 'value' => $user_groups - ), + ) ); } + $rules = array( 'relation' => 'AND', $rules, @@ -349,13 +364,38 @@ function filter_pre_get_posts( $query ) { $rules['bcc-login-visibility'] = true; $meta_query[] = $rules; - // Set the meta query to the complete, altered query $query->set('meta_query', $meta_query); return $query; } + /** + * Filters out posts that do not belong to the selected target groups. + * This filter applies to category lists and REST API results. + * + * @param WP_Query $query + * @return WP_Query + */ + function filter_by_selected_target_groups($query) { + if (!isset($_GET['target-groups'])) + return; + + if (is_admin() || array_key_exists('post_type', $query->query) && $query->query['post_type'] === 'nav_menu_item') + return; + + // Get original meta query + $meta_query = (array) $query->get('meta_query'); + $meta_query[] = array( + 'key' => 'bcc_groups', + 'value' => $_GET['target-groups'], + 'compare' => 'IN' + ); + + // Filter by selected target groups + $query->set('meta_query', $meta_query); + } + /** * Filters out menu items that the current users shouldn't see. * @@ -399,13 +439,41 @@ private function get_current_user_groups() { return array(); } - $person_uid = $this->_client->get_current_user_person_uid(); - if(!$person_uid) { + $person_uid = $this->_client->get_current_user_person_uid(); + if (!$person_uid) { return array(); } + return $this->_coreapi->get_groups_for_user($person_uid); } + private function get_user_bcc_groups_list() { + $site_groups = $this->_coreapi->get_site_groups(); + $user_site_groups = array(); + + if ( current_user_can( 'edit_posts' ) ) { + // Show all site groups for admins + $user_site_groups = $site_groups; + } + else { + $user_groups = $this->get_current_user_groups(); + if (!$user_groups) { + return; + } + + foreach ($site_groups as $site_group) { + if (in_array($site_group->uid, $user_groups)) { + $user_site_groups[] = $site_group; + } + } + } + + // Sort by name + usort($user_site_groups, fn($a, $b) => $a->name <=> $b->name); + + return $user_site_groups; + } + /** * Checks the `bccLoginVisibility` attribute and hides the block if * the current users shouldn't be allowed to see it. @@ -440,11 +508,14 @@ function on_render_block( $block_content, $block ) { $user_groups = $this->get_current_user_groups(); - if (!$user_groups) { return ''; } - if(count(array_intersect($block_groups, $user_groups)) == 0) { + + // Filter blocks which user should have access to - except when user has full content access + if (count(array_intersect($block_groups, $user_groups)) == 0 && + count(array_intersect($this->_settings->full_content_access_groups, $user_groups)) == 0 + ) { return ''; } } @@ -474,7 +545,7 @@ function on_render_menu_item( $item_id, $item, $depth, $args, $id ) { ?>

- levels as $key => $level ): ?> + levels as $key => $level ) : ?>

@@ -631,6 +701,15 @@ function bcc_quick_edit_save( $post_id ){ } } + function bcc_enqueue_filtering_scripts() { + wp_enqueue_style( 'filtering-css', BCC_LOGIN_URL . 'src/filtering.css' ); + wp_enqueue_script( 'filtering-js', BCC_LOGIN_URL . 'src/filtering.js', array( 'jquery' ) ); + } + + function bcc_enqueue_visibility_scripts() { + wp_enqueue_style( 'visibility-css', BCC_LOGIN_URL . 'src/visibility.css' ); + } + function bcc_enqueue_quick_edit_scripts( $pagehook ) { // do nothing if we are not on the target pages if ( 'edit.php' != $pagehook ) { @@ -651,6 +730,59 @@ function get_group_name($group_uid) { return ""; } + function bcc_groups_filtering() { + $user_site_groups = $this->get_user_bcc_groups_list(); + $bcc_groups_selected = isset($_GET['target-groups']) ? $_GET['target-groups'] : array(); + + $html = '
' . + ' Filter' . + '
' . + 'Close'; + + $html .= '
    '; + foreach ($user_site_groups as $group) : + $html .= '
  • ' . + 'uid, $bcc_groups_selected) ? 'checked' : '') . '/>' . + '' . + '
  • '; + endforeach; + $html .= '
'; + + $html .= '
' . + '
'; + + return $html; + } + + function bcc_groups_filtered_tags() { + $html = ''; + + if (isset($_GET['target-groups'])) { + $html .= '
'; + $html .= '' . __('Clear all', 'bcc-login') . ''; + + foreach ($_GET['target-groups'] as $target_group) { + $html .= '
' . + '' . $this->get_group_name($target_group) . '' . + 'X' . + '
'; + } + $html .= '
'; + } + + return $html; + } + + + function get_bcc_group_name_by_id($atts) { + $attributes = shortcode_atts(array('uid' => ''), $atts); + $uid = $attributes['uid']; + if (!$uid) + return; + + return $this->get_group_name($uid); + } + /** * Deletes all `bcc_login_visibility` values from the database. */ diff --git a/plugins/bcc-login/src/filtering.css b/plugins/bcc-login/src/filtering.css new file mode 100644 index 0000000..fc5704a --- /dev/null +++ b/plugins/bcc-login/src/filtering.css @@ -0,0 +1,155 @@ +.bcc-filter { + position: relative; +} + +.bcc-filter ul { + padding-left: 0 !important; + margin-bottom: 0 !important; +} + +.bcc-filter li { + position: relative; + margin-bottom: 4px !important; +} + +.bcc-filter li:before { + display: none !important; +} + +.bcc-filter label, +.bcc-filter input { + cursor: pointer; +} + +.bcc-filter input { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +.bcc-filter label { + color: #4B5563; + line-height: 20px; + font-size: 14px; + display: flex; + gap: 6px; + padding-block: 4px; + transition: .3s ease-in-out; +} + +.bcc-filter .bcc-checkbox { + width: 19px; + height: 19px; + border-radius: 4px; + border: 2px solid #E5E7EB; + flex-shrink: 0; +} + +.bcc-filter label:hover, +.bcc-filter input:checked+label { + color: #111827; + font-weight: 500; +} + +.bcc-filter input:checked+label .bcc-checkbox { + background-color: #30715E; + border: 2px solid #30715E; +} + +.bcc-filter #toggle-bcc-filter { + padding: 8px 12px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 6px; + border: 1px solid #2A5B4E; + background: #30715E; + color: #fff; + font-weight: bold; + box-shadow: 0px 4px 20px -10px rgba(58, 143, 118, 0.10), 20px 8px 20px -2px rgba(58, 143, 118, 0.06); +} + +.bcc-filter #close-bcc-groups { + position: absolute; + right: 16px; + top: 16px; + height: 40px; +} + +.bcc-filter #toggle-bcc-filter { + display: flex; + align-items: center; + gap: 4px; +} + +.bcc-filter #bcc-filter-groups.active { + display: block; +} + +body.no-scroll { + overflow: hidden; +} + +.bcc-target-groups__filtered { + display: flex; + align-items: center; + gap: 4px; + margin-bottom: 16px; +} + +.bcc-target-groups__item, #clear-bcc-groups { + padding: 2px 10px; + border-radius: 100rem; + background-color: rgb(243, 250, 247); + font-size: 14px; +} + +#clear-bcc-groups { + background-color: rgb(250, 243, 243); +} + +.bcc-target-groups__item span:after { + content: "|"; + opacity: 0.25; + padding: 0 4px; +} + +@media (max-width: 1023px) { + .bcc-filter #bcc-filter-groups { + position: fixed; + inset: 0; + top: var(--wp-admin--admin-bar--height); + z-index: 99999; + background: #fff; + padding: 16px; + text-align: left; + overflow-y: auto; + display: none; + } +} + +@media (min-width: 1024px) { + @supports (text-shadow: 1px 0 0 #000) { + .bcc-filter label:hover, + .bcc-filter input:checked+label { + font-weight: normal; + text-shadow: 0.2px 0 0 currentColor; + } + } + + .bcc-filter #close-bcc-groups, + .bcc-filter #toggle-bcc-filter { + display: none; + } + + .bcc-filter #bcc-filter-groups { + display: block; + position: relative; + } +} \ No newline at end of file diff --git a/plugins/bcc-login/src/filtering.js b/plugins/bcc-login/src/filtering.js new file mode 100644 index 0000000..34f2709 --- /dev/null +++ b/plugins/bcc-login/src/filtering.js @@ -0,0 +1,48 @@ +jQuery(function ($) { + $(document).on("click", "#clear-bcc-groups", function (e) { + e.preventDefault(); + window.history.pushState(null, null, window.location.href.split("?")[0]); + location.reload(); + }); + + $(document).on("click", "#toggle-bcc-filter", function () { + $("#bcc-filter-groups").addClass("active"); + $("body").addClass("no-scroll"); + }); + + $(document).on("click", "#close-bcc-groups", function () { + $("#bcc-filter-groups").removeClass("active"); + $("body").removeClass("no-scroll"); + }); + + $(document).on("click", ".remove-bcc-group", function () { + const groupId = $(this).attr("data-group-id"); + $( + '#bcc-filter-groups input[type="checkbox"][id="' + groupId + '"]' + ).trigger("click"); + $(this).parent().remove(); + }); + + $(document).on( + "change", + '#bcc-filter-groups input[type="checkbox"]', + function () { + const param = "target-groups[]="; + var filteredGroups = []; + + $('#bcc-filter-groups input[type="checkbox"]').each(function () { + if (this.checked) filteredGroups.push(this.value); + }); + + const url = window.location.href.split("?")[0]; + const queryParams = filteredGroups.length + ? "?" + param + filteredGroups.join("&" + param) + : ""; + + if (history.pushState) { + history.pushState(null, null, url + queryParams); + location.reload(); + } + } + ); +}); diff --git a/plugins/bcc-login/src/visibility.css b/plugins/bcc-login/src/visibility.css index 3a169fc..f3adc19 100644 --- a/plugins/bcc-login/src/visibility.css +++ b/plugins/bcc-login/src/visibility.css @@ -1,7 +1,6 @@ -.target-audience { - margin-top: 20px; +.bcc-groups__search.components-base-control { + margin-bottom: 24px !important; } - -.block-editor-block-inspector .target-audience .components-base-control { - margin-bottom: 0; +.bcc-groups__checkbox.components-base-control { + margin-bottom: 0.5rem !important; } \ No newline at end of file diff --git a/plugins/bcc-login/src/visibility.js b/plugins/bcc-login/src/visibility.js index 70e2bda..67ca502 100644 --- a/plugins/bcc-login/src/visibility.js +++ b/plugins/bcc-login/src/visibility.js @@ -1,6 +1,12 @@ +import { useState } from "react"; import { __, sprintf } from "@wordpress/i18n"; import { addFilter } from "@wordpress/hooks"; -import { PanelBody } from "@wordpress/components"; +import { + PanelBody, + PanelRow, + CheckboxControl, + SearchControl, +} from "@wordpress/components"; import { registerPlugin } from "@wordpress/plugins"; import { InspectorControls } from "@wordpress/block-editor"; import { PluginPostStatusInfo } from "@wordpress/edit-post"; @@ -13,6 +19,7 @@ import { } from "@wordpress/compose"; const { defaultLevel, levels, localName } = window.bccLoginPostVisibility; +let filteredSiteGroups = siteGroups; const visibilityOptions = [ { @@ -71,40 +78,53 @@ function GroupsOptions({ instanceId, onUpdateGroup, }) { + const [searchInput, setSearchInput] = useState(""); + if (!siteGroups) { return; } + + // Sort by name + siteGroups.sort((a, b) => { + return a.name.localeCompare(b.name); + }); + return (
{heading &&

{heading}

} - {siteGroups.map((group) => ( -

- { - const index = selectedGroups ? selectedGroups.indexOf(group.uid) : -1; - const newGroups = JSON.parse(JSON.stringify(selectedGroups)); - if (index === -1) { - newGroups.push(group.uid); - } else { - newGroups.splice(index, 1); - } - onUpdateGroup(newGroups); - }} - checked={selectedGroups ? selectedGroups.includes(group.uid) : false} - id={`bcc-login-post-${group.uid}-${instanceId}`} - aria-describedby={`bcc-login-post-${group.uid}-${instanceId}-description`} - className="bcc-groups__dialog-radio" - /> - -

+ { + setSearchInput(e); + + if (e == "") { + filteredSiteGroups = siteGroups; + } else { + filteredSiteGroups = siteGroups.filter((group) => + group.name.toLowerCase().includes(e.toLowerCase()) + ); + } + }} + /> + {filteredSiteGroups.map((group) => ( + { + const index = selectedGroups + ? selectedGroups.indexOf(group.uid) + : -1; + const newGroups = JSON.parse(JSON.stringify(selectedGroups)); + if (index === -1) { + newGroups.push(group.uid); + } else { + newGroups.splice(index, 1); + } + onUpdateGroup(newGroups); + }} + checked={selectedGroups ? selectedGroups.includes(group.uid) : false} + /> ))}
); @@ -190,17 +210,19 @@ addFilter( }} {...props} /> - { - setAttributes({ - bccGroups: value, - }); - }} - {...props} - /> + + { + setAttributes({ + bccGroups: value, + }); + }} + {...props} + /> +