All Posts in

December 3, 2012 - Comments Off on Drupal 7 Forms API: The One About the Date Fields

Drupal 7 Forms API: The One About the Date Fields

Drupal, as a content management system, allows you to create content types with date fields which means you can create events and calendars. There are many great modules which allow you to display content with date fields in calendars, forms, etc. But before you can fly, you must first learn to code... I think that's how the saying goes. Entering one, or even a couple of events into you site is not too difficult or cumbersome. The default node add forms are utilitarian if nothing else. I have even been know to gussy the forms up with some fieldsets, CSS and some occasional Jquery whiz-bang-iness. The challenge comes when you have to enter months worth of events at one sitting. After entering and saving a new event, the system will default to the current day (or whatever default relative date you set in the widget) the next time you add the next event. This means each time you add an event you have to set the month/day/year each time- and when this spans the next calendar year, or even several months, you finger may fall off from all the clicking needed.

The solution? Set the default date in the date widget programmatically, based on the last saved event date. This means if you are entering a lot of events in sequential order, you will have less clicking to do to set the date. It also means if you save an event several months in the future and later add a new event you will have to do the clicky-dance, but for adding many events at once, you will have saved yourself some time.

The way to change the default date in the form is to use the Drupal Forms API (formerly FAPI in D6). You will need to create a module, or add this code to an existing custom module. The Forms API, in simple terms, allows you to talk to Drupal and manipulate the forms through code. Instead of hacking away at a flat HTML file, editing <inputs> and trying to get form values to save in the right places, you can systematically address each form element and get/set values, change CSS attributes, add JS/Jquery and manipulate field settings/defaults. If you've ever installed Captcha, LoginToboggan or any other Drupal form altering module, that's exactly what they are doing. By 'hooking' into the Form API, they can perform all sorts of manipulation without rewriting or replacing the form's core- they simply alter it.

This function will find the currently displayed form and alter it if and only if it is the event form we want to alter. It next retrieves the date of the last event you saved and changes the sets that as the default value. If no date was last saved, then the form will default to the current date.

[cce_php]

function mymodule_form_alter($form, &$form_state, $form_id) {
switch ($form_id) {
case 'event_node_form' :
// Set the default start date for Events to the last saved event month
if ($form['#action'] == '/node/add/event') {
$date = variable_get('event_last_date', '');
$form['field_event_date']['und'][0]['#default_value']['value'] = $date['start'];
if (isset($date['end'])) {
$form['field_event_date']['und'][0]['#default_value']['value2'] = $date['end'];
}
}
break;
}
}

[/cce_php]

This next function reads the values of the event being saved and stores the date(s) as an array to the system table.

[cce_php]

function mymodule_node_presave($node) {
switch ($node->type) {
case 'event' :
$date['start'] = $node->field_event_date['und'][0]['value'];
if (isset($node->field_event_date['und'][0]['value2'])) {
$date['end'] = $node->field_event_date['und'][0]['value2'];
}
variable_set('event_last_date', $date);
break;
}
}

[/cce_php]

You will notice that there are 2 date fields being saved here, value and value2. If you have set the date field to allow an end date value to be set, it is called value2, and in this code is also saved. If you do not set it, or do not have it visible on the form, it will ignore it. The Second function calls hook_node_presave() which, like the Forms API, is an entry point into the Node API and allows you to interact with the node object via code. When any node is being processed for insertion/updating in Drupal, it will call this function and if it matches your 'event' type it will save the date field(s) to the system table for later retrieval by the first function. Place these two functions in a module and test it out. You will need to make sure your code matches  the content type name and CCK date field names of your site.

Modifications such as these can greatly improve the user experience of a site. When you are creating sites to be turned over to others for the content management, this attention to detail and usability can make their lives much easier.

Links:

Published by: chazcheadle in The Programming Mechanism
Tags:

November 28, 2012 - Comments Off on Drupal 7: Create Previous | Next links for nodes using CCK Date fields

Drupal 7: Create Previous | Next links for nodes using CCK Date fields

