itthinx / groups

Groups provides group-based user membership management, group-based capabilities and content access control. It integrates standard WordPress capabilities and application-specific capabilities along with an extensive API.
GNU General Public License v3.0
49 stars 35 forks source link

SQL errors multisite #62

Open JoryHogeveen opened 7 years ago

JoryHogeveen commented 7 years ago

WordPress database error Table DATABASE.PREFIX_groups_capability doesn't exist for query

SELECT * FROM PREFIX_groups_capability WHERE capability = 'edit_posts'

made by:

  1. include('wp-admin/admin-header.php'),
  2. do_action('in_admin_header'),
  3. WP_Hook->do_action,
  4. WP_Hook->apply_filters,
  5. call_user_func_array,
  6. wp_admin_bar_render,
  7. do_action_ref_array,
  8. WP_Hook->do_action,
  9. WP_Hook->apply_filters,
  10. call_user_func_array,
  11. wp_admin_bar_my_sites_menu,
  12. current_user_can,
  13. call_user_func_array,
  14. WP_User->has_cap,
  15. apply_filters('user_has_cap'),
  16. WP_Hook->apply_filters,
  17. call_user_func_array,
  18. Groups_WordPress::user_has_cap,
  19. Groups_User->can,
  20. apply_filters_ref_array,
  21. WP_Hook->apply_filters,
  22. call_user_func_array,
  23. Groups_WordPress::groups_user_can,
  24. Groups_Capability::read_by_capability,
  25. QM_DB->query,

referer: SITE/wp-admin/index.php

christianwach commented 2 years ago

I've just run into this issue which is reproducible on vanilla WordPress Multisite.

It happens when the Groups plugin is activated on a single site in WordPress Multisite (and Multi-Network) and a user who is not a super admin (i.e. subject to Groups capabilities) - and has multiple sites to which they have access - visits the WordPress back-end of the site where Groups is activated.

The wp_admin_bar_my_sites_menu() function loops through the User's sites and performs a switch_to_blog(), then calls current_user_can( 'read' ) while in the switched context. This causes Groups to look up the User's capabilities from the non-existent table on the switched-to site.

In cases where only one site has Groups activated, the following MU Plugin should prevent the errors, though it is somewhat flawed because it checks the read capability in the originating site.

// Filter the table prefix early.
add_filter( 'groups_get_table_prefix', 'my_groups_table_prefix', 10 );

/**
 * Filter the "Groups" database table prefix.
 *
 * @param str $prefix The current WordPress table prefix.
 * @return str $this->db_prefix The main site's table prefix.
 */
function my_groups_table_prefix( $prefix ) {

    global $wpdb;

    // Return early if there has not been a Multisite switch.
    if ( ! ( is_multisite() && ms_is_switched() ) ) {
        return $prefix;
    }

    // Return early if Groups is installed on the site.
    $groups_options = get_option( Groups_Options::option_key, 'not-installed' );
    if ( 'not-installed' !== $groups_options ) {
        return $prefix;
    }

    // Overwrite with the original site prefix.
    if ( ! empty( $GLOBALS['_wp_switched_stack'] ) ) {
        $original_site_id = reset( $GLOBALS['_wp_switched_stack'] );
        return $wpdb->get_blog_prefix( $original_site_id );
    }

    return $prefix;

}

A better option would be to check if Groups is installed on the switched-to site before calling _groups_get_tablename() but that's something that someone more familiar with the Groups code should probably do.

christianwach commented 1 year ago

FYI I've made a little MU Plugin that solves this:

https://gist.github.com/christianwach/334816adcb29565dbfe35fd8d5c6d5b5

The code should really be ported to the Groups plugin itself, but installing this will fix the problem in the short term.