Replacing the WordPress Dashboard with your own plugin page.

On Custom WordPress Installations, you may want to remove the wordpress dashboard completely and add your own dashboard or plugin page. Of course you can hide the other dashboard widgets and leave only your own, but if you want complete control, this is one solution. I was able to do this using the following approach:

On WordPress 3.1.1, the /wp-admin/index.php provides no support for overriding the wp_dashboard() function. After digging around for an hour or two and finding no hooks inside wp_dashboard(), I thought the best way to remove the dashboard would be to redirect the user from index.php to admin.php?page=your-page and modifying the admin menu item for the ‘Dashboard’ by using admin_init, and admin_menu hooks.

Redirecting from the dashboard to your plugin page:

function my_plugin_admin_init(){
global $pagenow;
		if(current_user_can('plugin_user_role') && $pagenow == 'index.php' && empty($_GET['page']))
		{
			wp_redirect(admin_url('admin.php?page=manage-applications'));
			exit;
		}
}
add_action('admin_init', 'my_plugin_admin_init');

In the code above, I only wanted to remove the dashboard for users under ‘plugin_user_role’, to remove the dashboard for all non-admin users, you can check if !current_user_can(‘manage_options’) in place of current_user_can(‘plugin_user_role’)

The second part is modifying the Admin Menu so that the dashboard menu item title is changed. It will still point to index.php, but index.php will now redirect to our page.

function my_admin_menu()
{
// create a menu page, this will be hidden later
		add_menu_page('Membership Applications', 'Reviews', 'review_members', 'manage-applications', $page_handler);

		global $submenu_file, $pagenow, $menu;

// rename this to change the 'Dashboard' Menu Title.
		$menu[2][0] = __('Applications');

// i only want to remove the dashboard for a specific user role
		if(current_user_can('plugin_user_role'))
		{
// if the current page is my the dashboard replacement, then highlight the 'Dashboard' menu item
			if(@$_GET['page'] == 'manage-applications')
			{
				$submenu_file = 'index.php';
				$pagenow = 'index.php';
			}
		}

// now remove the page from the menu, we have already linked
		remove_menu_page('manage-applications');
}
add_action('admin_menu', 'my_admin_menu');

On Custom WordPress Installations, you may want to remove the wordpress dashboard completely and add your own dashboard or plugin page. Of course you can hide the other dashboard widgets and leave only your own, but if you want complete control, this is one solution. I was able to do this using the following approach:

On WordPress 3.1.1, the /wp-admin/index.php provides no support for overriding the wp_dashboard() function. After digging around for an hour or two and finding no hooks inside wp_dashboard(), I thought the best way to remove the dashboard would be to redirect the user from index.php to admin.php?page=your-page and modifying the admin menu item for the ‘Dashboard’ by using admin_init, and admin_menu hooks.

Redirecting from the dashboard to your plugin page:

function my_plugin_admin_init(){
		if(current_user_can('plugin_user_role') && $pagenow == 'index.php' && empty($_GET['page']))
		{
			wp_redirect(admin_url('admin.php?page=manage-applications'));
			exit;
		}
}
add_action('admin_init', 'my_plugin_admin_init');

In the code above, I only wanted to remove the dashboard for users under ‘plugin_user_role’, to remove the dashboard for all non-admin users, you can check if !current_user_can(‘manage_options’) in place of current_user_can(‘plugin_user_role’)

The second part is modifying the Admin Menu so that the dashboard menu item title is changed. It will still point to index.php, but index.php will now redirect to our page.

function my_admin_menu()
{
// create a menu page, this will be hidden later
		add_menu_page('Membership Applications', 'Reviews', 'review_members', 'manage-applications', $page_handler);

		global $submenu_file, $pagenow, $menu;

// rename this to change the 'Dashboard' Menu Title.
		$menu[2][0] = __('Applications');

// i only want to remove the dashboard for a specific user role
		if(current_user_can('plugin_user_role'))
		{
// if the current page is my the dashboard replacement, then highlight the 'Dashboard' menu item
			if(@$_GET['page'] == 'manage-applications')
			{
				$submenu_file = 'index.php';
				$pagenow = 'index.php';
			}
		}

// now remove the page from the menu, we have already linked
		remove_menu_page('manage-applications');
}

WordPress Calendar Plugin Optimization

Screenshot_20160722_084902

Recently, I had to use the super handy WordPress Calendar Plugin. After adding a few repeating events and taking a look at the output it generated, I noticed the large number of queries that it executed! It executed at least 3 queries per day of the month being displayed! I was doing development that required displaying two months at a time, and the total number of queries was over 150!!

The plugin was fetching the events per-repetetition (weekly, monthly, yearly, etc) per-day. This would add up to more than 3 queries per day in the month.