Recently we needed to implement a Next | Previous link feature for a site for two content types. For providing these links on a simple content type like a blog, the Flippy module may fit the bill. Flippy creates a themeable pager that gets its date from the node's 'created' date field. Blogs generally will benefit from this method of sorting and navigation, but what if your content type has a different, CCK, date field that you want to use for the links. The following code will take your CCK date field and use it to compare with same CCK date field of the current node:
[cce_php]
field_event_date['und'][0]['value']));
// Find the nid of the node with the timestamp just prior to $date
$prev_nid = db_query("SELECT n.nid FROM {node} n LEFT JOIN {field_data_field_event_date} f ON n.nid = f.entity_id WHERE type = 'event' AND UNIX_TIMESTAMP(f.field_event_date_value) < :posted ORDER BY field_event_date_value DESC LIMIT 1", array(':posted' => $date))->fetchField();
// Find the nid of the node with the timestamp just after $date
$next_nid = db_query("SELECT n.nid FROM {node} n LEFT JOIN {field_data_field_event_date} f ON n.nid = f.entity_id WHERE type = 'event' AND UNIX_TIMESTAMP(f.field_event_date_value) > :posted ORDER BY field_event_date_value ASC LIMIT 1", array(':posted' => $date))->fetchField();

if ($prev_nid > 0) {
$prev_link = l('Previous', "node/$prev_nid", array('html'=>TRUE, 'attributes' => array('title' => 'See Previous', 'class' => array('prev-link'))));
print($prev_link);
}

if ($next_nid > 0) {
$next_link = l('Next', "node/$next_nid", array('html'=>TRUE, 'attributes' => array('title' => 'See Previous', 'class' => array('next-link'))));
print(" | " . $next_link);
}
?>

[/cce_php]

The two db_query() calls in the code query the database for nodes based on their CCK Date field which is converted from a Mysql date (MM/DD/YY HH:MM:SS) to the unix epoch timestamp format for comparison. If there is a resulting nid, it is stored for output by drupal's l() function. The field we have is for an event and the field's name is 'field_date_event_value', seen in the SQL. You will have to dig into your content type to determine the exact name of the field you will use. Additionally you can see the syntax for the l() function for adding additional attributes to the generated link. The third argument takes a series of nested arrays that hold the 'title', 'class', 'id', etc.

This code could be extended to generate fuller pager with First, Last, Skip 5, or even Random links.

Links:

Published by: chazcheadle in The Programming Mechanism
Tags:

November 7, 2012 - Comments Off on Hurricane Sandy Incident / Relief Map

Hurricane Sandy Incident / Relief Map

As you may know, the east coast was hit very hard last week by hurricane Sandy. Many people all throughout the tri-state region were less fortunate and suffered greatly. And planned sell their house. You can also sell your house anytime and pay off your mortgage with the help of experts as they can help you to make your home appeal to more buyers. Now, a week after the storm, much of New Jersey, Staten Island and Long Island are still reeling. Power has not been restored to many PSEG, ConEd and LIPA customers. Gas shortages in all areas persist, with people waiting hours in line to fill up and in need of services like Gas Line Repair to help with this. Most of us here lost power at our homes for part of the storm, but were otherwise unharmed. In an effort to help our neighbors and make the spread of information easier, we have set up a crowdsourced mapping site to share local knowledge about resources such as; shelters, emergency plumber services, and fuel.

From the website:

This site was launched by The Mechanism, a digital agency in New York City for anyone who was affected by the recent hurricane that ravaged the Northeast. We hope that by using crowdsourcing, we'll be able give back to the city and surrounding areas that have helped us for the past 11 years.

WHAT ELSE TO THINK ABOUT
We'll be updating this list.

Remember that while giving is good, beware of those out there who are not good and are trying to trick you by taking your money. In the aftermath of Hurricane Irene last year, the Federal Trade Commission's caution still holds true: "Scammers may try to take advantage of a disaster, and so consumers should be wary of urgent appeals for charitable donations, and watch out for fraudulent home repair schemes after a storm or other remodeling repairs, click to find out more here."

My House Painter can also help you out in getting exterior,interior painting which can enhance the look of your home. But you should also read more about avoiding home repair rip-offs and charity fraud from the FTC.

