Developer Diaries – WP Teams and Multisite Architecture

low angle photography of gray building at daytime
Photo by Anders Jildén on Unsplash

I went over the features that I wanted for WP Teams in the last developer diary. One question that keeps lingering in the back of my mind was if I should add multisite support for it.

This changes a lot of the data architecture. I originally figured that each Team could be a hidden post type, and that each team member was part of another hidden post type with a taxonomy attached for categories.

However, on multisite, things get complicated. I could theoretically do the architecture on the main site with the post types and taxonomies, but there are performance implications with always having to pull the data from the parent site.

I’m trying to ponder this and avoid a lot of custom database tables, but this may have to be the way to go.

Data Architecture

If multtisite is supported, there will have to be a global table for each team. There’s already going to be one for social networks, so that’s not a huge deal.

For the taxonomies, I’ll essentially have to re-create the way WordPress handles taxonomies at a more abstract level. Each taxonomy term will be attached to a taxonomy and team.

Then there’s the issue of the team members. There’s not really any concept in multisite of a network-wide media library. So I’d have to fake it. I can create a custom folder for the network in the uploads directory, and store this information in another global table.

This type of architecture will be hard to achieve and there’s a lot of risk in doing things wrong, so if you have any better ideas, please comment below.

I can always get rid of the multisite support, but I feel a Network Admin will not want to have to re-create each team from scratch for each site in the network. That would be cumbersome. Plus, with multisite support, I can theoretically integrate with other third-party plugins such as BuddyPress, BuddyBoss, and other network-friendly plugins.

Adding Single and Multisite Support

In order to make the plugin multisite compatible, I had to ensure that if the plugin is activated on a network, then the plugin can only be network activated and not active on the single-site level. This is pretty easy. All you have to to do is add a flag to the top of the plugin header.

<?php /** * Team * * @package teams * @copyright Copyright(c) 2020, MediaRon LLC * @license http://opensource.org/licenses/GPL-2.0 GNU General Public License, version 2 (GPL-2.0) * * Plugin Name: Teams * Plugin URI: https://wpteams.pro * Description: A way to display your teams off on a stylistic way. * Version: 1.0.0 * Author: MediaRon LLC * Author URI: https://mediaron.com * License: GPL2 * License URI: http://www.gnu.org/licenses/gpl-2.0.html * Text Domain: mr-teams * Domain Path: languages * Network: true */
Code language: PHP (php)

The Network: true simply states that if the plugin is installed on a network, it can only be network-activated, which is what I want in order to make it multisite compatible.

There’s other caveats such as options, so let’s go over that first.

Single vs. Multisite Options

On single-site, you can simply use get_option to retrieve the options for your plugin. On multisite, you’d want to use get_site_option. Since I’m completely fine with only a network-activated plugin on multisite, I just use get_site_option everywhere since it also works for single-site just fine without any extra crazy conditionals.

Testing for Multisite

To test for multisite, I came up with the following static method. It needs some more refactoring, but here’s a rough example.

/** * Checks if the plugin is on a multisite install. * * @since 1.0.0 * * @param bool $network_admin Check if in network admin. * * @return true if multisite, false if not. */ public static function is_multisite( $network_admin = false ) { if ( ! function_exists( 'is_plugin_active_for_network' ) ) { require_once ABSPATH . '/wp-admin/includes/plugin.php'; } $is_network_admin = false; if ( $network_admin ) { if ( is_network_admin() ) { if ( is_multisite() && is_plugin_active_for_network( MR_TEAMS_SLUG ) ) { return true; } } else { return false; } } if ( is_multisite() && is_plugin_active_for_network( MR_TEAMS_SLUG ) ) { return true; } return false; }
Code language: PHP (php)

The above checks if we’re in a multisite install and that plugin is active for the network. It also has an optional flag called $network_admin, which will ensure we’re in the network admin when performing the check.

Single vs. Multisite Admin Menus

Since I’m creating a top-level menu item, I don’t have to worry too much about targeting the right parent menu item in single vs. multisite.

Instead, I just use the same bit of code to register the top-level menu item.

if ( Functions::is_multisite() ) { add_action( 'network_admin_menu', array( $this, 'register_admin_menu' ) ); } else { add_action( 'admin_menu', array( $this, 'register_admin_menu' ) ); }
Code language: PHP (php)

After Plugin Row Action

One thing I wanted to add was a license prompt after the plugin row if a license isn’t active.