Well, I decided to step in and take some action. I spent well over ten hours optimizing the event-retrieval process and came up with a query that fetched the events and returned them in chronological order, allowing for filtering of past or future events. I had never done this type of system before, so I took a look at the author’s code and converted it to a very large mysql query. I’m posting it bellow for anyone who might be interested.

The following function fetches the latest events and sorts them using an additional column “diff“. which indicates the freshness of the event. A negative number indicates a past event. A positive number indicates a future event, and a value of 0 indicates an ongoing event. For infinitely repeating events, the diff will indicate the number of days until the next occurrence; but, for infinitely recurring monthly events, it will return a positive value only if the event ocurred more than 15 days ago.


function grab_latest_events($howmany = 3)
{
 global $wpdb;

 $events = $wpdb->get_results("SELECT *, if(event_recur = 'Y',
 if((event_repeats = 0 OR DATE_ADD(event_end, INTERVAL event_repeats YEAR) >= CURDATE()) AND
 (CURDATE() BETWEEN DATE_ADD(event_begin, INTERVAL YEAR(CURDATE())-YEAR(event_begin) YEAR) AND
 DATE_ADD(event_end, INTERVAL YEAR(CURDATE())-YEAR(event_end) YEAR)),
 0,
 if(event_repeats = 0,
 DATEDIFF(DATE_ADD(event_begin, INTERVAL YEAR(CURDATE())-YEAR(event_begin) YEAR), CURDATE())
 ,if(event_repeats>=(YEAR(CURDATE())-YEAR(event_end)),
 DATEDIFF(DATE_ADD(event_begin, INTERVAL YEAR(CURDATE())-YEAR(event_begin) YEAR), CURDATE()),
 DATEDIFF(DATE_ADD(event_end, INTERVAL event_repeats YEAR), CURDATE()))
 )
 )
 ,if(event_recur IN ('M'),
 if((event_repeats = 0 OR DATE_ADD(event_end, INTERVAL event_repeats MONTH) >= CURDATE()) AND # withn range
 ((MONTH(event_end) = MONTH(event_begin) AND DAYOFMONTH(CURDATE()) >= DAYOFMONTH(event_begin) AND DAYOFMONTH(CURDATE()) <= DAYOFMONTH(event_end) ) OR (MONTH(event_end) > MONTH(event_begin) AND
 (DAYOFMONTH(CURDATE()) <= DAYOFMONTH(event_end) OR DAYOFMONTH(CURDATE()) >= DAYOFMONTH(event_begin)))
 OR (MONTH(event_end) < MONTH(event_begin) AND (MONTH(CURDATE()) >= MONTH(event_end) OR MONTH(CURDATE()) <= MONTH(event_begin)) AND (DAYOFMONTH(CURDATE()) > DAYOFMONTH(event_end) OR
 DAYOFMONTH(CURDATE()) < DAYOFMONTH(CURDATE())) ) ), 0,    #IF MONTHLY AND WITHIN RANGE, RETURN 0 DENOMINATING AN OCURRING EVENT if(event_repeats = 0 OR DATEDIFF(DATE_ADD(event_end, INTERVAL event_repeats MONTH), CURDATE()) > 0,
 DATEDIFF(DATE_ADD(DATE_ADD(event_begin, INTERVAL YEAR(CURDATE())-YEAR(event_begin) YEAR), INTERVAL
 MONTH(CURDATE())-MONTH(event_begin)+((DAYOFMONTH(CURDATE())-14>DAYOFMONTH(event_begin))) MONTH), CURDATE())
 ,
 DATEDIFF(DATE_ADD(event_end, INTERVAL event_repeats MONTH), CURDATE())
 )
 )
 ,if(event_recur = 'W' AND
 (event_repeats = 0 OR DATE_ADD(event_end, INTERVAL event_repeats WEEK) >= CURDATE())
 AND if(DAYOFWEEK(event_begin) <= DAYOFWEEK(event_end),
 DAYOFWEEK(event_begin) < DAYOFWEEK(CURDATE()) AND DAYOFWEEK(event_end) >= DAYOFWEEK(CURDATE()),
 DAYOFWEEK(CURDATE()) >= DAYOFWEEK(event_begin) OR DAYOFWEEK(CURDATE()) <= DAYOFWEEK(event_end))
 , 0, #else

 if(event_recur = 'W' AND
 event_repeats = 0,
 abs(DAYOFWEEK(CURDATE())-DAYOFWEEK(event_begin)),
 if(event_recur = 'S' AND (CURDATE() <= event_end AND event_begin <= CURDATE()),
 0, DATEDIFF(event_begin, CURDATE()))
 )
 ))
 ) as diff FROM " . WP_CALENDAR_TABLE .
 " WHERE  (CURDATE() <= event_end AND event_begin <= CURDATE()) OR (if(event_recur = 'Y', if((event_repeats = 0 OR DATE_ADD(event_end, INTERVAL event_repeats YEAR) >= CURDATE()) AND
 (CURDATE() BETWEEN DATE_ADD(event_begin, INTERVAL YEAR(CURDATE())-YEAR(event_begin) YEAR) AND
 DATE_ADD(event_end, INTERVAL YEAR(CURDATE())-YEAR(event_end) YEAR)),
 0,
 if(event_repeats = 0,
 DATEDIFF(DATE_ADD(event_begin, INTERVAL YEAR(CURDATE())-YEAR(event_begin) YEAR), CURDATE())
 ,if(event_repeats>=(YEAR(CURDATE())-YEAR(event_end)),
 DATEDIFF(DATE_ADD(event_begin, INTERVAL YEAR(CURDATE())-YEAR(event_begin) YEAR), CURDATE()),
 DATEDIFF(DATE_ADD(event_end, INTERVAL event_repeats YEAR), CURDATE()))
 )
 )
 ,if(event_recur IN ('M'),
 if((event_repeats = 0 OR DATE_ADD(event_end, INTERVAL event_repeats MONTH) >= CURDATE()) AND # withn range
 ((MONTH(event_end) = MONTH(event_begin) AND DAYOFMONTH(CURDATE()) >= DAYOFMONTH(event_begin) AND DAYOFMONTH(CURDATE()) <= DAYOFMONTH(event_end) ) OR (MONTH(event_end) > MONTH(event_begin) AND
 (DAYOFMONTH(CURDATE()) <= DAYOFMONTH(event_end) OR DAYOFMONTH(CURDATE()) >= DAYOFMONTH(event_begin)))
 OR (MONTH(event_end) < MONTH(event_begin) AND (MONTH(CURDATE()) >= MONTH(event_end) OR MONTH(CURDATE()) <= MONTH(event_begin)) AND (DAYOFMONTH(CURDATE()) > DAYOFMONTH(event_end) OR
 DAYOFMONTH(CURDATE()) < DAYOFMONTH(CURDATE())) ) ), 0,    #IF MONTHLY AND WITHIN RANGE, RETURN 0 DENOMINATING AN OCURRING EVENT if(event_repeats = 0 OR DATEDIFF(DATE_ADD(event_end, INTERVAL event_repeats MONTH), CURDATE()) > 0,
 DATEDIFF(DATE_ADD(DATE_ADD(event_begin, INTERVAL YEAR(CURDATE())-YEAR(event_begin) YEAR), INTERVAL
 MONTH(CURDATE())-MONTH(event_begin)+((DAYOFMONTH(CURDATE())-14>DAYOFMONTH(event_begin))) MONTH), CURDATE())
 ,
 DATEDIFF(DATE_ADD(event_end, INTERVAL event_repeats MONTH), CURDATE())
 )
 )
 ,if(event_recur = 'W' AND
 (event_repeats = 0 OR DATE_ADD(event_end, INTERVAL event_repeats WEEK) >= CURDATE())
 AND if(DAYOFWEEK(event_begin) <= DAYOFWEEK(event_end),
 DAYOFWEEK(event_begin) < DAYOFWEEK(CURDATE()) AND DAYOFWEEK(event_end) >= DAYOFWEEK(CURDATE()),
 DAYOFWEEK(CURDATE()) >= DAYOFWEEK(event_begin) OR DAYOFWEEK(CURDATE()) <= DAYOFWEEK(event_end))
 , 0, #else

 if(event_recur = 'W' AND
 event_repeats = 0,
 abs(DAYOFWEEK(CURDATE())-DAYOFWEEK(event_begin)),
 if(event_recur = 'S' AND (CURDATE() <= event_end AND event_begin <= CURDATE()), 0, DATEDIFF(event_begin, CURDATE())) ) )) ) >= 0)" . //*/
 " ORDER BY diff ASC, event_begin=event_end DESC, event_begin ASC LIMIT $howmany");
 return $events;
}

