| |

Laboratorio: cómo hacer un plugin para WordPress

Post2PDFAlgo que nos gusta hacer en Sentido Web es explicar cómo se hacen las cosas, no solo mostrar scripts que encontramos o que inventamos, para así que quienes estén interesados, puedan aprender cómo hacerlo ellos mismos.

El otro día sacamos a la luz el plugin para WordPress Post2PDF y hoy vamos a explicar que es lo que hicimos para desarrollarlo.

El plugin consta de dos archivos principales (a parte de los de la librería), el plugin en sí y un script que es llamado por el plugin que es el que se encarga de la exportación a formato PDF.

Como bien dice en la entrada, este plugin está basado en la librería TCPDF, la cual permite crear documentos PDF pudiendo exportar HTML a este formato. Para usar esta librería nos crearemos una clase que extenderá de la clase TCPDF, aunque podríamos solamente instanciarla, al extenderla, podremos sobreescribir el método footer, el cual escribe el pie de página de las páginas del documento HTML.

La creación de nuestra clase es la siguiente:

define("_PDF_CREATOR_", "SW_Post2PDF");
define("__TITLE__", $wpdb->get_var('SELECT post_title FROM wp_posts WHERE id='.$_GET['id']));
define("__BLOGNAME__", get_option("blogname"));
define("__TOTAL_NUMBER_OF_PAGES__", "{nb}");
/* Clase que recibe un post y lo transforma a PDF
usando las clases de TCPDF (http://www.tecnick.com/public/code/cp_dpage.php?aiocp_dp=tcpdf) */
class SW_Post2PDF extends TCPDF{
private $_DOC_TITLE = "Blog post";
private $_DOC_SUBJECT = "";
private $_DOC_KEYWORDS = "";
private $_html = "";
// Constructor
function __construct() {
parent::__construct(PDF_PAGE_ORIENTATION, "pt", PDF_PAGE_FORMAT, true);
// Información del documento
parent::SetCreator(_PDF_CREATOR_);
parent::SetAuthor(_PDF_AUTHOR_);
parent::SetTitle($_DOC_TITLE);
parent::SetSubject($_DOC_SUBJECT);
parent::SetKeywords($_DOC_KEYWORDS);
// Márgenes del documento
parent::SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
// Salto de página automático
parent::SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
// Imágenes escaladas
parent::setImageScale(PDF_IMAGE_SCALE_RATIO);
// Idioma
$l = Array();
$l['a_meta_charset'] = "UTF-8";
$l['a_meta_dir'] = "ltr";
$l['a_meta_language'] = "en";
$l['w_page'] = "page";
parent::setLanguageArray($l);
// Toma las fuentes que se han especificado en la configuración del pluggin
parent::SetFont(get_option("sw_pdf_body_font"), "", get_option("sw_pdf_header_title_font_size"));
parent::setHeaderFont(Array(get_option("sw_pdf_header_title_font"), '', get_option("sw_pdf_header_title_font_size")));
parent::setBodyFont(Array(get_option("sw_pdf_body_font"), '', get_option("sw_pdf_body_font_size")));
parent::setFooterFont(Array(get_option("sw_pdf_footer_font"), '', get_option("sw_pdf_footer_font_size")));
parent::SetFooterMargin(PDF_MARGIN_FOOTER);
parent::AliasNbPages();
}
// Inicializa la cabecera de la página
public function setHeader() {
parent::SetHeaderMargin(PDF_MARGIN_HEADER);
parent::SetHeaderData(get_option("sw_pdf_header_image"),
get_option("sw_pdf_header_image_width"),
preg_replace('/(__\w+__)/e', '($1)',
get_option("sw_pdf_title")),
preg_replace('/(__\w+__)/e', '($1)',
get_option("sw_pdf_subtitle")));
}
// Añade el contenido que se va a exportar
public function setText($_txt) {
$this->_html .= $_txt;
}
// Inicializa el pie de página
public function Footer() {
parent::SetY(-15);
parent::SetFont(get_option("sw_pdf_footer_font"),'I',get_option("sw_pdf_footer_font_size"));
parent::SetTextColor(get_option("sw_pdf_footer_title_font_color_R"),
get_option("sw_pdf_footer_title_font_color_G"),
get_option("sw_pdf_footer_title_font_color_B"));
$footer = str_replace("__PAGE_NUMBER__", parent::PageNo(), preg_replace('/(__\w+__)/e', '($1)', get_option("sw_pdf_footer")));
parent::Cell(0,10, $footer,0,0,'C');
}
}

