WordPress 3.0 Plugin Activation Error – “Headers already sent”

Well, i have been customizing my WordPress a lot to produce something like the food directory or blogshopping tool which required a lot of hack on to WordPress to make everything work perfectly. Recently i have upgraded my WordPress to the latest version 3.0.1. Everything seems fine until one day i decided to enhance my site. Upon activting my WordPress plugin, an error message occurs stating "The plugin generated 3 characters of unexpected output during activation. If you notice “headers already sent” messages, problems with syndication feeds or other issues, try deactivating or removing this plugin.". Although the plugin successfully activated, it seems like there are some problem with the plugin that is causing this. I search high and low for it but couldn't seems to detect any header being sent explicitly without my knowledge.  To make matter worst, this caused all my timthumb (image of the fly) script to malfunction which caused ALL my images to break. Hence, none of the images generated by timthumb were generated on the website. This is disaster!!!  Why is my header being sent when there is NOTHING in my code that is sending it?!!! (panic)

I went to alert my hosting company (hostgator) about this and tried to resolved this on the server level as my test environment which is another host were functioning perfectly without causing me a single problem! However, they couldn't find any cause on their server side that may caused this problem and direct me back to the application problem and asked me to check my code. Puzzled by all the mystery that is happening on my test and live environment. I decided to look further into what could have happened. And here are some of the things that i found but doesn't happen to me.

Extra whitespace / Character

Extra whitespace or character before the tag will caused this to happen. This is a comment mistakes made by many new php developers. But in my case, this wasn't the problem.

My Situation

Soon, i found out my mistake. Apparently, my test environment server setting allows Unicode encoded file type to be read normally. However, the one on Hostgator only allows ANSCII to be read. Hence, all the Unicode encoded files were the culprits that is causing all this problems. It seems like the php setting made on the server can caused this to happen as the file type unknown to the php parser seems to bypassed the php output buffer and sent out the plaintext mime type before everything else which caused my timthumb to not work properly (since image sent in jpg mime instead of plaintext). This might be the reason why WordPress is giving you a message of "The plugin generated 3 characters of unexpected output during activation. If you notice “headers already sent” messages, problems with syndication feeds or other issues, try deactivating or removing this plugin." when you try to activate the plugin. It can also be caused by other plugins builder who are unaware that this might happen as their environment works perfectly and yours doesn't. Oh, the reason why anyone would want to change the encoding from ASCII to other form of encoding can be due to special character or other languages writing that ASCII doesn't support. Hence, changing the file encoding types allows php to display out the correct message. (WordPress is multilingual, this should happen more often than you think :)). Hope it helps 🙂

Remove WordPress Admin Menu Without Affecting WordPress Core System

In WordPress, each user type have different capability. Sometimes, we want to change these capability and the most easiest way to do that is to remove what they can see when they logged in. Especially when someone wants to change WordPress into a powerful CMS and remove certain admin menu without touching the core system. In most CMS, there are so much restriction on their core system that makes it really inflexible. Unlike other system, WordPress is able to modify their core codes using plugin without affecting the fundamental codes in WordPress. Hence, we can continue to upgrade our system without having to worry about updates that will kill your modification. In this article, i will show you how i remove WordPress admin menu using plugin style without affecting WordPress Core codes.

WordPress Admin Menu

If you are able to dig into WordPress code, you will notice that their menu is created by a single function using two global variables as parameter. You can easily find this code located at wp-admin/menu-header.php, line 157-158.

_wp_menu_output( $menu, $submenu );
do_action( 'adminmenu' );

From the look of the method, you would have easily guess that this method is also a global method which takes in global variables $menu and $submenu to construct a full flag admin menu in WordPress. However, this method is like a loop that takes in a variable and loop through whatever is contain in the variable given. Hence, we will have to look at how each global variable is built to determine how to properly remove a WordPress admin menu.

Global Variable - $menu

If you dig deeper into WordPress, you will notice that the global variable $menu and $submenu are located at wp-admin/menu.php, line 25 onwards. This two variables play an important part in our objective as they create and remove main and submenu in WordPress. If you look at the code from line 28-115, you will notice that both menu and submenu is constructed first regardless of permission.

$menu[0] = array( __('Dashboard'), 'read', 'index.php', '', 'menu-top', 'menu-dashboard', 'div' );

$menu[4] = array( '', 'read', 'separator1', '', 'wp-menu-separator' );

$menu[5] = array( __('Posts'), 'edit_posts', 'edit.php', '', 'open-if-no-js menu-top', 'menu-posts', 'div' );
	$submenu['edit.php'][5]  = array( __('Edit'), 'edit_posts', 'edit.php' );
	/* translators: add new post */
	$submenu['edit.php'][10]  = array( _x('Add New', 'post'), 'edit_posts', 'post-new.php' );

	$i = 15;
	foreach ( $wp_taxonomies as $tax ) {
		if ( $tax->hierarchical || ! in_array('post', (array) $tax->object_type, true) )
			continue;

		$submenu['edit.php'][$i] = array( esc_attr($tax->label), 'manage_categories', 'edit-tags.php?taxonomy=' . $tax->name );
		++$i;
	}

	$submenu['edit.php'][50] = array( __('Categories'), 'manage_categories', 'categories.php' );

