📖 PHP Building the Admin Interface

Once you have determined to develop and support a dynamic site with a back-end database, you will need to provide an interface for users to Create, Read, Update and Delete the data. These are known as CRUD apps. This provides full functionality to manage the data for the content of the site.

The CRUD approach to building dynamic sites is used commonly to create software that provides a template for a variety of sites where the site content is managed in a database. These are called Content Management Systems (CMS). Popular CMS software programs are WordPress, Drupal, Joomla!, Moodle and many others.

With the addition of the administrative edit tools will come additional displays, security and functionality. Increased focus on program flow through improved routing and processes will be beneficial to avoid 'spaghetti' code.

Page Purpose

The blog admin page will be used to insert new blog posts and delete or update existing blog posts. It will provide a form for editing existing records or collecting information for a new record. The form is identical for wither purpose. The only difference is you will provide a blank form for a new post and a pre-populated form for an edit. Access to this page will be restricted to members only.

Page Dependencies

Previous articles have described how to create the public view of a blog. This article will focus on developing the administrative interface that provides users the ability to manage content for the site. You should already have the back-end database with some content connected to your web app. If not, please review previous articles for help on building the back-end.

The admin page is designed for administrative access to the blog. Using memberID access control, we will also add administrative buttons as links to the blog page. This will allow us to use an existing page to avoid duplicating the blog list and display. Therefore, the admin page will only need to include the actual edit page for the blog. Any other tools will be incorporated into the 'public' pages with display controls on the administrative functions. Let's start with the HTML form.

Setting Up the Page

The admin page will need a form for users to add and edit blog content. The form will be submitted and processed like many of the other forms you have used. This time we will work toward improving our MVC pattern in our code. This means we will contibue the practice of accessing our data through functions saved in the config.php file. We already have a function that returns a single post data for the blog. We will use this same function to return the data for our form. The only edit you need to make to the function is to add the publish attribute to the resultset.

In addition to the select query, we will also need a way to insert a new blog post, edit and delete an existing blog post. We will create functions in the config.php file to manage these tasks, similar to the methods we used retrieving the data. Here are the functions.

// this function inserts a new record for a new blog post
// Notice that it retrieves the ID of the new post with $stmt->insert_id;
// Then it returns the postID upon successful insert and FALSE on fail
function insertPost($conn, $postTitle, $postContent, $publish, $authorID) {
	$stmt = $conn->stmt_init();
	if ($stmt->prepare("INSERT INTO `blog`(`postTitle`, `postContent`, `publish`, `authorID`) VALUES (?, ?, ?, ?)")) {
		$stmt->bind_param("ssii", $postTitle, $postContent, $publish, $authorID);
		$stmt->execute();
		$postID = $stmt->insert_id;
		$stmt->close();
		return $postID;
	} else {
		return FALSE;
	}
}

// this function saves edits for existing blog posts
function updatePost($conn, $postTitle, $postContent, $publish, $postID) {
	$stmt = $conn->stmt_init();
	if ($stmt->prepare("UPDATE `blog` SET `postTitle`= ?,`postContent`= ?,`publish`= ? WHERE `postID` = ?")) {
		$stmt->bind_param("ssii", $postTitle, $postContent, $publish, $postID);
		$stmt->execute();
		$stmt->close();
		return TRUE;
	} else {
		return FALSE;
	}
	
}

Creating the Admin Page for Blog Edits

The blog is probably maintained by a smaller group of approved bloggers. The application will need a way to manage the blog updates by only allowing authorized users access. This page will handle all the administrative work for creating, updating and deleting blog posts. We will access this page from a blog post link for edits or a Add New Blog Post link for a new post.

There are a few extra things we need on this page since it's an admin page. First, we need a way of checking to see that the visitors are authorized to access the page. We do this by checking to see if they are logged in. We can use this same access control for other pages in our site and we can create modified verions of this to control specific page content like admin links. Since we will want to use this throughout our application, we need a function we can call. Here is code to add to config.php that will help us control page access.

// Add this to config.php
function auth_user() {
	if(isset($_SESSION['memberID'])) {
		return TRUE;
	} else {
		return FALSE;
	}
}

// Add this to the page you want to control access to the page
// This will be added to the very top of the page
// We don't want to load or process anything if they are not authorized
// So we simply redirect them to an appropriate page if they are not logged in
// If they are logged in, get their session memberID and assign it to the memberID variable
if(auth_user()){
    $memberID = $_SESSION['memberID'];
} else {
    header('Location: blog.php');
    exit;
}

Controlling Page Elements Issued to Users

You will have different users visit your site with varied purposes. Some will want to visit just to read your blog. These visitors will need access to the public view of the blog pages. We can control that by creating a separate blog page and blog-admin page as we are doing here.

There are also times when you will want to provide different functionality to your logged in members than that of the public. For example, you might want to offer a 'Create New Post' button for a logged in member that would not be available to the public. To do this, you can create a function similar to the auth_user() function that controls whether a page element is included or not. The auth_admin() function below can control this process.

