Want to get Lullabot article, videocast, and podcast announcements delivered right to your in-box?
Let us know your email address (we won't share it) and we'll let you know when anything exciting happens.
How to create a "publish on" option for nodes
UPDATE: I've completely rewritten scheduler module now and it makes use of this technique (minus the CCK part). Has complete publish and unpublish options, along with JSCalendar support.

So for the new TWiT site, I needed a mechanism for being able to set a date to publish certain nodes on. I could have opted for the Scheduler module, but that was a bit bulky, 4.7 support was flaky, and it required another table in the database. I also wanted an easy way to integrate JSCalendar from the awesome Javascript Tools module.
What to do?
Combine in a module a cup of CCK, a quarter cup of JSTools, and a sprinkle of hooks, and voila, instant publish on capabilities!
Here's how the code actually breaks down:
First, define a hook_help to make it clear what your module does on the admin/modules page:
<?php
/**
* Implementation of hook_help().
*/
function YOUR_MODULE_NAME_help($section) {
switch ($section) {
case 'admin/modules#description':
return t('Use this module to schedule the publishing of podcasts.');
}
}
?>Next, define a new content type with CCK, in this example, my content type is "podcast". Add all of the necessary fields you need, and then add a textfield "publish on". Now, to get the JSCalendar to hook into this field, we need to use hook_form_alter() to add this capability to that field on the node/edit pages.
<?php
/**
* Make use of JS calendar picker on podcast edit forms
*/
function YOUR_MODULE_NAME_form_alter($form_id, &$form) {
if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
//set this to the type of content you want to publish on
if ($form['type']['#value'] == 'content-podcast') {
$form['field_publish_on'][0]['value']['#attributes'] = array('class' => 'jscalendar');
// Use only year, month, and day in textfield.
$form['#jscalendar_ifFormat'] = '%Y-%m-%d';
// Don't show time.
$form['#jscalendar_showsTime'] = 'false';
}
}
}
?>Great! Now we can use the Javascript calendar picker to set dates for when our podcasts should be published. Since we don't want our podcast published if a date has been selected, we need to make sure the podcast is unpublished when a date has been entered.
<?php
/**
* Implementation of hook_nodeapi().
*/
function YOUR_MODULE_NAME_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
if ($node->type == 'content-podcast') {
switch ($op) {
case 'submit':
//right before we save the node, we need to check if a "publish on" value has been set
//if it has been set, we want to make sure the node is unpublished
if ($node->field_publish_on[0]['value'] != '') {
$node->status = 0;
}
break;
}
}
?>Excellent! Now all we need to do is setup a cron job to run and publish these podcasts when their publish on date occurs.
<?php
/**
* Implementation of hook_cron().
*/
function YOUR_MODULE_NAME_cron() {
$nids = db_query('SELECT n.nid FROM {node_content_podcast} p INNER JOIN {node} n ON p.nid = n.nid WHERE n.status = 0 AND p.field_publish_on_value = CURDATE()');
while ($result = db_fetch_object($nids)) {
db_query('UPDATE {node} SET status = 1 WHERE nid = %d', $result->nid);
}
}
?>Bingo! Now we can set the date for when nodes should be published and it only took about a dozen lines of code.
Doesn't Drupal rock?
Comments on this post will automatically be closed three months from the original post date.



RSS Feed



Comments
!
this is freaking great.
Very slick
Nice! Thanks for sharing this.
A couple questions: Can you make this a day/time event, not just a day event?
And can you also add an unpublish day/time?
Yes, you can easily make
Yes, you can easily make this a day/time event as well. Just take out these lines:
<?php// Use only year, month, and day in textfield.
$form['#jscalendar_ifFormat'] = '%Y-%m-%d';
// Don't show time.
$form['#jscalendar_showsTime'] = 'false';
?>
As for an unpublish day/time, this would be easy too. Just add another CCK field for unpublishing. Then use in your hook_form_alter() make sure to duplicate that code to append to the new field. In hook_cron() you'll want to add another query that looks for all nodes that are published AND have an unpublish field that equals CURDATE().
Thanks again.
Excellent! You guys rock.
What about >= CURDATE() ?
Nice! Thinking though, what about using >= CURDATE instead of = curdate? Just in case, say the cron jobs go bad, or server goes down, etc. (I know, this never happends :)), the system can almost 'self-repair' but publishing any 'lagging' nodes that were missed during the outage?
Err, backwards logic
Lol. sorry about that on last post, I meant =< (less than or equal to).
The only problem with that
The only problem with that is you assume *all* content that is older than today should be published. There are many cases when that content may need to be unpublished, and hence, you could run into a problem there :-)
Use in an events module
Can this be done with the events module? I would like to use this to allow users to search through events by date ranges. This JSCalendar would make this so user friendly.
Yes, you can adapt the
Yes, you can adapt the hook_form_alter() to look for the 'event' type. Then you can simple append the "jscalendar" class to the input date for events. You'd have to figure out what fields to attach to, but this should be fairly straightforward.
cache update
and how about the cache? don't you have to flush the cache?
date change
The date field in CCK seems to have changed. All of the date fields now seem to require it to be in the format "YYYYMMDDTHH:MM:SS" (with T being an actual "T").
publish off?
Very nice work indeed. Anyone thought about using the same technique to unpublish a node?
The module doesn't work right.
The publish on time doesn't work correctly.
It states the format: "1981-11-24 15:24:07" (Is 1981 an error?)
But doesn't work unless you use 2006-07-23 15:24:07 -400 and even when you do that, it posts 4 hours behind.
Only CCK?
Lovely work on a most important area. A few questions, though:
1.) Does this work only with CCK content types?
2.) Can this be used to automatically unpublish nodes at a set date?
Extending this:
1.) Does this give a block? You could then use it as a kind of alerts thing
2.) Could you consider providing an option for showing a countdown? This could be something like, "21 days, 3 hours, 10 minutes to register", with the 'to register' field being definable by admin- I mean, not all nodes may deal with registration, so admins should have the choice to put whatever they want.
Just a though...
How much more work would it take to make this a CCK field type? I have yet to really crack open the CCK modules but that seems like an intuitive way of using this. Any thoughts? I'm gonna go look at some of the other field modules and see if I can't grok it.
Would it be possible to use
Would it be possible to use this to repeatedly publish/unpublish content on, e.g., the 1st of the month? (My client has 31 posts that they want to display on the appropriate date of the month.)
Keep up your great work Ted
Keep up your great work Ted :)
Good work, Ted! You can't
Good work, Ted! You can't imagine the quantity of sleepless nights i have searching the right decision with Publish On.
simple
thx guys, easy to follow :D