$menu[10] = array( __('Media'), 'upload_files', 'upload.php', '', 'menu-top', 'menu-media', 'div' );
	$submenu['upload.php'][5] = array( __('Library'), 'upload_files', 'upload.php');
	/* translators: add new file */
	$submenu['upload.php'][10] = array( _x('Add New', 'file'), 'upload_files', 'media-new.php');

$menu[15] = array( __('Links'), 'manage_links', 'link-manager.php', '', 'menu-top', 'menu-links', 'div' );
	$submenu['link-manager.php'][5] = array( __('Edit'), 'manage_links', 'link-manager.php' );
	/* translators: add new links */
	$submenu['link-manager.php'][10] = array( _x('Add New', 'links'), 'manage_links', 'link-add.php' );
	$submenu['link-manager.php'][15] = array( __('Link Categories'), 'manage_categories', 'edit-link-categories.php' );

$menu[20] = array( __('Pages'), 'edit_pages', 'edit-pages.php', '', 'menu-top', 'menu-pages', 'div' );
	$submenu['edit-pages.php'][5] = array( __('Edit'), 'edit_pages', 'edit-pages.php' );
	/* translators: add new page */
	$submenu['edit-pages.php'][10] = array( _x('Add New', 'page'), 'edit_pages', 'page-new.php' );

$menu[25] = array( sprintf( __('Comments %s'), "<span id='awaiting-mod' class='count-$awaiting_mod'><span class='pending-count'>" . number_format_i18n($awaiting_mod) . "</span></span>" ), 'edit_posts', 'edit-comments.php', '', 'menu-top', 'menu-comments', 'div' );

$_wp_last_object_menu = 25; // The index of the last top-level menu in the object menu group

$menu[59] = array( '', 'read', 'separator2', '', 'wp-menu-separator' );

$menu[60] = array( __('Appearance'), 'switch_themes', 'themes.php', '', 'menu-top', 'menu-appearance', 'div' );
	$submenu['themes.php'][5]  = array(__('Themes'), 'switch_themes', 'themes.php');
	$submenu['themes.php'][10] = array(__('Editor'), 'edit_themes', 'theme-editor.php');
	$submenu['themes.php'][15] = array(__('Add New Themes'), 'install_themes', 'theme-install.php');

$update_plugins = get_transient( 'update_plugins' );
$update_count = 0;
if ( !empty($update_plugins->response) )
	$update_count = count( $update_plugins->response );

$menu[65] = array( sprintf( __('Plugins %s'), "<span class='update-plugins count-$update_count'><span class='plugin-count'>" . number_format_i18n($update_count) . "</span></span>" ), 'activate_plugins', 'plugins.php', '', 'menu-top', 'menu-plugins', 'div' );
	$submenu['plugins.php'][5]  = array( __('Installed'), 'activate_plugins', 'plugins.php' );
	/* translators: add new plugin */
	$submenu['plugins.php'][10] = array(_x('Add New', 'plugin'), 'install_plugins', 'plugin-install.php');
	$submenu['plugins.php'][15] = array( __('Editor'), 'edit_plugins', 'plugin-editor.php' );

if ( current_user_can('edit_users') )
	$menu[70] = array( __('Users'), 'edit_users', 'users.php', '', 'menu-top', 'menu-users', 'div' );
else
	$menu[70] = array( __('Profile'), 'read', 'profile.php', '', 'menu-top', 'menu-users', 'div' );

if ( current_user_can('edit_users') ) {
	$_wp_real_parent_file['profile.php'] = 'users.php'; // Back-compat for plugins adding submenus to profile.php.
	$submenu['users.php'][5] = array(__('Authors & Users'), 'edit_users', 'users.php');
	$submenu['users.php'][10] = array(__('Add New'), 'create_users', 'user-new.php');
	$submenu['users.php'][15] = array(__('Your Profile'), 'read', 'profile.php');
} else {
	$_wp_real_parent_file['users.php'] = 'profile.php';
	$submenu['profile.php'][5] = array(__('Your Profile'), 'read', 'profile.php');
}

$menu[75] = array( __('Tools'), 'read', 'tools.php', '', 'menu-top', 'menu-tools', 'div' );
	$submenu['tools.php'][5] = array( __('Tools'), 'read', 'tools.php' );
	$submenu['tools.php'][10] = array( __('Import'), 'import', 'import.php' );
	$submenu['tools.php'][15] = array( __('Export'), 'import', 'export.php' );
	$submenu['tools.php'][20] = array( __('Upgrade'), 'install_plugins',  'update-core.php');

$menu[80] = array( __('Settings'), 'manage_options', 'options-general.php', '', 'menu-top', 'menu-settings', 'div' );
	$submenu['options-general.php'][10] = array(__('General'), 'manage_options', 'options-general.php');
	$submenu['options-general.php'][15] = array(__('Writing'), 'manage_options', 'options-writing.php');
	$submenu['options-general.php'][20] = array(__('Reading'), 'manage_options', 'options-reading.php');
	$submenu['options-general.php'][25] = array(__('Discussion'), 'manage_options', 'options-discussion.php');
	$submenu['options-general.php'][30] = array(__('Media'), 'manage_options', 'options-media.php');
	$submenu['options-general.php'][35] = array(__('Privacy'), 'manage_options', 'options-privacy.php');
	$submenu['options-general.php'][40] = array(__('Permalinks'), 'manage_options', 'options-permalink.php');
	$submenu['options-general.php'][45] = array(__('Miscellaneous'), 'manage_options', 'options-misc.php');

