[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-groups/classes/ -> class-bp-groups-group.php (source)

   1  <?php
   2  /**
   3   * BuddyPress Groups Classes.
   4   *
   5   * @package BuddyPress
   6   * @subpackage GroupsClasses
   7   * @since 1.0.0
   8   */
   9  
  10  // Exit if accessed directly.
  11  defined( 'ABSPATH' ) || exit;
  12  
  13  /**
  14   * BuddyPress Group object.
  15   *
  16   * @since 1.6.0
  17   */
  18  class BP_Groups_Group {
  19  
  20      /**
  21       * ID of the group.
  22       *
  23       * @since 1.6.0
  24       * @var int
  25       */
  26      public $id;
  27  
  28      /**
  29       * User ID of the group's creator.
  30       *
  31       * @since 1.6.0
  32       * @var int
  33       */
  34      public $creator_id;
  35  
  36      /**
  37       * Name of the group.
  38       *
  39       * @since 1.6.0
  40       * @var string
  41       */
  42      public $name;
  43  
  44      /**
  45       * Group slug.
  46       *
  47       * @since 1.6.0
  48       * @var string
  49       */
  50      public $slug;
  51  
  52      /**
  53       * Group description.
  54       *
  55       * @since 1.6.0
  56       * @var string
  57       */
  58      public $description;
  59  
  60      /**
  61       * Group status.
  62       *
  63       * Core statuses are 'public', 'private', and 'hidden'.
  64       *
  65       * @since 1.6.0
  66       * @var string
  67       */
  68      public $status;
  69  
  70      /**
  71       * Parent ID.
  72       *
  73       * ID of parent group, if applicable.
  74       *
  75       * @since 2.7.0
  76       * @var int
  77       */
  78      public $parent_id;
  79  
  80      /**
  81       * Controls whether the group has a forum enabled.
  82       *
  83       * @since 1.6.0
  84       * @since 3.0.0 Previously, this referred to Legacy Forums. It's still used by bbPress 2 for integration.
  85       *
  86       * @var int
  87       */
  88      public $enable_forum;
  89  
  90      /**
  91       * Date the group was created.
  92       *
  93       * @since 1.6.0
  94       * @var string
  95       */
  96      public $date_created;
  97  
  98      /**
  99       * Data about the group's admins.
 100       *
 101       * @since 1.6.0
 102       * @var array
 103       */
 104      protected $admins;
 105  
 106      /**
 107       * Data about the group's moderators.
 108       *
 109       * @since 1.6.0
 110       * @var array
 111       */
 112      protected $mods;
 113  
 114      /**
 115       * Total count of group members.
 116       *
 117       * @since 1.6.0
 118       * @var int
 119       */
 120      protected $total_member_count;
 121  
 122      /**
 123       * Is the current user a member of this group?
 124       *
 125       * @since 1.2.0
 126       * @var bool
 127       */
 128      protected $is_member;
 129  
 130      /**
 131       * Is the current user a member of this group?
 132       * Alias of $is_member for backward compatibility.
 133       *
 134       * @since 2.9.0
 135       * @var bool
 136       */
 137      protected $is_user_member;
 138  
 139      /**
 140       * Does the current user have an outstanding invitation to this group?
 141       *
 142       * @since 1.9.0
 143       * @var bool
 144       */
 145      protected $is_invited;
 146  
 147      /**
 148       * Does the current user have a pending membership request to this group?
 149       *
 150       * @since 1.9.0
 151       * @var bool
 152       */
 153      protected $is_pending;
 154  
 155      /**
 156       * Timestamp of the last activity that happened in this group.
 157       *
 158       * @since 1.2.0
 159       * @var string
 160       */
 161      protected $last_activity;
 162  
 163      /**
 164       * If this is a private or hidden group, does the current user have access?
 165       *
 166       * @since 1.6.0
 167       * @var bool
 168       */
 169      protected $user_has_access;
 170  
 171      /**
 172       * Can the current user know that this group exists?
 173       *
 174       * @since 2.9.0
 175       * @var bool
 176       */
 177      protected $is_visible;
 178  
 179      /**
 180       * Raw arguments passed to the constructor.
 181       *
 182       * Not currently used by BuddyPress.
 183       *
 184       * @since 2.0.0
 185       * @var array
 186       */
 187      public $args;
 188  
 189      /**
 190       * Constructor method.
 191       *
 192       * @since 1.6.0
 193       *
 194       * @param int|null $id   Optional. If the ID of an existing group is provided,
 195       *                       the object will be pre-populated with info about that group.
 196       * @param array    $args {
 197       *     Array of optional arguments.
 198       *     @type bool $populate_extras Deprecated.
 199       * }
 200       */
 201  	public function __construct( $id = null, $args = array() ) {
 202  
 203          // Deprecated notice about $args.
 204          if ( ! empty( $args ) ) {
 205              _deprecated_argument(
 206                  __METHOD__,
 207                  '1.6.0',
 208                  sprintf(
 209                      /* translators: 1: the name of the function. 2: the name of the file. */
 210                      esc_html__( '%1$s no longer accepts arguments. See the inline documentation at %2$s for more details.', 'buddypress' ),
 211                      __METHOD__,
 212                      __FILE__
 213                  )
 214              );
 215          }
 216  
 217          if ( ! empty( $id ) ) {
 218              $this->id = (int) $id;
 219              $this->populate();
 220          }
 221      }
 222  
 223      /**
 224       * Set up data about the current group.
 225       *
 226       * @since 1.6.0
 227       */
 228  	public function populate() {
 229          global $wpdb;
 230  
 231          // Get BuddyPress.
 232          $bp    = buddypress();
 233  
 234          // Check cache for group data.
 235          $group = wp_cache_get( $this->id, 'bp_groups' );
 236  
 237          // Cache missed, so query the DB.
 238          if ( false === $group ) {
 239              $group = $wpdb->get_row( $wpdb->prepare( "SELECT g.* FROM {$bp->groups->table_name} g WHERE g.id = %d", $this->id ) );
 240  
 241              wp_cache_set( $this->id, $group, 'bp_groups' );
 242          }
 243  
 244          // No group found so set the ID and bail.
 245          if ( empty( $group ) || is_wp_error( $group ) ) {
 246              $this->id = 0;
 247              return;
 248          }
 249  
 250          // Group found so setup the object variables.
 251          $this->id           = (int) $group->id;
 252          $this->creator_id   = (int) $group->creator_id;
 253          $this->name         = stripslashes( $group->name );
 254          $this->slug         = $group->slug;
 255          $this->description  = stripslashes( $group->description );
 256          $this->status       = $group->status;
 257          $this->parent_id    = (int) $group->parent_id;
 258          $this->enable_forum = (int) $group->enable_forum;
 259          $this->date_created = $group->date_created;
 260      }
 261  
 262      /**
 263       * Save the current group to the database.
 264       *
 265       * @since 1.6.0
 266       *
 267       * @return bool True on success, false on failure.
 268       */
 269  	public function save() {
 270          global $wpdb;
 271  
 272          $bp = buddypress();
 273  
 274          $this->creator_id   = apply_filters( 'groups_group_creator_id_before_save',   $this->creator_id,   $this->id );
 275          $this->name         = apply_filters( 'groups_group_name_before_save',         $this->name,         $this->id );
 276          $this->slug         = apply_filters( 'groups_group_slug_before_save',         $this->slug,         $this->id );
 277          $this->description  = apply_filters( 'groups_group_description_before_save',  $this->description,  $this->id );
 278          $this->status       = apply_filters( 'groups_group_status_before_save',       $this->status,       $this->id );
 279          $this->parent_id    = apply_filters( 'groups_group_parent_id_before_save',    $this->parent_id,    $this->id );
 280          $this->enable_forum = apply_filters( 'groups_group_enable_forum_before_save', $this->enable_forum, $this->id );
 281          $this->date_created = apply_filters( 'groups_group_date_created_before_save', $this->date_created, $this->id );
 282  
 283          /**
 284           * Fires before the current group item gets saved.
 285           *
 286           * Please use this hook to filter the properties above. Each part will be passed in.
 287           *
 288           * @since 1.0.0
 289           *
 290           * @param BP_Groups_Group $this Current instance of the group item being saved. Passed by reference.
 291           */
 292          do_action_ref_array( 'groups_group_before_save', array( &$this ) );
 293  
 294          // Groups need at least a name.
 295          if ( empty( $this->name ) ) {
 296              return false;
 297          }
 298  
 299          // Set slug with group title if not passed.
 300          if ( empty( $this->slug ) ) {
 301              $this->slug = sanitize_title( $this->name );
 302          }
 303  
 304          // Sanity check.
 305          if ( empty( $this->slug ) ) {
 306              return false;
 307          }
 308  
 309          // Check for slug conflicts if creating new group.
 310          if ( empty( $this->id ) ) {
 311              $this->slug = groups_check_slug( $this->slug );
 312          }
 313  
 314          if ( !empty( $this->id ) ) {
 315              $sql = $wpdb->prepare(
 316                  "UPDATE {$bp->groups->table_name} SET
 317                      creator_id = %d,
 318                      name = %s,
 319                      slug = %s,
 320                      description = %s,
 321                      status = %s,
 322                      parent_id = %d,
 323                      enable_forum = %d,
 324                      date_created = %s
 325                  WHERE
 326                      id = %d
 327                  ",
 328                      $this->creator_id,
 329                      $this->name,
 330                      $this->slug,
 331                      $this->description,
 332                      $this->status,
 333                      $this->parent_id,
 334                      $this->enable_forum,
 335                      $this->date_created,
 336                      $this->id
 337              );
 338          } else {
 339              $sql = $wpdb->prepare(
 340                  "INSERT INTO {$bp->groups->table_name} (
 341                      creator_id,
 342                      name,
 343                      slug,
 344                      description,
 345                      status,
 346                      parent_id,
 347                      enable_forum,
 348                      date_created
 349                  ) VALUES (
 350                      %d, %s, %s, %s, %s, %d, %d, %s
 351                  )",
 352                      $this->creator_id,
 353                      $this->name,
 354                      $this->slug,
 355                      $this->description,
 356                      $this->status,
 357                      $this->parent_id,
 358                      $this->enable_forum,
 359                      $this->date_created
 360              );
 361          }
 362  
 363          if ( false === $wpdb->query($sql) )
 364              return false;
 365  
 366          if ( empty( $this->id ) )
 367              $this->id = $wpdb->insert_id;
 368  
 369          /**
 370           * Fires after the current group item has been saved.
 371           *
 372           * @since 1.0.0
 373           *
 374           * @param BP_Groups_Group $this Current instance of the group item that was saved. Passed by reference.
 375           */
 376          do_action_ref_array( 'groups_group_after_save', array( &$this ) );
 377  
 378          wp_cache_delete( $this->id, 'bp_groups' );
 379  
 380          return true;
 381      }
 382  
 383      /**
 384       * Delete the current group.
 385       *
 386       * @since 1.6.0
 387       *
 388       * @return bool True on success, false on failure.
 389       */
 390  	public function delete() {
 391          global $wpdb;
 392  
 393          // Delete groupmeta for the group.
 394          groups_delete_groupmeta( $this->id );
 395  
 396          // Fetch the user IDs of all the members of the group.
 397          $user_ids    = BP_Groups_Member::get_group_member_ids( $this->id );
 398          $user_id_str = esc_sql( implode( ',', wp_parse_id_list( $user_ids ) ) );
 399  
 400          // Modify group count usermeta for members.
 401          $wpdb->query( "UPDATE {$wpdb->usermeta} SET meta_value = meta_value - 1 WHERE meta_key = 'total_group_count' AND user_id IN ( {$user_id_str} )" );
 402  
 403          // Now delete all group member entries.
 404          BP_Groups_Member::delete_all( $this->id );
 405  
 406          /**
 407           * Fires before the deletion of a group.
 408           *
 409           * @since 1.2.0
 410           *
 411           * @param BP_Groups_Group $this     Current instance of the group item being deleted. Passed by reference.
 412           * @param array           $user_ids Array of user IDs that were members of the group.
 413           */
 414          do_action_ref_array( 'bp_groups_delete_group', array( &$this, $user_ids ) );
 415  
 416          wp_cache_delete( $this->id, 'bp_groups' );
 417  
 418          $bp = buddypress();
 419  
 420          // Finally remove the group entry from the DB.
 421          if ( !$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name} WHERE id = %d", $this->id ) ) )
 422              return false;
 423  
 424          return true;
 425      }
 426  
 427      /**
 428       * Magic getter.
 429       *
 430       * @since 2.7.0
 431       *
 432       * @param string $key Property name.
 433       * @return mixed
 434       */
 435  	public function __get( $key ) {
 436          switch ( $key ) {
 437              case 'last_activity' :
 438              case 'total_member_count' :
 439              case 'forum_id' :
 440                  $retval = groups_get_groupmeta( $this->id, $key );
 441  
 442                  if ( 'last_activity' !== $key ) {
 443                      $retval = (int) $retval;
 444                  }
 445  
 446                  return $retval;
 447  
 448              case 'admins' :
 449                  return $this->get_admins();
 450  
 451              case 'mods' :
 452                  return $this->get_mods();
 453  
 454              case 'is_member' :
 455              case 'is_user_member' :
 456                  return $this->get_is_member();
 457  
 458              case 'is_invited' :
 459                  return groups_check_user_has_invite( bp_loggedin_user_id(), $this->id );
 460  
 461              case 'is_pending' :
 462                  return groups_check_for_membership_request( bp_loggedin_user_id(), $this->id );
 463  
 464              case 'user_has_access' :
 465                  return $this->get_user_has_access();
 466  
 467              case 'is_visible' :
 468                  return $this->is_visible();
 469  
 470              default :
 471                  return isset( $this->{$key} ) ? $this->{$key} : null;
 472          }
 473      }
 474  
 475      /**
 476       * Magic issetter.
 477       *
 478       * Used to maintain backward compatibility for properties that are now
 479       * accessible only via magic method.
 480       *
 481       * @since 2.7.0
 482       *
 483       * @param string $key Property name.
 484       * @return bool
 485       */
 486  	public function __isset( $key ) {
 487          switch ( $key ) {
 488              case 'admins' :
 489              case 'is_invited' :
 490              case 'is_member' :
 491              case 'is_user_member' :
 492              case 'is_pending' :
 493              case 'last_activity' :
 494              case 'mods' :
 495              case 'total_member_count' :
 496              case 'user_has_access' :
 497              case 'is_visible' :
 498              case 'forum_id' :
 499                  return true;
 500  
 501              default :
 502                  return isset( $this->{$key} );
 503          }
 504      }
 505  
 506      /**
 507       * Magic setter.
 508       *
 509       * Used to maintain backward compatibility for properties that are now
 510       * accessible only via magic method.
 511       *
 512       * @since 2.7.0
 513       *
 514       * @param string $key   Property name.
 515       * @param mixed  $value Property value.
 516       * @return bool
 517       */
 518  	public function __set( $key, $value ) {
 519          switch ( $key ) {
 520              case 'user_has_access' :
 521                  return $this->user_has_access = (bool) $value;
 522  
 523              default :
 524                  $this->{$key} = $value;
 525          }
 526      }
 527  
 528      /**
 529       * Get a list of the group's admins.
 530       *
 531       * Used to provide cache-friendly access to the 'admins' property of
 532       * the group object.
 533       *
 534       * @since 2.7.0
 535       *
 536       * @return array|null
 537       */
 538  	protected function get_admins() {
 539          if ( isset( $this->admins ) ) {
 540              return $this->admins;
 541          }
 542  
 543          $this->set_up_admins_and_mods();
 544          return $this->admins;
 545      }
 546  
 547      /**
 548       * Get a list of the group's mods.
 549       *
 550       * Used to provide cache-friendly access to the 'mods' property of
 551       * the group object.
 552       *
 553       * @since 2.7.0
 554       *
 555       * @return array|null
 556       */
 557  	protected function get_mods() {
 558          if ( isset( $this->mods ) ) {
 559              return $this->mods;
 560          }
 561  
 562          $this->set_up_admins_and_mods();
 563          return $this->mods;
 564      }
 565  
 566      /**
 567       * Set up admins and mods for the current group object.
 568       *
 569       * Called only when the 'admins' or 'mods' property is accessed.
 570       *
 571       * @since 2.7.0
 572       */
 573  	protected function set_up_admins_and_mods() {
 574          $admin_ids = BP_Groups_Member::get_group_administrator_ids( $this->id );
 575          $admin_ids_plucked = wp_list_pluck( $admin_ids, 'user_id' );
 576  
 577          $mod_ids = BP_Groups_Member::get_group_moderator_ids( $this->id );
 578          $mod_ids_plucked = wp_list_pluck( $mod_ids, 'user_id' );
 579  
 580          $admin_mod_ids = array_merge( $admin_ids_plucked, $mod_ids_plucked );
 581          $admin_mod_users = array();
 582  
 583          if ( ! empty( $admin_mod_ids ) ) {
 584              $admin_mod_users = get_users( array(
 585                  'include' => $admin_mod_ids,
 586                  'blog_id' => null,
 587              ) );
 588          }
 589  
 590          $admin_objects = $mod_objects = array();
 591          foreach ( $admin_mod_users as $admin_mod_user ) {
 592              $obj = new stdClass();
 593              $obj->user_id = $admin_mod_user->ID;
 594              $obj->user_login = $admin_mod_user->user_login;
 595              $obj->user_email = $admin_mod_user->user_email;
 596              $obj->user_nicename = $admin_mod_user->user_nicename;
 597  
 598              if ( in_array( $admin_mod_user->ID, $admin_ids_plucked, true ) ) {
 599                  $obj->is_admin = 1;
 600                  $obj->is_mod = 0;
 601                  $admin_objects[] = $obj;
 602              } else {
 603                  $obj->is_admin = 0;
 604                  $obj->is_mod = 1;
 605                  $mod_objects[] = $obj;
 606              }
 607          }
 608  
 609          $this->admins = $admin_objects;
 610          $this->mods   = $mod_objects;
 611      }
 612  
 613      /**
 614       * Checks whether the logged-in user is a member of the group.
 615       *
 616       * @since 2.7.0
 617       *
 618       * @return bool|int
 619       */
 620  	protected function get_is_member() {
 621          if ( isset( $this->is_member ) ) {
 622              return $this->is_member;
 623          }
 624  
 625          $this->is_member = groups_is_user_member( bp_loggedin_user_id(), $this->id );
 626          return $this->is_member;
 627      }
 628  
 629      /**
 630       * Checks whether the logged-in user has access to the group.
 631       *
 632       * @since 2.7.0
 633       *
 634       * @return bool
 635       */
 636  	protected function get_user_has_access() {
 637          if ( isset( $this->user_has_access ) ) {
 638              return $this->user_has_access;
 639          }
 640  
 641          if ( ( 'private' === $this->status ) || ( 'hidden' === $this->status ) ) {
 642  
 643              // Assume user does not have access to hidden/private groups.
 644              $this->user_has_access = false;
 645  
 646              // Group members or community moderators have access.
 647              if ( ( is_user_logged_in() && $this->get_is_member() ) || bp_current_user_can( 'bp_moderate' ) ) {
 648                  $this->user_has_access = true;
 649              }
 650          } else {
 651              $this->user_has_access = true;
 652          }
 653  
 654          return $this->user_has_access;
 655      }
 656  
 657      /**
 658       * Checks whether the current user can know the group exists.
 659       *
 660       * @since 2.9.0
 661       *
 662       * @return bool
 663       */
 664  	protected function is_visible() {
 665          if ( isset( $this->is_visible ) ) {
 666              return $this->is_visible;
 667          }
 668  
 669          if ( 'hidden' === $this->status ) {
 670  
 671              // Assume user can not know about hidden groups.
 672              $this->is_visible = false;
 673  
 674              // Group members or community moderators have access.
 675              if ( ( is_user_logged_in() && $this->get_is_member() ) || bp_current_user_can( 'bp_moderate' ) ) {
 676                  $this->is_visible = true;
 677              }
 678          } else {
 679              $this->is_visible = true;
 680          }
 681  
 682          return $this->is_visible;
 683      }
 684  
 685      /** Static Methods ****************************************************/
 686  
 687      /**
 688       * Get whether a group exists for a given slug.
 689       *
 690       * @since 1.6.0
 691       * @since 10.0.0 Updated to add the deprecated notice.
 692       *
 693       * @param string      $slug       Slug to check.
 694       * @param string|bool $table_name Deprecated.
 695       * @return int|null|bool False if empty slug, group ID if found; `null` if not.
 696       */
 697  	public static function group_exists( $slug, $table_name = false ) {
 698  
 699          if ( false !== $table_name ) {
 700              _deprecated_argument(
 701                  __METHOD__,
 702                  '1.6.0',
 703                  sprintf(
 704                      /* translators: 1: the name of the method. 2: the name of the file. */
 705                      esc_html__( '%1$s no longer accepts a table name argument. See the inline documentation at %2$s for more details.', 'buddypress' ),
 706                      __METHOD__,
 707                      __FILE__
 708                  )
 709              );
 710          }
 711  
 712          if ( empty( $slug ) ) {
 713              return false;
 714          }
 715  
 716          $groups = self::get(
 717              array(
 718                  'slug'              => $slug,
 719                  'per_page'          => 1,
 720                  'page'              => 1,
 721                  'update_meta_cache' => false,
 722                  'show_hidden'       => true,
 723              )
 724          );
 725  
 726          $group_id = null;
 727          if ( $groups['groups'] ) {
 728              $group_id = current( $groups['groups'] )->id;
 729          }
 730  
 731          return $group_id;
 732      }
 733  
 734      /**
 735       * Get the ID of a group by the group's slug.
 736       *
 737       * Alias of {@link BP_Groups_Group::group_exists()}.
 738       *
 739       * @since 1.6.0
 740       *
 741       * @param string $slug See {@link BP_Groups_Group::group_exists()}.
 742       * @return int|null|bool See {@link BP_Groups_Group::group_exists()}.
 743       */
 744  	public static function get_id_from_slug( $slug ) {
 745          return self::group_exists( $slug );
 746      }
 747  
 748      /**
 749       * Get whether a group exists for an old slug.
 750       *
 751       * @since 2.9.0
 752       *
 753       * @param string      $slug       Slug to check.
 754       *
 755       * @return int|null|false Group ID if found; null if not; false if missing parameters.
 756       */
 757  	public static function get_id_by_previous_slug( $slug ) {
 758          global $wpdb;
 759  
 760          if ( empty( $slug ) ) {
 761              return false;
 762          }
 763  
 764          $args = array(
 765              'meta_query'         => array(
 766                  array(
 767                      'key'   => 'previous_slug',
 768                      'value' => $slug
 769                  ),
 770              ),
 771              'orderby'            => 'meta_id',
 772              'order'              => 'DESC',
 773              'per_page'           => 1,
 774              'page'               => 1,
 775              'update_meta_cache'  => false,
 776              'show_hidden'        => true,
 777          );
 778          $groups = BP_Groups_Group::get( $args );
 779  
 780          $group_id = null;
 781          if ( $groups['groups'] ) {
 782              $group_id = current( $groups['groups'] )->id;
 783          }
 784  
 785          return $group_id;
 786      }
 787  
 788      /**
 789       * Get IDs of users with outstanding invites to a given group from a specified user.
 790       *
 791       * @since 1.6.0
 792       * @since 2.9.0 Added $sent as a parameter.
 793       *
 794       * @param  int      $user_id  ID of the inviting user.
 795       * @param  int      $group_id ID of the group.
 796       * @param  int|null $sent     Query for a specific invite sent status. If 0, this will query for users
 797       *                            that haven't had an invite sent to them yet. If 1, this will query for
 798       *                            users that have had an invite sent to them. If null, no invite status will
 799       *                            queried. Default: null.
 800       * @return array    IDs of users who have been invited to the group by the user but have not
 801       *                  yet accepted.
 802       */
 803  	public static function get_invites( $user_id, $group_id, $sent = null ) {
 804          if ( 0 === $sent ) {
 805              $sent_arg = 'draft';
 806          } else if ( 1 === $sent ) {
 807              $sent_arg = 'sent';
 808          } else {
 809              $sent_arg = 'all';
 810          }
 811  
 812          return groups_get_invites( array(
 813              'item_id'     => $group_id,
 814              'inviter_id'  => $user_id,
 815              'invite_sent' => $sent_arg,
 816              'fields'      => 'user_ids',
 817          ) );
 818      }
 819  
 820      /**
 821       * Get a list of a user's groups, filtered by a search string.
 822       *
 823       * @since 1.6.0
 824       *
 825       * @param string   $filter  Search term. Matches against 'name' and
 826       *                          'description' fields.
 827       * @param int      $user_id ID of the user whose groups are being searched.
 828       *                          Default: the displayed user.
 829       * @param mixed    $order   Not used.
 830       * @param int|null $limit   Optional. The max number of results to return.
 831       *                          Default: null (no limit).
 832       * @param int|null $page    Optional. The page offset of results to return.
 833       *                          Default: null (no limit).
 834       * @return false|array {
 835       *     @type array $groups Array of matched and paginated group IDs.
 836       *     @type int   $total  Total count of groups matching the query.
 837       * }
 838       */
 839  	public static function filter_user_groups( $filter, $user_id = 0, $order = false, $limit = null, $page = null ) {
 840          if ( empty( $user_id ) ) {
 841              $user_id = bp_displayed_user_id();
 842          }
 843  
 844          $args = array(
 845              'search_terms' => $filter,
 846              'user_id'      => $user_id,
 847              'per_page'     => $limit,
 848              'page'         => $page,
 849              'order'        => $order,
 850          );
 851  
 852          $groups = BP_Groups_Group::get( $args );
 853  
 854          // Modify the results to match the old format.
 855          $paged_groups = array();
 856          $i = 0;
 857          foreach ( $groups['groups'] as $group ) {
 858              $paged_groups[ $i ] = new stdClass;
 859              $paged_groups[ $i ]->group_id = $group->id;
 860              $i++;
 861          }
 862  
 863          return array( 'groups' => $paged_groups, 'total' => $groups['total'] );
 864      }
 865  
 866      /**
 867       * Get a list of groups, filtered by a search string.
 868       *
 869       * @since 1.6.0
 870       *
 871       * @param string      $filter  Search term. Matches against 'name' and
 872       *                             'description' fields.
 873       * @param int|null    $limit   Optional. The max number of results to return.
 874       *                             Default: null (no limit).
 875       * @param int|null    $page    Optional. The page offset of results to return.
 876       *                             Default: null (no limit).
 877       * @param string|bool $sort_by Column to sort by. Default: false (default
 878       *        sort).
 879       * @param string|bool $order   ASC or DESC. Default: false (default sort).
 880       * @return array {
 881       *     @type array $groups Array of matched and paginated group IDs.
 882       *     @type int   $total  Total count of groups matching the query.
 883       * }
 884       */
 885  	public static function search_groups( $filter, $limit = null, $page = null, $sort_by = false, $order = false ) {
 886          $args = array(
 887              'search_terms' => $filter,
 888              'per_page'     => $limit,
 889              'page'         => $page,
 890              'orderby'      => $sort_by,
 891              'order'        => $order,
 892          );
 893  
 894          $groups = BP_Groups_Group::get( $args );
 895  
 896          // Modify the results to match the old format.
 897          $paged_groups = array();
 898          $i = 0;
 899          foreach ( $groups['groups'] as $group ) {
 900              $paged_groups[ $i ] = new stdClass;
 901              $paged_groups[ $i ]->group_id = $group->id;
 902              $i++;
 903          }
 904  
 905          return array( 'groups' => $paged_groups, 'total' => $groups['total'] );
 906      }
 907  
 908      /**
 909       * Check for the existence of a slug.
 910       *
 911       * @since 1.6.0
 912       *
 913       * @param string $slug Slug to check.
 914       * @return string|null The slug, if found. Otherwise null.
 915       */
 916  	public static function check_slug( $slug ) {
 917          global $wpdb;
 918  
 919          $bp = buddypress();
 920  
 921          return $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM {$bp->groups->table_name} WHERE slug = %s", $slug ) );
 922      }
 923  
 924      /**
 925       * Get the slug for a given group ID.
 926       *
 927       * @since 1.6.0
 928       *
 929       * @param int $group_id ID of the group.
 930       * @return string|null The slug, if found. Otherwise null.
 931       */
 932  	public static function get_slug( $group_id ) {
 933          global $wpdb;
 934  
 935          $bp = buddypress();
 936  
 937          return $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM {$bp->groups->table_name} WHERE id = %d", $group_id ) );
 938      }
 939  
 940      /**
 941       * Check whether a given group has any members.
 942       *
 943       * @since 1.6.0
 944       *
 945       * @param int $group_id ID of the group.
 946       * @return bool True if the group has members, otherwise false.
 947       */
 948  	public static function has_members( $group_id ) {
 949          global $wpdb;
 950  
 951          $bp = buddypress();
 952  
 953          $members = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->groups->table_name_members} WHERE group_id = %d", $group_id ) );
 954  
 955          if ( empty( $members ) )
 956              return false;
 957  
 958          return true;
 959      }
 960  
 961      /**
 962       * Check whether a group has outstanding membership requests.
 963       *
 964       * @since 1.6.0
 965       *
 966       * @param int $group_id ID of the group.
 967       * @return int|null The number of outstanding requests, or null if
 968       *                  none are found.
 969       */
 970  	public static function has_membership_requests( $group_id ) {
 971          global $wpdb;
 972  
 973          $bp = buddypress();
 974  
 975          return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0", $group_id ) );
 976      }
 977  
 978      /**
 979       * Get outstanding membership requests for a group.
 980       *
 981       * @since 1.6.0
 982       *
 983       * @param int      $group_id ID of the group.
 984       * @param int|null $limit    Optional. Max number of results to return.
 985       *                           Default: null (no limit).
 986       * @param int|null $page     Optional. Page offset of results returned. Default:
 987       *                           null (no limit).
 988       * @return array {
 989       *     @type array $requests The requested page of located requests.
 990       *     @type int   $total    Total number of requests outstanding for the
 991       *                           group.
 992       * }
 993       */
 994  	public static function get_membership_requests( $group_id, $limit = null, $page = null ) {
 995          $args = array(
 996              'item_id' => $group_id
 997          );
 998          if ( $limit ) {
 999              $args['per_page'] = $limit;
1000          }
1001          if ( $page ) {
1002              $args['page'] = $page;
1003          }
1004  
1005          $requests = groups_get_requests( $args );
1006          $total    = count( groups_get_membership_requested_user_ids( $group_id ) );
1007  
1008          return array( 'requests' => $requests, 'total' => $total );
1009      }
1010  
1011      /**
1012       * Query for groups.
1013       *
1014       * @see WP_Meta_Query::queries for a description of the 'meta_query'
1015       *      parameter format.
1016       *
1017       * @since 1.6.0
1018       * @since 2.6.0 Added `$group_type`, `$group_type__in`, and `$group_type__not_in` parameters.
1019       * @since 2.7.0 Added `$update_admin_cache` and `$parent_id` parameters.
1020       * @since 2.8.0 Changed `$search_terms` parameter handling and added `$search_columns` parameter.
1021       * @since 2.9.0 Added `$slug` parameter.
1022       * @since 10.0.0 Added `$date_query` parameter.
1023       *
1024       * @param array $args {
1025       *     Array of parameters. All items are optional.
1026       *     @type string       $type               Optional. Shorthand for certain orderby/order combinations.
1027       *                                            'newest', 'active', 'popular', 'alphabetical', 'random'.
1028       *                                            When present, will override orderby and order params.
1029       *                                            Default: null.
1030       *     @type string       $orderby            Optional. Property to sort by. 'date_created', 'last_activity',
1031       *                                            'total_member_count', 'name', 'random', 'meta_id'.
1032       *                                            Default: 'date_created'.
1033       *     @type string       $order              Optional. Sort order. 'ASC' or 'DESC'. Default: 'DESC'.
1034       *     @type int          $per_page           Optional. Number of items to return per page of results.
1035       *                                            Default: null (no limit).
1036       *     @type int          $page               Optional. Page offset of results to return.
1037       *                                            Default: null (no limit).
1038       *     @type int          $user_id            Optional. If provided, results will be limited to groups
1039       *                                            of which the specified user is a member. Default: null.
1040        *     @type array|string $slug               Optional. Array or comma-separated list of group slugs to limit
1041        *                                            results to.
1042       *                                            Default: false.
1043       *     @type string       $search_terms       Optional. If provided, only groups whose names or descriptions
1044       *                                            match the search terms will be returned. Allows specifying the
1045       *                                            wildcard position using a '*' character before or after the
1046       *                                            string or both. Works in concert with $search_columns.
1047       *                                            Default: false.
1048         *     @type string       $search_columns     Optional. If provided, only apply the search terms to the
1049         *                                            specified columns. Works in concert with $search_terms.
1050         *                                            Default: empty array.
1051       *     @type array|string $group_type         Array or comma-separated list of group types to limit results to.
1052       *     @type array|string $group_type__in     Array or comma-separated list of group types to limit results to.
1053       *     @type array|string $group_type__not_in Array or comma-separated list of group types that will be
1054       *                                            excluded from results.
1055       *     @type array        $meta_query         Optional. An array of meta_query conditions.
1056       *                                            See {@link WP_Meta_Query::queries} for description.
1057       *     @type array        $date_query         Optional. Filter results by group last activity date. See first
1058       *                                            paramter of {@link WP_Date_Query::__construct()} for syntax. Only
1059       *                                            applicable if $type is either 'newest' or 'active'.
1060       *     @type array|string $value              Optional. Array or comma-separated list of group IDs. Results
1061       *                                            will be limited to groups within the list. Default: false.
1062       *     @type array|string $parent_id          Optional. Array or comma-separated list of group IDs. Results
1063       *                                            will be limited to children of the specified groups. Default: null.
1064       *     @type array|string $exclude            Optional. Array or comma-separated list of group IDs.
1065       *                                            Results will exclude the listed groups. Default: false.
1066       *     @type bool         $update_meta_cache  Whether to pre-fetch groupmeta for the returned groups.
1067       *                                            Default: true.
1068       *     @type bool         $update_admin_cache Whether to pre-fetch administrator IDs for the returned
1069       *                                            groups. Default: false.
1070       *     @type bool         $show_hidden        Whether to include hidden groups in results. Default: false.
1071        *     @type array|string $status             Optional. Array or comma-separated list of group statuses to limit
1072        *                                            results to. If specified, $show_hidden is ignored.
1073       *                                            Default: empty array.
1074        *     @type string       $fields             Which fields to return. Specify 'ids' to fetch a list of IDs.
1075        *                                            Default: 'all' (return BP_Groups_Group objects).
1076        *                                            If set, meta and admin caches will not be prefetched.
1077       * }
1078       * @return array {
1079       *     @type array $groups Array of group objects returned by the
1080       *                         paginated query. (IDs only if `fields` is set to `ids`.)
1081       *     @type int   $total  Total count of all groups matching non-
1082       *                         paginated query params.
1083       * }
1084       */
1085  	public static function get( $args = array() ) {
1086          global $wpdb;
1087  
1088          $function_args = func_get_args();
1089  
1090          // Backward compatibility with old method of passing arguments.
1091          if ( ! is_array( $args ) || count( $function_args ) > 1 ) {
1092              _deprecated_argument(
1093                  __METHOD__,
1094                  '1.7',
1095                  sprintf(
1096                      /* translators: 1: the name of the method. 2: the name of the file. */
1097                      esc_html__( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ),
1098                      __METHOD__,
1099                      __FILE__
1100                  )
1101              );
1102  
1103              $old_args_keys = array(
1104                  0 => 'type',
1105                  1 => 'per_page',
1106                  2 => 'page',
1107                  3 => 'user_id',
1108                  4 => 'search_terms',
1109                  5 => 'include',
1110                  6 => 'populate_extras',
1111                  7 => 'exclude',
1112                  8 => 'show_hidden',
1113              );
1114  
1115              $args = bp_core_parse_args_array( $old_args_keys, $function_args );
1116          }
1117  
1118          $defaults = array(
1119              'type'               => null,
1120              'orderby'            => 'date_created',
1121              'order'              => 'DESC',
1122              'per_page'           => null,
1123              'page'               => null,
1124              'user_id'            => 0,
1125              'slug'               => array(),
1126              'search_terms'       => false,
1127              'search_columns'     => array(),
1128              'group_type'         => '',
1129              'group_type__in'     => '',
1130              'group_type__not_in' => '',
1131              'meta_query'         => false,
1132              'date_query'         => false,
1133              'include'            => false,
1134              'parent_id'          => null,
1135              'update_meta_cache'  => true,
1136              'update_admin_cache' => false,
1137              'exclude'            => false,
1138              'show_hidden'        => false,
1139              'status'             => array(),
1140              'fields'             => 'all',
1141          );
1142  
1143          $r = bp_parse_args(
1144              $args,
1145              $defaults,
1146              'bp_groups_group_get'
1147          );
1148  
1149          $bp = buddypress();
1150  
1151          $sql = array(
1152              'select'     => "SELECT DISTINCT g.id",
1153              'from'       => "{$bp->groups->table_name} g",
1154              'where'      => '',
1155              'orderby'    => '',
1156              'pagination' => '',
1157          );
1158  
1159          if ( ! empty( $r['user_id'] ) ) {
1160              $sql['from'] .= " JOIN {$bp->groups->table_name_members} m ON ( g.id = m.group_id )";
1161          }
1162  
1163          $where_conditions = array();
1164  
1165          if ( ! empty( $r['status'] ) ) {
1166              if ( ! is_array( $r['status'] ) ) {
1167                  $r['status'] = preg_split( '/[\s,]+/', $r['status'] );
1168              }
1169              $r['status'] = array_map( 'sanitize_title', $r['status'] );
1170              $status_in = "'" . implode( "','", $r['status'] ) . "'";
1171              $where_conditions['status'] = "g.status IN ({$status_in})";
1172          } elseif ( empty( $r['show_hidden'] ) ) {
1173              $where_conditions['hidden'] = "g.status != 'hidden'";
1174          }
1175  
1176          if ( ! empty( $r['slug'] ) ) {
1177              if ( ! is_array( $r['slug'] ) ) {
1178                  $r['slug'] = preg_split( '/[\s,]+/', $r['slug'] );
1179              }
1180              $r['slug'] = array_map( 'sanitize_title', $r['slug'] );
1181              $slug_in = "'" . implode( "','", $r['slug'] ) . "'";
1182              $where_conditions['slug'] = "g.slug IN ({$slug_in})";
1183          }
1184  
1185          $search = '';
1186          if ( isset( $r['search_terms'] ) ) {
1187              $search = trim( $r['search_terms'] );
1188          }
1189  
1190          if ( $search ) {
1191              $leading_wild = ( ltrim( $search, '*' ) != $search );
1192              $trailing_wild = ( rtrim( $search, '*' ) != $search );
1193              if ( $leading_wild && $trailing_wild ) {
1194                  $wild = 'both';
1195              } elseif ( $leading_wild ) {
1196                  $wild = 'leading';
1197              } elseif ( $trailing_wild ) {
1198                  $wild = 'trailing';
1199              } else {
1200                  // Default is to wrap in wildcard characters.
1201                  $wild = 'both';
1202              }
1203              $search = trim( $search, '*' );
1204  
1205              $searches = array();
1206              $leading_wild = ( 'leading' == $wild || 'both' == $wild ) ? '%' : '';
1207              $trailing_wild = ( 'trailing' == $wild || 'both' == $wild ) ? '%' : '';
1208              $wildcarded = $leading_wild . bp_esc_like( $search ) . $trailing_wild;
1209  
1210              $search_columns = array( 'name', 'description' );
1211              if ( $r['search_columns'] ) {
1212                  $search_columns = array_intersect( $r['search_columns'], $search_columns );
1213              }
1214  
1215              foreach ( $search_columns as $search_column ) {
1216                  $searches[] = $wpdb->prepare( "$search_column LIKE %s", $wildcarded );
1217              }
1218  
1219              $where_conditions['search'] = '(' . implode(' OR ', $searches) . ')';
1220          }
1221  
1222          $meta_query_sql = self::get_meta_query_sql( $r['meta_query'] );
1223  
1224          if ( ! empty( $meta_query_sql['join'] ) ) {
1225              $sql['from'] .= $meta_query_sql['join'];
1226          }
1227  
1228          if ( ! empty( $meta_query_sql['where'] ) ) {
1229              $where_conditions['meta'] = $meta_query_sql['where'];
1230          }
1231  
1232          // Only use 'group_type__in', if 'group_type' is not set.
1233          if ( empty( $r['group_type'] ) && ! empty( $r['group_type__in']) ) {
1234              $r['group_type'] = $r['group_type__in'];
1235          }
1236  
1237          // Group types to exclude. This has priority over inclusions.
1238          if ( ! empty( $r['group_type__not_in'] ) ) {
1239              $group_type_clause = self::get_sql_clause_for_group_types( $r['group_type__not_in'], 'NOT IN' );
1240  
1241          // Group types to include.
1242          } elseif ( ! empty( $r['group_type'] ) ) {
1243              $group_type_clause = self::get_sql_clause_for_group_types( $r['group_type'], 'IN' );
1244          }
1245  
1246          if ( ! empty( $group_type_clause ) ) {
1247              $where_conditions['group_type'] = $group_type_clause;
1248          }
1249  
1250          if ( ! empty( $r['user_id'] ) ) {
1251              $where_conditions['user'] = $wpdb->prepare( "m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $r['user_id'] );
1252          }
1253  
1254          if ( ! empty( $r['include'] ) ) {
1255              $include        = implode( ',', wp_parse_id_list( $r['include'] ) );
1256              $where_conditions['include'] = "g.id IN ({$include})";
1257          }
1258  
1259          if ( ! is_null( $r['parent_id'] ) ) {
1260              // For legacy reasons, `false` means groups with no parent.
1261              if ( false === $r['parent_id'] ) {
1262                  $parent_id = 0;
1263              } else {
1264                  $parent_id = implode( ',', wp_parse_id_list( $r['parent_id'] ) );
1265              }
1266  
1267              $where_conditions['parent_id'] = "g.parent_id IN ({$parent_id})";
1268          }
1269  
1270          if ( ! empty( $r['exclude'] ) ) {
1271              $exclude        = implode( ',', wp_parse_id_list( $r['exclude'] ) );
1272              $where_conditions['exclude'] = "g.id NOT IN ({$exclude})";
1273          }
1274  
1275          /* Order/orderby ********************************************/
1276  
1277          $order   = $r['order'];
1278          $orderby = $r['orderby'];
1279  
1280          // If a 'type' parameter was passed, parse it and overwrite
1281          // 'order' and 'orderby' params passed to the function.
1282          if (  ! empty( $r['type'] ) ) {
1283  
1284              /**
1285               * Filters the 'type' parameter used to overwrite 'order' and 'orderby' values.
1286               *
1287               * @since 2.1.0
1288               *
1289               * @param array  $value Converted 'type' value for order and orderby.
1290               * @param string $value Parsed 'type' value for the get method.
1291               */
1292              $order_orderby = apply_filters( 'bp_groups_get_orderby', self::convert_type_to_order_orderby( $r['type'] ), $r['type'] );
1293  
1294              // If an invalid type is passed, $order_orderby will be
1295              // an array with empty values. In this case, we stick
1296              // with the default values of $order and $orderby.
1297              if ( ! empty( $order_orderby['order'] ) ) {
1298                  $order = $order_orderby['order'];
1299              }
1300  
1301              if ( ! empty( $order_orderby['orderby'] ) ) {
1302                  $orderby = $order_orderby['orderby'];
1303              }
1304          }
1305  
1306          // 'total_member_count' and 'last_activity' sorts require additional table joins.
1307          if ( 'total_member_count' === $orderby ) {
1308              $sql['from'] .= " JOIN {$bp->groups->table_name_groupmeta} gm_total_member_count ON ( g.id = gm_total_member_count.group_id )";
1309              $where_conditions['total_member_count'] = "gm_total_member_count.meta_key = 'total_member_count'";
1310          } elseif ( 'last_activity' === $orderby ) {
1311  
1312              $sql['from'] .= " JOIN {$bp->groups->table_name_groupmeta} gm_last_activity on ( g.id = gm_last_activity.group_id )";
1313              $where_conditions['last_activity'] = "gm_last_activity.meta_key = 'last_activity'";
1314          }
1315  
1316          // If 'meta_id' is the requested order, and there's no meta query, fall back to the default.
1317          if ( 'meta_id' === $orderby && empty( $meta_query_sql['join'] ) ) {
1318              $orderby = 'date_created';
1319          }
1320  
1321          // Process date query for 'date_created' and 'last_activity' sort.
1322          if ( 'date_created' === $orderby || 'last_activity' === $orderby ) {
1323              $date_query_sql = BP_Date_Query::get_where_sql( $r['date_query'], self::convert_orderby_to_order_by_term( $orderby ) );
1324  
1325              if ( ! empty( $date_query_sql ) ) {
1326                  $where_conditions['date'] = $date_query_sql;
1327              }
1328          }
1329  
1330          // Sanitize 'order'.
1331          $order = bp_esc_sql_order( $order );
1332  
1333          /**
1334           * Filters the converted 'orderby' term.
1335           *
1336           * @since 2.1.0
1337           *
1338           * @param string $value   Converted 'orderby' term.
1339           * @param string $orderby Original orderby value.
1340           * @param string $value   Parsed 'type' value for the get method.
1341           */
1342          $orderby = apply_filters( 'bp_groups_get_orderby_converted_by_term', self::convert_orderby_to_order_by_term( $orderby ), $orderby, $r['type'] );
1343  
1344          // Random order is a special case.
1345          if ( 'rand()' === $orderby ) {
1346              $sql['orderby'] = "ORDER BY rand()";
1347          } else {
1348              $sql['orderby'] = "ORDER BY {$orderby} {$order}";
1349          }
1350  
1351          if ( ! empty( $r['per_page'] ) && ! empty( $r['page'] ) && $r['per_page'] != -1 ) {
1352              $sql['pagination'] = $wpdb->prepare( "LIMIT %d, %d", intval( ( $r['page'] - 1 ) * $r['per_page']), intval( $r['per_page'] ) );
1353          }
1354  
1355          $where = '';
1356          if ( ! empty( $where_conditions ) ) {
1357              $sql['where'] = implode( ' AND ', $where_conditions );
1358              $where = "WHERE {$sql['where']}";
1359          }
1360  
1361          $paged_groups_sql = "{$sql['select']} FROM {$sql['from']} {$where} {$sql['orderby']} {$sql['pagination']}";
1362  
1363          /**
1364           * Filters the pagination SQL statement.
1365           *
1366           * @since 1.5.0
1367           *
1368           * @param string $value Concatenated SQL statement.
1369           * @param array  $sql   Array of SQL parts before concatenation.
1370           * @param array  $r     Array of parsed arguments for the get method.
1371           */
1372          $paged_groups_sql = apply_filters( 'bp_groups_get_paged_groups_sql', $paged_groups_sql, $sql, $r );
1373  
1374          $cached = bp_core_get_incremented_cache( $paged_groups_sql, 'bp_groups' );
1375          if ( false === $cached ) {
1376              $paged_group_ids = $wpdb->get_col( $paged_groups_sql );
1377              bp_core_set_incremented_cache( $paged_groups_sql, 'bp_groups', $paged_group_ids );
1378          } else {
1379              $paged_group_ids = $cached;
1380          }
1381  
1382          if ( 'ids' === $r['fields'] ) {
1383              // We only want the IDs.
1384              $paged_groups = array_map( 'intval', $paged_group_ids );
1385          } else {
1386              $uncached_group_ids = bp_get_non_cached_ids( $paged_group_ids, 'bp_groups' );
1387              if ( $uncached_group_ids ) {
1388                  $group_ids_sql = implode( ',', array_map( 'intval', $uncached_group_ids ) );
1389                  $group_data_objects = $wpdb->get_results( "SELECT g.* FROM {$bp->groups->table_name} g WHERE g.id IN ({$group_ids_sql})" );
1390                  foreach ( $group_data_objects as $group_data_object ) {
1391                      wp_cache_set( $group_data_object->id, $group_data_object, 'bp_groups' );
1392                  }
1393              }
1394  
1395              $paged_groups = array();
1396              foreach ( $paged_group_ids as $paged_group_id ) {
1397                  $paged_groups[] = new BP_Groups_Group( $paged_group_id );
1398              }
1399  
1400              $group_ids = array();
1401              foreach ( (array) $paged_groups as $group ) {
1402                  $group_ids[] = $group->id;
1403              }
1404  
1405              // Grab all groupmeta.
1406              if ( ! empty( $r['update_meta_cache'] ) ) {
1407                  bp_groups_update_meta_cache( $group_ids );
1408              }
1409  
1410              // Prefetch all administrator IDs, if requested.
1411              if ( $r['update_admin_cache'] ) {
1412                  BP_Groups_Member::prime_group_admins_mods_cache( $group_ids );
1413              }
1414  
1415              // Set up integer properties needing casting.
1416              $int_props = array(
1417                  'id', 'creator_id', 'enable_forum'
1418              );
1419  
1420              // Integer casting.
1421              foreach ( $paged_groups as $key => $g ) {
1422                  foreach ( $int_props as $int_prop ) {
1423                      $paged_groups[ $key ]->{$int_prop} = (int) $paged_groups[ $key ]->{$int_prop};
1424                  }
1425              }
1426  
1427          }
1428  
1429          // Find the total number of groups in the results set.
1430          $total_groups_sql = "SELECT COUNT(DISTINCT g.id) FROM {$sql['from']} $where";
1431  
1432          /**
1433           * Filters the SQL used to retrieve total group results.
1434           *
1435           * @since 1.5.0
1436           *
1437           * @param string $t_sql     Concatenated SQL statement used for retrieving total group results.
1438           * @param array  $total_sql Array of SQL parts for the query.
1439           * @param array  $r         Array of parsed arguments for the get method.
1440           */
1441          $total_groups_sql = apply_filters( 'bp_groups_get_total_groups_sql', $total_groups_sql, $sql, $r );
1442  
1443          $cached = bp_core_get_incremented_cache( $total_groups_sql, 'bp_groups' );
1444          if ( false === $cached ) {
1445              $total_groups = (int) $wpdb->get_var( $total_groups_sql );
1446              bp_core_set_incremented_cache( $total_groups_sql, 'bp_groups', $total_groups );
1447          } else {
1448              $total_groups = (int) $cached;
1449          }
1450  
1451          return array( 'groups' => $paged_groups, 'total' => $total_groups );
1452      }
1453  
1454      /**
1455       * Get the SQL for the 'meta_query' param in BP_Groups_Group::get()
1456       *
1457       * We use WP_Meta_Query to do the heavy lifting of parsing the
1458       * meta_query array and creating the necessary SQL clauses.
1459       *
1460       * @since 1.8.0
1461       *
1462       * @param array $meta_query An array of meta_query filters. See the
1463       *                          documentation for {@link WP_Meta_Query} for details.
1464       * @return array $sql_array 'join' and 'where' clauses.
1465       */
1466  	protected static function get_meta_query_sql( $meta_query = array() ) {
1467          global $wpdb;
1468  
1469          $sql_array = array(
1470              'join'  => '',
1471              'where' => '',
1472          );
1473  
1474          if ( ! empty( $meta_query ) ) {
1475              $groups_meta_query = new WP_Meta_Query( $meta_query );
1476  
1477              // WP_Meta_Query expects the table name at
1478              // $wpdb->group.
1479              $wpdb->groupmeta = buddypress()->groups->table_name_groupmeta;
1480  
1481              $meta_sql = $groups_meta_query->get_sql( 'group', 'g', 'id' );
1482              $sql_array['join']  = $meta_sql['join'];
1483              $sql_array['where'] = self::strip_leading_and( $meta_sql['where'] );
1484          }
1485  
1486          return $sql_array;
1487      }
1488  
1489      /**
1490       * Convert the 'type' parameter to 'order' and 'orderby'.
1491       *
1492       * @since 1.8.0
1493       *
1494       * @param string $type The 'type' shorthand param.
1495       *
1496       * @return array {
1497       *     @type string $order   SQL-friendly order string.
1498       *     @type string $orderby SQL-friendly orderby column name.
1499       * }
1500       */
1501  	protected static function convert_type_to_order_orderby( $type = '' ) {
1502          $order = $orderby = '';
1503  
1504          switch ( $type ) {
1505              case 'newest' :
1506                  $order   = 'DESC';
1507                  $orderby = 'date_created';
1508                  break;
1509  
1510              case 'active' :
1511                  $order   = 'DESC';
1512                  $orderby = 'last_activity';
1513                  break;
1514  
1515              case 'popular' :
1516                  $order   = 'DESC';
1517                  $orderby = 'total_member_count';
1518                  break;
1519  
1520              case 'alphabetical' :
1521                  $order   = 'ASC';
1522                  $orderby = 'name';
1523                  break;
1524  
1525              case 'random' :
1526                  $order   = '';
1527                  $orderby = 'random';
1528                  break;
1529          }
1530  
1531          return array( 'order' => $order, 'orderby' => $orderby );
1532      }
1533  
1534      /**
1535       * Convert the 'orderby' param into a proper SQL term/column.
1536       *
1537       * @since 1.8.0
1538       *
1539       * @param string $orderby Orderby term as passed to get().
1540       * @return string $order_by_term SQL-friendly orderby term.
1541       */
1542  	protected static function convert_orderby_to_order_by_term( $orderby ) {
1543          $order_by_term = '';
1544  
1545          switch ( $orderby ) {
1546              case 'date_created' :
1547              default :
1548                  $order_by_term = 'g.date_created';
1549                  break;
1550  
1551              case 'last_activity' :
1552                  $order_by_term = 'gm_last_activity.meta_value';
1553                  break;
1554  
1555              case 'total_member_count' :
1556                  $order_by_term = 'CONVERT(gm_total_member_count.meta_value, SIGNED)';
1557                  break;
1558  
1559              case 'name' :
1560                  $order_by_term = 'g.name';
1561                  break;
1562  
1563              case 'random' :
1564                  $order_by_term = 'rand()';
1565                  break;
1566  
1567              case 'meta_id' :
1568                  $order_by_term = buddypress()->groups->table_name_groupmeta . '.id';
1569                  break;
1570          }
1571  
1572          return $order_by_term;
1573      }
1574  
1575      /**
1576       * Get a list of groups whose names start with a given letter.
1577       *
1578       * @since 1.6.0
1579       *
1580       * @param string            $letter          The letter.
1581       * @param int|null          $limit           Optional. The max number of results to return.
1582       *                                           Default: null (no limit).
1583       * @param int|null          $page            Optional. The page offset of results to return.
1584       *                                           Default: null (no limit).
1585       * @param bool              $populate_extras Deprecated.
1586       * @param string|array|bool $exclude         Optional. Array or comma-separated list of group
1587       *                                           IDs to exclude from results.
1588       * @return false|array {
1589       *     @type array $groups Array of group objects returned by the
1590       *                         paginated query.
1591       *     @type int   $total  Total count of all groups matching non-
1592       *                         paginated query params.
1593       * }
1594       */
1595  	public static function get_by_letter( $letter, $limit = null, $page = null, $populate_extras = true, $exclude = false ) {
1596  
1597          if ( true !== $populate_extras ) {
1598              _deprecated_argument(
1599                  __METHOD__,
1600                  '1.6.0',
1601                  sprintf(
1602                      /* translators: 1: the name of the method. 2: the name of the file. */
1603                      esc_html__( '%1$s no longer accepts setting $populate_extras. See the inline documentation at %2$s for more details.', 'buddypress' ),
1604                      __METHOD__,
1605                      __FILE__
1606                  )
1607              );
1608          }
1609  
1610          // Multibyte compliance.
1611          if ( function_exists( 'mb_strlen' ) ) {
1612              if ( mb_strlen( $letter, 'UTF-8' ) > 1 || is_numeric( $letter ) || !$letter ) {
1613                  return false;
1614              }
1615          } else {
1616              if ( strlen( $letter ) > 1 || is_numeric( $letter ) || !$letter ) {
1617                  return false;
1618              }
1619          }
1620  
1621          return self::get(
1622              array(
1623                  'per_page'       => $limit,
1624                  'page'           => $page,
1625                  'search_terms'   => $letter . '*',
1626                  'search_columns' => array( 'name' ),
1627                  'exclude'        => $exclude,
1628              )
1629          );
1630      }
1631  
1632      /**
1633       * Get a list of random groups.
1634       *
1635       * Use BP_Groups_Group::get() with 'type' = 'random' instead.
1636       *
1637       * @since 1.6.0
1638       * @since 10.0.0 Deprecate the `$populate_extras` arg.
1639       *
1640       * @param int|null          $limit           Optional. The max number of results to return.
1641       *                                           Default: null (no limit).
1642       * @param int|null          $page            Optional. The page offset of results to return.
1643       *                                           Default: null (no limit).
1644       * @param int               $user_id         Optional. If present, groups will be limited to
1645       *                                           those of which the specified user is a member.
1646       * @param string|bool       $search_terms    Optional. Limit groups to those whose name
1647       *                                           or description field contain the search string.
1648       * @param bool              $populate_extras Deprecated.
1649       * @param string|array|bool $exclude         Optional. Array or comma-separated list of group
1650       *                                           IDs to exclude from results.
1651       * @return array {
1652       *     @type array $groups Array of group objects returned by the
1653       *                         paginated query.
1654       *     @type int   $total  Total count of all groups matching non-
1655       *                         paginated query params.
1656       * }
1657       */
1658  	public static function get_random( $limit = null, $page = null, $user_id = 0, $search_terms = false, $populate_extras = true, $exclude = false ) {
1659  
1660          if ( true !== $populate_extras ) {
1661              _deprecated_argument(
1662                  __METHOD__,
1663                  '10.0.0',
1664                  sprintf(
1665                      /* translators: 1: the name of the method. 2: the name of the file. */
1666                      esc_html__( '%1$s no longer accepts setting $populate_extras. See the inline documentation at %2$s for more details.', 'buddypress' ),
1667                      __METHOD__,
1668                      __FILE__
1669                  )
1670              );
1671          }
1672  
1673          return self::get(
1674              array(
1675                  'type'         => 'random',
1676                  'per_page'     => $limit,
1677                  'page'         => $page,
1678                  'user_id'      => $user_id,
1679                  'search_terms' => $search_terms,
1680                  'exclude'      => $exclude,
1681              )
1682          );
1683      }
1684  
1685      /**
1686       * Fetch extra data for a list of groups.
1687       *
1688       * This method is used throughout the class, by methods that take a
1689       * $populate_extras parameter.
1690       *
1691       * Data fetched:
1692       *     - Logged-in user's status within each group (is_member,
1693       *       is_confirmed, is_pending, is_banned)
1694       *
1695       * @since 1.6.0
1696       *
1697       * @param array        $paged_groups Array of groups.
1698       * @param string|array $group_ids    Array or comma-separated list of IDs matching
1699       *                                   $paged_groups.
1700       * @param string|bool  $type         Not used.
1701       * @return array $paged_groups
1702       */
1703  	public static function get_group_extras( &$paged_groups, &$group_ids, $type = false ) {
1704          $user_id = bp_loggedin_user_id();
1705  
1706          foreach ( $paged_groups as &$group ) {
1707              $group->is_member  = groups_is_user_member( $user_id, $group->id )  ? 1 : 0;
1708              $group->is_invited = groups_is_user_invited( $user_id, $group->id ) ? 1 : 0;
1709              $group->is_pending = groups_is_user_pending( $user_id, $group->id ) ? 1 : 0;
1710              $group->is_banned  = (bool) groups_is_user_banned( $user_id, $group->id );
1711          }
1712  
1713          return $paged_groups;
1714      }
1715  
1716      /**
1717       * Delete all invitations to a given group.
1718       *
1719       * @since 1.6.0
1720       *
1721       * @param int $group_id ID of the group whose invitations are being deleted.
1722       * @return int|null Number of rows records deleted on success, null on
1723       *                  failure.
1724       */
1725  	public static function delete_all_invites( $group_id ) {
1726          if ( empty( $group_id ) ) {
1727              return false;
1728          }
1729  
1730          $invites_class = new BP_Groups_Invitation_Manager();
1731  
1732          return $invites_class->delete( array(
1733              'item_id' => $group_id,
1734          ) );
1735      }
1736  
1737      /**
1738       * Get a total group count for the site.
1739       *
1740       * Will include hidden groups in the count only if
1741       * bp_current_user_can( 'bp_moderate' ).
1742       *
1743       * @since 1.6.0
1744       * @since 10.0.0 Added the `$skip_cache` parameter.
1745       *
1746       * @global BuddyPress $bp   The one true BuddyPress instance.
1747       * @global wpdb       $wpdb WordPress database object.
1748       *
1749       * @param bool $skip_cache Optional. Skip getting count from cache.
1750       *                         Defaults to false.
1751       * @return int
1752       */
1753  	public static function get_total_group_count( $skip_cache = false ) {
1754          global $wpdb;
1755  
1756          $cache_key = 'bp_total_group_count';
1757          $count     = wp_cache_get( $cache_key, 'bp' );
1758  
1759          if ( false === $count || true === $skip_cache ) {
1760              $hidden_sql = '';
1761              if ( ! bp_current_user_can( 'bp_moderate' ) ) {
1762                  $hidden_sql = "WHERE status != 'hidden'";
1763              }
1764  
1765              $bp    = buddypress();
1766              $count = $wpdb->get_var( "SELECT COUNT(id) FROM {$bp->groups->table_name} {$hidden_sql}" );
1767  
1768              wp_cache_set( $cache_key, (int) $count, 'bp' );
1769          }
1770  
1771          /**
1772           * Filters the total group count.
1773           *
1774           * @since 10.0.0
1775           *
1776           * @param int $count Total group count.
1777           */
1778          return (int) apply_filters( 'bp_groups_total_group_count', (int) $count );
1779      }
1780  
1781      /**
1782       * Get the member count for a group.
1783       *
1784       * @since 1.6.0
1785       * @since 10.0.0 Updated to use the `groups_get_group_members`.
1786       *
1787       * @param int  $group_id   Group ID.
1788       * @param bool $skip_cache Optional. Skip getting count from cache. Defaults to false.
1789       * @return int Count of confirmed members for the group.
1790       */
1791  	public static function get_total_member_count( $group_id, $skip_cache = false ) {
1792          $cache_key = 'total_member_count';
1793          $count     = groups_get_groupmeta( $group_id, $cache_key );
1794  
1795          if ( false === $count || true === $skip_cache ) {
1796              $members = groups_get_group_members(
1797                  array(
1798                      'group_id'   => $group_id,
1799                      'group_role' => array( 'member', 'admin', 'mod' ),
1800                      'type'       => 'active',
1801                  )
1802              );
1803  
1804              $count = $members['count'] ? $members['count'] : 0;
1805  
1806              groups_update_groupmeta( $group_id, $cache_key, (int) $count );
1807          }
1808  
1809          /**
1810           * Filters the total member count for a group.
1811           *
1812           * @since 10.0.0
1813           *
1814           * @param int $count    Total member count for group.
1815           * @param int $group_id The ID of the group.
1816           */
1817          return (int) apply_filters( 'bp_groups_total_member_count', (int) $count, (int) $group_id );
1818      }
1819  
1820      /**
1821       * Get an array containing ids for each group type.
1822       *
1823       * A bit of a kludge workaround for some issues
1824       * with bp_has_groups().
1825       *
1826       * @since 1.7.0
1827       *
1828       * @return array
1829       */
1830  	public static function get_group_type_ids() {
1831          global $wpdb;
1832  
1833          $bp  = buddypress();
1834          $ids = array();
1835  
1836          $ids['all']     = $wpdb->get_col( "SELECT id FROM {$bp->groups->table_name}" );
1837          $ids['public']  = $wpdb->get_col( "SELECT id FROM {$bp->groups->table_name} WHERE status = 'public'" );
1838          $ids['private'] = $wpdb->get_col( "SELECT id FROM {$bp->groups->table_name} WHERE status = 'private'" );
1839          $ids['hidden']  = $wpdb->get_col( "SELECT id FROM {$bp->groups->table_name} WHERE status = 'hidden'" );
1840  
1841          return $ids;
1842      }
1843  
1844      /**
1845       * Get SQL clause for group type(s).
1846       *
1847       * @since 2.6.0
1848       *
1849       * @param  string|array $group_types Group type(s).
1850       * @param  string       $operator    'IN' or 'NOT IN'.
1851       * @return string       $clause      SQL clause.
1852       */
1853  	protected static function get_sql_clause_for_group_types( $group_types, $operator ) {
1854          global $wpdb;
1855  
1856          // Sanitize operator.
1857          if ( 'NOT IN' !== $operator ) {
1858              $operator = 'IN';
1859          }
1860  
1861          // Parse and sanitize types.
1862          if ( ! is_array( $group_types ) ) {
1863              $group_types = preg_split( '/[,\s+]/', $group_types );
1864          }
1865  
1866          $types = array();
1867          foreach ( $group_types as $gt ) {
1868              if ( bp_groups_get_group_type_object( $gt ) ) {
1869                  $types[] = $gt;
1870              }
1871          }
1872  
1873          $tax_query = new WP_Tax_Query( array(
1874              array(
1875                  'taxonomy' => bp_get_group_type_tax_name(),
1876                  'field'    => 'name',
1877                  'operator' => $operator,
1878                  'terms'    => $types,
1879              ),
1880          ) );
1881  
1882          $site_id  = bp_get_taxonomy_term_site_id( bp_get_group_type_tax_name() );
1883          $switched = false;
1884          if ( $site_id !== get_current_blog_id() ) {
1885              switch_to_blog( $site_id );
1886              $switched = true;
1887          }
1888  
1889          $sql_clauses = $tax_query->get_sql( 'g', 'id' );
1890  
1891          $clause = '';
1892  
1893          // The no_results clauses are the same between IN and NOT IN.
1894          if ( false !== strpos( $sql_clauses['where'], '0 = 1' ) ) {
1895              $clause = self::strip_leading_and( $sql_clauses['where'] );
1896  
1897          // The tax_query clause generated for NOT IN can be used almost as-is.
1898          } elseif ( 'NOT IN' === $operator ) {
1899              $clause = self::strip_leading_and( $sql_clauses['where'] );
1900  
1901          // IN clauses must be converted to a subquery.
1902          } elseif ( preg_match( '/' . $wpdb->term_relationships . '\.term_taxonomy_id IN \([0-9, ]+\)/', $sql_clauses['where'], $matches ) ) {
1903              $clause = " g.id IN ( SELECT object_id FROM $wpdb->term_relationships WHERE {$matches[0]} )";
1904          }
1905  
1906          if ( $switched ) {
1907              restore_current_blog();
1908          }
1909  
1910          return $clause;
1911      }
1912  
1913      /**
1914       * Strips the leading AND and any surrounding whitespace from a string.
1915       *
1916       * Used here to normalize SQL fragments generated by `WP_Meta_Query` and
1917       * other utility classes.
1918       *
1919       * @since 2.7.0
1920       *
1921       * @param string $s String.
1922       * @return string
1923       */
1924  	protected static function strip_leading_and( $s ) {
1925          return preg_replace( '/^\s*AND\s*/', '', $s );
1926      }
1927  }


Generated: Fri May 20 01:00:54 2022 Cross-referenced by PHPXref 0.7.1