// Add this to config.php
function auth_admin(n) {
	if($_SESSION['role'] > n) {
		return TRUE;
	} else {
		return FALSE;
	}
}
// The above function works with a role value [n] stored in the db
// In this example, a common user might have a role value of 1 and the admin have role values greater than 1
// You will need to add code to the login script to access the role value on login

// Now add this to the page you want to control displayed elements
// This will be added to the very top of the page
// If they are logged in, assign the element code to a variable
// If they are not logged in, assign the NULL value to the variable to omit the control from the page view
if(auth_admin(n)){
    $adminButton = <<<HERE
    <form action="page.php" method=post">
        <input type="submit" name="edit" value="Create New Post">
    </form>
HERE;
} else {
    $adminButton = NULL;
}

// Add the button variable to the HTML page where you want the button to display
// If they are logged in they will see the button
// If they are not logged in they will not see the button
$pageContent .= $adminButton;

Checking for Submitted POST Data

This page incorporates several views and processes into one script. We need to track the script status to determine the appropriate process(es). We may need to know whether there is an edit request that will trigger teh blog form view. We will need the blog postID if we want to read or edit a specific blog post. We can track these requests with the use of form field name: value pairs provided during form submission. We can use the button names to trigger specific events and hidden form fields to keep track of specific posts.

Since this page will display a form for edits as well as new posts, we need to load the blog post data for edits. For any edits, we will need a postID. Since this is required for edits, we can use it to check for the need to get the data. Without it, we will just load a blank form. Add this code after the authenticating the visitor.

// check for incoming postID
// This is helpful for showing a blog post or pre-populating the blog edit form
if (filter_has_var(INPUT_POST, 'postID')) {
    $postID = filter_input(INPUT_POST, 'postID');
} elseif (filter_has_var(INPUT_GET, 'postID')) {
    $postID = filter_input(INPUT_GET, 'postID');
} else {
    $postID = NULL;
}

// We can also use the button named edit to trigger the form view
// Once this variable value is set to TRUE/FALSE we can determine if we need to display the form
// NOTE: If the postID is missing, we will get a blank form
// If the postID is available, we can query the db to load the post information for edit
if (filter_has_var(INPUT_POST, 'edit')) {
    $edit = TRUE;
} else {
    $edit = FALSE;
}

Form Processing

Next, we need to check for form submission. If it has been submitted, we need to process the form as we have processed forms in the past. Validate and sanitize the form data, then insert/update the database by calling one of the database functions from above.

// check $_POST for form submission and process form
if (filter_has_var(INPUT_POST, 'save')) {
    $postTitle = filter_input(INPUT_POST, 'postTitle');
    $postContent = filter_input(INPUT_POST, 'postContent');
    if (filter_has_var(INPUT_POST, 'publish') == 1) {
        $publish = 1;
    } else {
        $publish = 0;
    }
        if (!empty($postID)) {
			// update post with existing postID
            if(updatePost($conn, $postTitle, $postContent, $publish, $postID)) {
                $msg = "<p>Post updated.</p>";
            } else {
                $msg = "<p>Post not updated.</p>";
            }
            // $postID = updatePost($conn, $postTitle, $postContent, $publish, $postID);
        } else {
			// insert new post
            if($postID = insertPost($conn, $postTitle, $postContent, $publish, $memberID)) {
                $msg = "<p>Post saved. $postID</p>";
            } else {
                $msg = "<p>Post not saved.</p>";
            }
        }
}

Loading the Page

The HTML part of this page is fairly simple. We just need a form with a single line text field for the post title, a multi-line textarea for the blog poct content, a checkbox for the publish option and a save (submit) button. This form can be used for editing an existing post or creating a new post. The only difference between the two is whether wwe have an existing postID. SO, let's include a hidden field to capture the postID. We can set it to NULL for default if we are creating a new post and don't have a postID.

One final detail we need to consider is when should we grab the data from the database for an existing post. We want to do this just before we load the HTML form. This way we can capture the freshest updates frm teh database about the blog post. Notice I added the call to the database just before the form loads, but onlu if I have a postID. If I don't, I load the blank form for a new post to be created.

// query the database for the blog information
if (isset($postID)){
    $postData = blogPost($conn, $postID);
    $postTitle = $postData[0];
    $postContent = $postData[1];
    $publish = $postData[2];
    if ($publish == 1) {
        $publishChecked = "checked";
    }
}

// assemble HTML content and template
$pageContent .= <<<HERE
<h2>Edit Blog Post</h2>
$msg
<form action="" method="post">
    <label>Title: 
        <input type="text" name="postTitle" value="$postTitle">
    </label>
    <label>Post: 
        <textarea name="postContent">$postContent</textarea>
    </label>
    <label>Publish: <input type="checkbox" name="publish" $publishChecked></label>
    <input type="hidden" name="postID" value="$postID">
    <input type="submit" name="save" value="Save">
</form>
HERE;

Finishing Touches

The only thing left is to embellish the HTML with Bootstrap style, assemble the HTML and wrap it in the template like we've done with all the site pages.