Furthermore, its being done neat and nicely. After that a few loop is conducted to remove the menu and submenu according to the user permission. You can see that on line 152 - 209.

$_wp_submenu_nopriv = array();
$_wp_menu_nopriv = array();
// Loop over submenus and remove pages for which the user does not have privs.
foreach ( array( 'submenu' ) as $sub_loop ) {
	foreach ($$sub_loop as $parent => $sub) {
		foreach ($sub as $index => $data) {
			if ( ! current_user_can($data[1]) ) {
				unset(${$sub_loop}[$parent][$index]);
				$_wp_submenu_nopriv[$parent][$data[2]] = true;
			}
		}

		if ( empty(${$sub_loop}[$parent]) )
			unset(${$sub_loop}[$parent]);
	}
}

// Loop over the top-level menu.
// Menus for which the original parent is not acessible due to lack of privs will have the next
// submenu in line be assigned as the new menu parent.
foreach ( $menu as $id => $data ) {
	if ( empty($submenu[$data[2]]) )
		continue;
	$subs = $submenu[$data[2]];
	$first_sub = array_shift($subs);
	$old_parent = $data[2];
	$new_parent = $first_sub[2];
	// If the first submenu is not the same as the assigned parent,
	// make the first submenu the new parent.
	if ( $new_parent != $old_parent ) {
		$_wp_real_parent_file[$old_parent] = $new_parent;
		$menu[$id][2] = $new_parent;

		foreach ($submenu[$old_parent] as $index => $data) {
			$submenu[$new_parent][$index] = $submenu[$old_parent][$index];
			unset($submenu[$old_parent][$index]);
		}
		unset($submenu[$old_parent]);

		if ( isset($_wp_submenu_nopriv[$old_parent]) )
			$_wp_submenu_nopriv[$new_parent] = $_wp_submenu_nopriv[$old_parent];
	}
}

do_action('admin_menu', '');

// Remove menus that have no accessible submenus and require privs that the user does not have.
// Run re-parent loop again.
foreach ( $menu as $id => $data ) {
	// If submenu is empty...
	if ( empty($submenu[$data[2]]) ) {
		// And user doesn't have privs, remove menu.
		if ( ! current_user_can($data[1]) ) {
			$_wp_menu_nopriv[$data[2]] = true;
			unset($menu[$id]);
		}
	}
}

Now we have a basic understanding of how WordPress handle their admin menu according to user access. We are ready to remove or modify any user access to alter WordPress user capability to view a particular menu in WordPress.

Removing WordPress Admin Menu

After having you wasting your time reading all the way from the top to here, i finally getting back to track and write what this article is about. We understand from all the rubbish on top that the global variable $menu array contains all the top level menu item and the global variable $submenu array contains all submenu page of each top level menu item. We can perform a few methods to remove a WordPress Admin Menu. The first simple and very basic way of removing a WordPress admin menu is to unset the menu resist in the global array.

function remove_submenu() {
global $submenu;
//remove Theme editor
unset($submenu['themes.php'][10]);
}

function remove_menu() {
global $menu;
//remove post top level menu
unset($menu[5]);
}
add_action('admin_head', 'remove_menu');
add_action('admin_head', 'remove_submenu');

We can remove a set of admin menu by doing this.

function remove_menus () {
global $menu;
		$restricted = array(__('Dashboard'), __('Posts'), __('Media'), __('Links'), __('Pages'), __('Appearance'), __('Tools'), __('Users'), __('Settings'), __('Comments'), __('Plugins'));
		end ($menu);
		while (prev($menu)){
			$value = explode(' ',$menu[key($menu)][0]);
			if(in_array($value[0] != NULL?$value[0]:"" , $restricted)){unset($menu[key($menu)]);}
		}
}
add_action('admin_menu', 'remove_menus');

The above code can be further reduce by 4 lines but i will keep it as it is.

This is pretty simple but not all user have these access and you might want to do some checking before accessing an invalid array to be unset which might give an error to be display. Although this is simple and the objective is achieve by removing the display of the menu/submenu, the user will still be able to direct access via the url. Hence, we need something better. Something that will disable all admin menu and sub menu tab from accessing and viewing.

function remove_menus () {
global $menu, $submenu, $user_ID;
	$the_user = new WP_User($user_ID);
	$valid_page = "admin.php?page=contact-form-7/admin/admin.php";
	$restricted = array('index.php','edit.php','categories.php','upload.php','link-manager.php','edit-pages.php','edit-comments.php', 'themes.php', 'plugins.php', 'users.php', 'profile.php', 'tools.php', 'options-general.php');
	$restricted_str = 'widgets.php';
	end ($menu);
	while (prev($menu)){
		$menu_item = $menu[key($menu)];
		$restricted_str .= '|'.$menu_item[2];
		if(in_array($menu_item[2] , $restricted)){
			$submenu_item = $submenu[$menu_item[2]];
			if($submenu_item != NULL){
				$tmp = $submenu_item;
				$max = array_pop(array_keys($tmp));
				for($i = $max; $i > 0;$i-=5){

					 if($submenu_item[$i] != NULL){
						$restricted_str .= '|'.$submenu[$menu_item[2]][$i][2];
						unset($submenu[$menu_item[2]][$i]);
					}
				}
			}
			unset($menu[key($menu)]);
		}
	}
	$result = preg_match('/(.*?)\/wp-admin\/?('.$restricted_str.')??(('.$restricted_str.'){1})(.*?)/',$_SERVER['REQUEST_URI']);
	if ($result != 0 && $result != FALSE){
		wp_redirect(get_option('siteurl') . '/wp-admin/' . $valid_page);
		exit(0);
	}
}
add_action('admin_menu', 'remove_menus');