Also, the FBI has counselled on its Facebook page "to beware of fraudulent emails and websites claiming to conduct charitable relief efforts. Disasters prompt individuals with criminal intent to solicit contributions purportedly for a charitable organization or a good cause," and suggests reading "Tips on Avoiding Fraudulent Charitable Contribution Schemes" to learn more about avoiding online fraud.

As a crowdsourced map, the information comes directly from those on the ground and communication with those in the area. The information is curated as best as possible to ensure that the information is accurate and of use to those looking for information. If you would like to participate and share information about resources in your area the map can be found here: http://maps.themechanism.com

Our hearts go out to everyone who has been affected by the storm.

September 26, 2012 - Comments Off on Drupal 8: .htaccess file goodies

Drupal 8: .htaccess file goodies

Drupal 7 has been out in the wild for a little over a year now. It brought a myriad (sic, can you sic your own material?) of new features; Entities, more hooks, CCK in core... to name but a few. With Drupal 8's full release still in the distance, it will be interesting to see how it will compare with the current release. One change we noted is a potential update to the core .htaccess file, which acts as the concierge and first line of defense against malicious and accidental breeches.

The .htaccess file serves primarily to direct incoming traffic to your Drupal site by passing the request headers to index.php, which calls the appropriate data retrieval and rendering functions. In this manner, .htaccess passes a request for http://www.example.com/?q=user  to index.php which then displays the user login page if you are not already logged in. All requests to the website should be passed to index.php and only index.php. If for some reason, a malicious script made its way onto your server either intentionally or by a compromised user machine, it could be executed simply by pointing a browser at it.

This is where .htaccess steps in. In the new Drupal 8 iteration, even if a site were compromised and a script file was accidentally uploaded, the new rules will prevent them from being executed. Bear in mind that the current Drupal 7 .htaccess file already does a good job of protecting sites; this update is just an extra set of rules to help catch those pesky one-off gremlins.

If you take a peek at your .htaccess file you will also find the rules that allow you to force your website domain to add or drop the 'www' prefix. This is handy for SEO to prevent your site from showing confusing results for content located at www.example.com and example.com.

The .htaccess file is a gatekeeper, but like the inebriated porter in MacBeth, if too much crazyness goes on it can be fooled. Remember to keep your Drupal core up to date with the latest security fixes as well as all those custom and contributed modules. Check for file uploading, eval()s, stray .PHP files etc.

For the security conscious, you don't have to wait for D8 to add the new .htaccess rules, you can see the current patch here. You can try running the patch, or just copy and paste the 2 new lines of rules. The rules tell the webserver to only execute .php files found in your site's webroot folder, or in the /core directory. This should not impact your site negatively as normally only index.php should ever be served directly.

Here is the new rule. You can see that it checks for the the file being called, and if it is a .php file not in the webroot or /core directory, Apache will kick it to the curb with a big fat [F] code.

RewriteCond %{REQUEST_URI} !^/core/[^/]*.php$
RewriteRule "^.+/.*.php$" - [F]

Good luck, and happy Drupaling!

Published by: chazcheadle in The Programming Mechanism
Tags:

September 13, 2012 - Comments Off on Drush de Jour: The Case of the External Links and Broken JS

Drush de Jour: The Case of the External Links and Broken JS

The External Links module for Drupal is a nice, unobtrusive addition that adds an arrow icon next to off-site links to let users know the link will take them to a new site and open a new browser window. There is also a cool feature to include or exclude links based on regular expressions. Wheeeee!!!!!

Be warned, however, that you may enter a valid regular expression that could cause the javascript on your site to take a header. You will immediately know this is the case when you save your changes and the fieldset for the pattern matching is no longer collapsible. What happens is that the regular expression you entered is not validated against potential conflicts in the javascript that parses it on rendering. We had this issue when we tried to add an inclusion rule for PDF's. We wanted all PDF's hosted on the site to open a new window, despite the fact that they were 'internal'. Seems easy, add a wildcard and the extension and call it a day....

*.pdf

That didn't work. This isn't command line DOS, or *nix- add an escape to look for the period. It also broke Javascript on the site!

Drush to the rescue.

