This happens because plugins_loaded
fires before the global variable $wp_rewrite
exists.
From wp-settings.php
:
// Load active plugins.
foreach ( wp_get_active_and_valid_plugins() as $plugin )
include_once( $plugin );
unset( $plugin );
// Load pluggable functions.
require( ABSPATH . WPINC . '/pluggable.php' );
require( ABSPATH . WPINC . '/pluggable-deprecated.php' );
// Set internal encoding.
wp_set_internal_encoding();
// Run wp_cache_postload() if object cache is enabled and the function exists.
if ( WP_CACHE && function_exists( 'wp_cache_postload' ) )
wp_cache_postload();
do_action( 'plugins_loaded' );
// Define constants which affect functionality if not already defined.
wp_functionality_constants( );
// Add magic quotes and set up $_REQUEST ( $_GET + $_POST )
wp_magic_quotes();
do_action( 'sanitize_comment_cookies' );
/**
* WordPress Query object
* @global object $wp_the_query
* @since 2.0.0
*/
$wp_the_query = new WP_Query();
/**
* Holds the reference to @see $wp_the_query
* Use this global for WordPress queries
* @global object $wp_query
* @since 1.5.0
*/
$wp_query =& $wp_the_query;
/**
* Holds the WordPress Rewrite object for creating pretty URLs
* @global object $wp_rewrite
* @since 1.5.0
*/
$GLOBALS['wp_rewrite'] = new WP_Rewrite();
Solution: Hook into wp_loaded
, not plugins_loaded
.