The above function did just the thing. We will only required to provide the file name of the top level category and it will automatically disable all access to the subsequence admin sub menu. However, we will have to provide a valid page for user to gain access for the first time. The above code will disable ALL ADMIN MENU AND SUB MENU FOR ALL WORDPRESS ACCESS. The only page that was left accessible are the custom admin menu created by our user such as TweetMeme or Contact 7 form admin menu.

Easiest way to remove sub menu

After version 3.1, you are provided with the following methods to remove submenu

add_action( 'admin_menu', 'my_remove_menu_pages' );
function my_remove_menu_pages() {
        remove_menu_page('link-manager.php');
        //remove_menu_page('themes.php');
        remove_submenu_page( 'themes.php', 'themes.php' );
        remove_submenu_page( 'themes.php', 'theme-editor.php' );
        remove_submenu_page( 'themes.php', 'themes.php?page=custom-background' );
        remove_submenu_page( 'widgets.php', 'theme-editor.php' );
        remove_menu_page('tools.php');
        remove_menu_page('upload.php');
        remove_menu_page('edit-comments.php');
        remove_menu_page('plugins.php');
        remove_menu_page('admin.php?page=w3tc_general');
        remove_menu_page('admin.php?page=better_wp_security');
        remove_menu_page('admin.php?page=wpcf7');
        remove_submenu_page( 'index.php', 'update-core.php' );
        remove_submenu_page( 'options-general.php', 'options-discussion.php' );
        remove_submenu_page( 'options-general.php', 'options-writing.php' );
        remove_submenu_page( 'options-general.php', 'options-reading.php' );
        remove_submenu_page( 'options-general.php', 'options-permalink.php' );
        remove_submenu_page( 'options-general.php', 'options-media.php' );
}

Pretty simple and direct, first parameter is the file name or parent file name of the page you want to remove, second parameter is the submenu you wish to remove.

Concolusion

This is the way i use to remove admin menu in WordPress. We do not have to check for user access as the user will already be redirected to the specific page before they can enter the permission denial page. Have fun 🙂

Using WordPress dbDelta Function

Many of us who develop WordPress plugin might have come across dbDelta function. dbDelta function is usually used when one wish to create table for your WordPress plugin. However, this function might not be that easy to deal with since it is not an official function in WordPress. Nonetheless it is a powerful function that majority of us would want to utilize. In this article, we will talk about dbDelta function and how we can ensure that it perform what it is made to do.

dbDelta Function

Like i mention before in one of my article, dbDelta function has the ability to examine the current table structure, compares it to the desired table structure, and either adds or modifies the table as necessary, so it can be very handy for updates of our plugin. However, unlike many WordPress function, dbDelta function is the most picky and troublesome one.  In order for dbDelta function to work, a few criteria will have to be met.

  1. You have to put each field on its own line in your SQL statement.
  2. You have to have two spaces between the words PRIMARY KEY and the definition of your primary key.
  3. You must use the key word KEY rather than its synonym INDEX and you must include at least one KEY.

Well, the above criteria's seem easy to achieve. But wait till it hits you.

Strengthen and Weakness of dbDelta Function

The strength of this function is that we are assure that any modification to our table structure will be shown on the plugin. Hence, we won't have to worry about our user plugin not being updated whenever we change our table structure to accommodate new features. This function which is build by the WordPress community is definitely much more secure than other function that an individual came up with to solve such problem. Hence, the function itself is much more reliable. Using dbDelta also removes the need to request each individual instruction to be execute separately. Code can be sum up and dump into dbDelta function for it to run.

On the other end, like i mention earlier, this can be a real pain in the ass. dbDelta function is not very tolerant against mistakes. Hence, any mistakes made on your SQL query might just fail this function. Furthermore, certain restriction is given to you in order to utilize this function. If you accidentally break such restriction, the function will fail. Moreover, no documentation were provided for this method which makes it much more time consuming to get the hang of it. In case you haven't notice, dbDelta will only update new fields or keys. This means that if you decide to remove any particular field or keys on your table and hoping dbDelta will help you out with it, you are wrong.  And if dbDelta function fail to work for you, debugging it might just be as headache since printing out the message on dbDelta might not work well for you. To make things worst,  Wordpress will mark an error on your plugin if you try to exit(0) on some part of the script instead of stopping and display the printing message.

Using dbDelta function

Initially using dbDelta function wasn't that bad. We just have to be very careful with the spaces given. An example given by WordPress would be the one shown below,

$sql = "CREATE TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT,
	  time bigint(11) DEFAULT '0' NOT NULL,
	  name tinytext NOT NULL,
	  text text NOT NULL,
	  url VARCHAR(55) NOT NULL,
	  UNIQUE KEY id (id)
	);";

require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);

Well, if you copy directly and change the field name, it should work nicely for you. But take note of the spaces given. Here are a few example that will cause dbDelta function to fail.

$sql = "CREATE  TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT,
	  time bigint(11) DEFAULT '0' NOT NULL,
	  name tinytext NOT NULL,
	  text text NOT NULL,
	  url VARCHAR(55) NOT NULL,
	  UNIQUE KEY id (id)
	);";

