Multi-DB questions

Hello,

I have an old fashioned WPMU version (2.6) and something like 7 000 blogs installed.

My SQL can handle the database but I'm not able anymore to use MySQL tools such as phpmyadmin, because "show table status" command takes too long and returns too much infos.

I'd like to install multi-DB, and I ahve some questions for you. Can you please help me ?

Q1: Characters set of new databases : my current main database is latin1_swedish_ci, not utf8_general_ci. BUT wpmu tables do are utf8_general_ci. While using your https://premium.wpmudev.org/db-tools/db_sql.php, to create new tables, should I create databases like :

CREATE DATABASE wpmu00 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

or like :

CREATE DATABASE wpmu00 DEFAULT CHARACTER SET utf8 COLLATE latin1_swedish_ci;

or like :

CREATE DATABASE wpmu00 DEFAULT CHARACTER SET latin1_swedish_ci COLLATE latin1_swedish_ci;

?

Depending on what I do, every texts could be broken, or not; so it's very important to do the right choice...

Q2 : I don't understand the global table thing. It says :

"// Do not include default global tables"

and we have an eg. : add_global_table('global');
and below :
add_db_server('global', 'dc1', 1, 1,'64.120.23.72','192.168.0.101', 'wpmu_global', 'db_user_name', 'db_user_name_pass');

I have global tables used by plugins, what will happen to them ? Will they be moved or will they remain in the former database ?

Q3 : Not well coded plugins. I may have plugins that do hard SQL queries such as :

SELECT ID from mytable WHERE ...

They don't use the "$wpdb->" prefix while querying. Is it a problem ? Queries are only done to global tables, not blogs.

Q4 : list-hashes.php : what is the aim of this script ? And why there is an MD5 tool here : https://premium.wpmudev.org/db-tools/db_sql.php ? Shoulf I do something with it ? what ?

Q5 : Always in https://premium.wpmudev.org/db-tools/db_sql.php there is a "DB Array" tool, same question ?

Q6 : Your db.php calls a file named "wp-content/db-list.php" (line 54) but it's not in my server. What is it and what should we find in it ?

Your help will be much appreciated !

Thanks,