This went from a quick module addition to a murder mystery, minus the murder. Well, when clients aren't happy it might. Here's how we diagnosed the issue, which turned out to be fairly simple, but the troubleshooting process is important.
First off, since we work in a development site no one was going to be adversely affected. Next we know what was going on at the time things broke. I was the only one working on the site at the time so that narrowed it down to me and the changes I was making. If you have multiple developers working on a site concurrently, then version control, and backups are paramount.

So, we know I broke the site, and it was something to do with the External Links and specifically the regular expression I had just tried to save. This most likely means that the module saves data to the database in a custom table, or as a site variable. Drush can help inspect the second route very quickly-

% drush vget extlink
extlink_alert: 0
extlink_alert_text: "This link will take you to an external web site. We are not responsible for their content."
extlink_class: "ext"
extlink_exclude: ""
extlink_include: "*.pdf"
extlink_mailto_class: "mailto"
extlink_subdomains: 1
extlink_target: "_blank"

There it is! If no variables were found, then the next step is to check out the .install file for the offending module and look for a schema hook. But, we lucked out and can move along to spewing poorly formed regular expressions.

% drush vdel extlink_include and refresh, and we're back in business.
*.pdf

That didn't work, duh. This must be a 'javascript supported' pattern as the documentation says.

.*.pdf.

And now PDF's will open in a new window.

Links:

External Links

The Drush de Jour brings you the latest and possibly greatest bits of drush wisdom we use for developing and maintaining our Drupal sites.

 

Published by: chazcheadle in The Programming Mechanism
Tags: ,

August 31, 2012 - Comments Off on Changing Drupal’s Current Search de-activation widget

Changing Drupal’s Current Search de-activation widget

If you've used the Current Search block on any of your search pages, then you've seen that the default, and hardcoded, symbol for deselecting/deactivating a search term is: (-)

Not the prettiest, not the ugliest... but also, not easily changed. luckily the Current Search module manipulates and renders everything through the theme layer, which means WE can manipulate it as well using a custom theme function. The hook we will be using is  theme_facetapi_link_deactivate().

Add this to your template.php file with the appropriately named theme.

<?php
function mytheme_facetapi_deactivate_widget($variables) {
  return 'x';
}
?>

You can Replace the 'x' with anything you'd like, even a link to an icon! Here is a before and after example.

 


An extension to this would be to add controls to the Current Search settings form to allow changing the widget.

Links:

Published by: chazcheadle in The Programming Mechanism
Tags: , , ,

August 28, 2012 - Comments Off on Getting Node.js and Cron to play nice(ly)

Getting Node.js and Cron to play nice(ly)

So, you've written a bang up, killer node.js script that tweets your facepage, instasmacks your flickr and makes your coffee, but you need it to run every hour, or you won't get retweets of lomo-bird-toasty looking coffee mugs pictures from your friends... What to do!!!

Easy! add the node.js script you have written to a cron job that runs on the server when you want and you're done. Unless it doesn't work.

There are a couple of reasons why a node.js script won't run in a cron job. To start with, make sure your script runs properly when you are logged in as a user with permission to run the script, for instance:

% node coffee.js

If that doesn't work, you'll need to figure out why before moving on. Make sure that node.js is installed; 'node -v' should return the installed version of node.js.

Next, you will need to make sure any calls to files use the absolute path. e.g.,

'... require('include.inc') ...' should read, '... require('/var/www/include.inc') ...'

The reason to do this is that when cron runs the script, it does so without a full shell environment to inform it about where it is, and what paths are relative to each other. This can be hard to debug, since you can still run your script on the command line even though it won't run in cron.

Now, onto the cron job, Crontab syntax can vary from system to system, be sure to check the docs for your setup.

Edit your crontab:

% crontab -e

for editing with vim or use nano,

% env EDITOR=nano crontab -e

Add the command line for your script, and include the full path for the node.js binary- since cron won't automatically know where it is located*.

*  */3  *  *  *      /usr/local/bin/node /var/www/coffee.js

Save the crontab file and wait for the magic to happen!

More with Cron:

Crontabs can be run on any schedule you desire. The example above tells it to run every 3 hours. The syntax can seem confusing at first, but then when you get to know it, it can still be confusing but at least you can make it do what you want. For example, you can set a job to run Monday - Friday, every hour between 8am and 5pm.