require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);

The above contains an extra space between CREATE and TABLE. Hence, instead of one space we have two and dbDelta fail. The same thing might happen if there are an extra space between TABLE and your table name. Another good example might occur on the key level.

$sql = "CREATE  TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT,
	  time bigint(11) DEFAULT '0' NOT NULL,
	  name tinytext NOT NULL,
	  text text NOT NULL,
	  url VARCHAR(55) NOT NULL,
	  UNIQUE KEY id (id, time)
	);";

require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);

The above fail due to this:

UNIQUE KEY id (id, time)

the correct writing should be this:

UNIQUE KEY id (id,time)

where there are no spaces between the commons. On the other hand, try to avoid having any spaces between each commons such as these

$sql = "CREATE  TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT , 
	  time bigint(11) DEFAULT '0' NOT NULL , 
	  name tinytext NOT NULL , 
	  text text NOT NULL , 
	  url VARCHAR(55) NOT NULL , 
	  UNIQUE KEY id (id, time)
	);";

require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);

It is always safe to ensure that all keyword are separated by one space and between each commas there shouldn't be any spacing. Another thing to take note is that every table creation should have a KEY in order for it to work. And like the criteria stated, each field should have its own line like the one shown on WordPress example. And at the end of each instruction there should be semicolon to be safe!

The above are things you should be cautious when using dbDelta. However, i did learn some tricks when reading the code of dbDelta function. If you are creating multiple table or query with dbDelta, it can be done using one call.

#$table_name = 'test1'
$sql = "CREATE  TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT , 
	  time bigint(11) DEFAULT '0' NOT NULL , 
	  name tinytext NOT NULL , 
	  text text NOT NULL , 
	  url VARCHAR(55) NOT NULL , 
	  UNIQUE KEY id (id, time)
	);";
#$table_name = 'test2'
$sql .= "CREATE  TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT , 
	  time bigint(11) DEFAULT '0' NOT NULL , 
	  name tinytext NOT NULL , 
	  text text NOT NULL , 
	  url VARCHAR(55) NOT NULL , 
	  UNIQUE KEY id (id, time)
	);";
#$table_name = 'test3'
$sql = "CREATE  TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT , 
	  time bigint(11) DEFAULT '0' NOT NULL , 
	  name tinytext NOT NULL , 
	  text text NOT NULL , 
	  url VARCHAR(55) NOT NULL , 
	  UNIQUE KEY id (id, time)
	);";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);

The above is similar to having one instruction per dbDelta such as this:

require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
#$table_name = 'test1'
$sql = "CREATE  TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT , 
	  time bigint(11) DEFAULT '0' NOT NULL , 
	  name tinytext NOT NULL , 
	  text text NOT NULL , 
	  url VARCHAR(55) NOT NULL , 
	  UNIQUE KEY id (id, time)
	);";
dbDelta($sql);
#$table_name = 'test2'
$sql = "CREATE  TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT , 
	  time bigint(11) DEFAULT '0' NOT NULL , 
	  name tinytext NOT NULL , 
	  text text NOT NULL , 
	  url VARCHAR(55) NOT NULL , 
	  UNIQUE KEY id (id, time)
	);";
dbDelta($sql);
#$table_name = 'test3'
$sql .= "CREATE  TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT , 
	  time bigint(11) DEFAULT '0' NOT NULL , 
	  name tinytext NOT NULL , 
	  text text NOT NULL , 
	  url VARCHAR(55) NOT NULL , 
	  UNIQUE KEY id (id, time)
	);";
dbDelta($sql);

Hence, you might want to practice the initial one to make your code run more efficient. Another interesting thing to take note is that every last instruction will not be required to have semicolon. Hence,

#$table_name = 'test2'
$sql .= "CREATE  TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT , 
	  time bigint(11) DEFAULT '0' NOT NULL , 
	  name tinytext NOT NULL , 
	  text text NOT NULL , 
	  url VARCHAR(55) NOT NULL , 
	  UNIQUE KEY id (id, time)
	);";
#$table_name = 'test3'
$sql = "CREATE  TABLE " . $table_name . " (
	  id mediumint(9) NOT NULL AUTO_INCREMENT , 
	  time bigint(11) DEFAULT '0' NOT NULL , 
	  name tinytext NOT NULL , 
	  text text NOT NULL , 
	  url VARCHAR(55) NOT NULL , 
	  UNIQUE KEY id (id, time)
	)";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);

will work. This means that if you have only 1 SQL instruction for dbDelta to run, you can safely remove the semicolon. But if you have many SQL instructions, only the last instruction can exclude semicolon since dbDelta function use semicolon as delimiter for splitting each instruction and remove the last array data if it is empty. Hence, leaving the last semicolon will reduce the step required to complete dbDelta function.

Conclusion

dbDelta in WordPress can be really useful. We just need to be careful not to make those silly mistakes that might just cost us our precious time debugging it. Although it can't remove fields for us, it definitely help us save a lot of time by adding in new fields!

Guarantee Make WordPress Flash Uploader Work

Hungred Dot Com has always had its flash uploader disabled due to many reason which i personally have no idea why. Many people said it was due to WordPress 2.7 update which caused the incompatibility of flash 10 with the flash uploader, swfupload. And here goes the big discussion on how to make WordPress flash uploader WORK. Of course, i was just a pass by reader and tried some mention methods by the public which still fail. The flash uploader that i have is shown below,

