Themes have been introduced in Docxpresso in order to simplify the generation of documents with the help of its public API.

By loading a custom theme one can easily personalize the styles associated with tables, pragraphs and headings with the help of a CSS stylesheet even if no HTML5 code is ever used.

Beware, though, that no arbitrary stylesheet will do but it should follow specific rules that will be detailed below.

Let us first introduce the required loadTheme method which public API may be summarized as follows:

Signature

public loadTheme ($path)

Parameters

  • $path (type: string). The path to a CSS (theme) stylesheet.

How to use custom themes

To use a previously defined custom theme is extremely simple. Let us start by generating a simple document using the "word-blue" theme that comes bundled with Docxpresso while we postpone the details regarding its internal structure.

The following script generates a series of tables that will ressemble the ones that may be generated with a modern version of the MS Word editor:

<?php
/**
 * This sample script creates a document with the help of a Docxpresso theme
 */
require_once 'pathToDOCXPRESSO/CreateDocument.inc';
$doc = new Docxpresso\CreateDocument();
$format = '.pdf';//.pdf, .doc, .docx, .odt, .rtf
//we load the desired theme
$doc->loadTheme('../../themes/word-blue.css');
$doc->heading(array('text' => 'A sample document with a theme', 'level' => 1));
$doc->paragraph()
    ->text(array('text' => 'We are going to generate a series of tables with the different styles defined in the ' ))
    ->text(array('text' => 'word-blue' ))->style('font-weight: bold')
    ->text(array('text' => ' theme.'));
//list of table styles
$styles = array('Grid', 'Grid1', 'Grid2', 'Grid3', 'Grid4', 'List', 'List1', 'List2', 'List3', 'List4');
//loop over them
foreach ($styles as $style){
    $doc->heading(array('text' => 'Table style: ' . $style, 'level' =>2));
    $doc->table(array('grid' => array('4cm', '5cm', '5cm'), 'style' => $style, /*'mask' => array('bandedCol' => true)*/))
        ->row()
            ->cell()->paragraph(array('text' => 'Product'))
            ->cell()->text(array('text' => 'Reference'))
            ->cell()->text(array('text' => 'Availability'))
        ->row()
            ->cell()->paragraph(array('text' => 'Camera'))
            ->cell()->text(array('text' => '33-HJK-98'))
            ->cell()->text(array('text' => 'In stock'))
        ->row()
            ->cell()->paragraph(array('text' => 'MP3 Player'))
            ->cell()->text(array('text' => '34-KJU-02'))
            ->cell()->text(array('text' => '2 weeks'));
}
$doc->paragraph(array('text' => 'We finish this example by using a custom paragraph style.', 'style' => 'quote'));
//include in the render method the path where you want your document to be saved
$doc->render('theme' . $format); 
//echo a link to the generated document
echo 'You may download the generated document from the link below:<br/>';
echo '<a href="' . 'theme' . $format . '">Download document</a>';   

DOWNLOAD:download pdfdownload docdownload docxdownload odtdownload rtf

How to prepare a custom theme

Let us first have a look at the theme used in the previous example:

