Creando módulo para administración de contenido
Empezaremos con el funcionamiento principal de todo CMS, el administrador de contenidos. Desde aquí controlaremos la mayor parte de la información que se suba al sitio. Vamos a crear dos archivos, uno llamado page-contenido.php y resultado_contenido.php. La lógica de estos dos archivos es similar a la de configuración.
page-contenido.php se encarga de mostrar el formulario y copiar la información y enviarla a resultado_contenido.php, quien se encarga de enviarla a la base de datos y luego redireccionar a page-respuesta.php para enviarnos una respuesta de éxito o error de los datos guardados.
Código de page-contenido.php
<?php include 'header.php'; ?> <form class="pure-form pure-form-stacked" action="resultado_contenido.php" method="post" onsubmit="return false;"> <fieldset> <legend>Contenido</legend> <input type="hidden" name="id" value="" /> <label for="type">Tipo</label> <select name="type" id="type" class="pure-input-1"> <option value="">Seleccionar</option> <?php $tipo = retornar_tipo_contenido(); ?> <?php while(is_array($tipo) && list($k, $v) = each($tipo) ): ?> <option value="<?= $k ?>"><?= $v ?></option> <?php endwhile; ?> </select> <label for="category" class="only-post">Categoría</label> <div class="select-editable only-post"> <select onchange="this.nextElementSibling.value=this.value" class="pure-input-1"> <option value=""></option> <?php $options_category = cargar_datos_categoria() ?> <?php while(is_array($options_category) && list($k, $v) = each($options_category) ): ?> <option value="<?= $v['categoria'] ?>"><?= $v['categoria'] ?></option> <?php endwhile; ?> </select> <input type="text" name="category" value="" /> </div> <label for="title">Titulo</label> <input type="text" name="title" placeholder="Titulo" value="" class="pure-input-1"> <label for="title">URL</label> <input type="text" name="alias" value="" class="pure-input-1"> <label for="type">Contenido</label> <div class="adjoined-bottom"> <div class="grid-container"> <div class="grid-width-100"> <div id="editor"> </div> </div> </div> </div> <input type="hidden" name="content" id="content"> <button type="submit" id="send" class="pure-button pure-button-primary">Guardar</button> </fieldset> </form> <?php include 'footer.php'; ?>Hay que resaltar dos funciones que se están usando en el formulario:
- retornar_tipo_contenido(): Retorna el tipo de contenido que estamos subiendo, si es una página web, o es un post. Esta función debe ser agregada a lib/data.php
- cargar_datos_categoria(): Retorna las categorías que vayas creando en tu sitio web.
Agregar código en data.php:
function cargar_datos_categoria(){ $mysql = new Mysql(); $sql = <<<SQL SELECT DISTINCT(categoria) as categoria FROM contenidos WHERE categoria != '' SQL; $options = $mysql->search($sql); return $options; } function retornar_tipo_contenido(){ return ['PAGE'=>'Página', 'POST' => 'Post']; } Código resultado_contenido.php <?php $path = dirname(__FILE__); require_once( $path . '/../../setting/config.php'); require_once( $path . '/../../setting/mysql.php'); $content = $_POST['content']; $id = $_POST['id']; $title = $_POST['title']; $type = $_POST['type']; $category = ($type == 'PAGE') ? '': $_POST['category']; $date = date('Y-m-d H:i:s'); $alias = $_POST['alias']; if($id > 0){ $sql = <<<SQL UPDATE contenidos SET titulo = '$title', tipo= '$type', contenido = '$content', categoria = '$category', alias = '$alias' WHERE id='$id' SQL; }else{ $sql = <<<SQL INSERT INTO contenidos (titulo, tipo, contenido, categoria, alias) VALUES ('$title', '$type', '$content', '$category', '$alias') SQL; } $mysql = new Mysql(); $response = ( $mysql->execute($sql) ) ? 'Contenido guardado exitosamente!' : 'Error al guardar contenido.'; header("Location: " . Config::URL . "admin/page-respuesta.php?response=$response"); ?>Visualicemos el formulario de page-contenido.php entrando desde la opción de Ingresar Contenido en el menú principal del administrador. Debería mostrar lo siguiente:
[color=#a9a9a9]Pulsa imagen para ampliar[/color]
Nos encontramos con algo extraño, contenido no está visualizando ningún campo. Este campo es especial. Para esto necesitamos un plugin de Javascript llamado CKEditor. Lo podemos descargar en la siguiente página:
Recomiendo descargar la opción Full Package. Este plugin nos permite manipular HTML.
[color=#a9a9a9]Pulsa imagen para ampliar[/color]
Ya descargado creamos un directorio dentro de admin y lo llamamos vendor. Dentro del directo vendor pegamos el plugin de CKEditor. Proseguimos creando un nuevo directorio llamado js, donde crearemos dos archivos llamado ck-editor.js y main.js. Con estos dos archivos vamos a controlar el formulario de page-contenido.php.
Código ck-editor.js
/** * Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or http://ckeditor.com/license */ /* exported initSample */ if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) CKEDITOR.tools.enableHtml5Elements( document ); // The trick to keep the editor in the sample quite small // unless user specified own height. CKEDITOR.config.height = 250; CKEDITOR.config.width = 'auto'; var initCkEditor = ( function() { var wysiwygareaAvailable = isWysiwygareaAvailable(), isBBCodeBuiltIn = !!CKEDITOR.plugins.get( 'bbcode' ); return function() { var editorElement = CKEDITOR.document.getById( 'editor' ); // :((( if ( isBBCodeBuiltIn ) { editorElement.setHtml( 'Hello world!\n\n' + 'I\'m an instance of [url=http://ckeditor.com]CKEditor[/url].' ); } // Depending on the wysiwygare plugin availability initialize classic or inline editor. if ( wysiwygareaAvailable ) { CKEDITOR.replace( 'editor' ); } else { editorElement.setAttribute( 'contenteditable', 'true' ); CKEDITOR.inline( 'editor' ); // TODO we can consider displaying some info box that // without wysiwygarea the classic editor may not work. } }; function isWysiwygareaAvailable() { // If in development mode, then the wysiwygarea must be available. // Split REV into two strings so builder does not replace it :D. if ( CKEDITOR.revision == ( '%RE' + 'V%' ) ) { return true; } return !!CKEDITOR.plugins.get( 'wysiwygarea' ); } } )();Código main.js
window.addEventListener("load", function(){ initCkEditor(); //init ckeditor var btn = document.querySelector("#send"); btn.addEventListener("click", function(){ var content = CKEDITOR.instances.editor.getData(); document.querySelector("#content").value = encodeURI(content); document.querySelector("form").submit(); }); var type = document.querySelector("#type"); type.addEventListener("change", verTipo); function verTipo(){ var display = (this.value == 'PAGE') ? "none" : "block"; var el = document.querySelectorAll(".only-post"); for(var i = 0; i < el.length; i++){ el[i].style.display = display; } } var event = new CustomEvent("change"); type.dispatchEvent(event); });Ya solo nos falta llamar el CKEditor y los archivos javascript que guardamos en el directorio js, los agregamos en footer.php.
Nuevo código de footer.php
<script src="vendor/ckeditor/ckeditor.js"></script> <script src="js/ck-editor.js"></script> <script src="js/main.js"></script> </body> </html>Recargamos nuevamente el formulario de Ingresar Contenido y nos debe salir de la siguiente forma.
[color=#a9a9a9]Pulsa imagen para ampliar[/color]
Asi va el código de nuestro CMS.
Explicación del formulario de contenidos: Vamos a darle una breve explicación a cada campo del formulario del contenido para saber qué funcionamiento va a tener en nuestro sitio web final.
- Tipo: Define qué contenido estamos creando, si una página o un post.
- Categoría (solo para post): Define que tipo de post. En el caso del tutorial estamos creando una página web de películas, podemos definir cada post como una pelicula y la categoría por géneros: aventura, terror, comedia, drama, etc.
- Título: Nombre del post o página.
- URL (alias en la base de datos): esta será la URL con la que se cargará el contenido en nuestro sitio. Se recomienda que esta URL sea en minúsculas, sin tildes y los espacios reemplazados por guiones. Por ejemplo, si mi post se llama Iron Man, podría considerar que la url sea iron-man. Este campo podría ser tomado automáticamente para que el usuario no tenga que digitar manualmente, te queda como tarea automatizarlo.
- Contenido: El contenido de tu post o página. Gracias al plugin CKEditor tenemos la posibilidad de agregar HTML en este campo. Colocamos la información y la guardamos.
[color=#a9a9a9]Pulsa imagen para ampliar[/color]
Ahora solo nos falta consultar todos los contenidos que subimos al sitio desde el administrador. Creamos un archivo llamado page-contenido.php
<?php include('header.php'); ?> <?php $res = cargar_datos_contenidos(); $array_type = retornar_tipo_contenido(); ?> <div class="mid-page" style="text-align:right;" > <a href="page-contenido.php" class="pure-button pure-button-primary">Nuevo</a> </div> <table class="pure-table"> <thead> <tr> <th>#</th> <th>Titulo</th> <th>Fecha</th> <th>Tipo</th> <th>Categoría</th> <th>Acción</th> </tr> </thead> <tbody> <?php while(is_array($res) && list($k, $v) = each($res) ): ?> <tr> <td><?= $k+1 ?></td> <td><?= $v['titulo'] ?></td> <td><?= $v['fecha_publicacion'] ?></td> <td><?= $array_type [ $v['tipo'] ] ?></td> <td><?= $v['categoria'] ?></td> <td><a href="page-contenido.php?id=<?=$v['id']?>">Editar</a></td> </tr> <?php endwhile; ?> </tbody> </table> <?php include('footer.php'); ?>Agregar esta nueva funciónn en data.php
function cargar_datos_contenidos(){ $mysql = new Mysql(); $sql = <<<SQL SELECT * FROM contenidos SQL; $res = $mysql->search($sql); return $res; }Desde el menú principal del CMS entramos a la opción Consultar Contenido:
[color=rgb(169,169,169)]Pulsa imagen para ampliar[/color]
Solo falta editar page-contenido.php para que nos cargue lo que ya hemos guardado anteriormente.
Nuevo page-contenido.php
<?php include 'header.php'; ?> <?php $datos = cargar_contenido($_GET[id]); ?> <form class="pure-form pure-form-stacked" action="resultado_contenido.php" method="post" onsubmit="return false;"> <fieldset> <legend>Contenido</legend> <input type="hidden" name="id" value="<?= $datos['id']?>" /> <label for="type">Tipo</label> <select name="type" id="type" class="pure-input-1"> <option value="">Seleccionar</option> <?php $tipo = retornar_tipo_contenido(); ?> <?php while(is_array($tipo) && list($k, $v) = each($tipo) ): ?> <option value="<?= $k ?>" <?= ($k === $datos['tipo'] )? 'selected' : '' ?> ><?= $v ?></option> <?php endwhile; ?> </select> <label for="category" class="only-post">Categoría</label> <div class="select-editable only-post"> <select onchange="this.nextElementSibling.value=this.value" class="pure-input-1"> <option value=""></option> <?php $options_category = cargar_datos_categoria() ?> <?php while(is_array($options_category) && list($k, $v) = each($options_category) ): ?> <option value="<?= $v['categoria'] ?>"><?= $v['categoria'] ?></option> <?php endwhile; ?> </select> <input type="text" name="category" value="<?= $datos['categoria'] ?>" /> </div> <label for="title">Titulo</label> <input type="text" name="title" placeholder="Titulo" value="<?= $datos['titulo'] ?>" class="pure-input-1"> <label for="title">URL</label> <input type="text" name="alias" value="<?= $datos['alias'] ?>" class="pure-input-1"> <label for="type">Contenido</label> <div class="adjoined-bottom"> <div class="grid-container"> <div class="grid-width-100"> <div id="editor"> <?= urldecode($datos['contenido']) ?> </div> </div> </div> </div> <input type="hidden" name="content" id="content"> <button type="submit" id="send" class="pure-button pure-button-primary">Guardar</button> </fieldset> </form> <?php include 'footer.php'; ?>Y agregar a data.php
function cargar_contenido($id){ if($id > 0){ $mysql = new Mysql(); $sql = <<<SQL SELECT * FROM contenidos WHERE id = '$id' SQL; $res = $mysql->search($sql); $res = $res[0]; $type = $res['tipo']; }else{ $res = array(); } return $res; }Estos son todos los archivos para nuestro administrador de CMS. Ni uno mas ni uno menos.
Prueba que esté visualizando el contenido y actualizando correctamente. Si todo está funcionando ya hemos finalizado nuestro administrador del CMS.
Pero no cantemos victoria aún. Vamos por mitad de camino, nos falta ahora visualizar todo nuestro contenido al público, sino que gracia guardar información para nosotros.
Muchas gracias, es un tutorial que voy a leerlo con calma. Lo he visto por encima y es super completo. Saludos.