browser-uploader

After WordPress 2.8 was launched which was said that the flash uploader will be back kicking, but it doesn't! And slowly, it seems like my WordPress is getting bit and pieces of errors from firebug whenever I'm on WordPress. Furthermore, it gets really lag on Firefox when I'm on writing post. Very soon, some of the features failed such as the auto draft when you are adding post. But that doesn't bother me! Until i finished update my WordPress theme and fixed many stuff within this blog that i finally decided to solve my WordPress problem (back to topic, haha).

WordPress Flash Uploader Solutions

So i went to Google and perform a simple search which lead me to a lot of duplicate solution mention in the WordPress forum. Hence, i started my journey to resolve all these weird issues here and there in WordPress admin. Here are the solutions mention:

  • You'll have to go back to version 9 of Flash Player
    . Tried that, failed.
  • Check the permissions on the swfupload file. oh boy! moderator speaks up! but still not working.
  • Reuploading wp-includes and wp-admin fixed it. This must be it! still fail.
  • fix it by reuploading:
    /wp-includes/js/swfupload/
    And then clearing my browser cache.

    While everyone said 'it work!' in the forum, i still fail!
  • check swfupload.swf is in the folder of /wp-includes/js/swfupload/. YA! but it still not working!
  • issue was mod_security it was working previously! So i skipped this smartly 😀
  • I don't find that this works. The button is there, but clicking on it does absolutely nothing. It just sits there. God, you are lucky. Mine doesn't even exist.
  • The version of the swfupload in 2.6.5 did not work with Flash 10. 2.7 has the workaround for that. The moderator is back. Man he is one helpful guy! Updated to the latest version. But still fail.
  • Folks, make sure you're uploading the entire swfupload folder from WordPress 2.7, not just the swfupload.swf file.I uploaded the whole cow in and nothing happen!

That's it! Here are all the solution presented by the forum, other site are just copying each other work which still doesn't work for me. Hence, if you are like me then you should read on.

Guarantee Awake The Sleeping WordPress Flash Uploader

From here on, its a personal tried and error thing that will assure Hungred Dot Com safety at the same time guarantee that this flash uploader will work. Please backup both databases and your WordPress files before doing this. The situtation is that I had a few WordPress blog that i either setup for myself or for others after Hungred Dot Com. All other WordPress blog flash uploader work like charm but not this. Therefore, i can conclude something is wrong with this blog and not others (obvious).

According to the forum written above, it seems like everything is surrounding the folder of swfupload in /wp-includes/js/swfupload/. However, replacing it still doesn't work. May be its not that problem. Something else is being modified without me knowing. May be some plugin that i tired on Hungred Dot Com. Hence, i tried to remove the folder on /wp-includes/js/ which means every single JavaScript in WordPress is being removed, the admin site only of course. The removable really doesn't affect the main site. I upload the one in WordPress 2.8 that i downloaded from WordPress but it still doesn't work. The next try were to copy the whole folder /wp-includes/ and /wp-admin/ replacing the one stored on the server. This does takes a while but the site wasn't being affected. After the upload had complete, i tried the flash uploader but it still doesn't work. The folder /wp-content/ shouldn't had affected the admin page so i shouldn't touch that folder.

If my theory is correct, everything should have been replaced by the latest file that i have just uploaded. This means that i am actually performing a re-installation already. However, why is it still not working? My next though is that there exist a file that run in the previous version that wasn't replaced or removed by this sort of re-installation. Therefore, i decide to delete the folder /wp-includes/ and /wp-admin/ and replace with the latest one that i downloaded from WordPress. However, doing that will definitely killed my blog for a while since /wp-includes/ exist files that required for the site to function. My solution was to do it within the file manager provided by my host that allows me to directly interact with the server that is 100x faster than using FTP. Here is a screen shot of it.

file-manager

I upload the zip file through this file manager given by Hostgator and unzip into a folder. Deleting the folder of both /wp-includes/ and /wp-admin/ takes around 1 second and copying the new folder to Hungred Dot Com also takes around 1-2 second. This should be it! The fash uploader should work now! Unfortunately, it still doesn't work. DAMMIT!