Y para finalizar el script que exporta la entrada, tendremos que recuperar la entrada, crearnos un objeto de la entrada anterior y devolver el resultado de exportar a PDF el contenido de la entrada.

// Instanciamos nuestra clase
$pdf = new SW_Post2PDF();
// Formato de fecha
$post = get_post($_GET['id'], 'ARRAY_A');
// 2006-09-25 | 14:45:32 H
$fecha = mysql2date('Y-m-d | H:i:s', $post["post_date"])." H";
// Incluimos el título del post, la fecha y el contenido
$texto = '<h1>'.$post["post_title"].'</h1><sup>'.$fecha.'</sup><br /><br />'.wpautop($post["post_content"]);
$pdf->setHeader();
$pdf->AddPage();
$pdf->SetFont(get_option("sw_pdf_body_font"), '', get_option("sw_pdf_body_font_size"));
$pdf->SetFont("vera", "I", 10);
$pdf->SetTextColor(get_option("sw_pdf_body_title_font_color_R"),
get_option("sw_pdf_body_title_font_color_G"),
get_option("sw_pdf_body_title_font_color_B"));
$pdf->writeHTML($texto, true, 0);
$pdf->Output();

Lo siguiente es ver cómo hemos realizado el plugin para WordPress, para ello dividiremos la explicación en tres partes: función que se debe incluir en la plantilla, administración del plugin y creación de un submenú en las opciones de la administración de plugins en WP.

Post2PDF está pensado para que se incluya un icono en la plantilla del theme, que al ser pinchado llame al script que hemos explicado anteriormente para realizar la exportación. Para ello existe la función Post2PDF(), que se encarga de escribir el enlace en la plantilla.

function Post2PDF() {
global $id;
echo '<a href="'.get_option('siteurl').'/wp-content/plugins/Post2PDF/SW_Post2PDF.php?id='.$id.'" target="_blank">';
echo '<img src="'.get_option('sw_pdf_icon').'" alt="Post2PDF">';
echo '</a>';
}

Lo siguiente es crearnos la pantalla de administración del plugin, la cual se llamará así misma para actualizar los datos. Lo primero que hará es comprobar si se viene debido a haber pulsado el botón de actualizar (usando un campo oculto dentro del formulario como flag) y en ese caso actualizaremos los datos. Y mostraremos el HTML necesario para la página de administración del plugin, entre las cosas más destacadas resaltamos la detección de las fuentes instaladas.

