diff --git a/config/integrations/ultimatemember.php b/config/integrations/ultimatemember.php new file mode 100644 index 000000000..434446afe --- /dev/null +++ b/config/integrations/ultimatemember.php @@ -0,0 +1,99 @@ + [ + 'default' => 'no', + 'label' => _x('Enable Integration?', 'admin-text', 'site-reviews'), + 'sanitizer' => 'text', + 'tooltip' => sprintf(_x('This will enable the Ultimate Member integration with Site Reviews.', 'admin-text', 'site-reviews'), + sprintf('%s', glsr_admin_url('tools', 'general'), _x('Import Reviews', 'admin-text', 'site-reviews')) + ), + 'type' => 'yes_no', + ], + 'settings.integrations.ultimatemember.display_directory_ratings' => [ + 'default' => 'no', + 'depends_on' => [ + 'settings.integrations.ultimatemember.enabled' => ['yes'], + ], + 'label' => _x('Display Directory Ratings?', 'admin-text', 'site-reviews'), + 'sanitizer' => 'text', + 'tooltip' => _x('This will display the rating of each person in the Member Directory.', 'admin-text', 'site-reviews'), + 'type' => 'yes_no', + ], + 'settings.integrations.ultimatemember.display_empty' => [ + 'default' => 'no', + 'depends_on' => [ + 'settings.integrations.ultimatemember.enabled' => ['yes'], + 'settings.integrations.ultimatemember.display_directory_ratings' => ['yes'], + ], + 'label' => _x('Display Empty Ratings?', 'admin-text', 'site-reviews'), + 'sanitizer' => 'text', + 'tooltip' => _x('This will display the rating stars even if the member has no reviews.', 'admin-text', 'site-reviews'), + 'type' => 'yes_no', + ], + 'settings.integrations.ultimatemember.sorting' => [ + 'class' => 'regular-text', + 'default' => '', + 'depends_on' => [ + 'settings.integrations.ultimatemember.enabled' => ['yes'], + 'settings.integrations.ultimatemember.display_directory_ratings' => ['yes'], + ], + 'label' => _x('Member Sorting', 'admin-text', 'site-reviews'), + 'options' => [ + '' => _x('Average Rating', 'admin-text', 'site-reviews'), + 'bayesian' => _x('Bayesian Ranking', 'admin-text', 'site-reviews'), + ], + 'sanitizer' => 'text', + 'tooltip' => _x('This is the method used when sorting members by rating on the Members Directory page.', 'admin-text', 'site-reviews'), + 'type' => 'select', + ], + 'settings.integrations.ultimatemember.display_reviews_tab' => [ + 'default' => 'no', + 'depends_on' => [ + 'settings.integrations.ultimatemember.enabled' => ['yes'], + ], + 'label' => _x('Display Reviews Tab?', 'admin-text', 'site-reviews'), + 'sanitizer' => 'text', + 'tooltip' => _x('This will display the reviews tab in member profiles.', 'admin-text', 'site-reviews'), + 'type' => 'yes_no', + ], + 'settings.integrations.ultimatemember.summary' => [ + 'class' => 'large-text', + 'default' => '[site_reviews_summary assigned_users="profile_id"]', + 'depends_on' => [ + 'settings.integrations.ultimatemember.enabled' => ['yes'], + 'settings.integrations.ultimatemember.display_reviews_tab' => ['yes'], + ], + 'label' => _x('Summary Shortcode', 'admin-text', 'site-reviews'), + 'placeholder' => '[site_reviews_summary assigned_users="profile_id"]', + 'sanitizer' => 'text', + 'tooltip' => _x('Enter the rating summary shortcode used on the profile page', 'admin-text', 'site-reviews'), + 'type' => 'text', + ], + 'settings.integrations.ultimatemember.reviews' => [ + 'class' => 'large-text', + 'default' => '[site_reviews assigned_users="profile_id" hide="assigned_links" pagination="loadmore"]', + 'depends_on' => [ + 'settings.integrations.ultimatemember.enabled' => ['yes'], + 'settings.integrations.ultimatemember.display_reviews_tab' => ['yes'], + ], + 'label' => _x('Reviews Shortcode', 'admin-text', 'site-reviews'), + 'placeholder' => '[site_reviews assigned_users="profile_id" hide="assigned_links" pagination="loadmore"]', + 'sanitizer' => 'text', + 'tooltip' => _x('Enter the latest reviews shortcode used on the profile page', 'admin-text', 'site-reviews'), + 'type' => 'text', + ], + 'settings.integrations.ultimatemember.form' => [ + 'class' => 'large-text', + 'default' => '[site_reviews_form assigned_users="profile_id"]', + 'depends_on' => [ + 'settings.integrations.ultimatemember.enabled' => ['yes'], + 'settings.integrations.ultimatemember.display_reviews_tab' => ['yes'], + ], + 'label' => _x('Form Shortcode', 'admin-text', 'site-reviews'), + 'placeholder' => '[site_reviews_form assigned_users="profile_id"]', + 'sanitizer' => 'text', + 'tooltip' => _x('Enter the form shortcode used on the profile page', 'admin-text', 'site-reviews'), + 'type' => 'text', + ], +]; diff --git a/languages/site-reviews-en_US.mo b/languages/site-reviews-en_US.mo index d7a1c0acf..c89eeda78 100644 Binary files a/languages/site-reviews-en_US.mo and b/languages/site-reviews-en_US.mo differ diff --git a/languages/site-reviews-en_US.po b/languages/site-reviews-en_US.po index 50ccd5a49..07c469812 100644 --- a/languages/site-reviews-en_US.po +++ b/languages/site-reviews-en_US.po @@ -2085,11 +2085,21 @@ msgctxt "admin-text" msgid "Terms Accepted" msgstr "Terms Accepted" -#: config/integrations/woocommerce.php:6 +#: config/integrations/ultimatemember.php:6, config/integrations/woocommerce.php:6 msgctxt "admin-text" msgid "Enable Integration?" msgstr "Enable Integration?" +#: config/integrations/ultimatemember.php:8 +msgctxt "admin-text" +msgid "This will enable the Ultimate Member integration with Site Reviews." +msgstr "This will enable the Ultimate Member integration with Site Reviews." + +#: config/integrations/ultimatemember.php:9, config/integrations/woocommerce.php:9, views/integrations/woocommerce/tools/import-product-reviews.php:34, views/pages/tools/general/import-reviews.php:6, views/pages/tools/general/import-reviews.php:113 +msgctxt "admin-text" +msgid "Import Reviews" +msgstr "Import Reviews" + #: config/integrations/woocommerce.php:8 msgctxt "admin-text" msgid "" @@ -2103,11 +2113,6 @@ msgstr "" "need to first export them to a CSV file, and then import them using the %s " "tool." -#: config/integrations/woocommerce.php:9, views/integrations/woocommerce/tools/import-product-reviews.php:34, views/pages/tools/general/import-reviews.php:6, views/pages/tools/general/import-reviews.php:113 -msgctxt "admin-text" -msgid "Import Reviews" -msgstr "Import Reviews" - #: config/integrations/woocommerce.php:19 msgctxt "admin-text" msgid "Rating Style" @@ -2982,7 +2987,7 @@ msgctxt "admin-text" msgid "Tools" msgstr "Tools" -#: plugin/Controllers/MenuController.php:53, plugin/Controllers/MenuController.php:115, plugin/Controllers/MenuController.php:139 +#: plugin/Controllers/MenuController.php:53, plugin/Controllers/MenuController.php:115, plugin/Controllers/MenuController.php:140 msgctxt "admin-text" msgid "Addons" msgstr "Addons" @@ -3017,7 +3022,7 @@ msgctxt "admin-text" msgid "API" msgstr "API" -#: plugin/Controllers/MenuController.php:134, plugin/Controllers/MenuController.php:160 +#: plugin/Controllers/MenuController.php:134, plugin/Controllers/MenuController.php:161 msgctxt "admin-text" msgid "General" msgstr "General" @@ -3037,27 +3042,32 @@ msgctxt "admin-text" msgid "Schema" msgstr "Schema" -#: plugin/Controllers/MenuController.php:140 +#: plugin/Controllers/MenuController.php:139 +msgctxt "admin-text" +msgid "Integrations" +msgstr "Integrations" + +#: plugin/Controllers/MenuController.php:141 msgctxt "admin-text" msgid "Licenses" msgstr "Licenses" -#: plugin/Controllers/MenuController.php:161 +#: plugin/Controllers/MenuController.php:162 msgctxt "admin-text" msgid "Scheduled Actions" msgstr "Scheduled Actions" -#: plugin/Controllers/MenuController.php:162, views/pages/tools/sync.php:58 +#: plugin/Controllers/MenuController.php:163, views/pages/tools/sync.php:58 msgctxt "admin-text" msgid "Sync Reviews" msgstr "Sync Reviews" -#: plugin/Controllers/MenuController.php:163 +#: plugin/Controllers/MenuController.php:164 msgctxt "admin-text" msgid "Console" msgstr "Console" -#: plugin/Controllers/MenuController.php:164 +#: plugin/Controllers/MenuController.php:165 msgctxt "admin-text" msgid "System Info" msgstr "System Info" @@ -4643,6 +4653,21 @@ msgctxt "admin-text" msgid "Unapproved Review (Site Reviews)" msgstr "Unapproved Review (Site Reviews)" +#: plugin/Integrations/UltimateMember/DirectoryController.php:38, plugin/Integrations/UltimateMember/ProfileController.php:38 +msgctxt "admin-text" +msgid "Site Reviews: Display User Rating" +msgstr "Site Reviews: Display User Rating" + +#: plugin/Integrations/UltimateMember/DirectoryController.php:49, plugin/Integrations/UltimateMember/ProfileController.php:49 +msgctxt "admin-text" +msgid "Site Reviews: Highest rated first" +msgstr "Site Reviews: Highest rated first" + +#: plugin/Integrations/UltimateMember/DirectoryController.php:50, plugin/Integrations/UltimateMember/ProfileController.php:50 +msgctxt "admin-text" +msgid "Site Reviews: Lowest rated first" +msgstr "Site Reviews: Lowest rated first" + #: plugin/Modules/Html/TemplateTags.php:144 msgctxt "admin-text" msgid "View the review in WordPress →" diff --git a/languages/site-reviews.pot b/languages/site-reviews.pot index 79ead1507..f6387dcc8 100644 --- a/languages/site-reviews.pot +++ b/languages/site-reviews.pot @@ -1567,21 +1567,26 @@ msgstr "" msgid "This review is based on my own experience and is my genuine opinion." msgstr "" -#: config/integrations/woocommerce.php:6 +#: config/integrations/ultimatemember.php:6, config/integrations/woocommerce.php:6 msgctxt "admin-text" msgid "Enable Integration?" msgstr "" -#: config/integrations/woocommerce.php:8 +#: config/integrations/ultimatemember.php:8 msgctxt "admin-text" -msgid "This will completely replace the default WooCommerce review system with Site Reviews. If you have existing WooCommerce comment reviews, you may need to first export them to a CSV file, and then import them using the %s tool." +msgid "This will enable the Ultimate Member integration with Site Reviews." msgstr "" -#: config/integrations/woocommerce.php:9, views/integrations/woocommerce/tools/import-product-reviews.php:34, views/pages/tools/general/import-reviews.php:6, views/pages/tools/general/import-reviews.php:113 +#: config/integrations/ultimatemember.php:9, config/integrations/woocommerce.php:9, views/integrations/woocommerce/tools/import-product-reviews.php:34, views/pages/tools/general/import-reviews.php:6, views/pages/tools/general/import-reviews.php:113 msgctxt "admin-text" msgid "Import Reviews" msgstr "" +#: config/integrations/woocommerce.php:8 +msgctxt "admin-text" +msgid "This will completely replace the default WooCommerce review system with Site Reviews. If you have existing WooCommerce comment reviews, you may need to first export them to a CSV file, and then import them using the %s tool." +msgstr "" + #: config/integrations/woocommerce.php:19 msgctxt "admin-text" msgid "Rating Style" @@ -2428,7 +2433,7 @@ msgctxt "admin-text" msgid "Tools" msgstr "" -#: plugin/Controllers/MenuController.php:53, plugin/Controllers/MenuController.php:115, plugin/Controllers/MenuController.php:139 +#: plugin/Controllers/MenuController.php:53, plugin/Controllers/MenuController.php:115, plugin/Controllers/MenuController.php:140 msgctxt "admin-text" msgid "Addons" msgstr "" @@ -2463,7 +2468,7 @@ msgctxt "admin-text" msgid "API" msgstr "" -#: plugin/Controllers/MenuController.php:134, plugin/Controllers/MenuController.php:160 +#: plugin/Controllers/MenuController.php:134, plugin/Controllers/MenuController.php:161 msgctxt "admin-text" msgid "General" msgstr "" @@ -2483,27 +2488,32 @@ msgctxt "admin-text" msgid "Schema" msgstr "" -#: plugin/Controllers/MenuController.php:140 +#: plugin/Controllers/MenuController.php:139 +msgctxt "admin-text" +msgid "Integrations" +msgstr "" + +#: plugin/Controllers/MenuController.php:141 msgctxt "admin-text" msgid "Licenses" msgstr "" -#: plugin/Controllers/MenuController.php:161 +#: plugin/Controllers/MenuController.php:162 msgctxt "admin-text" msgid "Scheduled Actions" msgstr "" -#: plugin/Controllers/MenuController.php:162, views/pages/tools/sync.php:58 +#: plugin/Controllers/MenuController.php:163, views/pages/tools/sync.php:58 msgctxt "admin-text" msgid "Sync Reviews" msgstr "" -#: plugin/Controllers/MenuController.php:163 +#: plugin/Controllers/MenuController.php:164 msgctxt "admin-text" msgid "Console" msgstr "" -#: plugin/Controllers/MenuController.php:164 +#: plugin/Controllers/MenuController.php:165 msgctxt "admin-text" msgid "System Info" msgstr "" @@ -4738,6 +4748,21 @@ msgctxt "admin-text" msgid "Unapproved Review (Site Reviews)" msgstr "" +#: plugin/Integrations/UltimateMember/DirectoryController.php:38, plugin/Integrations/UltimateMember/ProfileController.php:38 +msgctxt "admin-text" +msgid "Site Reviews: Display User Rating" +msgstr "" + +#: plugin/Integrations/UltimateMember/DirectoryController.php:49, plugin/Integrations/UltimateMember/ProfileController.php:49 +msgctxt "admin-text" +msgid "Site Reviews: Highest rated first" +msgstr "" + +#: plugin/Integrations/UltimateMember/DirectoryController.php:50, plugin/Integrations/UltimateMember/ProfileController.php:50 +msgctxt "admin-text" +msgid "Site Reviews: Lowest rated first" +msgstr "" + #: plugin/Modules/Html/Form.php:24 msgid "Submit Form" msgstr "" diff --git a/plugin/Database/CountManager.php b/plugin/Database/CountManager.php index b514d269d..ef5745d6c 100644 --- a/plugin/Database/CountManager.php +++ b/plugin/Database/CountManager.php @@ -3,6 +3,7 @@ namespace GeminiLabs\SiteReviews\Database; use GeminiLabs\SiteReviews\Database; +use GeminiLabs\SiteReviews\Helpers\Cast; use GeminiLabs\SiteReviews\Helpers\Str; use GeminiLabs\SiteReviews\Modules\Rating; @@ -21,6 +22,21 @@ public function posts(int $postId): void glsr()->action('ratings/count/post', $postId, $counts); } + public function postsAverage(int $postId): float + { + return Cast::toFloat(get_post_meta($postId, static::META_AVERAGE, true)); + } + + public function postsRanking(int $postId): float + { + return Cast::toFloat(get_post_meta($postId, static::META_RANKING, true)); + } + + public function postsReviews(int $postId): int + { + return Cast::toInt(get_post_meta($postId, static::META_REVIEWS, true)); + } + public function recalculate(): void { $this->recalculateFor('post'); @@ -53,6 +69,21 @@ public function terms(int $termId): void glsr()->action('ratings/count/term', $termId, $counts); } + public function termsAverage(int $termId): float + { + return Cast::toFloat(get_term_meta($termId, static::META_AVERAGE, true)); + } + + public function termsRanking(int $termId): float + { + return Cast::toFloat(get_term_meta($termId, static::META_RANKING, true)); + } + + public function termsReviews(int $termId): int + { + return Cast::toInt(get_term_meta($termId, static::META_REVIEWS, true)); + } + public function users(int $userId): void { $counts = glsr_get_ratings(['assigned_users' => $userId]); @@ -62,6 +93,21 @@ public function users(int $userId): void glsr()->action('ratings/count/user', $userId, $counts); } + public function usersAverage(int $userId): float + { + return Cast::toFloat(get_user_meta($userId, static::META_AVERAGE, true)); + } + + public function usersRanking(int $userId): float + { + return Cast::toFloat(get_user_meta($userId, static::META_RANKING, true)); + } + + public function usersReviews(int $userId): int + { + return Cast::toInt(get_user_meta($userId, static::META_REVIEWS, true)); + } + protected function metaId(string $metaGroup): string { return "{$metaGroup}_id"; diff --git a/plugin/Integrations/UltimateMember/Controller.php b/plugin/Integrations/UltimateMember/Controller.php deleted file mode 100644 index 97c7f40a1..000000000 --- a/plugin/Integrations/UltimateMember/Controller.php +++ /dev/null @@ -1,36 +0,0 @@ -author_id) { - return $defaultUrl; - } - if ('none' !== $type && $url === $defaultUrl) { - return ''; - } - return $url; - } - - /** - * @filter site-reviews/assigned_users/profile_id - */ - public function filterProfileId(int $profileId): int - { - if (empty($profileId)) { - return (int) um_get_requested_user(); - } - return $profileId; - } -} diff --git a/plugin/Integrations/UltimateMember/Controllers/Controller.php b/plugin/Integrations/UltimateMember/Controllers/Controller.php new file mode 100644 index 000000000..68d2f769e --- /dev/null +++ b/plugin/Integrations/UltimateMember/Controllers/Controller.php @@ -0,0 +1,137 @@ +author_id) { + return $defaultUrl; + } + if ('none' !== $type && $url === $defaultUrl) { + return ''; + } + return $url; + } + + /** + * @filter site-reviews/enqueue/public/inline-styles + */ + public function filterInlineStyles(string $css): string + { + if (glsr_get_option('integrations.ultimatemember.display_directory_ratings', false, 'bool')) { + $css .= '.um-directory .um-members-grid .um-member-rating:has(.glsr-star-rating) {display:flex; justify-content:center;}'; + $css .= '.um-directory .um-members-list .um-member-rating:has(.glsr-star-rating) {display:flex;}'; + $css .= '.um-directory .glsr-star-rating {margin:3px 0;}'; + } + if (glsr_get_option('integrations.ultimatemember.display_reviews_tab', false, 'bool')) { + $css .= '.um-reviews-summary .glsr-summary-text {--glsr-summary-text: var(--glsr-text-base);}'; + $css .= '.um-reviews-summary {padding-top:var(--glsr-gap-lg); padding-bottom:var(--glsr-gap-xl);}'; + $css .= '.um-reviews-form:has(div) {border-top: 3px solid #eee; padding:var(--glsr-gap-xl) 0;}'; + $css .= '.um-reviews-reviews:has(.glsr-reviews) {border-top: 3px solid #eee; padding-top:var(--glsr-gap-xl);}'; + } + return $css; + } + + /** + * @filter site-reviews/assigned_users/profile_id + */ + public function filterProfileId(int $profileId): int + { + if (empty($profileId)) { + return (int) um_get_requested_user(); + } + return $profileId; + } + + /** + * @filter site-reviews/settings + */ + public function filterSettings(array $settings): array + { + return array_merge(glsr()->config('integrations/ultimatemember'), $settings); + } + + /** + * @filter site-reviews/settings/sanitize + */ + public function filterSettingsCallback(array $settings, array $input): array + { + $enabled = Arr::get($input, 'settings.integrations.ultimatemember.enabled'); + if ('yes' === $enabled && !$this->gatekeeper()->allows()) { // this renders any error notices + $settings = Arr::set($settings, 'settings.integrations.ultimatemember.enabled', 'no'); + } + $shortcodes = [ + 'form' => 'site_reviews_form', + 'reviews' => 'site_reviews', + 'summary' => 'site_reviews_summary', + ]; + foreach ($shortcodes as $key => $shortcode) { + $path = "settings.integrations.ultimatemember.{$key}"; + $value = Arr::get($input, $path); + if (1 !== preg_match("/^\[{$shortcode}(\s[^\]]*\]|\])$/", $value)) { + continue; + } + if (!str_contains($value, 'assigned_users')) { + $value = str_replace($shortcode, sprintf('%s assigned_users="profile_id"', $shortcode), $value); + $settings = Arr::set($settings, $path, $value); + } + } + return $settings; + } + + /** + * @filter site-reviews/integration/subsubsub + */ + public function filterSubsubsub(array $subsubsub): array + { + $subsubsub['ultimatemember'] = 'Ultimate Member'; + return $subsubsub; + } + + /** + * @action admin_init + */ + public function renderNotice(): void + { + if (glsr_get_option('integrations.ultimatemember.enabled', false, 'bool')) { + $this->gatekeeper()->allows(); // this renders any error notices + } + } + + /** + * @action site-reviews/settings/ultimatemember + */ + public function renderSettings(string $rows): void + { + glsr(Template::class)->render('integrations/ultimatemember/settings', [ + 'context' => [ + 'rows' => $rows, + ], + ]); + } + + protected function gatekeeper(): Gatekeeper + { + return new Gatekeeper([ + 'ultimate-member/ultimate-member.php' => [ + 'minimum_version' => '2.5', + 'name' => 'Ultimate Member', + 'plugin_uri' => 'https://wordpress.org/plugins/ultimate-member/', + 'untested_version' => '3.0', + ], + ]); + } +} diff --git a/plugin/Integrations/UltimateMember/Controllers/DirectoryController.php b/plugin/Integrations/UltimateMember/Controllers/DirectoryController.php new file mode 100644 index 000000000..1db401f9b --- /dev/null +++ b/plugin/Integrations/UltimateMember/Controllers/DirectoryController.php @@ -0,0 +1,136 @@ +usersReviews($userId); + if (0 < $total || glsr_get_option('integrations.ultimatemember.display_empty', false, 'bool')) { + $rating = glsr(CountManager::class)->usersAverage($userId); + $html = glsr(Builder::class)->div([ + 'class' => 'um-member-rating', + 'text' => glsr_star_rating($rating, $total), + ]); + } + $data['glsr_rating_html'] = $html; + return $data; + } + + /** + * @filter um_admin_extend_directory_options_profile + */ + public function filterDirectoryProfileOptions(array $fields): array + { + $fields[] = [ + 'id' => '_um_glsr_display_user_rating', + 'type' => 'checkbox', + 'label' => _x('Site Reviews: Display User Rating', 'admin-text', 'site-reviews'), + 'value' => UM()->query()->get_meta_value('_um_glsr_display_user_rating', null, 'na'), + ]; + return $fields; + } + + /** + * @filter um_members_directory_sort_fields + */ + public function filterDirectoryProfileSortOptions(array $options): array + { + $options['glsr_highest_rated'] = _x('Site Reviews: Highest rated first', 'admin-text', 'site-reviews'); + $options['glsr_lowest_rated'] = _x('Site Reviews: Lowest rated first', 'admin-text', 'site-reviews'); + return $options; + } + + /** + * Used when the UM "Custom usermeta table" setting is disabled. + * + * @param string $sortby + * + * @filter um_modify_sortby_parameter + */ + public function filterDirectorySortBy(array $queryArgs, $sortby): array + { + if (!in_array($sortby, ['glsr_highest_rated', 'glsr_lowest_rated'])) { + return $queryArgs; + } + $order = 'glsr_highest_rated' === $sortby ? 'DESC' : 'ASC'; + $sortKey = 'bayesian' === glsr_get_option('integrations.ultimatemember.sorting') + ? CountManager::META_RANKING + : CountManager::META_AVERAGE; + $queryArgs['meta_query'] ??= []; + $queryArgs['meta_query'][] = [ + 'relation' => 'OR', + [ + 'compare' => 'NOT EXISTS', + 'key' => $sortKey, + 'type' => 'NUMERIC', + ], + '_rating_key' => [ + 'compare' => 'EXISTS', + 'key' => $sortKey, + 'type' => 'NUMERIC', + ], + ]; + $queryArgs['orderby'] = [ + '_rating_key' => $order, + 'user_registered' => 'DESC', + ]; + unset($queryArgs['order']); + return $queryArgs; + } + + /** + * Used when the UM "Custom usermeta table" setting is enabled. + * + * @param \um\core\Member_Directory_Meta $query + * @param array $directoryData + * @param string $sortby + * + * @action um_pre_users_query + */ + public function modifyQuerySortby($query, $directoryData, $sortby): void + { + if (!in_array($sortby, ['glsr_highest_rated', 'glsr_lowest_rated'])) { + return; + } + $order = esc_sql('glsr_highest_rated' === $sortby ? 'DESC' : 'ASC'); + $sortKey = 'bayesian' === glsr_get_option('integrations.ultimatemember.sorting') + ? CountManager::META_RANKING + : CountManager::META_AVERAGE; + $query->joins[] = glsr(Query::class)->sql( + "LEFT JOIN table|usermeta AS glsr_user_meta ON (glsr_user_meta.user_id = u.ID AND glsr_user_meta.meta_key = %s)", + $sortKey + ); + $query->sql_order = " ORDER BY CAST(glsr_user_meta.meta_value AS SIGNED) {$order}, u.user_registered DESC"; + } + + /** + * @param array $args + * + * @action um_members_just_after_name_tmpl + * @action um_members_list_after_user_name_tmpl + */ + public function modifyTmpl($args): void + { + $displayRating = Arr::get($args, 'glsr_display_user_rating'); + if (empty($displayRating)) { + return; + } + echo "<# if ('undefined' !== typeof user.glsr_rating_html) { #>{{{user.glsr_rating_html}}}<# } #>"; + } +} diff --git a/plugin/Integrations/UltimateMember/Controllers/ProfileController.php b/plugin/Integrations/UltimateMember/Controllers/ProfileController.php new file mode 100644 index 000000000..f14c3e9cd --- /dev/null +++ b/plugin/Integrations/UltimateMember/Controllers/ProfileController.php @@ -0,0 +1,137 @@ + 'um-faicon-star', + 'name' => __('Reviews', 'site-reviews'), + ]; + return $tabs; + } + + /** + * @filter site-reviews/reviews/fallback + */ + public function filterReviewsFallback(string $fallback, array $args): string + { + if ($args['fallback'] !== __('There are no reviews yet. Be the first one to write one.', 'site-reviews')) { + return $fallback; + } + $value = get_current_user_id() === um_get_requested_user() + ? __('You have not received any reviews.', 'site-reviews') + : __('This person has not received any reviews.', 'site-reviews'); + return glsr(Builder::class)->p([ + 'class' => 'glsr-no-margins', + 'text' => $value, + ]); + } + + /** + * @filter site-reviews/summary/value/percentages + */ + public function filterSummaryPercentagesValue(string $value, TagContract $tag): string + { + if (!empty(array_sum($tag->ratings))) { + return $value; + } + return ''; + } + + /** + * @filter site-reviews/summary/value/text + */ + public function filterSummaryRatingValue(string $value, TagContract $tag): string + { + $value = get_current_user_id() === um_get_requested_user() + ? __('Your rating', 'site-reviews') + : __('User rating', 'site-reviews'); + return glsr(Builder::class)->h4($value); + } + + /** + * @filter site-reviews/summary/value/rating + */ + public function filterSummaryTextValue(string $value, TagContract $tag): string + { + if (!empty(array_sum($tag->ratings))) { + return $value; + } + if (get_current_user_id() === um_get_requested_user()) { + return __('No one has reviewed you yet.', 'site-reviews'); + } + return __('No one has reviewed this person yet.', 'site-reviews'); + } + + /** + * @action um_profile_content_user_reviews + */ + public function renderReviewsTab(): void + { + if (!glsr_get_option('integrations.ultimatemember.display_reviews_tab', false, 'bool')) { + return; + } + glsr(Template::class)->render('templates/ultimatemember/reviews', [ + 'context' => [ + 'form' => $this->shortcodeForm(), + 'reviews' => $this->shortcodeReviews(), + 'summary' => $this->shortcodeSummary(), + ], + ]); + } + + protected function shortcodeForm(): string + { + if (!is_user_logged_in()) { + $text = sprintf(__('You must be %s to review this person.', 'site-reviews'), glsr(SiteReviewsFormShortcode::class)->loginLink()); + return glsr(Template::class)->build('templates/login-register', [ + 'context' => compact('text'), + ]); + } else { + $ratings = glsr_get_ratings([ + 'assigned_users' => um_get_requested_user(), + 'status' => 'all', + 'user__in' => get_current_user_id(), + ]); + if (0 < $ratings->reviews) { + return ''; + } + } + return do_shortcode(glsr_get_option('integrations.ultimatemember.form')); + } + + protected function shortcodeReviews(): string + { + add_filter('site-reviews/reviews/fallback', [$this, 'filterReviewsFallback'], 20, 2); + $shortcode = do_shortcode(glsr_get_option('integrations.ultimatemember.reviews')); + remove_filter('site-reviews/reviews/fallback', [$this, 'filterReviewsFallback'], 20); + return $shortcode; + } + + protected function shortcodeSummary(): string + { + add_filter('site-reviews/summary/value/percentages', [$this, 'filterSummaryPercentagesValue'], 20, 2); + add_filter('site-reviews/summary/value/rating', [$this, 'filterSummaryRatingValue'], 20, 2); + add_filter('site-reviews/summary/value/text', [$this, 'filterSummaryTextValue'], 20, 2); + $shortcode = do_shortcode(glsr_get_option('integrations.ultimatemember.summary')); + remove_filter('site-reviews/summary/value/percentages', [$this, 'filterSummaryPercentagesValue'], 20); + remove_filter('site-reviews/summary/value/rating', [$this, 'filterSummaryRatingValue'], 20); + remove_filter('site-reviews/summary/value/text', [$this, 'filterSummaryTextValue'], 20); + return $shortcode; + } +} diff --git a/plugin/Integrations/UltimateMember/Hooks.php b/plugin/Integrations/UltimateMember/Hooks.php index 56577ee74..cb067e22b 100644 --- a/plugin/Integrations/UltimateMember/Hooks.php +++ b/plugin/Integrations/UltimateMember/Hooks.php @@ -3,23 +3,57 @@ namespace GeminiLabs\SiteReviews\Integrations\UltimateMember; use GeminiLabs\SiteReviews\Hooks\AbstractHooks; +use GeminiLabs\SiteReviews\Integrations\UltimateMember\Controllers\Controller; +use GeminiLabs\SiteReviews\Integrations\UltimateMember\Controllers\DirectoryController; +use GeminiLabs\SiteReviews\Integrations\UltimateMember\Controllers\ProfileController; class Hooks extends AbstractHooks { public function run(): void { - if (!$this->isInstalled()) { - return; - } $this->hook(Controller::class, [ - ['filterAvatarUrl', 'site-reviews/avatar/generate', 10, 2], - ['filterProfileId', 'site-reviews/assigned_users/profile_id', 5], + ['filterSettings', 'site-reviews/settings'], + ['filterSettingsCallback', 'site-reviews/settings/sanitize', 10, 2], + ['filterSubsubsub', 'site-reviews/integration/subsubsub'], + ['renderNotice', 'admin_init'], + ['renderSettings', 'site-reviews/settings/ultimatemember'], ]); + if ($this->isInstalled()) { + $this->hook(Controller::class, [ + ['filterAvatarUrl', 'site-reviews/avatar/generate', 10, 2], + ['filterProfileId', 'site-reviews/assigned_users/profile_id', 5], + ]); + } + if ($this->isEnabled()) { + $this->hook(Controller::class, [ + ['filterInlineStyles', 'site-reviews/enqueue/public/inline-styles'], + ]); + $this->hook(DirectoryController::class, [ + ['filterAjaxMembersData', 'um_ajax_get_members_data', 50, 2], + ['filterDirectoryProfileOptions', 'um_admin_extend_directory_options_profile', 15], + ['filterDirectoryProfileSortOptions', 'um_members_directory_sort_fields'], + ['filterDirectorySortBy', 'um_modify_sortby_parameter', 100, 2], + ['modifyQuerySortby', 'um_pre_users_query', 10, 3], + ['modifyTmpl', 'um_members_just_after_name_tmpl', 1], + ['modifyTmpl', 'um_members_list_after_user_name_tmpl', 1], + ]); + $this->hook(ProfileController::class, [ + ['filterProfileTabs', 'um_user_profile_tabs', 100], + ['renderReviewsTab', 'um_profile_content_user_reviews'], + ]); + } + } + + protected function isEnabled(): bool + { + return 'yes' === $this->option('integrations.ultimatemember.enabled') + && $this->isInstalled(); } protected function isInstalled(): bool { - return function_exists('um_get_default_avatar_uri') + return function_exists('UM') + && function_exists('um_get_default_avatar_uri') && function_exists('um_get_requested_user'); } } diff --git a/plugin/Modules/Html/Tags/SummaryTag.php b/plugin/Modules/Html/Tags/SummaryTag.php index 88cb6bb30..1b0af3b31 100644 --- a/plugin/Modules/Html/Tags/SummaryTag.php +++ b/plugin/Modules/Html/Tags/SummaryTag.php @@ -7,8 +7,7 @@ class SummaryTag extends Tag { - /** @var array */ - protected $ratings; + public array $ratings = []; protected function hideOption(): string { diff --git a/templates/ultimatemember/reviews.php b/templates/ultimatemember/reviews.php new file mode 100644 index 000000000..7e8515b8c --- /dev/null +++ b/templates/ultimatemember/reviews.php @@ -0,0 +1,11 @@ + + +