However, i can assure that my WordPress is clean and definitely should have the flash uploader i set out for (the clean here refer to any files that might killed my flash uploader that wasn't being deleted previously). The next culprit will be the plugin i have used in WordPress! Some WordPress developers must have done something that caused all this problem! I went over to my WordPress plugin page and deactivate all my WordPress plugin immediately, went to upload a file, and..

flash-uploader

Damn! It was some plugin exist in my WordPress all along (may be not?)! So i hand picked those plugin that associate with WordPress add post page that could caused this. After i enabled most of it, i left the last one plugin that might just be the criminal that does all these. Guess what? None of them were. It seems like after i enabled and disabled all plugin, the flash uploader were enabled again. Other functionality such as auto save draft and stuff were also back online. Confused.

Conclusion

The above method will surely assure that your WordPress is clean again but it might caused you some problem. Depending on how desperate you are (HELL YEAH I WAS!), you might just tried some of the things above or just skipped more of it. Nonetheless, i am just trying to reinstall the whole WordPress and minimize the damage that will caused to the problem. In my case, nothing was missing and everything sail smoothly again. Hope this help! (man, this is one whole story. To the point damnit! *slap myself*)

WordPress Text Formatting Problem – Solved!

In Hungred Dot Com, we have been having problem with text formatting in WordPress for all our codes due to WordPress smart quotes functionality. Most of us who write code for the public usually uses those smart plugin such as 'SyntaxHighlighter Evolved' to present it nicely to our users. The problem with using external plugins such as this is that WordPress smart quotes doesn't see the tag for the plugin in this case,

,
as one of excluding formatting tag. Tag such as 'pre', 'code', 'kbd', 'style', 'script', 'tt' are excluded from smart quotes which you can personally view it on the source code of WordPress located at wp-includes/formatting.php. Hence, your WordPress codes article will not be showing '"' instead of the normal '"' symbol. However, there are ways to solve such problem and here we will present them to you to eliminate all these trouble once and for all!

Include Tag In WordPress Text Formatting Function

One way to solve this problem is to add the plugin tag into the core function wptexturize which locate at wp-includes/formatting.php. In that file you will notice the following function,

/**
 * Replaces common plain text characters into formatted entities
 *
 * As an example,
 * <code>
 * 'cause today's effort makes it worth tomorrow's "holiday"...
 * </code>
 * Becomes:
 * <code>
 * ’cause today’s effort makes it worth tomorrow’s “holiday”…
 * </code>
 * Code within certain html blocks are skipped.
 *
 * @since 0.71
 * @uses $wp_cockneyreplace Array of formatted entities for certain common phrases
 *
 * @param string $text The text to be formatted
 * @return string The string replaced with html entities
 */
function wptexturize($text) {
	global $wp_cockneyreplace;
	$output = '';
	$curl = '';
	$textarr = preg_split('/(<.*>|\[.*\])/Us', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
	$stop = count($textarr);
	
	/* translators: opening curly quote */
	$opening_quote = _x('“', 'opening curly quote');
	/* translators: closing curly quote */
	$closing_quote = _x('”', 'closing curly quote');
	
	$no_texturize_tags = apply_filters('no_texturize_tags', array('pre', 'code', 'kbd', 'style', 'script', 'tt'));
	$no_texturize_shortcodes = apply_filters('no_texturize_shortcodes', array('code'));
	$no_texturize_tags_stack = array();
	$no_texturize_shortcodes_stack = array();

	// if a plugin has provided an autocorrect array, use it
	if ( isset($wp_cockneyreplace) ) {
		$cockney = array_keys($wp_cockneyreplace);
		$cockneyreplace = array_values($wp_cockneyreplace);
	} else {
		$cockney = array("'tain't","'twere","'twas","'tis","'twill","'til","'bout","'nuff","'round","'cause");
		$cockneyreplace = array("’tain’t","’twere","’twas","’tis","’twill","’til","’bout","’nuff","’round","’cause");
	}

	$static_characters = array_merge(array('---', ' -- ', '--', ' - ', 'xn–', '...', '``', '\'s', '\'\'', ' (tm)'), $cockney);
	$static_replacements = array_merge(array('—', ' — ', '–', ' – ', 'xn--', '…', $opening_quote, '’s', $closing_quote, ' ™'), $cockneyreplace);

	$dynamic_characters = array('/\'(\d\d(?:’|\')?s)/', '/(\s|\A|")\'/', '/(\d+)"/', '/(\d+)\'/', '/(\S)\'([^\'\s])/', '/(\s|\A)"(?!\s)/', '/"(\s|\S|\Z)/', '/\'([\s.]|\Z)/', '/(\d+)x(\d+)/');
	$dynamic_replacements = array('’$1','$1‘', '$1″', '$1′', '$1’$2', '$1' . $opening_quote . '$2', $closing_quote . '$1', '’$1', '$1×$2');

	for ( $i = 0; $i < $stop; $i++ ) {
		$curl = $textarr[$i];

		if ( !empty($curl) && '<' != $curl{0} && '[' != $curl{0}
				&& empty($no_texturize_shortcodes_stack) && empty($no_texturize_tags_stack)) { // If it's not a tag
			// static strings
			$curl = str_replace($static_characters, $static_replacements, $curl);
			// regular expressions
			$curl = preg_replace($dynamic_characters, $dynamic_replacements, $curl);
		} else {
			wptexturize_pushpop_element($curl, $no_texturize_tags_stack, $no_texturize_tags, '<', '>');
			wptexturize_pushpop_element($curl, $no_texturize_shortcodes_stack, $no_texturize_shortcodes, '[', ']');
		}

		$curl = preg_replace('/&([^#])(?![a-zA-Z1-4]{1,8};)/', '&$1', $curl);
		$output .= $curl;
	}

	return $output;
}

You can add your tag into the function on this link,

$no_texturize_tags = apply_filters('no_texturize_tags', array('pre', 'code', 'kbd', 'style', 'script', 'tt'));

for our example we will add [\php\]

$no_texturize_tags = apply_filters('no_texturize_tags', array('pre', 'code', 'kbd', 'style', 'script', 'tt', ''));

Although this solved your problem but this solution also required you to edit the codes in the WordPress which will be replaced with every new release of WordPress.

Remove WordPress Text Formatting

The most efficient way is to remove the root of the problem! Unless you desperately want WordPress text formatting to be made available, you will want to remove this. Otto42 who is one of the moderator suggested a good way to eliminate such problem. We will add the following two code to remove the function wptexturize in WordPress which perform the formatting in our theme function.php file.

remove_filter('comment_text', 'wptexturize');
remove_filter('the_excerpt', 'wptexturize');
remove_filter('the_content', 'wptexturize');
remove_filter('the_rss_content', 'wptexturize');

This way all your text and code will be safe from formatting on that theme. You can also create a very small plugin that do this by placing the above three links to ANY WordPress plugin (may be you don't even have to create any plugin for this).

Replace WordPress Default Text Formatting

For those who want WordPress smart quote to be enabled but doesn't want it to format your codes, you can try to replace the function wptexturize. You can do this on your theme or any plugin available for you. Basically, you can remove the default function wptexturize through the following code,

remove_filter('comment_text', 'wptexturize');
remove_filter('the_excerpt', 'wptexturize');
remove_filter('the_content', 'wptexturize');
remove_filter('the_rss_content', 'wptexturize');

After that on the same page, you can copy the following code and add the action hook for your new wptexturize solution that cater to your personal need.

function my_wptexturize($text) {
	global $wp_cockneyreplace;
	$output = '';
	$curl = '';
	$textarr = preg_split('/(<.*>|\[.*\])/Us', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
	$stop = count($textarr);
	
	/* translators: opening curly quote */
	$opening_quote = _x('“', 'opening curly quote');
	/* translators: closing curly quote */
	$closing_quote = _x('”', 'closing curly quote');
	
	$no_texturize_tags = apply_filters('no_texturize_tags', array('pre', 'code', 'kbd', 'style', 'script', 'tt', ''));
	$no_texturize_shortcodes = apply_filters('no_texturize_shortcodes', array('code'));
	$no_texturize_tags_stack = array();
	$no_texturize_shortcodes_stack = array();

	// if a plugin has provided an autocorrect array, use it
	if ( isset($wp_cockneyreplace) ) {
		$cockney = array_keys($wp_cockneyreplace);
		$cockneyreplace = array_values($wp_cockneyreplace);
	} else {
		$cockney = array("'tain't","'twere","'twas","'tis","'twill","'til","'bout","'nuff","'round","'cause");
		$cockneyreplace = array("’tain’t","’twere","’twas","’tis","’twill","’til","’bout","’nuff","’round","’cause");
	}

	$static_characters = array_merge(array('---', ' -- ', '--', ' - ', 'xn–', '...', '``', '\'s', '\'\'', ' (tm)'), $cockney);
	$static_replacements = array_merge(array('—', ' — ', '–', ' – ', 'xn--', '…', $opening_quote, '’s', $closing_quote, ' ™'), $cockneyreplace);

	$dynamic_characters = array('/\'(\d\d(?:’|\')?s)/', '/(\s|\A|")\'/', '/(\d+)"/', '/(\d+)\'/', '/(\S)\'([^\'\s])/', '/(\s|\A)"(?!\s)/', '/"(\s|\S|\Z)/', '/\'([\s.]|\Z)/', '/(\d+)x(\d+)/');
	$dynamic_replacements = array('’$1','$1‘', '$1″', '$1′', '$1’$2', '$1' . $opening_quote . '$2', $closing_quote . '$1', '’$1', '$1×$2');

	for ( $i = 0; $i < $stop; $i++ ) {
		$curl = $textarr[$i];

		if ( !empty($curl) && '<' != $curl{0} && '[' != $curl{0}
				&& empty($no_texturize_shortcodes_stack) && empty($no_texturize_tags_stack)) { // If it's not a tag
			// static strings
			$curl = str_replace($static_characters, $static_replacements, $curl);
			// regular expressions
			$curl = preg_replace($dynamic_characters, $dynamic_replacements, $curl);
		} else {
			wptexturize_pushpop_element($curl, $no_texturize_tags_stack, $no_texturize_tags, '<', '>');
			wptexturize_pushpop_element($curl, $no_texturize_shortcodes_stack, $no_texturize_shortcodes, '[', ']');
		}

		$curl = preg_replace('/&([^#])(?![a-zA-Z1-4]{1,8};)/', '&$1', $curl);
		$output .= $curl;
	}

	return $output;
}
remove_filter('comment_text', 'wptexturize');
remove_filter('the_excerpt', 'wptexturize');
remove_filter('the_content', 'wptexturize');
remove_filter('the_rss_content', 'wptexturize');

add_filter('comment_text', 'my_wptexturize');
add_filter('the_excerpt', 'my_wptexturize');
add_filter('the_content', 'my_wptexturize');
add_filter('the_rss_content', 'my_wptexturize');

This way you will solved your problem of code being wrongly formatted and at the meantime have the capability of smart quote. The only fall back of this method is that you might need to maintain this code in the future if WordPress ever update this function so that you will always have the latest version of smart quote.

Article Formatted Solution

If your post have many articles and you haven't had this problem solved at the beginning, your visitors will still be seeing formatted code in your article and might just drive your visitors away! Hence, you might want to consider reversing the function of wptexturize to return the format for you. You can do this by adding the reversed version of wptexturize and placed in on either a plugin or your theme.

We used hungred smart quotes to solve our issue on the above mention matters.

Summary

Smart quote in WordPress can be annoying and troublesome. Nonetheless, it also benefits those who truly wanted such function built within WordPress as it might just destroy your layout due to the unencoded tag by other writers. Hence, for those who are troubled by this, hopefully the solutions above help!