The conditional column “diff” cannot be used in the WHERE statement, which forced me to copy the code and paste it inside the where statement for filtering out the past events.  Until Next Time!!

Accents in WordPress Permalinks

Just finished quite a bit of code tracing to figure out why accents are stripped from permalinks in wordpress. It all boils down to a sanitize_title filter (the function is sanitize_title_with_dashes) which calls remove_accents. I created a plugin which removes the ‘dashes’ function and replaces it with the same code except it doesnt call remove_accents.

Edit: Sorry. This file is no longer available!
Download PermalinksWithAccents Plugin

Checked List Control for wxWidgets

For any people who are looking for a checked list component for wxWidgets– you might find this article revealing.

I’ve been using wxWidgets for a couple of months and I have to say it’s awesome. But, when I looked in the docs for a checked list control, I was not very excited to find that it does not exist in the 2.8.10 release. After doing some googling, I found the wiki page that gives some hints on using a subclass of wxListCtrl as a checked list control.

The wiki will tell you get the .cpp and the .h from the webupdate component page. The specific files I used can be downloaded from these locations:

  1. download the latest wxcheckedlistctrl.php revision from this page: http://wxcode.svn.sourceforge.net/viewvc/wxcode/trunk/wxCode/components/webupdate/src/checkedlistctrl.cpp?view=log
  2. download the latest revision for wxcheckedlistctrl.h from: http://wxcode.svn.sourceforge.net/viewvc/wxcode/trunk/wxCode/components/webupdate/include/wx/checkedlistctrl.h?view=log
  3. download the bitmap images from: http://wxcode.svn.sourceforge.net/viewvc/wxcode/trunk/wxCode/components/webupdate/include/wx/checked.xpm?view=log
  4. http://wxcode.svn.sourceforge.net/viewvc/wxcode/trunk/wxCode/components/webupdate/include/wx/checked_dis.xpm?view=log
  5. http://wxcode.svn.sourceforge.net/viewvc/wxcode/trunk/wxCode/components/webupdate/include/wx/unchecked.xpm?view=log
  6. http://wxcode.svn.sourceforge.net/viewvc/wxcode/trunk/wxCode/components/webupdate/include/wx/unchecked_dis.xpm?view=log

