WordPress.org

Make WordPress Core

Opened 9 years ago

Closed 6 years ago

Last modified 4 years ago

#14511 closed enhancement (fixed)

new function - wp_get_sites($args)

Reported by: transom Owned by:
Milestone: 3.7 Priority: normal
Severity: normal Version:
Component: Multisite Keywords: has-patch needs-testing
Focuses: Cc:

Description (last modified by nacin)

With the deprication of get_blog_list (and the dire warnings), we had a need for a function to retrieve a list of blogs. At first blush, it appears that one could use get_blogs_of_user. It seems to assume that the same admin (userid 1) is going to create all sites. If you have multiple network_admins, then a search for a single user's sites won't return a full list.

So I have adapted the code from wp-admin/ms-sites.php and with a nod to wp_list_pages - am submitting wp_get_sites for a future release.

This function accepts an argument list to filter the results, modify the order, and limit the range of results. I wrote it with an eye to provide an interface consistent with other wp functions, as well as potentially replacing the sql query in wp-admin/ms-sites.php.

The initial set of arguments include:

			'include_id' 		,				// includes only these sites in the results, comma-delimited
			'exclude_id' 		,				// excludes these sites from the results, comma-delimted
			'blogname_like' 	,				// domain or path is like this value
			'ip_like'			,				// Match IP address
			'reg_date_since'	,				// sites registered since (accepts pretty much any valid date like tomorrow, today, 5/12/2009, etc.)
			'reg_date_before'	,				// sites registered before
			'include_user_id'	,				// only sites owned by these users, comma-delimited
			'exclude_user_id'	,				// don't include sites owned by these users, comma-delimited
			'include_spam'		=> false,		// Include sites marked as "spam"
			'include_deleted'	=> false,		// Include deleted sites
			'include_archived'	=> false,		// Include archived sites
			'include_mature'	=> false,		// Included blogs marked as mature
			'public_only'		=> true,		// Include only blogs marked as public
			'sort_column'		=> 'registered',// or registered, last_updated, blogname, site_id
			'order'				=> 'asc',		// or desc
			'limit_results'		,				// return this many results
			'start'				,				// return results starting with this item

The usual warning are provided. It works for me but I haven't tested it completely yet. But I am assuming this could be helpful to others and I have no doubt about getting comments back <grin>

Attachments (12)

wp-get-sites.php (4.5 KB) - added by transom 9 years ago.
Source for wp_get_sites
wp_get_sites.diff (4.7 KB) - added by transom 9 years ago.
Add wp_get_sites to ms-functions.php
wp-get-sites.2.php (4.4 KB) - added by transom 9 years ago.
Standalone version of wp_get_sites() - toss in functions.php to test
wp-get-sites.3.php (3.7 KB) - added by pbaylies 7 years ago.
Standalone version of wp_get_sites() - toss in functions.php to test
14511.diff (1.5 KB) - added by jeremyfelt 6 years ago.
14511.2.diff (1.8 KB) - added by jeremyfelt 6 years ago.
14511.3.diff (1.9 KB) - added by jeremyfelt 6 years ago.
14511.4.diff (2.0 KB) - added by jeremyfelt 6 years ago.
14511.5.diff (4.0 KB) - added by jeremyfelt 6 years ago.
14511_wp_parse_id_list.diff (656 bytes) - added by jamescollins 6 years ago.
14511_offset.diff (2.9 KB) - added by jamescollins 6 years ago.
14511_offset2.diff (2.9 KB) - added by jamescollins 6 years ago.

Download all attachments as: .zip

Change History (59)

@transom
9 years ago

Source for wp_get_sites

#1 @scribu
9 years ago

  • Keywords has-patch added; multisite get_blogs_by_user removed

Pretty neat.

#2 @transom
9 years ago

Found a bug will submit new patch shortly (joining on the registration log causes interesting problems vis-a-vie blogs not created via registration - duh!)

#3 @transom
9 years ago

Attached is a patch for wp-includes/ms-functions.php (replacing the farked version)

#4 @nacin
9 years ago

  • Description modified (diff)

#5 @nacin
9 years ago

This probably generates quite a bit of notices (turn on WP_DEBUG) since most of the variables being extracted don't actually exist in the array. include_id is being considered a value, not the key -- should be include_id => '' instead.

Lots of LIKEs and such. This query probably isn't very efficient, but it's a start we can work off of.

#6 @transom
9 years ago

Changing the "isset" to not-empty (after defining defaults for all strings).

I am confused by your comment re: variables being extracted not existing in the array - after the wp_parse_args there should be a value (even if it is the default) for each variable.

Include_id is supposed to be a string of blog_ids to be included in the results.

Will post new diff shortly.

@transom
9 years ago

Add wp_get_sites to ms-functions.php

@transom
9 years ago

Standalone version of wp_get_sites() - toss in functions.php to test

#7 @transom
9 years ago

Updated diff and attached file for wp_get_sites that can used in functions.php to test functionality

#8 follow-up: @kahless
9 years ago

Copied wp_get_sites2.php into my themes functions.php and am getting

