Main Page Content
The Abcs Of Cms Part Iii
Workflow Theory Examined
In this model of a content management system (CMS) we are installing a very basic workflow;- An author writes and then submits an article to be considered for publication.
- An editor checks/corrects the article for spelling and grammar. The editor may also do fact checking. If the editor determines that the article is not acceptable enough he can route the article back to the author for changes. A time and day may be defined for completion of editing tasks within any given time period.
- When the editor has finished with the article he forwards it to an approval source. This person decides if the content is acceptable for publication in appropriate forums (web site, magazine, daily publication, etc.) within the rules established for content on those forums. If the approval source finds the article unacceptable they can route the article back to the author for improvement. Again, some sort of time/day restriction may be applied to approval tasks.
- Once approved the article is sent to be scheduled. The scheduler will set the publication date and the date that the article expires.
Specifying Workflow
Each element in a CMS, such as the article being worked with in this model, may have a different workflow scheme. This could involve different levels of approval or different personnel resources.For instance, say there is a daily announcements section on the front page of your Intranet site. The workflow could be;- Announcement Submitted
- Announcement is reviewed, edited, and scheduled for publication by one person assigned the task. The task must be completed by 7:45am EST, Monday - Friday.
- Who are the potential authors?
- Once an element is submitted who should it go to for editing and/or approval?
- Once approved, who has the responsibility to schedule the release of this element to the appropriate forum?
Article Submission
Here is the form for submitting an article, subart.php
;
<? session_start(); ?><?//connect to and select databaseif(!($dbconnect = mysql_pconnect("127.0.0.1", "cms_user", "cms_password"))){ print("Failed to connect to database!"); exit(); }if(!mysql_select_db("cms", $dbconnect)){ print("Failed to select database!"); exit(); }As in the page listing this author's articles (//query to get navigation from database
$qnav = "SELECT URL ";$qnav .= "FROM tblNavigation ";$qnav .= "WHERE accesslevel = '$level' ";if(!($dbnav = mysql_query($qnav, $dbconnect))){
print("MySQL reports: " . mysql_error() . ""); exit(); }//query to get available editors
$qedit = "SELECT name ";$qedit .= "FROM tblUser ";$qedit .= "WHERE accesslevel = 'editor' ";if(!($dbedit = mysql_query($qedit, $dbconnect))){
print("MySQL reports: " . mysql_error() . ""); exit(); }?><html>
<head><title>CMS</title><LINK REL="StyleSheet" HREF="cms.css" type="text/css"></head><body><div class="left">
<?// list the nav links for this type of userwhile($dbrow = mysql_fetch_object($dbnav)){
print($dbrow->URL . "<br>"); }?></div><div class="right">
<h1>Submit An Article</h1>
<form action="cmssubmit.php" method="POST">
<table cellpadding="3" cellspacing="0" border="1"><tr><td>Article Title</td><td><input type="text" name="title" size="64" maxlength="64"></td></tr><tr><td>Author email</td><td><? print($emailid) ?></td></tr><tr><td>Article Teaser</td><td><textarea name="teaser" cols="50" rows="3" wrap="virtual" maxlength="255"></textarea></td></tr><tr><td>Article Body</td><td><textarea name="body" cols="50" rows="25" wrap="virtual"></textarea></td></tr><tr><td>Editor</td><td><select name="editor"><option>---Select Editor---</option><?//list the editors available
while($dbrow = mysql_fetch_object($dbedit)){
print("<option>" . $dbrow->name . "</option>"); }?></select></td></tr><tr><td>Date Submitted<br>Format - YYYY-MM-DD</td><td><input type="text" name="submitted" size="10" maxlength="10"></td></tr><tr><td></td><td><INPUT type="submit" name="action" value="Save"> <INPUT type="submit" name="action" value="Submit Article"> <INPUT type="reset"></td></tr></table></form></div></body></html>
myart.php
) the code in the <div class="left">
prints out the navigation links for available for authors. We will be adding to this as the CMS is developed and other users, such as editors, approvers, and schedulers become users of the system.Just after the comment "//list the editors available"
, the PHP code will create a drop down option in the form, allowing the author to choose his editor. While we have taken a rather loose approach in this series, you may want the editor to be chosen automatically for each author in other situations. If that is the case you will have to modify your users table, adding a column to contain editor information for each author. In the case of the announcement example above you could just hard code the information in the page where announcements are submitted or have a specially designated access level for certain types of editing/approving chores (i.e. EditorA, EditorB, etc. ).You'll also note that there are three buttons for form actions, 'Save', 'Submit Article', and 'Reset'. This is different from most form handling via a web-interface, but the result allows an efficient way to use the workflow process. If the author needs to perform editing on his or her article, or maybe has not quite put the finishing touches on it, the 'Save' button allows the article to be sent to the database with no notification (as you will see in the script that processes the submission) to an editor. The author will then be able to return to the article at a later time to perform whatever changes that they need to perform. The 'Submit Article' button send the article to the database and notifies and editor. Of course, the 'Reset' button clears the form.Here is the script that processes article submission, cmssubart.php;<? session_start(); ?><?//connect to and select databaseif(!($dbconnect = mysql_pconnect("127.0.0.1", "cms_user", "cms_password"))){ print("Failed to connect to database!"); exit(); }The path for the content can be selected by using multiple buttons in the form; (leaving out the 'Reset' button)if(!mysql_select_db("cms", $dbconnect)){
print("Failed to select database!"); exit(); }// perform action based on which button was pushed on submit form
switch($action){ case "Save": // query to insert saved elements only $qsave = "INSERT INTO tblArticle(title, teaser, body, author) "; $qsave .= "VALUES('$title', '$teaser', '$body', '$emailid') ";if(!($dbsave = mysql_query($qsave, $dbconnect))){
print("MySQL reports: " . mysql_error() . "<br>"); exit(); }break;
case "Submit Article":
//query to submit article $qsubmit = "INSERT INTO tblArticle(title, teaser, body, author, editor, submitted) "; $qsubmit .= "VALUES('$title', '$teaser', '$body', '$emailid', '$editor', '$submitted') ";if(!($dbsubmit = mysql_query($qsubmit, $dbconnect))){
print("MySQL reports: " . mysql_error() . "<br>"); exit(); }//select editor information and send an email
$qeditor = "SELECT email "; $qeditor .= "FROM tblUser "; $qeditor .= "WHERE name = '$editor' ";if(!($dbeditor = mysql_query($qeditor, $dbconnect))){
print("MySQL reports: " . mysql_error() . "<br>"); exit(); }//message to editor
$dbeditor = mysql_fetch_object($dbeditor); $messeditor = "$author has submitted an article, $title, for editing."; $messeditor .= "Please review this article at your earliest convenience.";
mail("$dbeditor->email", "CMS Article Submission", $messeditor, "From: CMS System");
break;
}header("Location: myart.php"); exit; ?>
<INPUT type="submit" name="action" value="Save"> <INPUT type="submit" name="action" value="Submit Article">
Each button has the name 'action', and the value of the action is the 'value' of each button. Within the PHP script that processes the article submission the value of the variable
$action
is the value of the button pushed. By using;switch($action){}
(which is similar to ASP's
SELECT CASE
) we can select what should be done with the article. This gives you the opportunity to specify multiple actions for any given form, you are only limited by the amount of action buttons you can create. A word of caution is in order here, you must provide adequate training, along with a help system or other clues so that users of the CMS understand what each action perfroms.If the author chooses an editor, includes a submission date, and clicks the 'Submit Article' button he or she will no longer have the opportunity to edit the article (unless the article is 'sent back' to them from someone higher up the workflow ladder). The article will show up on their 'My Articles' page, from where they will be able to preview / review the article.An Author Edits
Doing Reviews
The author can submit articles, now he or she needs to be able to edit articles which have not been submitted to an editor. To enable this action we are going to modify our original myart.php, placing a link next to the articles where editing is allowed. Articles needing editing will be the first to be listed, while articles already forwarded to editing will only be available for review. (You can just replace the old myart.php with the following code.)<? session_start(); ?><?//connect to and select databaseif(!($dbconnect = mysql_pconnect("127.0.0.1", "cms_user", "cms_password"))){ print("Failed to connect to database!"); exit(); }if(!mysql_select_db("cms", $dbconnect)){ print("Failed to select database!"); exit(); }This line of code,//query to get navigation from database
$qnav = "SELECT URL ";$qnav .= "FROM tblNavigation ";$qnav .= "WHERE accesslevel = '$level' ";if(!($dbnav = mysql_query($qnav, $dbconnect))){
print("MySQL reports: " . mysql_error() . ""); exit(); }//query to get article information
$qart = "SELECT a.ID, a.title, a.publish, a.editor, u.name ";$qart .= "FROM tblArticle a, tblUser u ";$qart .= "WHERE u.email = '$emailid' ";$qart .= "AND a.author = u.email ";$qart .= "ORDER BY a.editor ";if(!($dbart = mysql_query($qart, $dbconnect))){
print("MySQL reports: " . mysql_error() . ""); exit(); }?>
<html><head><title>CMS</title><LINK REL="StyleSheet" HREF="cms.css" type="text/css"></head><body><div class="left">
<?while($dbrow = mysql_fetch_object($dbnav)){ print($dbrow->URL . "<br>"); }?></div><div class="right">
<?$dbartrow = mysql_fetch_object($dbart);if($dbartrow->ID == ""){
//if there are no articles for this author print("You have not placed any articles in the Content Management System"); }else { //print article links for this author mysql_data_seek($dbart, 0); print("<h3>Welcome " . $dbartrow->name . "</h3>");while($dbartrow = mysql_fetch_object($dbart)){
//if there is an editor print only a link to the article preview if($dbartrow->editor != ""){ print("<a href=\"artprvw.php?aid=" . $dbartrow->ID . "\">" . $dbartrow->title . "</a><br>"); } else { print("<a href=\"artprvw.php?aid=" . $dbartrow->ID . "\">" . $dbartrow->title . "</a> ( <a href=\"authed.php?aid=" . $dbartrow->ID . "\">Edit</a> )<br>"); } } }?></div></body></html>
if($dbartrow->editor != "")
, tests for the existence of an editor in the record and prints out the links accordingly. If an editor exists then a link to the article preview is printed. If no editor exists for this article then the article preview link is printed, along with a link to a page where the author can edit their own article.The following code block is for an author to preview an article (artprvw.php); <? session_start(); ?><?//connect to and select databaseif(!($dbconnect = mysql_pconnect("127.0.0.1", "cms_user", "cms_password"))){ print("Failed to connect to database!"); exit(); }if(!mysql_select_db("cms", $dbconnect)){ print("Failed to select database!"); exit(); }This will display the article as it is selected from 'My Articles' so that the author may preview the work as it might appear on a web site. You can use the same techniques to display the article on a web site or Intranet site, just build a template that extracts the relevant information from the database and displays it in a readable form. You may also want to include things like the author's name and email address, and date published.One of the more interesting aspects of the code for previewing the article is;//query to get navigation from database
$qnav = "SELECT URL ";$qnav .= "FROM tblNavigation ";$qnav .= "WHERE accesslevel = '$level' ";if(!($dbnav = mysql_query($qnav, $dbconnect))){
print("MySQL reports: " . mysql_error() . ""); exit(); }//get article information from database
$qart = "SELECT a.ID, a.title, a.teaser, a.body ";$qart .= "FROM tblArticle a ";$qart .= "WHERE a.ID = $aid ";if(!($dbart = mysql_query($qart, $dbconnect))){
print("MySQL reports: " . mysql_error() . ""); exit(); }//place database items in variables for easier manipulation
$dbartrow = mysql_fetch_object($dbart);$atitle = $dbartrow->title;$ateaser = $dbartrow->teaser;$abody = $dbartrow->body;?>
<html><head><title>CMS Article Preview</title><LINK REL="StyleSheet" HREF="cms.css" type="text/css"></head><body><div class="left">
<?while($dbrow = mysql_fetch_object($dbnav)){ print($dbrow->URL . "<br>"); }?></div><div class="right">
<?print("<h2>" . $atitle . "</h2>");print("<p>" . $ateaser . "</p>");//place proper HTML paragraph mark up in bodyprint("<p>" . ereg_replace(chr(10).chr(13), "</p><p>", $abody) . "</p>");?></div></body></html>
print("<p>" . ereg_replace(chr(10).chr(13), "</p><p>", $abody) . "</p>");
This line of code prints out the body of the article with the proper HTML paragraph mark-up. It prints an opening paragraph tag, followed by a new line. Then the PHP function ereg_replace()
replaces each linefeed (char(10)
) and carriage return (char(13)
) combination with a closing, and then opening paragraph tag. When the article is entered into the CMS an author will generally hit enter twice at the end of the paragraph, which gives the linefeed carriage return combination. We close the line of code by printing out a closing paragraph tag. Why do we do this? Two reasons:- Since the data in the database contains no mark-up of any kind it makes it easier to output the data to multiple formats.
- Users do not have to be taught mark-up, saving time and easing their ability to use the system
This is a paragraph.
</p>
<p>
This is another paragraph.
</p>
Changing Things
Giving authors the opportunity to save articles in the database without sending them through the workflow process until they are ready offers a big advantage for many situations. As you might imagine, working on an article can be a lengthy process, full of edits, and ravaged with changes. While many would fire up their favorite word processor or text editor, with a plan to cut-n-paste the article into the CMS later, there are many who would prefer to work with the article directly in the environment that it is destined for. Given that, here is the code for authed.php;<? session_start(); ?><?//connect to and select databaseif(!($dbconnect = mysql_pconnect("127.0.0.1", "cms_user", "cms_password"))){ print("Failed to connect to database!"); exit(); }if(!mysql_select_db("cms", $dbconnect)){ print("Failed to select database!"); exit(); }Note that we have given the author the options (again) to save or submit the article. If the author chooses to save the article it will still be available in the list of articles that he or she can edit themselves. Submitting the article starts it forward through the workflow process.To process this code we are going to borrow the code we used originally for submitting articles with small modifications to the SQL queries. It will be called cmsauthed.php;//query to get navigation from database
$qnav = "SELECT URL ";$qnav .= "FROM tblNavigation ";$qnav .= "WHERE accesslevel = '$level' ";if(!($dbnav = mysql_query($qnav, $dbconnect))){
print("MySQL reports: " . mysql_error() . ""); exit(); }//query to get available editors
$qedit = "SELECT name ";$qedit .= "FROM tblUser ";$qedit .= "WHERE accesslevel = 'editor' ";if(!($dbedit = mysql_query($qedit, $dbconnect))){
print("MySQL reports: " . mysql_error() . ""); exit(); }//query to get article information
$qart = "SELECT a.ID, a.title, a.teaser, a.body ";$qart .= "FROM tblArticle a ";$qart .= "WHERE a.ID = $aid ";if(!($dbart = mysql_query($qart, $dbconnect))){
print("MySQL reports: " . mysql_error() . ""); exit(); }//place database items in variables for easier manipulation
$dbartrow = mysql_fetch_object($dbart);$atitle = $dbartrow->title;$ateaser = $dbartrow->teaser;$abody = $dbartrow->body;?>
<html><head><title>CMS</title><LINK REL="StyleSheet" HREF="cms.css" type="text/css"></head><body><div class="left">
<?// list the nav links for this type of userwhile($dbrow = mysql_fetch_object($dbnav)){
print($dbrow->URL . "<br>"); }?></div><div class="right">
<h1>Edit An Article</h1>
<form action="cmsauthed.php" method="POST">
<table cellpadding="3" cellspacing="0" border="1"><tr><td>Article Title</td><td><input type="hidden" name="aid" value="<? print($aid) ; ?>"><input type="text" name="title" size="64" maxlength="64" value="<? print($atitle); ?>"></td></tr><tr><td>Author email</td><td><? print($emailid) ?></td></tr><tr><td>Article Teaser</td><td><textarea name="teaser" cols="50" rows="3" wrap="virtual" maxlength="255"><? print($ateaser); ?></textarea></td></tr><tr><td>Article Body</td><td><textarea name="body" cols="50" rows="25" wrap="virtual"><? print($abody); ?></textarea></td></tr><tr><td>Editor</td><td><select name="editor"><option>---Select Editor---</option><?//list the editors available
while($dbrow = mysql_fetch_object($dbedit)){
print("<option>" . $dbrow->name . "</option>"); }?></select></td></tr><tr><td>Date Submitted<br>Format - YYYY-MM-DD</td><td><input type="text" name="submitted" size="10" maxlength="10"></td></tr><tr><td></td><td><INPUT type="submit" name="action" value="Save"> <INPUT type="submit" name="action" value="Submit Article"> <INPUT type="reset"></td></tr></table></form></div></body></html>
<? session_start(); ?><?//connect to and select databaseif(!($dbconnect = mysql_pconnect("127.0.0.1", "cms_user", "cms_password"))){ print("Failed to connect to database!"); exit(); }Instead of performing INSERT's during this process we perform UPDATE's of the information already contained in the database. The path that the article takes is the same as before, depending on the button clicked during the submission process. This multi-button functionality gives the CMS a lot of flexibility.if(!mysql_select_db("cms", $dbconnect)){
print("Failed to select database!"); exit(); }// perform action based on which button was pushed on submit form
switch($action){ case "Save": // query to insert saved elements only $qsave = "UPDATE tblArticle "; $qsave .= "SET title = '$title', "; $qsave .= "teaser = '$teaser', "; $qsave .= "body = '$body', "; $qsave .= "author = '$emailid' "; $qsave .= "WHERE ID = '$aid' ";if(!($dbsave = mysql_query($qsave, $dbconnect))){
print("MySQL reports: " . mysql_error() . "<br>"); exit(); }break;
case "Submit Article":
//query to submit article $qsubmit = "UPDATE tblArticle "; $qsubmit .= "SET title = '$title', "; $qsubmit .= "teaser = '$teaser', "; $qsubmit .= "body = '$body', "; $qsubmit .= "author = '$emailid', "; $qsubmit .= "editor = '$editor', "; $qsubmit .= "submitted = '$submitted' "; $qsubmit .= "WHERE ID = '$aid' ";if(!($dbsubmit = mysql_query($qsubmit, $dbconnect))){
print("MySQL reports: " . mysql_error() . "<br>"); exit(); }//select editor information and send an email
$qeditor = "SELECT email "; $qeditor .= "FROM tblUser "; $qeditor .= "WHERE name = '$editor' "; $qeditor .= "AND accesslevel = 'editor' ";if(!($dbeditor = mysql_query($qeditor, $dbconnect))){
print("MySQL reports this: " . mysql_error() . "<br>"); exit(); }//message to editor
$dbeditor = mysql_fetch_object($dbeditor); $messeditor = "$author has submitted an article, $title, for editing."; $messeditor .= "Please review this article at your earliest convenience.";
//mail("$dbeditor->email", "CMS Article Submission", $messeditor, "From: CMS System");
break;
}header("Location: myart.php"); exit; ?>