pages->blogs->id ); } /** * Retrieve a set of blogs. * * @since 1.2.0 * @since 2.0.0 Added $include_blog_ids, $update_meta_cache parameters * @since 10.0.0 Added $date_query parameter * * @see BP_Blogs_Blog::get() for a description of arguments and return value. * * @param array|string $args { * Arguments are listed here with their default values. For more * information about the arguments, see {@link BP_Blogs_Blog::get()}. * @type string $type Default: 'active'. * @type int|bool $user_id Default: false. * @type array $include_blog_ids Default: false. * @type string|bool $search_terms Default: false. * @type int $per_page Default: 20. * @type int $page Default: 1. * @type array $date_query Default: false. * @type bool $update_meta_cache Whether to pre-fetch blogmeta. Default: true. * } * @return array See {@link BP_Blogs_Blog::get()}. */ function bp_blogs_get_blogs( $args = '' ) { // Parse query arguments. $r = bp_parse_args( $args, array( 'type' => 'active', // 'active', 'alphabetical', 'newest', or 'random'. 'include_blog_ids' => false, // Array of blog IDs to include. 'user_id' => false, // Limit to blogs this user can post to. 'search_terms' => false, // Limit to blogs matching these search terms. 'per_page' => 20, // The number of results to return per page. 'page' => 1, // The page to return if limiting per page. 'date_query' => false, // Filter blogs by date query. 'update_meta_cache' => true, // Whether to pre-fetch blogmeta. ), 'blogs_get_blogs' ); // Get the blogs. $blogs = BP_Blogs_Blog::get( $r ); /** * Filters a set of blogs. * * @since 1.2.0 * * @param array $blogs Array of blog data. * @param array $r Parsed query arguments. */ return apply_filters( 'bp_blogs_get_blogs', $blogs, $r ); } /** * Populate the BP blogs table with existing blogs. * * Warning: By default, this will remove all existing records from the BP * blogs and blogmeta tables before re-populating the tables. * * @since 1.0.0 * @since 2.6.0 Accepts $args as a parameter. * * @param array $args { * Array of arguments. * @type int $offset The offset to use. * @type int $limit The number of blogs to record at one time. * @type array $blog_ids Blog IDs to record. If empty, all blogs will be recorded. * @type array $site_id The network site ID to use. * } * @return bool */ function bp_blogs_record_existing_blogs( $args = array() ) { global $wpdb; // Query for all sites in network. $r = bp_parse_args( $args, array( 'offset' => (int) bp_get_option( '_bp_record_blogs_offset' ), 'limit' => 50, 'blog_ids' => array(), 'site_id' => $wpdb->siteid, ), 'record_existing_blogs' ); // Truncate all BP blogs tables if starting fresh. if ( empty( $r['offset'] ) && empty( $r['blog_ids'] ) ) { $bp = buddypress(); // Truncate user blogs table. $truncate = $wpdb->query( "TRUNCATE {$bp->blogs->table_name}" ); if ( is_wp_error( $truncate ) ) { return false; } // Truncate user blogmeta table. $truncate = $wpdb->query( "TRUNCATE {$bp->blogs->table_name_blogmeta}" ); if ( is_wp_error( $truncate ) ) { return false; } } // Multisite. if ( is_multisite() ) { $sql = array(); $sql['select'] = $wpdb->prepare( "SELECT blog_id, last_updated FROM {$wpdb->base_prefix}blogs WHERE mature = 0 AND spam = 0 AND deleted = 0 AND site_id = %d", $r['site_id'] ); // Omit root blog if large network. if ( bp_is_large_install() ) { $sql['omit_root_blog'] = $wpdb->prepare( "AND blog_id != %d", bp_get_root_blog_id() ); } // Filter by selected blog IDs. if ( ! empty( $r['blog_ids'] ) ) { $in = implode( ',', wp_parse_id_list( $r['blog_ids'] ) ); $sql['in'] = "AND blog_id IN ({$in})"; } $sql['orderby'] = 'ORDER BY blog_id ASC'; $sql['limit'] = $wpdb->prepare( "LIMIT %d", $r['limit'] ); if ( ! empty( $r['offset'] ) ) { $sql['offset'] = $wpdb->prepare( "OFFSET %d", $r['offset'] ); } $blogs = $wpdb->get_results( implode( ' ', $sql ) ); // Record a single site. } else { // Just record blog for the current user only. $record = bp_blogs_record_blog( $wpdb->blogid, get_current_user_id(), true ); if ( false === $record ) { return false; } else { return true; } } // Bail if there are no blogs. if ( empty( $blogs ) ) { // Make sure we remove our offset marker. if ( is_multisite() ) { bp_delete_option( '_bp_record_blogs_offset' ); } return false; } // Loop through users of blogs and record the relationship. foreach ( (array) $blogs as $blog ) { // Ensure that the cache is clear after the table TRUNCATE above. wp_cache_delete( $blog->blog_id, 'bp_blog_meta' ); // Get all users. $users = get_users( array( 'blog_id' => $blog->blog_id, 'fields' => 'ID' ) ); // Continue on if no users exist for this site (how did this happen?). if ( empty( $users ) ) { continue; } // Loop through users and record their relationship to this blog. foreach ( (array) $users as $user_id ) { bp_blogs_add_user_to_blog( $user_id, false, $blog->blog_id ); // Clear cache. bp_blogs_clear_blog_object_cache( $blog->blog_id, $user_id ); } // Update blog last activity timestamp. if ( ! empty( $blog->last_updated ) && false !== strtotime( $blog->last_updated ) ) { bp_blogs_update_blogmeta( $blog->blog_id, 'last_activity', $blog->last_updated ); } } // See if we need to do this again. if ( is_multisite() && empty( $r['blog_ids'] ) ) { $sql['offset'] = $wpdb->prepare( " OFFSET %d", $r['limit'] + $r['offset'] ); // Check if there are more blogs to record. $blog_ids = $wpdb->get_results( implode( ' ', $sql ) ); // We have more blogs; record offset and re-run function. if ( ! empty( $blog_ids ) ) { bp_update_option( '_bp_record_blogs_offset', $r['limit'] + $r['offset'] ); bp_blogs_record_existing_blogs( array( 'offset' => $r['limit'] + $r['offset'], 'limit' => $r['limit'], 'blog_ids' => $r['blog_ids'], 'site_id' => $r['site_id'] ) ); // Bail since we have more blogs to record. return; // No more blogs; delete offset marker. } else { bp_delete_option( '_bp_record_blogs_offset' ); } } /** * Fires after the BP blogs tables have been populated with existing blogs. * * @since 2.4.0 */ do_action( 'bp_blogs_recorded_existing_blogs' ); // No errors. return true; } /** * Check whether a given blog should be recorded in activity streams. * * If $user_id is provided, you can restrict site from being recordable * only to particular users. * * @since 1.7.0 * * @param int $blog_id ID of the blog being checked. * @param int $user_id Optional. ID of the user for whom access is being checked. * @return bool True if blog is recordable, otherwise false. */ function bp_blogs_is_blog_recordable( $blog_id, $user_id = 0 ) { /** * Filters whether or not a blog is globally activity stream recordable. * * @since 1.7.0 * * @param bool $value Whether or not recordable. Default true. * @param int $blog_id Current blog ID. */ $recordable_globally = apply_filters( 'bp_blogs_is_blog_recordable', true, $blog_id ); if ( !empty( $user_id ) ) { /** * Filters whether or not a blog is globally activity stream recordable for user. * * @since 1.7.0 * * @param bool $recordable_globally Whether or not recordable. * @param int $blog_id Current blog ID. * @param int $user_id Current user ID. */ $recordable_for_user = apply_filters( 'bp_blogs_is_blog_recordable_for_user', $recordable_globally, $blog_id, $user_id ); } else { $recordable_for_user = $recordable_globally; } if ( !empty( $recordable_for_user ) ) { return true; } return $recordable_globally; } /** * Check whether a given blog should be tracked by the Blogs component. * * If $user_id is provided, the developer can restrict site from * being trackable only to particular users. * * @since 1.7.0 * * @param int $blog_id ID of the blog being checked. * @param int $user_id Optional. ID of the user for whom access is being checked. * @return bool True if blog is trackable, otherwise false. */ function bp_blogs_is_blog_trackable( $blog_id, $user_id = 0 ) { /** * Filters whether or not a blog is globally trackable. * * @since 1.7.0 * * @param bool $value Whether or not trackable. * @param int $blog_id Current blog ID. */ $trackable_globally = apply_filters( 'bp_blogs_is_blog_trackable', bp_blogs_is_blog_recordable( $blog_id, $user_id ), $blog_id ); if ( !empty( $user_id ) ) { /** * Filters whether or not a blog is globally trackable for user. * * @since 1.7.0 * * @param bool $value Whether or not trackable. * @param int $blog_id Current blog ID. * @param int $user_id Current user ID. */ $trackable_for_user = apply_filters( 'bp_blogs_is_blog_trackable_for_user', $trackable_globally, $blog_id, $user_id ); } else { $trackable_for_user = $trackable_globally; } if ( !empty( $trackable_for_user ) ) { return $trackable_for_user; } return $trackable_globally; } /** * Make BuddyPress aware of a new site so that it can track its activity. * * @since 1.0.0 * * @param int $blog_id ID of the blog being recorded. * @param int $user_id ID of the user for whom the blog is being recorded. * @param bool $no_activity Optional. Whether to skip recording an activity * item about this blog creation. Default: false. * @return false|null Returns false on failure. */ function bp_blogs_record_blog( $blog_id, $user_id, $no_activity = false ) { if ( empty( $user_id ) ) $user_id = bp_loggedin_user_id(); // If blog is not recordable, do not record the activity. if ( !bp_blogs_is_blog_recordable( $blog_id, $user_id ) ) return false; $name = get_blog_option( $blog_id, 'blogname' ); $url = get_home_url( $blog_id ); if ( empty( $name ) ) { $name = $url; } $description = get_blog_option( $blog_id, 'blogdescription' ); $close_old_posts = get_blog_option( $blog_id, 'close_comments_for_old_posts' ); $close_days_old = get_blog_option( $blog_id, 'close_comments_days_old' ); $moderation = get_blog_option( $blog_id, 'comment_moderation' ); $thread_depth = get_blog_option( $blog_id, 'thread_comments' ); if ( ! empty( $thread_depth ) ) { $thread_depth = get_blog_option( $blog_id, 'thread_comments_depth' ); } else { // Perhaps filter this? $thread_depth = 1; } $recorded_blog = new BP_Blogs_Blog; $recorded_blog->user_id = $user_id; $recorded_blog->blog_id = $blog_id; $recorded_blog_id = $recorded_blog->save(); $is_recorded = !empty( $recorded_blog_id ) ? true : false; bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'url', $url ); bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'name', $name ); bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'description', $description ); bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'last_activity', bp_core_current_time() ); bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'close_comments_for_old_posts', $close_old_posts ); bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'close_comments_days_old', $close_days_old ); bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'thread_comments_depth', $thread_depth ); bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'comment_moderation', $moderation ); $is_private = !empty( $_POST['blog_public'] ) && (int) $_POST['blog_public'] ? false : true; /** * Filters whether or not a new blog is public. * * @since 1.5.0 * * @param bool $is_private Whether or not blog is public. */ $is_private = !apply_filters( 'bp_is_new_blog_public', !$is_private ); /** * Fires after BuddyPress has been made aware of a new site for activity tracking. * * @since 1.0.0 * @since 2.6.0 Added $no_activity as a parameter. * * @param BP_Blogs_Blog $recorded_blog Current blog being recorded. Passed by reference. * @param bool $is_private Whether or not the current blog being recorded is private. * @param bool $is_recorded Whether or not the current blog was recorded. * @param bool $no_activity Whether to skip recording an activity item for this blog creation. */ do_action_ref_array( 'bp_blogs_new_blog', array( &$recorded_blog, $is_private, $is_recorded, $no_activity ) ); } add_action( 'bp_insert_site', 'bp_blogs_record_blog', 10, 2 ); /** * Update blog name in BuddyPress blogmeta table. * * @global object $wpdb DB Layer. * * @param string $oldvalue Value before save. Passed by do_action() but * unused here. * @param string $newvalue Value to change meta to. */ function bp_blogs_update_option_blogname( $oldvalue, $newvalue ) { global $wpdb; bp_blogs_update_blogmeta( $wpdb->blogid, 'name', $newvalue ); } add_action( 'update_option_blogname', 'bp_blogs_update_option_blogname', 10, 2 ); /** * Update blog description in BuddyPress blogmeta table. * * @global object $wpdb DB Layer. * * @param string $oldvalue Value before save. Passed by do_action() but * unused here. * @param string $newvalue Value to change meta to. */ function bp_blogs_update_option_blogdescription( $oldvalue, $newvalue ) { global $wpdb; bp_blogs_update_blogmeta( $wpdb->blogid, 'description', $newvalue ); } add_action( 'update_option_blogdescription', 'bp_blogs_update_option_blogdescription', 10, 2 ); /** * Update "Close comments for old posts" option in BuddyPress blogmeta table. * * @since 2.0.0 * * @global object $wpdb DB Layer. * * @param string $oldvalue Value before save. Passed by do_action() but * unused here. * @param string $newvalue Value to change meta to. */ function bp_blogs_update_option_close_comments_for_old_posts( $oldvalue, $newvalue ) { global $wpdb; bp_blogs_update_blogmeta( $wpdb->blogid, 'close_comments_for_old_posts', $newvalue ); } add_action( 'update_option_close_comments_for_old_posts', 'bp_blogs_update_option_close_comments_for_old_posts', 10, 2 ); /** * Update "Close comments after days old" option in BuddyPress blogmeta table. * * @since 2.0.0 * * @global object $wpdb DB Layer. * * @param string $oldvalue Value before save. Passed by do_action() but * unused here. * @param string $newvalue Value to change meta to. */ function bp_blogs_update_option_close_comments_days_old( $oldvalue, $newvalue ) { global $wpdb; bp_blogs_update_blogmeta( $wpdb->blogid, 'close_comments_days_old', $newvalue ); } add_action( 'update_option_close_comments_days_old', 'bp_blogs_update_option_close_comments_days_old', 10, 2 ); /** * When toggling threaded comments, update thread depth in blogmeta table. * * @since 2.0.0 * * @global object $wpdb DB Layer. * * @param string $oldvalue Value before save. Passed by do_action() but * unused here. * @param string $newvalue Value to change meta to. */ function bp_blogs_update_option_thread_comments( $oldvalue, $newvalue ) { global $wpdb; if ( empty( $newvalue ) ) { $thread_depth = 1; } else { $thread_depth = get_option( 'thread_comments_depth' ); } bp_blogs_update_blogmeta( $wpdb->blogid, 'thread_comments_depth', $thread_depth ); } add_action( 'update_option_thread_comments', 'bp_blogs_update_option_thread_comments', 10, 2 ); /** * When updating comment depth, update thread depth in blogmeta table. * * @since 2.0.0 * * @global object $wpdb DB Layer. * * @param string $oldvalue Value before save. Passed by do_action() but * unused here. * @param string $newvalue Value to change meta to. */ function bp_blogs_update_option_thread_comments_depth( $oldvalue, $newvalue ) { global $wpdb; $comments_enabled = get_option( 'thread_comments' ); if ( $comments_enabled ) { bp_blogs_update_blogmeta( $wpdb->blogid, 'thread_comments_depth', $newvalue ); } } add_action( 'update_option_thread_comments_depth', 'bp_blogs_update_option_thread_comments_depth', 10, 2 ); /** * When updating comment moderation, mirror value in blogmeta table. * * @since 3.0.0 * * @param string $oldvalue Value before save. Passed by do_action() but unused here. * @param string $newvalue Value to change meta to. */ function bp_blogs_update_option_comment_moderation( $oldvalue, $newvalue ) { bp_blogs_update_blogmeta( $GLOBALS['wpdb']->blogid, 'comment_moderation', $newvalue ); } add_action( 'update_option_comment_moderation', 'bp_blogs_update_option_comment_moderation', 10, 2 ); /** * Syncs site icon URLs to blogmeta. * * @since 2.7.0 * * @param int|string $old_value Old value * @param int|string $new_value New value */ function bp_blogs_update_option_site_icon( $old_value, $new_value ) { $blog_id = get_current_blog_id(); if ( 0 === $new_value ) { bp_blogs_update_blogmeta( $blog_id, 'site_icon_url_thumb', 0 ); bp_blogs_update_blogmeta( $blog_id, 'site_icon_url_full', 0 ); } else { // Save site icon URL as blogmeta. bp_blogs_update_blogmeta( $blog_id, 'site_icon_url_thumb', bp_blogs_get_site_icon_url( $blog_id, bp_core_avatar_thumb_width() ) ); bp_blogs_update_blogmeta( $blog_id, 'site_icon_url_full', bp_blogs_get_site_icon_url( $blog_id, bp_core_avatar_full_width() ) ); } } add_action( 'update_option_site_icon', 'bp_blogs_update_option_site_icon', 10, 2 ); /** * Deletes the 'url' blogmeta for a site. * * Fires when a site's details are updated, which generally happens when * editing a site under "Network Admin > Sites". * * @since 2.3.0 * * @param int $site_id The site ID. */ function bp_blogs_delete_url_blogmeta( $site_id = 0 ) { bp_blogs_delete_blogmeta( (int) $site_id, 'url' ); } add_action( 'clean_site_cache', 'bp_blogs_delete_url_blogmeta' ); /** * Record activity metadata about a published blog post. * * @since 2.2.0 * * @param int $activity_id ID of the activity item. * @param WP_Post $post Post object. * @param array $args Array of arguments. */ function bp_blogs_publish_post_activity_meta( $activity_id, $post, $args ) { if ( empty( $activity_id ) || 'post' != $post->post_type ) { return; } bp_activity_update_meta( $activity_id, 'post_title', $post->post_title ); if ( ! empty( $args['post_url'] ) ) { $post_permalink = $args['post_url']; } else { $post_permalink = $post->guid; } bp_activity_update_meta( $activity_id, 'post_url', $post_permalink ); // Update the blog's last activity. bp_blogs_update_blogmeta( $args['item_id'], 'last_activity', bp_core_current_time() ); /** * Fires after BuddyPress has recorded metadata about a published blog post. * * @since 1.0.0 * * @param int $ID ID of the blog post being recorded. * @param WP_Post $post WP_Post object for the current blog post. * @param string $value ID of the user associated with the current blog post. */ do_action( 'bp_blogs_new_blog_post', $post->ID, $post, $args['user_id'] ); } add_action( 'bp_activity_post_type_published', 'bp_blogs_publish_post_activity_meta', 10, 3 ); /** * Updates a blog post's activity meta entry during a post edit. * * @since 2.2.0 * @since 2.5.0 Add the post type tracking args object parameter * * @param WP_Post $post Post object. * @param BP_Activity_Activity $activity Activity object. * @param object $activity_post_object The post type tracking args object. */ function bp_blogs_update_post_activity_meta( $post, $activity, $activity_post_object ) { if ( empty( $activity->id ) || empty( $activity_post_object->action_id ) ) { return; } // Update post title in activity meta. $existing_title = bp_activity_get_meta( $activity->id, 'post_title' ); if ( $post->post_title !== $existing_title ) { bp_activity_update_meta( $activity->id, 'post_title', $post->post_title ); if ( ! empty( $activity_post_object->comments_tracking->action_id ) ) { // Now update activity meta for post comments... sigh. add_filter( 'comments_clauses', 'bp_blogs_comments_clauses_select_by_id' ); $comments = get_comments( array( 'post_id' => $post->ID ) ); remove_filter( 'comments_clauses', 'bp_blogs_comments_clauses_select_by_id' ); if ( ! empty( $comments ) ) { $activity_ids = array(); $comment_ids = wp_list_pluck( $comments, 'comment_ID' ); // Set up activity args. $args = array( 'update_meta_cache' => false, 'show_hidden' => true, 'per_page' => 99999, ); // Query for old-style "new_blog_comment" activity items. $args['filter'] = array( 'object' => $activity_post_object->comments_tracking->component_id, 'action' => $activity_post_object->comments_tracking->action_id, 'primary_id' => get_current_blog_id(), 'secondary_id' => implode( ',', $comment_ids ), ); $activities = bp_activity_get( $args ); if ( ! empty( $activities['activities'] ) ) { $activity_ids = (array) wp_list_pluck( $activities['activities'], 'id' ); } // Query for activity comments connected to a blog post. unset( $args['filter'] ); $args['meta_query'] = array( array( 'key' => 'bp_blogs_' . $post->post_type . '_comment_id', 'value' => $comment_ids, 'compare' => 'IN', ) ); $args['type'] = 'activity_comment'; $args['display_comments'] = 'stream'; $activities = bp_activity_get( $args ); if ( ! empty( $activities['activities'] ) ) { $activity_ids = array_merge( $activity_ids, (array) wp_list_pluck( $activities['activities'], 'id' ) ); } // Update activity meta for all found activity items. if ( ! empty( $activity_ids ) ) { foreach ( $activity_ids as $aid ) { bp_activity_update_meta( $aid, 'post_title', $post->post_title ); } } unset( $activities, $activity_ids, $comment_ids, $comments ); } } } // Add post comment status to activity meta if closed. if( 'closed' == $post->comment_status ) { bp_activity_update_meta( $activity->id, 'post_comment_status', $post->comment_status ); } else { bp_activity_delete_meta( $activity->id, 'post_comment_status' ); } } add_action( 'bp_activity_post_type_updated', 'bp_blogs_update_post_activity_meta', 10, 3 ); /** * Update Activity and blogs meta and eventually sync comment with activity comment * * @since 2.5.0 * * @param int|bool $activity_id ID of recorded activity, or false if sync is active. * @param WP_Comment|null $comment The comment object. * @param array $activity_args Array of activity arguments. * @param object|null $activity_post_object The post type tracking args object. * @return WP_Error|bool|int Returns false if no activity, the activity id otherwise. */ function bp_blogs_comment_sync_activity_comment( &$activity_id, $comment = null, $activity_args = array(), $activity_post_object = null ) { if ( empty( $activity_args ) || empty( $comment->post->ID ) || empty( $activity_post_object->comment_action_id ) ) { return false; } // Set the current blog id. $blog_id = get_current_blog_id(); // These activity metadatas are used to build the new_blog_comment action string. if ( ! empty( $activity_id ) && ! empty( $activity_args['item_id'] ) && 'new_blog_comment' === $activity_post_object->comment_action_id ) { // Add some post info in activity meta. bp_activity_update_meta( $activity_id, 'post_title', $comment->post->post_title ); bp_activity_update_meta( $activity_id, 'post_url', esc_url_raw( add_query_arg( 'p', $comment->post->ID, home_url( '/' ) ) ) ); } // Sync comment - activity comment. if ( ! bp_disable_blogforum_comments() ) { if ( ! empty( $_REQUEST['action'] ) ) { $existing_activity_id = get_comment_meta( $comment->comment_ID, 'bp_activity_comment_id', true ); if ( ! empty( $existing_activity_id ) ) { $activity_args['id'] = $existing_activity_id; } } if ( empty( $activity_post_object ) ) { $activity_post_object = bp_activity_get_post_type_tracking_args( $comment->post->post_type ); } if ( isset( $activity_post_object->action_id ) && isset( $activity_post_object->component_id ) ) { // Find the parent 'new_post_type' activity entry. $parent_activity_id = bp_activity_get_activity_id( array( 'component' => $activity_post_object->component_id, 'type' => $activity_post_object->action_id, 'item_id' => $blog_id, 'secondary_item_id' => $comment->comment_post_ID ) ); // Try to create a new activity item for the parent blog post. if ( empty( $parent_activity_id ) ) { $parent_activity_id = bp_activity_post_type_publish( $comment->post->ID, $comment->post ); } } // We found the parent activity entry // so let's go ahead and reconfigure some activity args. if ( ! empty( $parent_activity_id ) ) { // Set the parent activity entry ID. $activity_args['activity_id'] = $parent_activity_id; // Now see if the WP parent comment has a BP activity ID. $comment_parent = 0; if ( ! empty( $comment->comment_parent ) ) { $comment_parent = get_comment_meta( $comment->comment_parent, 'bp_activity_comment_id', true ); } // WP parent comment does not have a BP activity ID // so set to 'new_' . post_type activity ID. if ( empty( $comment_parent ) ) { $comment_parent = $parent_activity_id; } $activity_args['parent_id'] = $comment_parent; $activity_args['skip_notification'] = true; // Could not find corresponding parent activity entry // so wipe out $args array. } else { $activity_args = array(); } // Record in activity streams. if ( ! empty( $activity_args ) ) { $activity_id = bp_activity_new_comment( $activity_args ); if ( empty( $activity_args['id'] ) ) { // The activity metadata to inform about the corresponding comment ID. bp_activity_update_meta( $activity_id, "bp_blogs_{$comment->post->post_type}_comment_id", $comment->comment_ID ); // The comment metadata to inform about the corresponding activity ID. add_comment_meta( $comment->comment_ID, 'bp_activity_comment_id', $activity_id ); // These activity metadatas are used to build the new_blog_comment action string. if ( 'new_blog_comment' === $activity_post_object->comment_action_id ) { bp_activity_update_meta( $activity_id, 'post_title', $comment->post->post_title ); bp_activity_update_meta( $activity_id, 'post_url', esc_url_raw( add_query_arg( 'p', $comment->post->ID, home_url( '/' ) ) ) ); } } /** * Fires after an activity comment is added from a WP post comment. * * @since 2.6.0 * * @param int $activity_id The activity comment ID. * @param WP_Comment $post_type_comment WP Comment object. * @param array $activity_args Activity comment arguments. * @param object $activity_post_object The post type tracking args object. */ do_action( 'bp_blogs_comment_sync_activity_comment', $activity_id, $comment, $activity_args, $activity_post_object ); } } // Update the blogs last active date bp_blogs_update_blogmeta( $blog_id, 'last_activity', bp_core_current_time() ); if ( 'new_blog_comment' === $activity_post_object->comment_action_id ) { /** * Fires after BuddyPress has recorded metadata about a published blog post comment. * * @since 2.5.0 * * @param int $value Comment ID of the blog post comment being recorded. * @param WP_Post $post WP_Comment object for the current blog post. * @param string $value ID of the user associated with the current blog post comment. */ do_action( 'bp_blogs_new_blog_comment', $comment->comment_ID, $comment, bp_loggedin_user_id() ); } return $activity_id; } add_action( 'bp_activity_post_type_comment', 'bp_blogs_comment_sync_activity_comment', 10, 4 ); /** * Record a user's association with a blog. * * This function is hooked to several WordPress actions where blog roles are * set/changed ('add_user_to_blog', 'profile_update', 'user_register'). It * parses the changes, and records them as necessary in the BP blog tracker. * * BuddyPress does not track blogs for users with the 'subscriber' role by * default, though as of 2.1.0 you can filter 'bp_blogs_get_allowed_roles' to * modify this behavior. * * @param int $user_id The ID of the user. * @param string|bool $role User's WordPress role for this blog ID. * @param int $blog_id Blog ID user is being added to. * @return false|null False on failure. */ function bp_blogs_add_user_to_blog( $user_id, $role = false, $blog_id = 0 ) { global $wpdb; // If no blog ID was passed, use the root blog ID. if ( empty( $blog_id ) ) { $blog_id = isset( $wpdb->blogid ) ? $wpdb->blogid : bp_get_root_blog_id(); } // If no role was passed, try to find the blog role. if ( empty( $role ) ) { // Get user capabilities. $key = $wpdb->get_blog_prefix( $blog_id ). 'capabilities'; $user_roles = array_keys( (array) bp_get_user_meta( $user_id, $key, true ) ); // User has roles so lets. if ( ! empty( $user_roles ) ) { // Get blog roles. $blog_roles = array_keys( bp_get_current_blog_roles() ); // Look for blog only roles of the user. $intersect_roles = array_intersect( $user_roles, $blog_roles ); // If there's a role in the array, use the first one. This isn't // very smart, but since roles aren't exactly hierarchical, and // WordPress does not yet have a UI for multiple user roles, it's // fine for now. if ( ! empty( $intersect_roles ) ) { $role = array_shift( $intersect_roles ); } } } // Bail if no role was found or role is not in the allowed roles array. if ( empty( $role ) || ! in_array( $role, bp_blogs_get_allowed_roles() ) ) { return false; } // Record the blog activity for this user being added to this blog. bp_blogs_record_blog( $blog_id, $user_id, true ); } add_action( 'add_user_to_blog', 'bp_blogs_add_user_to_blog', 10, 3 ); add_action( 'profile_update', 'bp_blogs_add_user_to_blog' ); add_action( 'user_register', 'bp_blogs_add_user_to_blog' ); /** * The allowed blog roles a member must have to be recorded into the * `bp_user_blogs` pointer table. * * This added and was made filterable in BuddyPress 2.1.0 to make it easier * to extend the functionality of the Blogs component. * * @since 2.1.0 * * @return string */ function bp_blogs_get_allowed_roles() { /** * Filters the allowed roles a member must have to be recorded into bp_user_blogs pointer table. * * @since 2.1.0 * * @param array $value Array of potential roles user needs. */ return apply_filters( 'bp_blogs_get_allowed_roles', array( 'contributor', 'author', 'editor', 'administrator' ) ); } /** * Remove a blog-user pair from BP's blog tracker. * * @param int $user_id ID of the user whose blog is being removed. * @param int $blog_id Optional. ID of the blog being removed. Default: current blog ID. */ function bp_blogs_remove_user_from_blog( $user_id, $blog_id = 0 ) { global $wpdb; if ( empty( $blog_id ) ) { $blog_id = $wpdb->blogid; } bp_blogs_remove_blog_for_user( $user_id, $blog_id ); } add_action( 'remove_user_from_blog', 'bp_blogs_remove_user_from_blog', 10, 2 ); /** * Rehook WP's maybe_add_existing_user_to_blog with a later priority. * * WordPress catches add-user-to-blog requests at init:10. In some cases, this * can precede BP's Blogs component. This function bumps the priority of the * core function, so that we can be sure that the Blogs component is loaded * first. See https://buddypress.trac.wordpress.org/ticket/3916. * * @since 1.6.0 */ function bp_blogs_maybe_add_user_to_blog() { if ( ! is_multisite() ) return; remove_action( 'init', 'maybe_add_existing_user_to_blog' ); add_action( 'init', 'maybe_add_existing_user_to_blog', 20 ); } add_action( 'init', 'bp_blogs_maybe_add_user_to_blog', 1 ); /** * Remove the "blog created" item from the BP blogs tracker and activity stream. * * @param int $blog_id ID of the blog being removed. */ function bp_blogs_remove_blog( $blog_id ) { $blog_id = (int) $blog_id; /** * Fires before a "blog created" item is removed from blogs * tracker and activity stream. * * @since 1.5.0 * * @param int $blog_id ID of the blog having its item removed. */ do_action( 'bp_blogs_before_remove_blog', $blog_id ); BP_Blogs_Blog::delete_blog_for_all( $blog_id ); /** * Fires after a "blog created" item has been removed from blogs * tracker and activity stream. * * @since 1.0.0 * * @param int $blog_id ID of the blog who had its item removed. */ do_action( 'bp_blogs_remove_blog', $blog_id ); } add_action( 'bp_delete_site', 'bp_blogs_remove_blog' ); /** * Remove a blog from the tracker for a specific user. * * @param int $user_id ID of the user for whom the blog is being removed. * @param int $blog_id ID of the blog being removed. */ function bp_blogs_remove_blog_for_user( $user_id, $blog_id ) { $blog_id = (int) $blog_id; $user_id = (int) $user_id; /** * Fires before a blog is removed from the tracker for a specific user. * * @since 1.5.0 * * @param int $blog_id ID of the blog being removed. * @param int $user_id ID of the user having the blog removed for. */ do_action( 'bp_blogs_before_remove_blog_for_user', $blog_id, $user_id ); BP_Blogs_Blog::delete_blog_for_user( $blog_id, $user_id ); /** * Fires after a blog has been removed from the tracker for a specific user. * * @since 1.0.0 * * @param int $blog_id ID of the blog that was removed. * @param int $user_id ID of the user having the blog removed for. */ do_action( 'bp_blogs_remove_blog_for_user', $blog_id, $user_id ); } add_action( 'remove_user_from_blog', 'bp_blogs_remove_blog_for_user', 10, 2 ); /** * Remove a synced activity comment from the activity stream. * * @since 2.5.0 * * @param bool $deleted True when a comment post type activity was successfully removed. * @param int $comment_id ID of the comment to be removed. * @param object $activity_post_object The post type tracking args object. * @param string $activity_type The post type comment activity type. * * @return bool True on success. False on error. */ function bp_blogs_post_type_remove_comment( $deleted, $comment_id, $activity_post_object, $activity_type = '' ) { // Remove synced activity comments, if needed. if ( ! bp_disable_blogforum_comments() ) { // Get associated activity ID from comment meta $activity_id = get_comment_meta( $comment_id, 'bp_activity_comment_id', true ); /** * Delete the associated activity comment & also remove * child post comments and associated activity comments. */ if ( ! empty( $activity_id ) ) { // Fetch the activity comments for the activity item. $activity = bp_activity_get( array( 'in' => $activity_id, 'display_comments' => 'stream', 'spam' => 'all', ) ); // Get all activity comment IDs for the pending deleted item. if ( ! empty( $activity['activities'] ) ) { $activity_ids = bp_activity_recurse_comments_activity_ids( $activity ); $activity_ids[] = $activity_id; // Delete activity items. foreach ( $activity_ids as $activity_id ) { bp_activity_delete( array( 'id' => $activity_id ) ); } // Remove associated blog comments. bp_blogs_remove_associated_blog_comments( $activity_ids ); // Rebuild activity comment tree. BP_Activity_Activity::rebuild_activity_comment_tree( $activity['activities'][0]->item_id ); // Set the result. $deleted = true; } } } // Backcompat for comments about the 'post' post type. if ( 'new_blog_comment' === $activity_type ) { /** * Fires after a blog comment activity item was removed from activity stream. * * @since 1.0.0 * * @param int $value ID for the blog associated with the removed comment. * @param int $comment_id ID of the comment being removed. * @param int $value ID of the current logged in user. */ do_action( 'bp_blogs_remove_comment', get_current_blog_id(), $comment_id, bp_loggedin_user_id() ); } return $deleted; } add_action( 'bp_activity_post_type_remove_comment', 'bp_blogs_post_type_remove_comment', 10, 4 ); /** * Removes blog comments that are associated with activity comments. * * @since 2.0.0 * * @see bp_blogs_remove_synced_comment() * @see bp_blogs_sync_delete_from_activity_comment() * * @param array $activity_ids The activity IDs to check association with blog * comments. * @param bool $force_delete Whether to force delete the comments. If false, * comments are trashed instead. */ function bp_blogs_remove_associated_blog_comments( $activity_ids = array(), $force_delete = true ) { // Query args. $query_args = array( 'meta_query' => array( array( 'key' => 'bp_activity_comment_id', 'value' => implode( ',', (array) $activity_ids ), 'compare' => 'IN', ) ) ); // Get comment. $comment_query = new WP_Comment_Query; $comments = $comment_query->query( $query_args ); // Found the corresponding comments // let's delete them! foreach ( $comments as $comment ) { wp_delete_comment( $comment->comment_ID, $force_delete ); // If we're trashing the comment, remove the meta key as well. if ( empty( $force_delete ) ) { delete_comment_meta( $comment->comment_ID, 'bp_activity_comment_id' ); } } } /** * Get the total number of blogs being tracked by BuddyPress. * * @return int $count Total blog count. */ function bp_blogs_total_blogs() { $count = wp_cache_get( 'bp_total_blogs', 'bp' ); if ( false === $count ) { $blogs = BP_Blogs_Blog::get_all(); $count = $blogs['total']; wp_cache_set( 'bp_total_blogs', $count, 'bp' ); } return $count; } /** * Get the total number of blogs being tracked by BP for a specific user. * * @since 1.2.0 * * @param int $user_id ID of the user being queried. Default: on a user page, * the displayed user. Otherwise, the logged-in user. * @return int $count Total blog count for the user. */ function bp_blogs_total_blogs_for_user( $user_id = 0 ) { if ( empty( $user_id ) ) { $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id(); } // No user ID? do not attempt to look at cache. if ( empty( $user_id ) ) { return 0; } $count = wp_cache_get( 'bp_total_blogs_for_user_' . $user_id, 'bp' ); if ( false === $count ) { $count = BP_Blogs_Blog::total_blog_count_for_user( $user_id ); wp_cache_set( 'bp_total_blogs_for_user_' . $user_id, $count, 'bp' ); } return $count; } /** * Remove the all data related to a given blog from the BP blogs tracker and activity stream. * * @param int $blog_id The ID of the blog to expunge. */ function bp_blogs_remove_data_for_blog( $blog_id ) { /** * Fires before all data related to a given blog is removed from blogs tracker * and activity stream. * * @since 1.5.0 * * @param int $blog_id ID of the blog whose data is being removed. */ do_action( 'bp_blogs_before_remove_data_for_blog', $blog_id ); // If this is regular blog, delete all data for that blog. BP_Blogs_Blog::delete_blog_for_all( $blog_id ); /** * Fires after all data related to a given blog has been removed from blogs tracker * and activity stream. * * @since 1.0.0 * * @param int $blog_id ID of the blog whose data is being removed. */ do_action( 'bp_blogs_remove_data_for_blog', $blog_id ); } add_action( 'bp_delete_site', 'bp_blogs_remove_data_for_blog', 1 ); /** * Get all of a user's blogs, as tracked by BuddyPress. * * @see BP_Blogs_Blog::get_blogs_for_user() for a description of parameters * and return values. * * @param int $user_id See {@BP_Blogs_Blog::get_blogs_for_user()}. * @param bool $show_hidden See {@BP_Blogs_Blog::get_blogs_for_user()}. * @return array See {@BP_Blogs_Blog::get_blogs_for_user()}. */ function bp_blogs_get_blogs_for_user( $user_id, $show_hidden = false ) { return BP_Blogs_Blog::get_blogs_for_user( $user_id, $show_hidden ); } /** * Retrieve a list of all blogs. * * @see BP_Blogs_Blog::get_all() for a description of parameters and return values. * * @param int|null $limit See {@BP_Blogs_Blog::get_all()}. * @param int|null $page See {@BP_Blogs_Blog::get_all()}. * @return array See {@BP_Blogs_Blog::get_all()}. */ function bp_blogs_get_all_blogs( $limit = null, $page = null ) { return BP_Blogs_Blog::get_all( $limit, $page ); } /** * Retrieve a random list of blogs. * * @see BP_Blogs_Blog::get() for a description of parameters and return values. * * @param int|null $per_page See {@BP_Blogs_Blog::get()}. * @param int|null $page See {@BP_Blogs_Blog::get()}. * @return array See {@BP_Blogs_Blog::get()}. */ function bp_blogs_get_random_blogs( $per_page = null, $page = null ) { return BP_Blogs_Blog::get( array( 'type' => 'random', 'per_page' => $per_page, 'page' => $page ) ); } /** * Check whether a given blog is hidden. * * @see BP_Blogs_Blog::is_hidden() for a description of parameters and return values. * * @param int $blog_id See {@BP_Blogs_Blog::is_hidden()}. * @return bool See {@BP_Blogs_Blog::is_hidden()}. */ function bp_blogs_is_blog_hidden( $blog_id ) { return BP_Blogs_Blog::is_hidden( $blog_id ); } /* * Blog meta functions * * These functions are used to store specific blogmeta in one global table, * rather than in each blog's options table. Significantly speeds up global blog * queries. By default each blog's name, description and last updated time are * stored and synced here. */ /** * Delete a metadata from the DB for a blog. * * @global object $wpdb WordPress database access object. * * @param int $blog_id ID of the blog whose metadata is being deleted. * @param string|bool $meta_key Optional. The key of the metadata being deleted. If * omitted, all BP metadata associated with the blog will * be deleted. * @param string|bool $meta_value Optional. If present, the metadata will only be * deleted if the meta_value matches this parameter. * @param bool $delete_all Optional. If true, delete matching metadata entries for * all objects, ignoring the specified blog_id. Otherwise, only * delete matching metadata entries for the specified blog. * Default: false. * @return bool True on success, false on failure. */ function bp_blogs_delete_blogmeta( $blog_id, $meta_key = false, $meta_value = false, $delete_all = false ) { global $wpdb; // Legacy - if no meta_key is passed, delete all for the blog_id. if ( empty( $meta_key ) ) { $table_name = buddypress()->blogs->table_name_blogmeta; $sql = "SELECT meta_key FROM {$table_name} WHERE blog_id = %d"; $query = $wpdb->prepare( $sql, $blog_id ); $keys = $wpdb->get_col( $query ); // With no meta_key, ignore $delete_all. $delete_all = false; } else { $keys = array( $meta_key ); } add_filter( 'query', 'bp_filter_metaid_column_name' ); add_filter( 'sanitize_key', 'bp_blogs_filter_meta_column_name' ); $retval = false; foreach ( $keys as $key ) { $retval = delete_metadata( 'bp_blog', $blog_id, $key, $meta_value, $delete_all ); } remove_filter( 'query', 'bp_filter_metaid_column_name' ); remove_filter( 'sanitize_key', 'bp_blogs_filter_meta_column_name' ); return $retval; } /** * Get metadata for a given blog. * * @since 1.2.0 * * @global object $wpdb WordPress database access object. * * @param int $blog_id ID of the blog whose metadata is being requested. * @param string $meta_key Optional. If present, only the metadata matching * that meta key will be returned. Otherwise, all * metadata for the blog will be fetched. * @param bool $single Optional. If true, return only the first value of the * specified meta_key. This parameter has no effect if * meta_key is not specified. Default: true. * @return mixed The meta value(s) being requested. */ function bp_blogs_get_blogmeta( $blog_id, $meta_key = '', $single = true ) { add_filter( 'query', 'bp_filter_metaid_column_name' ); add_filter( 'sanitize_key', 'bp_blogs_filter_meta_column_name' ); $retval = get_metadata( 'bp_blog', $blog_id, $meta_key, $single ); remove_filter( 'sanitize_key', 'bp_blogs_filter_meta_column_name' ); remove_filter( 'query', 'bp_filter_metaid_column_name' ); return $retval; } /** * Update a piece of blog meta. * * @global object $wpdb WordPress database access object. * * @param int $blog_id ID of the blog whose metadata is being updated. * @param string $meta_key Key of the metadata being updated. * @param mixed $meta_value Value to be set. * @param mixed $prev_value Optional. If specified, only update existing * metadata entries with the specified value. * Otherwise, update all entries. * @return bool|int Returns false on failure. On successful update of existing * metadata, returns true. On successful creation of new metadata, * returns the integer ID of the new metadata row. */ function bp_blogs_update_blogmeta( $blog_id, $meta_key, $meta_value, $prev_value = '' ) { add_filter( 'query', 'bp_filter_metaid_column_name' ); add_filter( 'sanitize_key', 'bp_blogs_filter_meta_column_name' ); $retval = update_metadata( 'bp_blog', $blog_id, $meta_key, $meta_value, $prev_value ); remove_filter( 'sanitize_key', 'bp_blogs_filter_meta_column_name' ); remove_filter( 'query', 'bp_filter_metaid_column_name' ); return $retval; } /** * Add a piece of blog metadata. * * @since 2.0.0 * * @param int $blog_id ID of the blog. * @param string $meta_key Metadata key. * @param mixed $meta_value Metadata value. * @param bool $unique Optional. Whether to enforce a single metadata value * for the given key. If true, and the object already has a value for * the key, no change will be made. Default: false. * @return int|bool The meta ID on successful update, false on failure. */ function bp_blogs_add_blogmeta( $blog_id, $meta_key, $meta_value, $unique = false ) { add_filter( 'query', 'bp_filter_metaid_column_name' ); add_filter( 'sanitize_key', 'bp_blogs_filter_meta_column_name' ); $retval = add_metadata( 'bp_blog', $blog_id, $meta_key, $meta_value, $unique ); remove_filter( 'sanitize_key', 'bp_blogs_filter_meta_column_name' ); remove_filter( 'query', 'bp_filter_metaid_column_name' ); return $retval; } /** * Remove all blog associations for a given user. * * @param int $user_id ID whose blog data should be removed. * @return bool Returns false on failure. */ function bp_blogs_remove_data( $user_id ) { if ( !is_multisite() ) return false; /** * Fires before all blog associations are removed for a given user. * * @since 1.5.0 * * @param int $user_id ID of the user whose blog associations are being removed. */ do_action( 'bp_blogs_before_remove_data', $user_id ); // If this is regular blog, delete all data for that blog. BP_Blogs_Blog::delete_blogs_for_user( $user_id ); /** * Fires after all blog associations are removed for a given user. * * @since 1.0.0 * * @param int $user_id ID of the user whose blog associations were removed. */ do_action( 'bp_blogs_remove_data', $user_id ); } add_action( 'wpmu_delete_user', 'bp_blogs_remove_data' ); add_action( 'bp_make_spam_user', 'bp_blogs_remove_data' ); /** * Deletes user XProfile data on the 'delete_user' hook. * * @since 6.0.0 * * @param int $user_id The ID of the deleted user. */ function bp_blogs_remove_data_on_delete_user( $user_id ) { if ( ! bp_remove_user_data_on_delete_user_hook( 'blogs', $user_id ) ) { return; } bp_blogs_remove_data( $user_id ); } add_action( 'delete_user', 'bp_blogs_remove_data_on_delete_user' ); /** * Restore all blog associations for a given user. * * @since 2.2.0 * * @param int $user_id ID whose blog data should be restored. */ function bp_blogs_restore_data( $user_id = 0 ) { if ( ! is_multisite() ) { return; } // Get the user's blogs. $user_blogs = get_blogs_of_user( $user_id ); if ( empty( $user_blogs ) ) { return; } $blogs = array_keys( $user_blogs ); foreach ( $blogs as $blog_id ) { bp_blogs_add_user_to_blog( $user_id, false, $blog_id ); } } add_action( 'bp_make_ham_user', 'bp_blogs_restore_data', 10, 1 ); /** * Checks whether blog creation is enabled. * * Returns true when blog creation is enabled for logged-in users only, or * when it's enabled for new registrations. * * @since 1.0.0 * @since 7.0.0 The function has been moved into `bp-blogs/bp-blogs-functions.php`. * * @return bool True if blog registration is enabled. */ function bp_blog_signup_enabled() { $bp = buddypress(); $retval = true; $active_signup = 'all'; if ( isset( $bp->site_options['registration'] ) ) { $active_signup = $bp->site_options['registration']; } /** * Filters whether or not blog creation is enabled. * * Return "all", "none", "blog" or "user". * * @since 1.0.0 * * @param string $active_signup Value of the registration site option creation status. */ $active_signup = apply_filters( 'wpmu_active_signup', $active_signup ); if ( 'none' === $active_signup || 'user' === $active_signup ) { $retval = false; } return $retval; } /** * Returns the Blog signup's submitted vars. * * @since 7.0.0 * * @return array An associative array containing the Blog signup's submitted vars. */ function bp_blogs_get_signup_form_submitted_vars() { $exprected_vars = array( 'blogname' => '', 'blog_title' => '', 'blog_public' => 0, ); $submitted_vars = bp_parse_args( $_POST, $exprected_vars ); return array_map( 'wp_unslash', array_intersect_key( $submitted_vars, $exprected_vars ) ); } /** * Validate a blog creation submission. * * Essentially, a wrapper for {@link wpmu_validate_blog_signup()}. * * @since 1.0.0 * @since 7.0.0 Add the blog_name and blog_title parameters. * The function has been moved into `bp-blogs/bp-blogs-functions.php`. * * @return array Contains the new site data and error messages. */ function bp_blogs_validate_blog_form( $blog_name = '', $blog_title = '' ) { $user = ''; if ( is_user_logged_in() ) { $user = wp_get_current_user(); } if ( ! $blog_name && ! $blog_title ) { $submitted_vars = bp_blogs_get_signup_form_submitted_vars(); if ( array_filter( $submitted_vars ) ) { $blog_name = $submitted_vars['blogname']; $blog_title = $submitted_vars['blog_title']; } } return wpmu_validate_blog_signup( $blog_name, $blog_title, $user ); } /** * Gets the site icon URL even when BuddyPress is not network activated. * * @since 7.0.0 * * @param integer $blog_id The ID of the blog to get the site icon URL for. * @param integer $size The size of the site icon. * @return string The site icon URL */ function bp_blogs_get_site_icon_url( $blog_id = 0, $size = 512 ) { if ( is_multisite() && ! bp_is_network_activated() && ! bp_is_root_blog( $blog_id ) ) { $switched_blog = false; $url = ''; if ( $blog_id && get_current_blog_id() !== (int) $blog_id ) { switch_to_blog( $blog_id ); $switched_blog = true; } $site_icon_id = get_option( 'site_icon' ); if ( $site_icon_id ) { $site_icon_data = wp_get_attachment_metadata( $site_icon_id ); $sizes = wp_list_pluck( $site_icon_data['sizes'], 'width' ); sort( $sizes ); $closest = 'full'; foreach ( $sizes as $width ) { $closest = array( $width, $width ); if ( (int) $size < (int) $width ) { break; } } $url = wp_get_attachment_image_url( $site_icon_id, $closest ); } if ( $switched_blog ) { restore_current_blog(); } return $url; } return get_site_icon_url( $size, '', $blog_id ); }