Undefined property: wpdb::$site_id in /path-to-wp-content/wp-content/themes/delicious/functions.php on line 159

and line 159 is

$query .= "WHERE b.site_id = '{$wpdb->site_id}' ";

I am running the latest nightly build.

#9 in reply to: ↑ 8 ; follow-up: @kahless
9 years ago

Replying to kahless:

Copied wp_get_sites2.php into my themes functions.php and am getting

Undefined property: wpdb::$site_id in /path-to-wp-content/wp-content/themes/delicious/functions.php on line 159

and line 159 is

$query .= "WHERE b.site_id = '{$wpdb->site_id}' ";

I am running the latest nightly build.

I am running a subdirectory install if that makes any difference.

#10 @nacin
9 years ago

  • Keywords 3.2-early added
  • Milestone changed from Awaiting Review to Future Release

Will likely need some thought and a new patch.

#11 in reply to: ↑ 9 @cesperanc
8 years ago

Replying to kahless:

Replying to kahless:

Copied wp_get_sites2.php into my themes functions.php and am getting

Undefined property: wpdb::$site_id in /path-to-wp-content/wp-content/themes/delicious/functions.php on line 159

and line 159 is

$query .= "WHERE b.site_id = '{$wpdb->site_id}' ";

I am running the latest nightly build.

I am running a subdirectory install if that makes any difference.

I've the same problem here. Renaming {$wpdb->site_id} to {$wpdb->siteid} seams to resolve the problem.

#12 @garyc40
8 years ago

  • Cc garyc40@… added
  • Keywords needs-patch added; has-patch removed

#13 @mikeschinkel
8 years ago

  • Cc mikeschinkel@… added

#14 @aneesme
8 years ago

No caching?

#15 @westi
8 years ago

  • Keywords 3.2-early removed

Not for 3.2

#16 @BjornW
8 years ago

  • Cc mailings@… added

#17 @xyzzy
7 years ago

  • Cc dennen@… added

@pbaylies
7 years ago

Standalone version of wp_get_sites() - toss in functions.php to test

#18 @pbaylies
7 years ago

  • Cc pbaylies added
  • Keywords has-patch needs-testing added; needs-patch removed

I've uploaded a new patch for this, rewritten the original without the join and some of the options, and most of the LIKEs; all data in the query should be known or sanitized as well. So what do we need to do to get a function like this back into core.

#19 @mordauk
7 years ago

  • Cc pippin@… added

@jeremyfelt
6 years ago

#20 @jeremyfelt
6 years ago

  • Milestone changed from Future Release to 3.7

A wp_get_sites() would be nice.

IMO, it doesn't necessarily need to duplicate the efforts of get_blog_list() (deprecated in [15170]). It should provide a straight forward method of accessing information about the sites in a specified network.

I've attached 14511.diff as a starting point. Caching needs to be added and most likely the site query would need to return more than blog_id, domain, path.

Moving to 3.7 for discussion.

#21 @nacin
6 years ago

14511.diff is simple and definitely an improvement over get_blog_list(), which I've previously ranted about.

I'd argue that $network_id should be a default argument in $args, and that setting it to null, bool, or 'all' should allow all network IDs to be queried; it should probably also take an array of network IDs to query. What about querying regardless of the value of public or other flags? (As in, you want any sites whether it is public or not.) What about querying by domain and by path? What about wp_is_large_network()? Is it worth looking into a proper WP_Site_Query class?

Not suggesting this should get out of hand, but just tossing out some ideas. I'm fine with 14511.diff, with minor modifications, for 3.7.

#22 @Mat Lipe
6 years ago

  • Cc Mat Lipe added

@jeremyfelt
6 years ago

#23 @jeremyfelt
6 years ago

14511.2.diff does a few things better/differently.

  • $network_id defaults to null as a default argument in $args
  • If $network_id is passed as null, bool, or all, sites from all networks are returned
  • If $network_id is passed as a single network ID or an array of network IDs, only those sites are returned
  • Arguments for public, archived, mature, spam, deleted are accepted. By default they are left out of the query
  • All DB fields are returned in the response rather than just blog_id, domain, and path.

Have not hit querying by domain/path yet.

@jeremyfelt
6 years ago

#24 @jeremyfelt
6 years ago

14511.3.diff is the above with the realization that there is no reason to reprocess results into a new array.

Also starts to add caching, though invalidation is likely going to be a bit weird. I'm guessing we need a last_updated key to rely on, but then need to figure out all the places that indicate a refresh is needed.

#25 @blobaugh
6 years ago

  • Cc ben@… added

#26 @martythornley
6 years ago

  • Cc marty@… added

@jeremyfelt
6 years ago

#27 @jeremyfelt
6 years ago

14511.4.diff removes the initial caching attempts, to be addressed at a later time, and adds a default limit argument of 100 for the query.

Also use %d instead of %s in the prepare statement as we're dealing with int and enum.

Last edited 6 years ago by jeremyfelt (previous) (diff)

#28 follow-up: @nacin
6 years ago