// Muestra la pantalla de administracion del plugin y actualiza los datos modificados
function sw_write_plugin_submenu() {
// Si se actualizan los valores del plugin, se actualizan en las opciones de WP
if (isset($_POST["sw_form"])) {
update_option("sw_pdf_title", stripslashes(isset($_POST["sw_pdf_title"])? $_POST["sw_pdf_title"]: get_option('blogname')));
update_option("sw_pdf_subtitle", stripslashes(isset($_POST["sw_pdf_subtitle"])? $_POST["sw_pdf_subtitle"]: "[#the_title()#]"));
update_option("sw_pdf_author", stripslashes(isset($_POST["sw_pdf_author"])? $_POST["sw_pdf_author"]: __SW_PDF_TITLE_DEFAULT__));
update_option("sw_pdf_header_image", stripslashes(isset($_POST["sw_pdf_header_image"])? $_POST["sw_pdf_header_image"]: ""));
update_option("sw_pdf_header_image_width", stripslashes(isset($_POST["sw_pdf_header_image_width"])? $_POST["sw_pdf_header_image_width"]: ""));
update_option("sw_pdf_header_title_font", stripslashes(isset($_POST["sw_pdf_header_title_font"])? $_POST["sw_pdf_header_title_font"]: "freesans"));
update_option("sw_pdf_header_title_font_size", stripslashes(isset($_POST["sw_pdf_header_title_font_size"])? $_POST["sw_pdf_header_title_font_size"]: "12"));
update_option("sw_pdf_header_title_font_color_R", stripslashes(isset($_POST["sw_pdf_header_title_font_color_R"])? $_POST["sw_pdf_header_title_font_color_R"]: "0"));
update_option("sw_pdf_header_title_font_color_G", stripslashes(isset($_POST["sw_pdf_header_title_font_color_G"])? $_POST["sw_pdf_header_title_font_color_G"]: "0"));
update_option("sw_pdf_header_title_font_color_B", stripslashes(isset($_POST["sw_pdf_header_title_font_color_B"])? $_POST["sw_pdf_header_title_font_color_B"]: "0"));
update_option("sw_pdf_body_font_size", stripslashes(isset($_POST["sw_pdf_body_font_size"])? $_POST["sw_pdf_body_font_size"]: "12"));
update_option("sw_pdf_body_font", stripslashes(isset($_POST["sw_pdf_body_font"])? $_POST["sw_pdf_body_font"]: "freesans"));
update_option("sw_pdf_body_title_font_color_R", stripslashes(isset($_POST["sw_pdf_body_title_font_color_R"])? $_POST["sw_pdf_body_title_font_color_R"]: "0"));
update_option("sw_pdf_body_title_font_color_G", stripslashes(isset($_POST["sw_pdf_body_title_font_color_G"])? $_POST["sw_pdf_body_title_font_color_G"]: "0"));
update_option("sw_pdf_body_title_font_color_B", stripslashes(isset($_POST["sw_pdf_body_title_font_color_B"])? $_POST["sw_pdf_body_title_font_color_B"]: "0"));
update_option("sw_pdf_footer", stripslashes(isset($_POST["sw_pdf_footer"])? $_POST["sw_pdf_footer"]: "Page {nb}"));
update_option("sw_pdf_footer_font", stripslashes(isset($_POST["sw_pdf_footer_font"])? $_POST["sw_pdf_footer_font"]: "freesans"));
update_option("sw_pdf_footer_font_size", stripslashes(isset($_POST["sw_pdf_footer_font_size"])? $_POST["sw_pdf_footer_font_size"]: "8"));
update_option("sw_pdf_footer_title_font_color_R", stripslashes(isset($_POST["sw_pdf_footer_title_font_color_R"])? $_POST["sw_pdf_footer_title_font_color_R"]: "0"));
update_option("sw_pdf_footer_title_font_color_G", stripslashes(isset($_POST["sw_pdf_footer_title_font_color_G"])? $_POST["sw_pdf_footer_title_font_color_G"]: "0"));
update_option("sw_pdf_footer_title_font_color_B", stripslashes(isset($_POST["sw_pdf_footer_title_font_color_B"])? $_POST["sw_pdf_footer_title_font_color_B"]: "0"));
update_option("sw_pdf_icon", stripslashes(isset($_POST["sw_pdf_icon"])? $_POST["sw_pdf_icon"]: get_settings('siteurl')."/wp-content/plugins/Post2PDF/pdf.gif"));
}
// Recupera los ficheros PHP de un directorio
function phpFiles($val) {
return preg_match("/\.php$/", $val);
}
// Leo los ficheros php del directorio fonts para saber que fuentes existen
$fuentes = array_values(array_filter(scandir(get_option('__SW_POST2PDF_PATH__')."/fonts"), "phpFiles"));
// Muestra el HTML de la pantalla de administracion
?>
<div class="wrap">
<h2>Post2PDF Options</h2>
<fieldset class="options">
<form name="form" method="post">
<input type="hidden" name="sw_form" value="1" />
<h3>PDF Header</h3>
<table class="optiontable">
<tr valign="top">
<th scope="row">Title:</th>
<td><input name="sw_pdf_title" type="text" id="sw_pdf_title" value="<?php echo (get_option("sw_pdf_title") != "")? get_option("sw_pdf_title"): get_option('blogname'); ?>" size="40" /></td>
</tr>
<tr valign="top">
<th scope="row">Subtitle:</th>
<td><input name="sw_pdf_subtitle" type="text" id="sw_pdf_subtitle" value="<?php echo (get_option("sw_pdf_subtitle") != "")? get_option("sw_pdf_subtitle"): "[#the_title()#]"; ?>" size="40" /></td>
</tr>
<tr valign="top">
<th scope="row">Font size:</th>
<td><input name="sw_pdf_header_title_font_size" type="text" id="sw_pdf_header_title_font_size" value="<?php echo (get_option("sw_pdf_header_title_font_size") != "")? get_option("sw_pdf_header_title_font_size"): "12"; ?>" size="3" /></td>
</tr>
<tr valign="top">
<th scope="row">Font:</th>
<td>
<select name="sw_pdf_header_title_font" id="sw_pdf_header_title_font">
<?php
foreach($fuentes as $fuente) {
$_fuente = preg_replace("/\.php$/", "",$fuente);
?>
<option value="<?php echo $_fuente; ?>"
<?php echo get_option("sw_pdf_header_title_font") == $_fuente? " selected ":""; ?>
><?php echo $_fuente; ?></option>
<?php
}
?>
</select>
</td>
</tr>
<tr valign="top">
<th scope="row">Font color (R, G, B):</th>
<td>
<input name="sw_pdf_header_title_font_color_R" type="text" id="sw_pdf_header_title_font_color_R" value="<?php echo (get_option("sw_pdf_header_title_font_color_R") != "")? get_option("sw_pdf_header_title_font_color_R"): "0"; ?>" size="3" />
&nbsp;
<input name="sw_pdf_header_title_font_color_G" type="text" id="sw_pdf_header_title_font_color_G" value="<?php echo (get_option("sw_pdf_header_title_font_color_G") != "")? get_option("sw_pdf_header_title_font_color_G"): "0"; ?>" size="3" />
&nbsp;
<input name="sw_pdf_header_title_font_color_B" type="text" id="sw_pdf_header_title_font_color_B" value="<?php echo (get_option("sw_pdf_header_title_font_color_B") != "")? get_option("sw_pdf_header_title_font_color_B"): "0"; ?>" size="3" />
</td>
</tr>
<tr valign="top">
<th scope="row">Image:</th>
<td><input name="sw_pdf_header_image" type="text" id="sw_pdf_header_image" value="<?php echo (get_option("sw_pdf_header_image") != "")? get_option("sw_pdf_header_image"): ""; ?>" size="40" onchange="document.getElementById('sw_head_image').src=this.value" />
<br /><strong>Only GIF and JPEG images are allowed</strong>
<br /><em>[http://domain.com/images/heade_pdf.png]</em>
</td>
</tr>
<tr valign="top">
<th scope="row">Image width:</th>
<td><input name="sw_pdf_header_image_width" type="text" id="sw_pdf_header_image_width" value="<?php echo (get_option("sw_pdf_header_image_width") != "")? get_option("sw_pdf_header_image_width"): ""; ?>" size="3" />
</td>
</tr>
<tr valign="top">
<td colspan="2" align="center"><img id="sw_head_image" src="<?php echo (get_option("sw_pdf_header_image") != "")? get_option("sw_pdf_header_image"): get_settings('siteurl')."/wp-content/plugins/Post2PDF/no-image.png"; ?>" alt="No image available"/></td>
</tr>
</table>
<h3>PDF Body</h3>
<table class="optiontable">
<tr valign="top">
<th scope="row">Font:</th>
<td>
<select name="sw_pdf_body_font" id="sw_pdf_body_font">
<?php
foreach($fuentes as $fuente) {
$_fuente = preg_replace("/\.php$/", "",$fuente);
?>
<option value="<?php echo $_fuente; ?>"
<?php echo get_option("sw_pdf_body_font") == $_fuente? " selected ":""; ?>
><?php echo $_fuente; ?></option>
<?php
}
?>
</select>
</td>
</tr>
<tr valign="top">
<th scope="row">Font size:</th>
<td><input name="sw_pdf_body_font_size" type="text" id="sw_pdf_body_font_size" value="<?php echo (get_option("sw_pdf_body_font_size") != "")? get_option("sw_pdf_body_font_size"): "12"; ?>" size="3" /></td>
</tr>
<tr valign="top">
<th scope="row">Font color (R, G, B):</th>
<td>
<input name="sw_pdf_body_title_font_color_R" type="text" id="sw_pdf_body_title_font_color_R" value="<?php echo (get_option("sw_pdf_body_title_font_color_R") != "")? get_option("sw_pdf_body_title_font_color_R"): "0"; ?>" size="3" />
&nbsp;
<input name="sw_pdf_body_title_font_color_G" type="text" id="sw_pdf_body_title_font_color_G" value="<?php echo (get_option("sw_pdf_body_title_font_color_G") != "")? get_option("sw_pdf_body_title_font_color_G"): "0"; ?>" size="3" />
&nbsp;
<input name="sw_pdf_body_title_font_color_B" type="text" id="sw_pdf_body_title_font_color_B" value="<?php echo (get_option("sw_pdf_body_title_font_color_B") != "")? get_option("sw_pdf_body_title_font_color_B"): "0"; ?>" size="3" />
</td>
</tr>
</table>
<h3>PDF Footer</h3>
<table class="optiontable">
<tr valign="top">
<th scope="row">Footer:</th>
<td><input name="sw_pdf_footer" type="text" id="sw_pdf_footer" value="<?php echo (get_option("sw_pdf_footer") != "")? get_option("sw_pdf_footer"): "Page {nb}"; ?>" size="40" /></td>
</tr>
<tr valign="top">
<th scope="row">Font:</th>
<td>
<select name="sw_pdf_footer_font" id="sw_pdf_footer_font">
<?php
foreach($fuentes as $fuente) {
$_fuente = preg_replace("/\.php$/", "",$fuente);
?>
<option value="<?php echo $_fuente; ?>"
<?php echo get_option("sw_pdf_footer_font") == $_fuente? " selected ":""; ?>
><?php echo $_fuente; ?></option>
<?php
}
?>
</select>
</td>
</tr>
<tr valign="top">
<th scope="row">Font size:</th>
<td><input name="sw_pdf_footer_font_size" type="text" id="sw_pdf_footer_font_size" value="<?php echo (get_option("sw_pdf_footer_font_size") != "")? get_option("sw_pdf_footer_font_size"): "8"; ?>" size="3" /></td>
</tr>
<tr valign="top">
<th scope="row">Font color (R, G, B):</th>
<td>
<input name="sw_pdf_footer_title_font_color_R" type="text" id="sw_pdf_footer_title_font_color_R" value="<?php echo (get_option("sw_pdf_footer_title_font_color_R") != "")? get_option("sw_pdf_footer_title_font_color_R"): "0"; ?>" size="3" />
&nbsp;
<input name="sw_pdf_footer_title_font_color_G" type="text" id="sw_pdf_footer_title_font_color_G" value="<?php echo (get_option("sw_pdf_footer_title_font_color_G") != "")? get_option("sw_pdf_footer_title_font_color_G"): "0"; ?>" size="3" />
&nbsp;
<input name="sw_pdf_footer_title_font_color_B" type="text" id="sw_pdf_footer_title_font_color_B" value="<?php echo (get_option("sw_pdf_footer_title_font_color_B") != "")? get_option("sw_pdf_footer_title_font_color_B"): "0"; ?>" size="3" />
</td>
</tr>
</table>
<h3>Miscellaneous</h3>
<table class="optiontable">
<tr valign="top">
<th scope="row">Author (PDF file):</th>
<td><input name="sw_pdf_author" type="text" id="sw_pdf_author" value="<?php echo (get_option("sw_pdf_author") != "")? get_option("sw_pdf_author"): __SW_PDF_TITLE_DEFAULT__; ?>" size="40" /></td>
</tr>
<tr valign="top">
<th scope="row">PDF icon:</th>
<td><input name="sw_pdf_icon" type="text" id="sw_pdf_icon" size="40" onchange="document.getElementById('sw_pdf_icon_image').src=this.value" value="<?php echo (get_option("sw_pdf_icon") != "")? get_option("sw_pdf_icon"): get_settings('siteurl') ."/wp-content/plugins/Post2PDF/pdf.gif"; ?>"/>
<br /><em>[http://domain.com/images/pdf.gif]</em>
</td>
</tr>
<tr valign="top">
<td colspan="2" align="center"><img id="sw_pdf_icon_image" src="<?php echo (get_option("sw_pdf_icon") != "")? get_option("sw_pdf_icon"): get_settings('siteurl') ."/wp-content/plugins/Post2PDF/pdf.gif"; ?>" alt="No image available"/></td>
</tr>
</table>
<p class="submit"><input type="submit" name="Update" value="Update Settings &raquo;" /></p>
</fieldset>
</div>
<?php
}

Y por último, el código necesario para añadir la pantalla de administración del plugin.

function sw_add_plugin_submenu() {
if (function_exists('add_submenu_page')) {
add_submenu_page('plugins.php', 'Post2PDF', 'Post2PDF', 1, __FILE__, 'sw_write_plugin_submenu');
}
}
add_action('admin_menu', 'sw_add_plugin_submenu');

Similar Posts