then edit the wxcheckedlistctrl.h to point to the right xpm images for the control. Include the .h and .cpp files in your project. I had to write a few additional hacks to the .h file but I got it to work just fine. There are a couple of methods not implemented in the implementation file. Today I spent quite a while trying to sort the items in the list using the SortItems method, then found out that It wasn’t implemented. Below, is the SortItems method for wxCheckedListCtrl as written by me, each row should have a unique value set by SetItemData(..)


bool SortItems(wxListCtrlCompare c, long le)
{
long ic = GetItemCount();
long *b_CE = new long[ic*2];    // first half is checked.. 2nd is enabled

long chc = 0, enc = 0;
for(long l=0;l<ic;++l)
{
if(IsChecked(l))
b_CE[chc++] = GetItemData(l);
if(IsEnabled(l))
b_CE[ic+(enc++)] = GetItemData(l);
}

if(!wxListCtrl::SortItems(c, le))
{
delete [] b_CE;
return false;
}

CheckAll(false);
EnableAll(false);
for(long l=0;l<ic;++l)
{
for(long l2=0;l2<chc;l2++)
if(b_CE[l2] == GetItemData(l))
Check(l, true);
for(long l2=0;l2<enc;l2++)
if(b_CE[ic+l2] == GetItemData(l))
Enable(l, true);
}

delete [] b_CE;
//             wxASSERT_MSG(0, wxT("Not implemented yet ! sorry... ")); return FALSE;
return true;
}

Using LIBCurl with C++ Simple OOP Static Class ExampleUsando LIBCurl en C++ Ejemplo de OOP

This is a quick class in C++ that I slapped together from an example I found at http://www.luckyspin.org/?p=28.

I’ve been writing a php bot using curl for one of my favorite online games and I decided to make it public. This would be one of my latest public releases in a while. It turned out that PHP is not the best language to use due to poor portability. I played around with bambalam (PHP ‘compiler’) and also WinBinder, but both packages are severely outdated. All my code was written in PHP5, and bambalam only supports php 4. So, Now I’m going back to hardcore programming and coming up with a solution soon. I’ve already got libcurl, and boost hooked up and ready to go!

#include <iostream>
#include "curl/curl.h"

class MyCurl
{
private:

public:
// Write any errors in here

static int writer(char *data, size_t size, size_t nmemb, std::string *buffer_in)
{

// Is there anything in the buffer?
if (buffer_in != NULL)
{
// Append the data to the buffer
buffer_in->append(data, size * nmemb);

// How much did we write?
return size * nmemb;
}

return 0;
}

static std::string get(const char* url)
{
CURL *curl;
CURLcode result;

// Create our curl handle
curl = curl_easy_init();

char errorBuffer[CURL_ERROR_SIZE];
// Write all expected data in here
std::string buffer;

if (curl)
{
// Now set up all of the curl options
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookies.txt");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, MyCurl::writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);

// Attempt to retrieve the remote page
result = curl_easy_perform(curl);

// Always cleanup
curl_easy_cleanup(curl);
}

if(result == CURLE_OK)
return buffer;
return std::string();
}
};