14511.4.diff looks good. A few things:

  • Some basic unit tests would be stellar.
  • If get_results() returns no results, the response will be array( 0 => null ) — I imagine an empty array was desired.
  • If wp_is_large_network() is true, null is returned — I imagine an empty array was desired.
  • I would document public, deleted, etc., as "defaults". The trick is to set them to null, which is ! isset().
  • Some super basic unit tests would be fantastic. Probably just testing 'public' => null, true, and false; and also the return value for when nothing matches (as in an empty array).

@jeremyfelt
6 years ago

#29 in reply to: ↑ 28 @jeremyfelt
6 years ago

14511.5.diff adds basic unit tests and ensures proper return of an empty array if no results return.

Replying to nacin:

  • If get_results() returns no results, the response will be array( 0 => null ) — I imagine an empty array was desired.

I always got an empty array with how it was setup, though the updated patch uses $wpdb->get_results( $query, ARRAY_A ) to make sure an array is returned rather than null if no results are found.

Last edited 6 years ago by jeremyfelt (previous) (diff)

#30 follow-up: @nacin
6 years ago

I think wp_get_sites() should only return sites *from that network* by default. You should need to explicitly pass null to this function to get sites from any network.

This is similar to how WP_User_Query works (only users assigned to a site), and also the network admin (only sites for the network being edited).

I think the roadmap for this function, by the way, should be to replace all direct queries to $wpdb->blogs in WP_MS_Sites_List_Table, and ideally any other non-complex direct queries to $wpdb->blogs elsewhere.

#31 @nacin
6 years ago

In 25445:

Introduce wp_get_sites(), a long-awaited replacement for get_blog_list().

props jeremyfelt.
see #14511.

#32 @toscho
6 years ago

There should be one white space before 'intval':

$network_ids = array_map('intval', (array) $args['network_id'] );

#33 @toscho
6 years ago

  • Cc info@… added

#34 @nacin
6 years ago

As reported by markoheijnen, archived remains an ENUM of '0' and '1'. These are indexed from 1, so querying for the integer 1 means we're actually querying the ENUM 0. Going to write a test to demonstrate this.

We've worked to eliminate ENUM from the database previously, but all of those former ENUM fields became strings. ([6732].) In this case, it should become a tinyint(2) like the related fields. I am not familiar with what an upgrade routine might look like for this. pento might have some ideas.

http://dev.mysql.com/doc/refman/5.0/en/enum.html

#35 @nacin
6 years ago

In 25446:

Proper treatment of the 'archived' field in wp_get_sites(). see #14511.

#36 @nacin
6 years ago

Open ticket for ENUM/archived is #12832.

#37 in reply to: ↑ 30 @jeremyfelt
6 years ago

Replying to nacin:

This is similar to how WP_User_Query works (only users assigned to a site), and also the network admin (only sites for the network being edited).

That makes sense. Random info for another ticket: the WP_MS_Users_List_Table overwrites that user query with blog_id => 0, so all users are returned on all networks.

I think the roadmap for this function, by the way, should be to replace all direct queries to $wpdb->blogs in WP_MS_Sites_List_Table, and ideally any other non-complex direct queries to $wpdb->blogs elsewhere.

Agreed. There's a bunch that can be cleaned up. To go all the way, we'd also want to handle domain and path searches.

#38 in reply to: ↑ 38 ; follow-up: @jamescollins
6 years ago

14511_wp_parse_id_list.diff​ uses WordPress' built in wp_parse_id_list() function to parse the network_id parameter.

#39 @jamescollins
6 years ago

Given that we have a limit parameter, I thought it would be useful to also add an offset parameter.

This allows people to query the first 100 sites, then the second 100 sites if required.

14511_offset.diff​ implements this, including unit tests.

Last edited 6 years ago by jamescollins (previous) (diff)

#40 @SergeyBiryukov
6 years ago

In 25487:

Use wp_parse_id_list() to parse the 'network_id' parameter in wp_get_sites().

props jamescollins.
see #14511.

#41 follow-up: @SergeyBiryukov
6 years ago

In 14511_offset.diff, looks like intval( $args['limit'] ) > 0 in line 2057 can be just $args['limit']. Same for $args['offset'].

#42 in reply to: ↑ 41 @jamescollins
6 years ago

Replying to SergeyBiryukov:

In 14511_offset.diff, looks like intval( $args['limit'] ) > 0 in line 2057 can be just $args['limit']. Same for $args['offset'].

Thanks for the feedback SergeyBiryukov.

I've implemented this in 14511_offset2.diff.

#43 @SergeyBiryukov
6 years ago

In 25488:

Introduce 'offset' parameter for wp_get_sites().

props jamescollins.
see #14511.

#44 @jeremyfelt
6 years ago

Should we revert/modify [25446] now that [25448] converts archived from enum to tinyint?

#45 @nacin
6 years ago

In 25590:

Revert [25446] now that wp_blogs.archived is no longer an ENUM field. see #14511.

#46 @nacin
6 years ago

  • Resolution set to fixed
  • Status changed from new to closed

I'm going to close this as fixed. New enhancements can be brought up in new tickets.

This ticket was mentioned in Slack in #core-multisite by jeremyfelt. View the logs.


4 years ago

Note: See TracTickets for help on using tickets.