Gautier.

  • drmike

    use MySQL tools such as phpmyadmin

    I'm going to throw this in since I know lots about this and little about MySQL in general. Your phpmyadmin is set up incorrectly. Unless you have a version from more than 3 years ago or so, you can define it to show only 'x' number of tables at one time.

    I talk about it in this thread here:

    https://premium.wpmudev.org/forums/topic/blogs-will-not-install-upon-creation

    Not sure if you have root access but it;s a quick easy fix that will help everybody out on that server.

  • Aaron

    1. I think you are fine defaulting them to unicode. Of course you will have a verified backup just in case.
    2. You need to define each global table that any wpmu plugins rely on. The move script will place them there. Also in the future before you install plugins with global tables you need to define them (we try to say that in the install instructions too).

    3. You will have to fix any hardcoded plugins to use the $wpdb class for querying and use the prefixes for table names.

    4. They are just helpful tools when you need to figure out which of your up to 4096 dbs a specific blog's table is in.

    5. Ditto, probably most useful if you are custom coding a script to move tables between dbs.

    6. db-list is an optional file if you don't want to put every db define in the db-config.php file.

  • Gautier_Girard

    Hello guys,

    Thanks for your replies !

    I'll check my plugins, will do the backup and the try it.

    Drmike, I use the last phpmyadmin version, and have in my config file :

    $cfg['MaxDbList'] = 30;
    $cfg['MaxTableList'] = 30;
    $cfg['ShowStats'] = false;
    $cfg['Servers'][$i]['CountTables'] = false;

    I my phpmyadmin I increased a lot the memory_limit and the two max execution time variables.

    I don't know why but phpmyadmin still freezes. It seems to be a show table status from issue. I tried few mins ago and a processlist displays :

    | 135055 | root | localhost | | Query | 783 | | SHOW TABLE STATUS FROM wpmu

    And now I have a 500 error.

    Servers'load average is < 1 though.

    Thanks a lot guys!

  • Gautier_Girard

    Hello,

    I'm looking at my plugins and I need to come back to you about my question 3 and your reply Aaron.

    I'd be afraid to break everything while doing this...

    You say :

    3. You will have to fix any hardcoded plugins to use the $wpdb class for querying and use the prefixes for table names.

    - So if I take the Post Indexer plugin, and queries like that :

    INSERT IGNORE INTO " . $wpdb->base_prefix . "site_posts
    (post_id, blog_id, etc...

    This query is right and do not need any modification, right ?

    And I'll have to add "site_posts" to the list of global tables, right ?

    Now if I take another plugin that use blogs tables that will be moved. Let's look at "AHP Sitewide Recent Posts for WordPress MU".

    Queries are quite not optimized for WPMU and I think some other plugins might have similar ones, that's why I need to really understand what I have to do. I have some queries like these :

    foreach ($blogs as $blog) {

    // we need _posts, _comments, and _options tables for this to work
    $blogOptionsTable = "wp_".$blog."_options";
    $blogPostsTable = "wp_".$blog."_posts";
    $blogCommentsTable = "wp_".$blog."_comments";

    [...]
    // fetch the ID, post title, post content, post date, and user's email for the latest post
    $thispost = $wpdb->get_results("SELECT $blogPostsTable.ID, $blogPostsTable.post_title,
    $blogPostsTable.post_content, $blogPostsTable.post_date, wp_users.display_name,
    wp_users.user_email, wp_users.user_login
    FROM $blogPostsTable, wp_users
    WHERE wp_users.ID = $blogPostsTable.post_author
    AND post_status = 'publish' AND post_type = 'post'
    AND post_date >= DATE_SUB(CURRENT_DATE(), INTERVAL $how_long DAY)
    AND $blogPostsTable.id > 1
    ORDER BY $blogPostsTable.id DESC limit 0,1");
    }

    Can you please tell me if I'm correct or not ?

    // we need _posts, _comments, and _options tables for this to work
    $blogOptionsTable = $wpdb->base_prefix.$blog."_options";
    $blogPostsTable = $wpdb->base_prefix.$blog."_posts";
    $blogCommentsTable = $wpdb->base_prefix.$blog."_comments";

    It's okay and I don't need to change anything else ?

    When everything will be installed I don't get how WPMU will know $wpdb->base_prefix.$blog."_options" is in database xyz... does it do a mapping between the table queries and the databases according to the blog number ?

    And so the MySQL query that's next causes me headaches... should it look like this ?

    $thispost = $wpdb->get_results("SELECT $blogPostsTable.ID, $blogPostsTable.post_title,
    $blogPostsTable.post_content, $blogPostsTable.post_date, {$wpdb->users}.display_name,
    {$wpdb->users}.user_email, {$wpdb->users}.user_login
    FROM $blogPostsTable, {$wpdb->users}
    WHERE {$wpdb->users}.ID = $blogPostsTable.post_author
    AND post_status = 'publish' AND post_type = 'post'
    AND post_date >= DATE_SUB(CURRENT_DATE(), INTERVAL $how_long DAY)
    AND $blogPostsTable.id > 1
    ORDER BY $blogPostsTable.id DESC limit 0,1");

    Is it all right like this ?
    - Does {$wpdb->anyglobaltable} equals $wpdb->base_prefix . "anyglobaltable" ?

    Thanks a lot for your help in advance.

    Best regards,

    Gautier.

  • Aaron

    Yes, yes, yes, and for the last question

    Does {$wpdb->anyglobaltable} equals $wpdb->base_prefix . "anyglobaltable" ?

    Only the core WPMU tables are registered in the class like that so you can call them directly via their name.

    Looking at those queries for AHP sitewide posts I would very strongly recommend against using it. That is an incredibly inefficient way to do it. Use our sitewide posts plugin instead with all our extensions to it (tags, search, etc.)

  • Gautier_Girard

    Hello,

    Thanks Aaron for your replies!

    I agree with you regarding AHP, I installed 2 years ago and didn't remember of this kind of handling it... I'll take care of it after the big change.

    I checked my plugins, setup my config file for 256 dbs, and did a backup.

    To finalize the install :

    - I need to create the 256 databases with your tool, AND the global database (empty, no table in it), right ?

    - After that I triple check my config files, as recommended by Andrew here : https://premium.wpmudev.org/forums/topic/couple-questions-and-please-let-me-know-is-this-how-you-install-multidb

    - I upload the files somewhere like wp-content/scripts, db-config.php in wp-content (*)

    *- If I've well understood how you handle it : I can wait for the move to be finished and working before uploading db.php to wp-content ?

    * - Doing it that way, even if move-blogs crashes, my install should not be broken ?

    Nothing else ?

    Thanks a lot for your patience.

    Regards,

    Gautier

  • VentureMaker

    - I need to create the 256 databases with your tool, AND the global database (empty, no table in it), right ?

    All 256 DBs and global DB have to be empty.
    And yes, you end up with 257 DB unless you use 'vip' DBs for certain blogs (like your main blog).

    * - Doing it that way, even if move-blogs crashes, my install should not be broken ?

    Correct if you don't delete your single DB (the one from which you're moving into multi).

    Nothing else ?

    Try and see :slight_smile: If you have backups you don't risk anything.
    At least nothing else I can think of.

  • Gautier_Girard

    Hello,

    Thanks VentureMaker and Aaron for your support.

    It's 02:42am here, and well, I have to say, my WPMU now works with Multi-DB !!! :grinning:slight_smile:)

    To all people, I'd recommend not waiting to have more than something like 3500 blogs before using it. With my 7000+ (55k tables), even with a server only dedicated to MySQL with 16gigs of RAM, and an optimized my.cnf, that was a real pain to do the switch...

    WoooooHHoooooooooooo !

    Gautier

  • Gautier_Girard

    Hello,

    Many plugins are broken... can you please help me ? I don't get how to solve that.

    For example, this SQL request seems not working with multi-db :

    <br />
    		$query_blogs = "SELECT contacts.email, contacts.id_email, blogs.blog_id FROM " . $wpdb->base_prefix . "contacts as contacts, " . $wpdb->base_prefix . "blogs as blogs<br />
    		WHERE<br />
    		contacts.id_email LIKE '%".$something."'<br />
    		AND<br />
    		contacts.id_blog = blogs.blog_id<br />
    		AND contacts.deleted = '0'<br />
    		AND blogs.deleted = '0'<br />
    		AND blogs.archived = '0'<br />
    		AND blogs.mature = '0'<br />
    		AND blogs.spam = '0'<br />
    		AND blogs.public = '1'";<br />
    		$result_blogs = mysql_query($query_blogs);<br />

    And the 2nd query of this script :

    $enc_query0 = "SELECT post_title, post_id, post_content_stripped, post_author
    FROM " . $wpdb->base_prefix . "site_posts
    WHERE
    blog_id = '" . $blog_id . "'
    AND
    (post_published_gmt > '".$jmoinssept1."' AND post_published_gmt < '".$yersterday2."')
    LIMIT 5;";

    Where is the problem ?

    I did added the former "wp_contacts" table into db-config and it has been filled as expected last night.

    AHP Sitewide Recent Posts for WordPress MU is broken, and Sitewide Feed is broken too.

    AHP Sitewide Recent Posts I have queries like that :

    $blogs = $wpdb->get_col("SELECT blog_id FROM {$wpdb->blogs} WHERE<br />
    		public = '1' AND archived = '0' AND mature = '0' AND spam = '0' AND deleted = '0' AND blog_id != '1' AND<br />
    		last_updated >= DATE_SUB(CURRENT_DATE(), INTERVAL $how_long DAY)<br />
    		ORDER BY last_updated DESC");<br />
    <br />
    			$blogOptionsTable = $wpdb->base_prefix.$blog."_options";<br />
    		    $blogPostsTable = $wpdb->base_prefix.$blog."_posts";<br />
    		    $blogCommentsTable = $wpdb->base_prefix.$blog."_comments";<br />
    			// fetch the ID, post title, post content, post date, and user's email for the latest post<br />
    			$thispost = $wpdb->get_results("SELECT $blogPostsTable.ID, $blogPostsTable.post_title,<br />
    				$blogPostsTable.post_content, $blogPostsTable.post_date, " . $wpdb->base_prefix . "users.display_name,<br />
    				" . $wpdb->base_prefix . "users.user_email, " . $wpdb->base_prefix . "users.user_login<br />
    				FROM $blogPostsTable, " . $wpdb->base_prefix . "users<br />
    				WHERE " . $wpdb->base_prefix . "users.ID = $blogPostsTable.post_author<br />
    				AND post_status = 'publish' AND post_type = 'post'<br />
    				AND post_date >= DATE_SUB(CURRENT_DATE(), INTERVAL $how_long DAY)<br />
    				AND $blogPostsTable.id > 1<br />
    				ORDER BY $blogPostsTable.id DESC limit 0,1");<br />
    <br />
    					$options = $wpdb->get_results("SELECT option_value FROM<br />
    					$blogOptionsTable WHERE option_name IN ('siteurl','blogname')<br />
    					ORDER BY option_name DESC");<br />

    And as for WPMU_feed, I think I'll be able to solve the problem if I understand what it is on the two others.

    Anyone could help me solve the problems ? I don't get at all what coule be the problems...

  • Gautier_Girard

    The top of my db-config.php is like that :


    // Plugin Name: Multi-DB
    // Plugin URI: https://premium.wpmudev.org/project/Multiple-Databases
    // Author: Andrew Billits (Incsub)
    // Version: 2.6.0
    //------------------------------------------------------------------------//
    //---DB Scaling-----------------------------------------------------------//
    //------------------------------------------------------------------------//
    // 16,256,4096
    define ('DB_SCALING', '256');
    //------------------------------------------------------------------------//
    //---DC IPs---------------------------------------------------------------//
    //------------------------------------------------------------------------//
    // Usage: add_dc_ip(IP, DC)
    // EX: add_dc_ip('123.123.123.', 'dc1');
    add_dc_ip('xx.165.215.26', 'dc1');
    //------------------------------------------------------------------------//
    //---Global Tables--------------------------------------------------------//
    //------------------------------------------------------------------------//
    // Do not include default global tables
    // Leave off base prefix (eg: wp_)
    //
    // Usage: add_global_table(TABLE_NAME)
    // EX: add_global_table('something');
    add_global_table('annuaires');
    add_global_table('blog_activity');
    add_global_table('comment_activity');
    add_global_table('contacts');
    add_global_table('edoo');
    add_global_table('mass_mailer');
    add_global_table('post_activity');
    add_global_table('site_posts');
    add_global_table('term_counts');
    add_global_table('user_activity');

    //------------------------------------------------------------------------//
    //---DB Servers-----------------------------------------------------------//
    //------------------------------------------------------------------------//
    // Database servers grouped by dataset.
    // R can be 0 (no reads) or a positive integer indicating the order
    // in which to attempt communication (all locals, then all remotes)
    //
    // Usage: add_db_server(DS, DC, READ, WRITE, HOST, LAN_HOST, NAME, USER, PASS)
    // EX: add_db_server('global', 'dc1', 1, 1,'global.mysql.example.com:3509','global.mysql.example.lan:3509', 'global-db', 'globaluser', 'globalpassword');
    //
    // Note: you can also place this section in a file called db-list.php in wp-content
    add_db_server('global', 'dc1', 1, 1,'xx.165.215.26','x.165.215.26', 'wpmu_global', 'xx', 'xx');

    add_db_server('00', 'dc1', 1, 1,'xx.165.215.26','xx.165.215.26', 'wpmu_00', 'xx', 'xx');
    [...]

  • Gautier_Girard

    Hello,

    Yes. I solved the first issue.

    As for AHP Recent Posts, I fixed it too, using Post indexer. For those who will have the problem, look at the code I pasted under this post, and replace it with this new one :


    // get a list of blogs in order of most recent update. show only public and nonarchived/spam/mature/deleted
    $blogs = $wpdb->get_col("SELECT blog_id FROM {$wpdb->blogs} WHERE
    public = '1' AND archived = '0' AND mature = '0' AND spam = '0' AND deleted = '0' AND blog_id != '1' AND
    last_updated >= DATE_SUB(CURRENT_DATE(), INTERVAL $how_long DAY)
    ORDER BY last_updated DESC");

    if ($blogs) {

    foreach ($blogs as $blog) {

    // we need _posts, _comments, and _options tables for this to work
    $blogOptionsTable = $wpdb->base_prefix.$blog."_options";
    $blogPostsTable = $wpdb->base_prefix.$blog."_posts";
    $blogCommentsTable = $wpdb->base_prefix.$blog."_comments";

    // debug block
    if ($debug) {
    echo '<hr>processing blog '.$blog.' = <a href="'.
    $options[0]->option_value.'">'.$options[1]->option_value.'
    ';
    }

    // Courtesy of Gautier, a nice looking SQL query that works with Multi-DB using Incsub's Post Indexer :-)

    $thispost = $wpdb->get_row("SELECT post_id, post_title, post_content_stripped, post_published_gmt, post_author, post_permalink
    FROM " . $wpdb->base_prefix . "site_posts
    WHERE
    blog_id = " . $blog . " AND post_published_gmt >= DATE_SUB(CURRENT_DATE(), INTERVAL $how_long DAY)
    LIMIT 1;");

    // if it is found put it to the output
    if($thispost) {
    $u = get_userdata($thispost->post_author);
    $thispost_user_login = $u->user_login;
    $thispost_ID = $thispost->post_id;
    $thispost_post_content = $thispost->post_content_stripped;
    $thispost_post_date = $thispost->post_published_gmt;
    $thispost_display_name = $u->display_name;
    $thispost_permalink = $thispost->post_permalink;

    When it's done do a search and replace in your script to transform former object variables such as $thispost->user_login to non-objects variables like that : $thispost_user_login . You'll have 5-6 S & R I think.

    The last thing that doesn't work now is my global RSS (wpmu_feed). Don't know what's / where's the problem. ;-(

  • Gautier_Girard

    I can't find what's going on with Sitewide Feed.

    Here is what I have so far :

    It's an MU site wide RSS feed. It is working when I open the RSS feed on the browser / when I wget its URL. It does work when I open it like that.

    BUT

    I'm using the WP's classic Magpie RSS to display this sidewide RSS as a widget in my main blog's sidebar.

    Before Multi DB it went well but since, it displays an error message :

    'An error has occurred, which probably means the feed is down. Try again later.'

    We can find this error message in wp-includes/rss.php .

    It may come from any plugin priority ? or something else ?

    Any idea ?

    Thanks a lot,

    Gautier.

  • Gautier_Girard

    Upload didn't work :


    <?php
    /*
    Plugin Name: Sitewide Feed
    Plugin URI: http://www.itdamager.com/plugins/wpmu-sitewide-feed/
    Description: Creates three rss 2.0 feeds showing recent posts, comments, and pages from all blogs.
    Author: I.T. Damager
    Author URI: http://www.itdamager.com/
    Version: 0.3.2
    License: GPL
    */

    class wpmu_sitefeed {

    var $version = '0.3.2';

    function wpmu_sitefeed() {
    add_action('init', array(&$this, 'wpmu_sitefeed_init'));
    }

    function wpmu_sitefeed_init() {
    $this->apply_settings();
    if ($this->cache) $this->cache = $this->check_cache();
    if ($this->trigger('posts')) return $this->outputfeed('posts');
    if ($this->trigger('comments')) return $this->outputfeed('comments');
    if ($this->trigger('pages')) return $this->outputfeed('pages');
    add_action('publish_post', array(&$this, 'expire_post_feeds'));
    add_action('delete_post', array(&$this, 'expire_post_feeds'));
    add_action('private_to_published', array(&$this, 'expire_post_feeds'));
    add_action('comment_post', array(&$this, 'expire_comments_feed'));
    add_action('delete_comment', array(&$this, 'expire_comments_feed'));
    add_action('trackback_post', array(&$this, 'expire_comments_feed'));
    add_action('wp_set_comment_status', array(&$this, 'expire_comments_feed'));
    add_action('wpmuadminedit', array(&$this, 'expire_feeds')); // in case the admin deletes a blog
    add_action('admin_menu', array(&$this, 'add_submenu'));
    }

    function trigger($type) {
    global $wpdb;
    if ($wpdb->blogid != $this->triggerblog) return false;
    if ($type == 'posts') $url = $this->triggerurl;
    if ($type == 'comments') $url = $this->triggerurl.$this->commentsurl;
    if ($type == 'pages') $url = $this->triggerurl.$this->pagesurl;
    if( constant( 'VHOST' ) == 'yes' ) {
    return (substr($_SERVER['REQUEST_URI'], strlen($url)*-1) == $url) ? true : false;
    } else {
    if ($type == 'posts' && $_GET['wpmu-feed'] == 'posts') return true;
    if ($type == 'comments' && $_GET['wpmu-feed'] == 'comments') return true;
    if ($type == 'pages' && $_GET['wpmu-feed'] == 'pages') return true;
    return false;
    }
    }

    function sizelimit($array) {
    return (count($array) >= $this->feedcount) ? intval($this->feedcount) : intval(count($array));
    }

    function check_cache() {
    global $wp_object_cache;
    return (is_object($wp_object_cache) && $wp_object_cache->cache_enabled == true) ? true : false;
    }

    function cache_expire_time() {
    global $wp_object_cache;
    return ($wp_object_cache->expiration_time/60);
    }

    function add_submenu() {
    get_currentuserinfo();
    if (!is_site_admin()) return false;
    add_submenu_page('wpmu-admin.php', 'Sitewide Feed Configuration', 'Site Feed', 10, 'wpmu_sitewide_feed', array(&$this,'config_page'));
    }

    function save_settings() {
    global $wpdb, $wp_db_version, $updated, $configerror;
    check_admin_referer();
    // validate all input!
    if (preg_match('/^[0-9]+$/',$_POST['triggerblog']) && $_POST['triggerblog'] > 0) $triggerblog = intval($_POST['triggerblog']);
    else $configerror[] = 'Trigger blog must be a numeric blog ID. Default: 1';

    if (preg_match('/^\/[a-zA-Z0-9_\/\-]+\/$/',$_POST['triggerurl'])) $triggerurl = $_POST['triggerurl'];
    else $configerror[] = 'Invalid trigger URL. Must be a relative path beginning with and ending with a "/". Default: /wpmu-feed/';

    if (preg_match('/^[a-zA-Z0-9_\-]+\/$/',$_POST['commentsurl'])) $commentsurl = $_POST['commentsurl'];
    else $configerror[] = 'Invalid comments URL. Must be a relative path ending with a "/". Default: comments/';

    if (preg_match('/^[a-zA-Z0-9_\-]+\/$/',$_POST['pagesurl'])) $pagesurl = $_POST['pagesurl'];
    else $configerror[] = 'Invalid pages URL. Must be a relative path ending with a "/". Default: pages/';

    if (preg_match('/^[0-9]+$/',$_POST['feedcount']) && $_POST['feedcount'] > 0) $feedcount = intval($_POST['feedcount']);
    else $configerror[] = 'Post count must be a number greater than zero. Default: 20';

    if (preg_match('/^[a-zA-Z0-9_\-\s\.]+$/',$_POST['feedtitle']) || $_POST['feedtitle'] == '') $feedtitle = $_POST['feedtitle'];
    else $configerror[] = 'Invalid feed title.';

    if (preg_match('/^[a-zA-Z0-9_\-\s\.\,]+$/',$_POST['feeddesc']) || $_POST['feeddesc'] == '') $feeddesc = $_POST['feeddesc'];
    else $configerror[] = 'Invalid feed description.';

    if (preg_match('/^[a-zA-Z0-9_\-]+$/',$_POST['untitled']) || $_POST['untitled'] == '') $untitled = $_POST['untitled'];
    else $configerror[] = 'Invalid untitled post title. Default: untitled';

    if ($_POST['showstats'] == 1 || $_POST['showstats'] == 0) $showstats = intval($_POST['showstats']);
    else $configerror[] = 'Show stats: Must be a one or zero. Default: 1';

    if ($_POST['excerpt'] == 0 || $_POST['excerpt'] == 1) $excerpt = intval($_POST['excerpt']);
    else $configerror[] = 'Use excerpts: Must be a one or zero. Default: 0';

    if ($_POST['etag'] == 1 || $_POST['etag'] == 0) $etag = intval($_POST['etag']);
    else $configerror[] = 'Use ETag Header: Must be a one or zero. Default: 1';

    if ($_POST['cache'] == 1 || $_POST['cache'] == 0) $cache = intval($_POST['cache']);
    else $configerror[] = 'Use Object Cache: Must be a one or zero. Default: 1';

    if (preg_match('/^[0-9]+$/',$_POST['expiretime']) && $_POST['expiretime'] >= 0) $expiretime = intval($_POST['expiretime']);
    elseif ($wp_db_version > 3513) $configerror[] = 'Expire time must be a number equal to or greater than zero. Default: 0 (expire only when needed)';
    else $configerror[] = 'Expire time must be a number equal to or greater than zero. Default: '.$this->cache_expire_time().' (expire to account for future dated posts)';

    if ($_POST['expiretime'] > $this->cache_expire_time())
    $configerror[] = 'Expire Minutes: Cannot exceed WP Object Cache expiration time of '.$this->cache_expire_time().' minutes.';

    if ($wpdb->blogid == $_POST['triggerblog'] && ($_POST['triggerurl'] == '/' || stristr($_POST['triggerurl'],'wp-admin')))
    $configerror[] = 'Doh! That combination of blog id and trigger url may have locked you out of your site!';

    if (is_array($configerror)) return $configerror;

    $settings = compact('triggerblog','triggerurl','commentsurl','pagesurl','feedtitle','feeddesc','feedcount','excerpt','untitled','showstats','cache','etag','expiretime');
    foreach($settings as $setting => $value) if ($this->$setting != $value) $changed = true;
    if ($changed) {
    update_site_option('wpmu_sitefeed_settings', $settings);
    $this->expire_feeds();
    $this->apply_settings($settings);
    return $updated = true;
    }
    }

    function set_defaults() {
    global $wp_db_version;
    // do not edit here - use the admin screen
    $this->feedcount = 20;
    $this->triggerblog = 1;
    if( constant( 'VHOST' ) == 'yes' ) {
    $this->triggerurl = '/wpmu-feed/';
    $this->commentsurl = 'comments/';
    $this->pagesurl = 'pages/';
    } else {
    $this->triggerurl = '?wpmu-feed=posts';
    $this->commentsurl = '?wpmu-feed=comments';
    $this->pagesurl = '?wpmu-feed=pages';
    }
    $this->untitled = 'untitled';
    $this->showstats = 1;
    $this->excerpt = 0;
    $this->cache = 1;
    $this->etag = 1;
    $this->feedtitle = get_site_option('site_name').' Master Site Feed';
    $this->feeddesc = 'Shows all posts, comments, and pages from all blogs on this WPMU powered site';
    ($wp_db_version > 3513) ? $this->expiretime = 0 : ($this->cache_expire_time() > 15) ? $this->expiretime = 15 : $this->expiretime = $this->cache_expire_time();
    }

    function apply_settings($settings = false) {
    if (!$settings) $settings = get_site_option('wpmu_sitefeed_settings');
    if (is_array($settings)) foreach($settings as $setting => $value) $this->$setting = $value;
    else $this->set_defaults();
    }

    function delete_settings() {
    global $wpdb, $updated;
    $settings = get_site_option('wpmu_sitefeed_settings');
    if ($settings) {
    $wpdb->query("DELETE FROM $wpdb->sitemeta WHERE
    meta_key = 'wpmu_sitefeed_settings'");
    if ($this->check_cache()) wp_cache_delete('wpmu_sitefeed_settings','site-options');
    $this->set_defaults();
    $this->expire_feeds();
    return $updated = true;
    }
    }

    function create_testlink($type) {
    global $wpdb;
    if ($type == 'posts') $url = $this->triggerurl;
    if ($type == 'comments') $url = $this->triggerurl.$this->commentsurl;
    if ($type == 'pages') $url = $this->triggerurl.$this->pagesurl;
    $domainpath = $wpdb->get_row("SELECT domain, path FROM ".$wpdb->blogs." WHERE blog_id = '".$this->triggerblog."'",ARRAY_A);
    if (!is_array($domainpath)) return 'Trigger blog ID is was not found!';
    return 'untrailingslashit($domainpath['domain'].$domainpath['path']).$url.'" target="_blank">test link';
    }

    function untrailingslashit($str) {
    return (substr($str,-1) == '/') ? substr($str,0,strlen($str)-1) : $str;
    }

    function create_map($type) {
    global $wpdb;
    $multiplier = 100; // new setting to dig deep for posts/comments until we workaround wpmu_update_blogs_date messing with timestamp
    $blogs = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs
    WHERE public = '1' AND archived = '0' AND last_updated != '0000-00-00 00:00:00'
    ORDER BY last_updated DESC LIMIT ".$this->feedcount*$multiplier);
    if (!is_array($blogs)) return false; // New Site?
    foreach($blogs as $blogid) {
    if ($type == 'posts') {
    $results = $wpdb->get_results("SELECT ID,post_date_gmt
    FROM ".$wpdb->base_prefix.$blogid."_posts
    WHERE post_status = 'publish' AND (post_type = 'post' OR post_type = '') AND post_date_gmt < '".gmdate("Y-m-d H:i:s")."'
    ORDER BY post_date_gmt DESC LIMIT ".$this->feedcount*$multiplier);
    } elseif ($type == 'comments') {
    $defcomment = "Hi, this is a comment.
    To delete a comment, just log in, and view the posts\' comments, there you will have the option to edit or delete them.";
    $results = $wpdb->get_results("SELECT comment_ID, comment_date_gmt, comment_post_ID,
    ".$wpdb->base_prefix.$blogid."_posts.ID, ".$wpdb->base_prefix.$blogid."_posts.post_password
    FROM ".$wpdb->base_prefix.$blogid."_comments
    LEFT JOIN ".$wpdb->base_prefix.$blogid."_posts ON comment_post_id = id
    WHERE ".$wpdb->base_prefix.$blogid."_posts.post_status IN ('publish', 'static', 'object')
    AND comment_content != '".$defcomment."'
    AND ".$wpdb->base_prefix.$blogid."_comments.comment_approved = '1'
    AND post_date_gmt < '" . gmdate("Y-m-d H:i:s") . "'
    ORDER BY comment_date_gmt DESC LIMIT " . $this->feedcount*$multiplier);
    } elseif ($type == 'pages') {
    $aboutpage = 'This is an example of a WordPress page, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many pages like this one or sub-pages as you like and manage all of your content inside of WordPress.';
    $results = $wpdb->get_results("SELECT ID,post_date_gmt
    FROM ".$wpdb->base_prefix.$blogid."_posts
    WHERE post_content != '".$aboutpage."' AND post_status = 'static' OR (post_status = 'publish' AND post_type = 'page')
    AND post_date_gmt < '".gmdate("Y-m-d H:i:s")."'
    ORDER BY post_date_gmt DESC LIMIT ".$this->feedcount*$multiplier);
    }
    if (is_array($results)) {
    foreach($results as $result) {
    if ($type == 'posts' || $type == 'pages') {
    $map[] = array($blogid,$result->ID,$result->post_date_gmt);
    $ID[] = $result->ID;
    $date_gmt[] = $result->post_date_gmt;
    } elseif ($type == 'comments') {
    $map[] = array($blogid,$result->comment_ID,$result->comment_date_gmt);
    $ID[] = $result->comment_ID;
    $date_gmt[] = $result->comment_date_gmt;
    }
    }
    }
    }
    if (is_array($map)) {
    array_multisort($date_gmt, SORT_DESC, $ID, SORT_ASC, $map);
    return array_slice($map,0,$this->sizelimit($map));
    }
    }

    function get_data($type) {
    global $wpdb;
    $map = $this->create_map($type);
    if (!is_array($map)) return false;
    foreach($map as $item) {
    if ($type == 'posts' || $type == 'pages') {
    $row = $wpdb->get_row("SELECT * FROM ".$wpdb->base_prefix.intval($item[0])."_posts WHERE ID = '".intval($item[1])."'");
    if ($row->ID) {
    if (!$row->post_title) $row->post_title = $this->untitled;
    $row->blogid = intval($item[0]);
    $rows[] = $row;
    }
    } elseif ($type =='comments') {
    $row = $wpdb->get_row("SELECT * FROM ".$wpdb->base_prefix.intval($item[0])."_comments WHERE comment_ID = '".intval($item[1])."'");
    if ($row->comment_ID) {
    $row->blogid = intval($item[0]);
    $rows[] = $row;
    }
    }
    }
    if ($rows) return $rows;
    }

    function latest_time() {
    global $posts, $comments;
    return ($posts) ? $posts[0]->post_date_gmt : $comments[0]->comment_date_gmt;
    }

    function save_feed($name,$data) {
    if ($this->cache) update_site_option($name.'_ts',time());
    return ($this->cache) ? wp_cache_set($name,$data,'site-options') : false;
    }

    function fetch_feed($name) {
    if ($this->cache) {
    $expires = get_site_option($name.'_ts')+($this->expiretime*60);
    if ($expires <= time()) $this->expire_feed($name);
    }
    return ($this->cache) ? wp_cache_get($name,'site-options') : false;
    }

    function expire_feed($name = 'wpmu_sitefeed_cache') {
    return ($this->check_cache()) ? wp_cache_delete($name,'site-options') : false;
    }

    function expire_comments_feed() {
    return $this->expire_feed('wpmu_sitecomments_cache');
    }

    function expire_pages_feed() {
    return $this->expire_feed('wpmu_sitepages_cache');
    }

    function expire_post_feeds() {
    $this->expire_feed('wpmu_siteposts_cache');
    $this->expire_feed('wpmu_sitepages_cache');
    }

    function expire_feeds() {
    $this->expire_feed();
    $this->expire_comments_feed();
    $this->expire_pages_feed();
    }

    function outputfeed($type) {
    if ($type == 'posts') $name = 'wpmu_sitefeed_cache';
    if ($type == 'comments') $name = 'wpmu_sitecomments_cache';
    if ($type == 'pages') $name = 'wpmu_sitepages_cache';
    if ($this->cache) {
    $feed = $this->fetch_feed($name);
    if ($feed) {
    $cached = true;
    } else {
    $feed = $this->generate_feed($type);
    $saved = $this->save_feed($name,$feed);
    }
    } else {
    $feed = $this->generate_feed($type);
    }
    if ($this->showstats) {
    $feed .= "<!-- ".get_num_queries()." queries ".number_format(timer_stop(),3)." seconds.";
    if ($cached) $feed .= " (cached)";
    $feed .= " -->\r\n";
    }
    preg_match('/<pubDate>(.*)<\/pubDate>/',$feed,$match);
    $lastmodified = date("D, j M Y H:i:s", strtotime($match[1]))." GMT" ;
    $etag = md5($lastmodified);
    header('Content-type: text/xml; charset='.get_settings('blog_charset'), true);
    if ($this->etag && ($_SERVER['HTTP_IF_NONE_MATCH'] == '"' . $etag . '"' || $lastmodified == $_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
    header('HTTP/1.1 304 Not Modified');
    header('Cache-Control: private');
    header('ETag: "'.$etag.'"');
    } else {
    if ($this->etag) {
    header('Last-Modified: ' . $lastmodified);
    header('ETag: "'.$etag.'"');
    }
    echo $feed;
    }
    exit();
    }

    function generate_feed($type) {
    global $posts, $comments, $post, $comment;
    if ($type == 'posts') $posts = $this->get_data($type);
    if ($type == 'comments') $comments = $this->get_data($type);
    if ($type == 'pages') $posts = $this->get_data($type);
    ob_start();
    echo '<?xml version="1.0" encoding="'.get_settings('blog_charset').'"?'.'>';
    ?>

    <!-- generator="wordpress/<?php bloginfo_rss('version') ?>" -->
    <rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    <?php do_action('rss2_ns'); ?>
    >

    <channel>
    <title><?php echo utf8_encode("Agence Presse : tous les communiqués de presse"); if ($type == 'comments') echo ' Commentaires'; if ($type == 'pages') echo ' Pages'; ?></title>
    <link><?php bloginfo_rss('url') ?></link>
    <description><?php echo utf8_encode("Recevez en temps réel, tous les communiqués de presse relayés par les agences de presse inscrites gratuitement sur http://Agence-Presse.net .");?></description>
    <pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', $this->latest_time(), false); ?></pubDate>
    <generator>http://wordpress.org/?v=<?php bloginfo_rss('version'); ?></generator>
    <language><?php echo get_option('rss_language'); ?></language>
    <?php do_action('rss2_head'); ?>
    <?php if ($posts) { foreach ($posts as $post) { switch_to_blog($post->blogid); start_wp(); ?>
    <item>
    <title><?php the_title_rss() ?></title>
    <link><?php permalink_single_rss() ?></link>
    <comments><?php comments_link(); ?></comments>
    <pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_post_time('Y-m-d H:i:s', true), false); ?></pubDate>
    <dc:creator><?php the_author() ?></dc:creator>
    <?php the_category_rss() ?>

    <guid isPermaLink="false"><?php the_guid(); ?></guid>
    <?php if ($this->excerpt) : ?>
    <description><![CDATA[<?php the_excerpt_rss() ?>]]></description>
    <?php else : ?>
    <description><![CDATA[<?php the_excerpt_rss() ?>]]></description>
    <?php if ( strlen( $post->post_content ) > 0 ) : ?>
    <content:encoded><![CDATA[<?php the_content('', 0, '') ?>]]></content:encoded>
    <?php else : ?>
    <content:encoded><![CDATA[<?php the_excerpt_rss() ?>]]></content:encoded>
    <?php endif; ?>
    <?php endif; ?>
    <wfw:commentRss><?php bloginfo_rss('url') ?>/comments/feed/</wfw:commentRss>

    <?php rss_enclosure(); ?>
    <?php do_action('rss2_item'); ?>
    </item>
    <?php restore_current_blog(); } } ?>
    <?php if ($comments) { foreach ($comments as $comment) { switch_to_blog($comment->blogid); get_post_custom($comment->comment_post_ID); ?>
    <item>
    <title>by: <?php comment_author_rss() ?></title>
    <link><?php comment_link() ?></link>
    <pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_comment_time('Y-m-d H:i:s', true), false); ?></pubDate>
    <guid><?php comment_link() ?></guid>
    <?php if (!empty($comment->post_password) && $_COOKIE['wp-postpass'] != $comment->post_password) { ?>
    <description>Protected Comments: Please enter your password to view comments.</description>
    <content:encoded><![CDATA[<?php echo get_the_password_form() ?>]]></content:encoded>
    <?php } else { ?>
    <description><?php comment_text_rss() ?></description>
    <content:encoded><![CDATA[<?php comment_text() ?>]]></content:encoded>
    <?php } // close check for password ?>
    </item>
    <?php restore_current_blog(); } } ?>
    </channel>
    </rss>
    <?php
    $feed = ob_get_contents();
    ob_end_clean();
    return $feed;
    }

    function config_page() {
    global $updated, $configerror;
    get_currentuserinfo();
    if (!is_site_admin()) die(__('<p>You do not have permission to access this page.</p>'));
    if ($_POST['action'] == 'update') {
    if ($_POST['reset'] != 1) $this->save_settings();
    else $this->delete_settings();
    }
    if ($updated) { ?>
    <div id="message" class="updated fade"><p><?php _e('Options saved.') ?></p></div>
    <?php } elseif (is_array($configerror)) { ?>
    <div class="error"><p><?php echo implode('
    ',$configerror); ?></p></div>
    <?php } ?>
    <div class="wrap">
    <h2>Sitewide Feed Options</h2>
    <fieldset class="options">
    <p>This plugin creates three (3) seperate RSS 2.0 feeds from posts, comments, and pages across all blogs on your WPMU powered site. (version: <?php echo $this->version; ?>:wink: (Plugin Homepage | Help)</p>
    <?php if (!$this->check_cache()) { ?>
    <p style="color:#CC0000;font-weight:bold;">NOTE: Your WPMU is not using WP Object Cache. Performance will be degraded and site load increased. Please use the object cache for maximum performance.</p>
    <?php } elseif (!$this->cache) { ?>
    <p style="color:#CC0000;font-weight:bold;">NOTE: You have disabled usage of the WP Object Cache for this plugin. Performance will be degraded and site load increased. Please use the object cache for maximum performance.</p>
    <?php } ?>
    <form name="sitefeedform" action="" method="post">
    <table width="100%" cellspacing="2" cellpadding="5" class="editform">
    <tr valign="top">
    <th scope="row"><?php _e('Trigger Blog ID:') ?>
    </th>
    <td><input name="triggerblog" type="text" id="triggerblog" value="<?php echo $this->triggerblog; ?>" size="3" /></td>
    </tr>
    <tr valign="top">
    <th scope="row"><?php _e('Feed URL (relative path):') ?>
    </th>
    <td><input name="triggerurl" type="text" id="triggerurl" value="<?php echo $this->triggerurl; ?>" size="25" />
    (<?php echo $this->create_testlink('posts'); ?>:wink:</td>
    </tr>
    <tr valign="top">
    <th scope="row"><?php _e('Comments Feed URL (appended to Feed URL):') ?>
    </th>
    <td><input name="commentsurl" type="text" id="commentsurl" value="<?php echo $this->commentsurl; ?>" size="25" />
    (<?php echo $this->create_testlink('comments'); ?>:wink:</td>
    </tr>
    <tr valign="top">
    <th scope="row"><?php _e('Pages Feed URL (appended to Feed URL):') ?>
    </th>
    <td><input name="pagesurl" type="text" id="pagesurl" value="<?php echo $this->pagesurl; ?>" size="25" />
    (<?php echo $this->create_testlink('pages'); ?>:wink:</td>
    </tr>
    <tr valign="top">
    <th scope="row"><?php _e('Feed Title:') ?>
    </th>
    <td><input name="feedtitle" type="text" id="feedtitle" value="<?php echo $this->feedtitle; ?>" size="60" /></td>
    </tr>
    <tr valign="top">
    <th scope="row"><?php _e('Feed Description:') ?>
    </th>
    <td><input name="feeddesc" type="text" id="feeddesc" value="<?php echo $this->feeddesc; ?>" size="60" /></td>
    </tr>
    <tr valign="top">
    <th width="33%" scope="row"><?php _e('Show the most recent:') ?></th>
    <td><input name="feedcount" type="text" id="feedcount" value="<?php echo $this->feedcount; ?>" size="3" /> <?php _e('posts') ?></td>
    </tr>
    <tr valign="top">
    <th scope="row"><?php _e('For each article, show:') ?>
    </th>
    <td><label>
    <input name="excerpt" type="radio" value="0" <?php checked(0, $this->excerpt); ?> />
    <?php _e('Full text') ?>
    </label>

    <label>
    <input name="excerpt" type="radio" value="1" <?php checked(1, $this->excerpt); ?> />
    <?php _e('Summary') ?>
    </label>
    </td>
    </tr>
    <tr valign="top">
    <th scope="row"><?php _e('Untitled post title:') ?>
    </th>
    <td><input name="untitled" type="text" id="untitled" value="<?php echo $this->untitled; ?>" size="25" /></td>
    </tr>
    <tr valign="top">
    <th scope="row"><?php _e('Append stats to feed:') ?>
    </th>
    <td><label>
    <input name="showstats" type="checkbox" id="showstats" value="1" <?php checked(1, $this->showstats); ?> />
    </label>
    </td>
    </tr>
    <tr valign="top">
    <th scope="row"><?php _e('Use ETag header:') ?>
    </th>
    <td><label>
    <input name="etag" type="checkbox" id="etag" value="1" <?php checked(1, $this->etag); ?> />
    </label>
    </td>
    </tr>
    <tr valign="top">
    <th scope="row"><?php _e('Use Object Cache:') ?>
    </th>
    <td><label>
    <input name="cache" type="checkbox" id="cache" value="1" <?php checked(1, $this->cache); ?> />
    </label>
    </td>
    </tr>
    <tr valign="top">
    <th width="33%" scope="row"><?php _e('Expire feed from cache after:') ?></th>
    <td><input name="expiretime" type="text" id="expiretime" value="<?php echo $this->expiretime; ?>" size="3" />
    <?php _e('minutes') ?></td>
    </tr>
    <tr valign="top">
    <th scope="row"> </th>
    <td> </td>
    </tr>
    <tr valign="top">
    <th scope="row"><?php _e('Reset all settings to default:') ?>
    </th>
    <td><label>
    <input name="reset" type="checkbox" value="1" />
    </label>
    </td>
    </tr>
    </table>
    <p class="submit">
    <input type="hidden" name="action" value="update" />
    <input type="submit" name="Submit" value="<?php _e('Update Options') ?> »" />
    </p>
    </form>
    </fieldset>
    </div>
    <?php
    }
    }

    //all your posts, comments, pages, and base are belong to us!
    if (defined('ABSPATH')) $wpmu_sitefeed = new wpmu_sitefeed();

    ?>

Thank NAME, for their help.

Let NAME know exactly why they deserved these points.

Gift a custom amount of points.