Taking on 2011

In 2011, I have decided to take a step into the social media world. This includes posting some of my code snippets on this blog and keep it updated on my latest developments. Not only that, but I also plan on making contributions to any open source projects that I come across. I find that I’m constantly making improvements and hacking away at jquery/wordpress plugins and PHP code. This year I will make an effort to share these improvements with the open source community. I hope this will help in forming relations with other developers and designers.

My other goal is to successfully establish Sofus.mx as a web design entity. Sofus.mx will be the counterpart to Projectivemotion.com. I have focused my work now on web development. I will be on the lookout for a talented web designer to add to the design team.

Last month I finished a private implementation of the zencoder.com API for a private cms with Amazon S3 Support. I will post some code snippets and analysis soon on the following posts.

I’m currently developing Travel Agent CMS v.2 which has become a rather large project with some beautifully complex features.

Also.. I have a very interesting review on freelancer.com coming up soon.

Why NOT To Use MODX CMS!!

At first glance, MODX CMS appears to be a robust CMS with great flexibility and a sweet templating engine, but behind the scenes is a mediocre jumble of code, old and forgotten documentation, and a bunch of plugins/addons that will leave you scratching your head.

To be more fair, MODX CMS is an average CMS with a few nice features. The template variables are a nice addition, but it’s not as innovative as it poses to be. The content structure, however, is very easy to use and consists of a tree structure that allows the creation of parent documents and children directories. The cache system is also very fast and reliable.

The software aims to be a super flexible system that can be used as a framework. If that is true, then It is one of the most broken frameworks I’ve ever experienced. The clumsy template editor makes it so hard to get some speed in the development process. You will get lost within your template blocks and even booted out of the admin panel– having to reload all the windows and your whole theme development environment. The bottom line is that without a file system and a good IDE, a CMS is garbage for any serious developer.

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;
}