*  08-17  *  *  1-5     /usr/local/bin/node /var/www/coffee.js

 

*You can get the path to the node binary with:

% which node

Published by: chazcheadle in The Programming Mechanism
Tags: ,

August 23, 2012 - Comments Off on Open Source: Sharing is Caring

Open Source: Sharing is Caring

Today's post is not specifically about Drupal, unless you only read the parts about Drupal. We here at The Mechanism, work to create awesome and exciting websites for our clients, which often means creating very specific and specialized tools for them. In the process of generating all that code, we are always mindful of making the code reusable and flexible. And, since we work with Open Source technologies we look for ways to give back to the community. A couple of our recent projects have components that we're making available for others to learn from and use.

To that end, we've begun putting that code up on GitHub. GitHub is, in a nutshell, a sharable, online repository for your code and it lets you track changes. Our 'git repo' is here. Feel free to fork(copy) the code and use it and feel free to contribute or submit patches. These projects were built with a specific use in mind, but you never know what new features or directions they can go in.

In addtion to the Addressfield_link module I wrote about earlier this week, Ben has added his awesome social media caching library written in Node.js/MongoDB. This api will let you pull twitter/instagram/etc. feeds and store them in MongoDB for parsing or display on a website. Keep an eye on themechanism.com where you'll be able to see it in action starting next week.

And finally for those of you familiar with GitHub's Octocat, Ben also created our very own...

MECHTOCAT!

Published by: chazcheadle in The Programming Mechanism
Tags: , ,

August 17, 2012 - Comments Off on Adding new fields to Drupal’s Addressfield

Adding new fields to Drupal’s Addressfield

Drupal 7's commerce module is extremely powerful due in large part to being built on the new entity framework. One of the submodules under the hood of commerce is addressfield, which stores xNAL compliant addresses for customer profiles. It stores the basic street(s), city, state, zip/postal code, country. For the purposes of commerce, this is an appropriate solution. However, if you want to capture more data for taking orders, or use this field in a non-commerce application, you may want to have additional fields included.

To this end, we can add more fields as 'formatters' to the addressfield module. There is an example module which ships with addressfield and I also found a similar sandbox project which adds phone numbers to the addressfield- I based this project largely off of that project. For future development we'll add validation handlers and possibly extend it to include email contact information as well.

Here is a screenshot of the resulting field:

Addressfield Link

The project can be found here.

Links:

Published by: chazcheadle in The Programming Mechanism
Tags:

July 31, 2012 - Comments Off on Drush de Jour: Drush aliases, aka… Drush aliases

Drush de Jour: Drush aliases, aka… Drush aliases

The complexity of developing and maintaining multiple Drupal sites can grow like kudzu. Keeping on top of them is important not only for version control of your codebase but also for streamlining development to production site transitions. Until now we've just shown examples of how to drush it up nice with a single site- go to that site's directory, type drush, be happy. But when you have multiple sites on one or more servers that you need to interact with, Drush can help make your life easier.

Instead of writing scripts to 'cd' here, or 'cd' there to get into the right Drupal installation directory to perform a Drush task, you can create aliases for each site that work like nicknames. For example, we have a 'dev' and a 'prod' site on a server. Instead of changing back and forth between the directories to Drushify, we create aliases for them and can call them from anywhere.

First, create a new file in ~/.drush called <aliasname>.alias.drushrc.php and put this code in it:

<?php
$aliases['prod'] = array(
  'root' => '/var/www/vhosts/themechanism.com',
  'uri' => 'www.themechanism.com',
  );
?>

Now, from anywhere on the system, you can call Drush and perform commands on your site.

$ drush @prod status

You can set an alias for a remote site, copy files between prod and dev, sql-sync your database between sites, etc. etc.

Further Drush alias examples can be found in drush/examples/example.aliases.drushrc.php or wherever you installed drush.

 

The Drush de Jour brings you the latest and possibly greatest bits of drush wisdom we use for developing and maintaining our Drupal sites.

Published by: chazcheadle in The Programming Mechanism
Tags: ,