Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I want to create "city" taxonomy in all sites of MultiSite. But i want to show same listing in every blog and i want to edit it from only master site and not letting other blog owners edit it. I think only solution for this is setting a master site for specific taxonomy in MultiSite. So when someone try to use "city" taxonomy from other blogs, they will see master site's city list. How can i do that?

<?php
$master_site = 1;
...when city taxonomy need:
switch_to_blog( $master_site );
...use list of "city" taxonomy"...
restore_current_blog();
share|improve this question
    
this is insteresting other solution: scottbasgaard.com/2011/03/… maybe helps you to help me ^^ –  Ünsal Korkmaz Sep 17 '11 at 21:15
    
1 more example: shibashake.com/wordpress-theme/… –  Ünsal Korkmaz Sep 25 '11 at 14:58
    
Ünsal, please edit your question instead of adding comments. –  kaiser Jun 30 '13 at 22:55

2 Answers 2

First when you register your custom taxonomy use the capabilities argument and define your custom capabilities:

'capabilities' => array(
    'manage_terms' => 'manage_cities',
    'edit_terms'   => 'edit_cities',
    'delete_terms' => 'delete_cities',
    'assign_terms' => 'assign_cities'
),

and only give your users the assign_terms capability this way they wont be able to create new terms, only YOU.

Then use the nice solution you linked in the comment , change the $taxonomies_to_sync array according to your taxonomy, and you should be fine.

share|improve this answer
    
That link is not a proper solution imo. I am talking about lots of sites.. That plugin will probably exceed php run time. btw.. shibashake.com/wordpress-theme/… cant we use this? –  Ünsal Korkmaz Sep 25 '11 at 14:58

(disclaimer: this involves a core WP hack, tread carefully)

I have a Multisite network where I wanted the primary blog (id == 1) to set the taxonomy activity_type for all other sites on the network.

I used the code below to include hooks when creating, editing or deleting terms in that custom taxonomy which then mimics that task on all subsites. What is not covered here is restricting users on other sites from adding/editing/deleting terms - I used a combination of jQuery, CSS and remove_action functions to hide those UI elements from my subsites.

//When an activity type is added to the primary site, also add it to the sub-sites
function as_act_type_add ($term_id, $tt_id, $taxonomy){
    $new_act_type = get_term($term_id, 'activity_type', ARRAY_A);
        //get parent data if necessary      
        $parent_term = get_term_by('term_id', $new_act_type['parent'], 'activity_type', ARRAY_A);
    $sites = as_network_ids();  

    foreach($sites as $site){
        switch_to_blog($site);

        $exist_check = term_exists($new_act_type['name'], 'activity_type'); //check if the created term exists on the subsite already
            $site_parent = term_exists( $parent_term['name'], 'activity_type' ); //check if the parent term exists
            $parent_term_id = $site_parent['term_id']; // get numeric term id
        if(is_array($exist_check)){
            //do nothing - in the future, we want this to update the existing term but punt for now
        } else {
            wp_insert_term(
              $new_act_type['name'], // the term 
              'activity_type', // the taxonomy
              array(
                'description'=> $new_act_type['description'],
                'slug' => $new_act_type['slug'],
                'parent' => $parent_term_id
              )
            );
                //since we might have added children, you have to delete the cache, or else they wont display right away
            delete_option("activity_type_children");

        } //end term_exists 
        restore_current_blog();     
    } //end foreach
        //and delete cache for main site    
    delete_option("activity_type_children");
}
//triggered whenever a term is added
add_action("create_activity_type", "as_act_type_add", 10, 3);

function as_act_type_update($term_id, $tt_id, $taxonomy){
    //the term hasnt been changed yet, but we want to get it anyway in case the name has been changed
$legacy_term = get_term($term_id, 'activity_type', ARRAY_A);
$edited_act_type = $_POST;
    if($edited_act_type['parent']){
        $parent_term = get_term_by('term_id', $edited_act_type["parent"], 'activity_type', ARRAY_A);
    }
$sites = as_network_ids();

foreach($sites as $site){

    switch_to_blog($site);
            //cehck to see if the updated term exists on the site
        $exist_check = term_exists($legacy_term['name'], 'activity_type');

        if($parent_term){
            //check to make sure we have the parent
            $site_parent_term = term_exists($parent_term['name'], 'activity_type');
        }
            //if so, update it
        if(is_array($exist_check)){     
                //since wp_update_term calls the edit_term hook, we need to unhook to avoid an infinite loop    
            remove_action("edit_activity_type", "as_act_type_update", 10, 3);
                //update that fool
            wp_update_term(
                $exist_check['term_id'], // the term id
                'activity_type', // the taxonomy
                array(
                    'name'        => $edited_act_type['name'],
                    'description' => $edited_act_type['description'],
                    'slug'        => $edited_act_type['slug'],
                    'parent'    => $site_parent_term['term_id'] //if this doesnt exist, WP will default to 0, or no parent
                )
            );
        } //end is_array check
    restore_current_blog();     
} //end foreach
} //end update term func 
add_action("edit_activity_type", "as_act_type_update", 10, 3);


function as_act_type_delete($term_id, $tt_id, $taxonomy){
//somehow this also works with bulk delete- I didnt think it would but apprarently it does. sacrificial goat must have worked.
$deleted_act_type = get_site_transient( 'as_last_activity_type_delete' ); //temp transient set in wp-includes/taxonomy.php to store deleted term data

if ( false === ( $deleted_act_type)) {
    //do nothing if no transient available
} else {
    //we have the deleted term data fromt he transient, so use it here
    $sites = as_network_ids();  

    foreach($sites as $site){
        switch_to_blog($site);
            $exist_check = term_exists($deleted_act_type->name, 'activity_type');
            if(is_array($exist_check)){
                    //unhook action to avoid infinite loop
                remove_action("delete_activity_type", "as_act_type_delete", 10, 3);
                wp_delete_term($exist_check['term_id'], 'activity_type');
                //add_action("delete_activity_type", "as_act_type_delete", 10, 3);
            } //end exist check
        restore_current_blog();     
    } //end foreach
        //now clear the data from the transient
        delete_site_transient( 'as_last_activity_type_delete' );
} //end false check for transient
} //end update term 

add_action("delete_activity_type", "as_act_type_delete", 9, 3);

This also requires a hack to WP core (yes, beware of this carinal sin for it is a terrible transgression). In wp-includes/taxonomy.php find line 1767 or the $term = (int) $term; line within the wp_delete_term function. There, place this line:

set_site_transient('as_last_activity_type_delete',get_term($term,'activity_type'));

I might also leaving yourself a comment here and also tattooing a reminder of this change somewhere because you will have to manually update taxonomy.php every time you update WordPress. This sucks but the reason we're setting this transient is so we can lookup the deleted term by its slug rather than its ID. The action hook delete_{tax_type} gives us the term_id for the deleted term but we can't be sure that will be the same on all of our network sites, so we have to get the term slug before it is deleted... thus the core hack. I don't love it, I'm not proud of it, but it works. If you only care about pushing terms to your network sites and dont care about removing them from your main site, you could actually skip this and not have to hack core - I needed to be able to create and delete from a single site and this was the only way I found.

You will also notice a line in my code where this happens $sites = as_network_ids();. That is simply a helper function I've created elsewhere that returns a list of all the network blog ids along with some extra data I use for a lot of other functions. You can get the blog list using this function (warning: it is officially deprecated but hasn't been replaced yet) or by writing your own SQL.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.