p {font-family: Calibri; font-size: 11pt}
a {font-family: Calibri; font-size: 11pt}
h1 {font-family: "Calibri Light"; color: #2E74B5; font-size: 16pt; page-break-after: avoid; page-break-inside: avoid; margin-bottom: 0; margin-top: 0.1666in}
h2 {font-family: "Calibri Light"; color: #2E74B5; font-size: 13pt; page-break-after: avoid; page-break-inside: avoid; margin-bottom: 0; margin-top: 0.0277in}
h3 {font-family: "Calibri Light"; color: #1F4D78; font-size: 12pt; page-break-after: avoid; page-break-inside: avoid; margin-bottom: 0; margin-top: 0.0277in}
h4 {font-family: "Calibri Light"; color: #2E74B5; font-style: italic; font-size: 11pt; page-break-after: avoid; page-break-inside: avoid; margin-bottom: 0; margin-top: 0.0277in}
h5 {font-family: "Calibri Light"; color: #2E74B5; font-size: 11pt; page-break-after: avoid; page-break-inside: avoid; margin-bottom: 0; margin-top: 0.0277in}
h6 {font-family: "Calibri Light"; color: #1F4D78; font-size: 11pt; page-break-after: avoid; page-break-inside: avoid; margin-bottom: 0; margin-top: 0.0277in}
table {}
table td {border: 1px solid #333; font-family: Calibri; padding: 0 5px; margin: 0; width: 100%}
table td.NE {}
table td.NW {}
table td.SE {}
table td.SW {}
table td.firstRow {}
table td.lastRow {}
table td.bandedRow {}
table td.firstCol {}
table td.lastCol {}
table td.bandedCol {}

p.Title {font-size: 28pt; font-family: "Calibri Light"; letter-spacing: -0.0069in}
p.subtitle {color: #5a5a5a; letter-spacing: 0.0104in}
p.quote {font-size: 11pt; font-family: Calibri; text-align: center; font-style: italic}

table.Grid {}
table.Grid td{font-family: Calibri; font-size: 11pt; border: 1px solid #9cc2e5}
table.Grid td.firstRow {font-weight: bold; border-bottom: 2px solid #9cc2e5}
table.Grid td.lastRow {font-weight: bold; border-top: 2px solid #9cc2e5}
table.Grid td.bandedRow {}
table.Grid td.firstCol {font-weight: bold}
table.Grid td.lastCol {font-weight: bold}
table.Grid td.bandedCol {}

table.Grid1 {}
table.Grid1 td{font-family: Calibri; font-size: 11pt; border: 1px solid #9cc2e5}
table.Grid1 td.firstRow {font-weight: bold; border-bottom: 2px solid #9cc2e5; background-color: transparent}
table.Grid1 td.lastRow {font-weight: bold; border-top: 2px solid #9cc2e5; ; background-color: transparent}
table.Grid1 td.bandedRow {background-color: #deeaf6}
table.Grid1 td.firstCol {font-weight: bold}
table.Grid1 td.lastCol {font-weight: bold}
table.Grid1 td.bandedCol {background-color: #deeaf6}

table.Grid2 {}
table.Grid2 td{font-family: Calibri; font-size: 11pt; border: 1px solid #9cc2e5}
table.Grid2 td.firstRow {font-weight: bold; border-top: none; border-right: none; border-left: none; border-bottom: 1px solid #9cc2e5; background-color: transparent}
table.Grid2 td.lastRow {font-weight: bold; border-bottom: none; border-right: none; border-left: none; border-top: 1px solid #9cc2e5; ; background-color: transparent}
table.Grid2 td.bandedRow {background-color: #deeaf6}
table.Grid2 td.firstCol {font-weight: bold; border: none; text-align: right; background-color: transparent}
table.Grid2 td.lastCol {font-weight: bold}
table.Grid2 td.bandedCol {background-color: #deeaf6}

table.Grid3 {}
table.Grid3 td{font-family: Calibri; font-size: 11pt; border: 1px solid #9cc2e5}
table.Grid3 td.NE {border-left: 1px solid #9cc2e5}
table.Grid3 td.NW {border-right: 1px solid #9cc2e5}
table.Grid3 td.firstRow {font-weight: bold; color: #ffffff; background-color: #5b9bd5; border-left: none; border-right: none}
table.Grid3 td.lastRow { border-top: 2px solid #9cc2e5;}
table.Grid3 td.bandedRow {background-color: #deeaf6}
table.Grid3 td.firstCol {font-weight: bold;}
table.Grid3 td.lastCol {font-weight: bold}
table.Grid3 td.bandedCol {background-color: #deeaf6}

table.Grid4 {}
table.Grid4 td{font-family: Calibri; font-size: 11pt; border: 1px solid #ffffff; background-color: #deeaf6}
table.Grid4 td.NE {border-left: 1px solid #ffffff}
table.Grid4 td.NW {border-right: 1px solid #ffffff}
table.Grid4 td.SE {border-left: 1px solid #ffffff}
table.Grid4 td.SW {border-right: 1px solid #ffffff}
table.Grid4 td.firstRow {font-weight: bold; color: #ffffff; background-color: #5b9bd5; border-left: none; border-right: none}
table.Grid4 td.lastRow { font-weight: bold; color: #ffffff; background-color: #5b9bd5; border-left: none; border-right: none}
table.Grid4 td.bandedRow {background-color: #bdd6ee}
table.Grid4 td.firstCol {font-weight: bold;color: #ffffff; background-color: #5b9bd5;}
table.Grid4 td.lastCol {font-weight: bold;color: #ffffff; background-color: #5b9bd5;}
table.Grid4 td.bandedCol {background-color: #bdd6ee}

table.List {}
table.List td{font-family: Calibri; font-size: 11pt; border: none}
table.List td.firstRow {font-weight: bold; border-bottom: 1px solid #9cc2e5;}
table.List td.lastRow {font-weight: bold; border-top: 1px solid #9cc2e5;}
table.List td.bandedRow {background-color: #deeaf6}
table.List td.firstCol {font-weight: bold}
table.List td.lastCol {font-weight: bold}
table.List td.bandedCol {background-color: #deeaf6}

table.List1 {}
table.List1 td{font-family: Calibri; font-size: 11pt; border-bottom: 1px solid #9cc2e5; border-top: 1px solid #9cc2e5; border-left: none; border-right: none}
table.List1 td.firstRow {font-weight: bold; border-bottom: 2px solid #9cc2e5;}
table.List1 td.lastRow {font-weight: bold; border-top: 2px solid #9cc2e5;}
table.List1 td.bandedRow {background-color: #deeaf6}
table.List1 td.firstCol {font-weight: bold}
table.List1 td.lastCol {font-weight: bold}
table.List1 td.bandedCol {background-color: #deeaf6}

table.List2 {border: 1px solid #5b9bd5;}
table.List2 td{font-family: Calibri; font-size: 11pt; border: none}
table.List2 td.firstRow {font-weight: bold; color: #ffffff; background-color: #5b9bd5;}
table.List2 td.lastRow {font-weight: bold; color: #ffffff; border-top: 2px solid #5b9bd5;}
table.List2 td.bandedRow {border-bottom: 1px solid #5b9bd5; border-top: 1px solid #5b9bd5;}
table.List2 td.firstCol {font-weight: bold}
table.List2 td.lastCol {font-weight: bold}
table.List2 td.bandedCol {border-right: 1px solid #5b9bd5; border-left: 1px solid #5b9bd5;}

table.List3 {border: 1px solid #5b9bd5;}
table.List3 td{font-family: Calibri; font-size: 11pt; border-bottom: 1px solid #5b9bd5; border-top: 1px solid #5b9bd5; border-left: none; border-right: none}
table.List3 td.firstRow {font-weight: bold; color: #ffffff; background-color: #5b9bd5;}
table.List3 td.lastRow {font-weight: bold; color: #ffffff; border-top: 2px solid #5b9bd5;}
table.List3 td.bandedRow {background-color: #deeaf6}
table.List3 td.firstCol {font-weight: bold}
table.List3 td.lastCol {font-weight: bold}
table.List3 td.bandedCol {background-color: #deeaf6;}

table.List4 {border: 4px solid #5b9bd5; background-color: #5b9bd5; color: #ffffff}
table.List4 td.NE {border-right: none}
table.List4 td{font-family: Calibri; font-size: 11pt;  background-color: #5b9bd5; color: #ffffff; border: none}
table.List4 td.firstRow {font-weight: bold; color: #ffffff; background-color: #5b9bd5; border-bottom: 2px solid #ffffff;}
table.List4 td.lastRow {font-weight: bold; color: #ffffff; background-color: #5b9bd5; border-top: 2px solid #ffffff;}
table.List4 td.bandedRow {border-bottom: 1px solid #5b9bd5; border-top: 1px solid #5b9bd5;}
table.List4 td.firstCol {font-weight: bold; border-right: 1px solid #ffffff}
table.List4 td.lastCol {font-weight: bold; border-left: 1px solid #ffffff}
table.List4 td.bandedCol {border-left: 1px solid #5b9bd5; border-right: 1px solid #5b9bd5;}     

As commented above the structure of the theme CSS selectors is not arbitrary but has to follow strict standards that we now pass to describe.

In order to improve performance the inheritance has been pretty reduced so one only may style:

  • Tags: p, a, h1 to h6 and table (see below).
  • Classes: with no inheritance.
  • Table cells:
    • Generic table cell.
    • First row cells via the firstRow class.
    • Last row cells via the LastRow class.
    • First column cells via the firstCol class.
    • Last column cells via the lastCol class.
    • Even row cells via the bandedRow class.
    • Even column cells via the bandedCol class.
    • Upper left corner cell via the NW class.
    • Upper right corner cell via the NE class.
    • Lower left corner cell via the SW class.
    • Lower right corner cell via the SE class.

The simplest way to generate your own theme is to copy the above one and carry out the required modifications.

After loading the theme with the loadTheme method the "tag selectors" are all directly applied without any additional procedure.

if one wishes to apply one of the defined class one should include it in the style of the options array just like this:

$doc->paragraph(array('text' => 'Some text.', 'style' => 'quote'));   

The above command will create a paragraph with the style p.quote if defined.

If we do the same with a table, i.e.

$doc->table(array('grid' => array('4cm', '5cm', '5cm'), 'style' => 'List1'));   

The created table will automatically only incorporate the following styles:

  • Global table style: table.List1.
  • Generic table cell style: table.List1 td.
  • First row cells: table.List1 td.firstRow.
  • First column cells: table.List1 td.firstCol.
  • Even row cells: table.List1 td.bandedRow.
  • Upper left corner cell: table.List1 td.NW.
  • Upper right corner cell: table.List1 td.NE.
  • Lower right corner cell: table.List1 td.SE.

One may customize this behaviour by using the table method mask option. For example, if one wants to create a banded column table with no banded rows one should use:

$mask = array('bandedCol' => true, 'bandedRow' => false);
$doc->table(array('grid' => array('4cm', '5cm', '5cm'), 'style' => 'List1', 'mask => $mask));   

Like you can see from the above examples with the help of a custom theme one may build nicely formatted content with a single line of code!!