Using Template in Codeigniter

This tutorial will show you an example on how to use template in Codeigniter. In an web application a template is recommended because there are certain regions or areas which are common to all pages and only the body portion of the page gets changed. Common areas like header, footer, left sidebar or right sidebar are mainly common areas for most of the web applications. So we will fix those common areas in the template file so that every page will use those common areas in the application and body portion of each page will contain content which is specific to the page.

We will use here Colin Williams template library to demonstrate the template system in Codeigniter. Now we will see step by step process how can we use the template library in Codeigniter application.

If you want to use Template library with Codeigniter 3 then you can read Using Template in Codeigniter 3

Step 1. Put this below template.php file under <project root>/application/config/ directory

<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');
/*
  |--------------------------------------------------------------------------
  | Active template
  |--------------------------------------------------------------------------
  |
  | The $template['active_template'] setting lets you choose which template
  | group to make active.  By default there is only one group (the
  | "default" group).
  |
 */
$template['active_template'] = 'public';

/*
  |--------------------------------------------------------------------------
  | Explaination of template group variables
  |--------------------------------------------------------------------------
  |
  | ['template'] The filename of your master template file in the Views folder.
  |   Typically this file will contain a full XHTML skeleton that outputs your
  |   full template or region per region. Include the file extension if other
  |   than ".php"
  | ['regions'] Places within the template where your content may land.
  |   You may also include default markup, wrappers and attributes here
  |   (though not recommended). Region keys must be translatable into variables
  |   (no spaces or dashes, etc)
  | ['parser'] The parser class/library to use for the parse_view() method
  |   NOTE: See http://codeigniter.com/forums/viewthread/60050/P0/ for a good
  |   Smarty Parser that works perfectly with Template
  | ['parse_template'] FALSE (default) to treat master template as a View. TRUE
  |   to user parser (see above) on the master template
  |
  | Region information can be extended by setting the following variables:
  | ['content'] Must be an array! Use to set default region content
  | ['name'] A string to identify the region beyond what it is defined by its key.
  | ['wrapper'] An HTML element to wrap the region contents in. (We
  |   recommend doing this in your template file.)
  | ['attributes'] Multidimensional array defining HTML attributes of the
  |   wrapper. (We recommend doing this in your template file.)
  |
  | Example:
  | $template['default']['regions'] = array(
  |    'header' => array(
  |       'content' => array('<h1>Welcome</h1>','<p>Hello World</p>'),
  |       'name' => 'Page Header',
  |       'wrapper' => '<div>',
  |       'attributes' => array('id' => 'header', 'class' => 'clearfix')
  |    )
  | );
  |
 */

/*
  |--------------------------------------------------------------------------
  | Default Template Configuration (adjust this or create your own)
  |--------------------------------------------------------------------------
 */
//public template
$template['public']['template'] = 'template/template';
$template['public']['regions'] = array(
    'title',
    'content'
);
$template['public']['parser'] = 'parser';
$template['public']['parser_method'] = 'parse';
$template['public']['parse_template'] = TRUE;

/* End of file template.php */
/* Location: ./config/template.php */

We have defined two regions title and content because those two regions will be changing according to the page content. You can also define other regions if you want them to be updated according to the page content. We have used the Codeigniter’s default parser to parse the template regions. We have used parse_template to TRUE to parse the template.

Step 2. Now put this below template.php template library under <project root>/application/libraries/ directory. If you look at the below template library file you will see I have added extra regions, i.e., ‘_meta’ => array() which will contain meta tags for the page. I have also added the below code snippets so that each page can contain meta tags specific to that page only.

/**
     * Dynamically include meta tags in the template
     * 
     * @param string $key meta name
     * @param string $value meta content
     * @return bool
     */
    function add_meta($key, $val) {
        $success = FALSE;
        $meta = '<meta name="' . $key . '" content="' . $val . '" />';

        if (!in_array($meta, $this->meta)) {
            $this->meta[] = $meta;
            $this->write('_meta', $meta);
            $success = TRUE;
        }

        return $success;
    }

Template library file.

<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');
/**
 * CodeIgniter
 *
 * An open source application development framework for PHP 4.3.2 or newer
 *
 * @package CodeIgniter
 * @author  ExpressionEngine Dev Team
 * @copyright  Copyright (c) 2006, EllisLab, Inc.
 * @license http://codeigniter.com/user_guide/license.html
 * @link http://codeigniter.com
 * @since   Version 1.0
 * @filesource
 */
// --------------------------------------------------------------------

/**
 * CodeIgniter Template Class
 *
 * This class is and interface to CI's View class. It aims to improve the
 * interaction between controllers and views. Follow @link for more info
 *
 * @package		CodeIgniter
 * @author		Colin Williams
 * @subpackage	Libraries
 * @category	Libraries
 * @link		http://www.williamsconcepts.com/ci/libraries/template/index.html
 * @copyright  Copyright (c) 2008, Colin Williams.
 * @version 1.4.1
 * 
 */
class CI_Template {

    var $CI;
    var $config;
    var $template;
    var $master;
    var $regions = array(
        '_scripts' => array(),
        '_styles' => array(),
        '_meta' => array()
    );
    var $output;
    var $js = array();
    var $css = array();
    var $meta = array();
    var $parser = 'parser';
    var $parser_method = 'parse';
    var $parse_template = FALSE;

    /**
     * Constructor
     *
     * Loads template configuration, template regions, and validates existence of 
     * default template
     *
     * @access	public
     */
    function CI_Template() {
        // Copy an instance of CI so we can use the entire framework.
        $this->CI = & get_instance();

        // Load the template config file and setup our master template and regions
        include(APPPATH . 'config/template' . EXT);
        if (isset($template)) {
            $this->config = $template;
            $this->set_template($template['active_template']);
        }
    }

    // --------------------------------------------------------------------

    /**
     * Use given template settings
     *
     * @access  public
     * @param   string   array key to access template settings
     * @return  void
     */
    function set_template($group) {
        if (isset($this->config[$group])) {
            $this->template = $this->config[$group];
        } else {
            show_error('The "' . $group . '" template group does not exist. Provide a valid group name or add the group first.');
        }
        $this->initialize($this->template);
    }

    // --------------------------------------------------------------------

    /**
     * Set master template
     *
     * @access  public
     * @param   string   filename of new master template file
     * @return  void
     */
    function set_master_template($filename) {
        if (file_exists(APPPATH . 'views/' . $filename) or file_exists(APPPATH . 'views/' . $filename . EXT)) {
            $this->master = $filename;
        } else {
            show_error('The filename provided does not exist in <strong>' . APPPATH . 'views</strong>. Remember to include the extension if other than ".php"');
        }
    }

    // --------------------------------------------------------------------

    /**
     * Dynamically add a template and optionally switch to it
     *
     * @access  public
     * @param   string   array key to access template settings
     * @param   array properly formed
     * @return  void
     */
    function add_template($group, $template, $activate = FALSE) {
        if (!isset($this->config[$group])) {
            $this->config[$group] = $template;
            if ($activate === TRUE) {
                $this->initialize($template);
            }
        } else {
            show_error('The "' . $group . '" template group already exists. Use a different group name.');
        }
    }

    // --------------------------------------------------------------------

    /**
     * Initialize class settings using config settings
     *
     * @access  public
     * @param   array   configuration array
     * @return  void
     */
    function initialize($props) {
        // Set master template
        if (isset($props['template'])
                && (file_exists(APPPATH . 'views/' . $props['template']) or file_exists(APPPATH . 'views/' . $props['template'] . EXT))) {
            $this->master = $props['template'];
        } else {
            // Master template must exist. Throw error.
            show_error('Either you have not provided a master template or the one provided does not exist in <strong>' . APPPATH . 'views</strong>. Remember to include the extension if other than ".php"');
        }

        // Load our regions
        if (isset($props['regions'])) {
            $this->set_regions($props['regions']);
        }

        // Set parser and parser method
        if (isset($props['parser'])) {
            $this->set_parser($props['parser']);
        }
        if (isset($props['parser_method'])) {
            $this->set_parser_method($props['parser_method']);
        }

        // Set master template parser instructions
        $this->parse_template = isset($props['parse_template']) ? $props['parse_template'] : FALSE;
    }

    // --------------------------------------------------------------------

    /**
     * Set regions for writing to
     *
     * @access  public
     * @param   array   properly formed regions array
     * @return  void
     */
    function set_regions($regions) {
        if (count($regions)) {
            $this->regions = array(
                '_scripts' => array(),
                '_styles' => array(),
                '_meta' => array()
            );
            foreach ($regions as $key => $region) {
                // Regions must be arrays, but we take the burden off the template 
                // developer and insure it here
                if (!is_array($region)) {
                    $this->add_region($region);
                } else {
                    $this->add_region($key, $region);
                }
            }
        }
    }

    // --------------------------------------------------------------------

    /**
     * Dynamically add region to the currently set template
     *
     * @access  public
     * @param   string   Name to identify the region
     * @param   array Optional array with region defaults
     * @return  void
     */
    function add_region($name, $props = array()) {
        if (!is_array($props)) {
            $props = array();
        }

        if (!isset($this->regions[$name])) {
            $this->regions[$name] = $props;
        } else {
            show_error('The "' . $name . '" region has already been defined.');
        }
    }

    // --------------------------------------------------------------------

    /**
     * Empty a region's content
     *
     * @access  public
     * @param   string   Name to identify the region
     * @return  void
     */
    function empty_region($name) {
        if (isset($this->regions[$name]['content'])) {
            $this->regions[$name]['content'] = array();
        } else {
            show_error('The "' . $name . '" region is undefined.');
        }
    }

    // --------------------------------------------------------------------

    /**
     * Set parser
     *
     * @access  public
     * @param   string   name of parser class to load and use for parsing methods
     * @return  void
     */
    function set_parser($parser, $method = NULL) {
        $this->parser = $parser;
        $this->CI->load->library($parser);

        if ($method) {
            $this->set_parser_method($method);
        }
    }

    // --------------------------------------------------------------------

    /**
     * Set parser method
     *
     * @access  public
     * @param   string   name of parser class member function to call when parsing
     * @return  void
     */
    function set_parser_method($method) {
        $this->parser_method = $method;
    }

    // --------------------------------------------------------------------

    /**
     * Write contents to a region
     *
     * @access	public
     * @param	string	region to write to
     * @param	string	what to write
     * @param	boolean	FALSE to append to region, TRUE to overwrite region
     * @return	void
     */
    function write($region, $content, $overwrite = FALSE) {
        if (isset($this->regions[$region])) {
            if ($overwrite === TRUE) { // Should we append the content or overwrite it
                $this->regions[$region]['content'] = array($content);
            } else {
                $this->regions[$region]['content'][] = $content;
            }
        }

        // Regions MUST be defined
        else {
            show_error("Cannot write to the '{$region}' region. The region is undefined.");
        }
    }

    // --------------------------------------------------------------------

    /**
     * Write content from a View to a region. 'Views within views'
     *
     * @access	public
     * @param	string	region to write to
     * @param	string	view file to use
     * @param	array	variables to pass into view
     * @param	boolean	FALSE to append to region, TRUE to overwrite region
     * @return	void
     */
    function write_view($region, $view, $data = NULL, $overwrite = FALSE) {
        $args = func_get_args();

        // Get rid of non-views
        unset($args[0], $args[2], $args[3]);

        // Do we have more view suggestions?
        if (count($args) > 1) {
            foreach ($args as $suggestion) {
                if (file_exists(APPPATH . 'views/' . $suggestion . EXT) or file_exists(APPPATH . 'views/' . $suggestion)) {
                    // Just change the $view arg so the rest of our method works as normal
                    $view = $suggestion;
                    break;
                }
            }
        }

        $content = $this->CI->load->view($view, $data, TRUE);
        $this->write($region, $content, $overwrite);
    }

    // --------------------------------------------------------------------

    /**
     * Parse content from a View to a region with the Parser Class
     *
     * @access  public
     * @param   string   region to write to
     * @param   string   view file to parse
     * @param   array variables to pass into view for parsing
     * @param   boolean  FALSE to append to region, TRUE to overwrite region
     * @return  void
     */
    function parse_view($region, $view, $data = NULL, $overwrite = FALSE) {
        $this->CI->load->library('parser');

        $args = func_get_args();

        // Get rid of non-views
        unset($args[0], $args[2], $args[3]);

        // Do we have more view suggestions?
        if (count($args) > 1) {
            foreach ($args as $suggestion) {
                if (file_exists(APPPATH . 'views/' . $suggestion . EXT) or file_exists(APPPATH . 'views/' . $suggestion)) {
                    // Just change the $view arg so the rest of our method works as normal
                    $view = $suggestion;
                    break;
                }
            }
        }

        $content = $this->CI->{$this->parser}->{$this->parser_method}($view, $data, TRUE);
        $this->write($region, $content, $overwrite);
    }

    // --------------------------------------------------------------------

    /**
     * Dynamically include javascript in the template
     * 
     * NOTE: This function does NOT check for existence of .js file
     *
     * @access  public
     * @param   string   script to import or embed
     * @param   string  'import' to load external file or 'embed' to add as-is
     * @param   boolean  TRUE to use 'defer' attribute, FALSE to exclude it
     * @return  TRUE on success, FALSE otherwise
     */
    function add_js($script, $type = 'import', $defer = FALSE) {
        $success = TRUE;
        $js = NULL;

        $this->CI->load->helper('url');

        switch ($type) {
            case 'import':
                $filepath = base_url() . $script;
                $js = '<script type="text/javascript" src="' . $filepath . '"';
                if ($defer) {
                    $js .= ' defer="defer"';
                }
                $js .= "></script>";
                break;

            case 'embed':
                $js = '<script type="text/javascript"';
                if ($defer) {
                    $js .= ' defer="defer"';
                }
                $js .= ">";
                $js .= $script;
                $js .= '</script>';
                break;

            default:
                $success = FALSE;
                break;
        }

        // Add to js array if it doesn't already exist
        if ($js != NULL && !in_array($js, $this->js)) {
            $this->js[] = $js;
            $this->write('_scripts', $js);
        }

        return $success;
    }

    // --------------------------------------------------------------------

    /**
     * Dynamically include CSS in the template
     * 
     * NOTE: This function does NOT check for existence of .css file
     *
     * @access  public
     * @param   string   CSS file to link, import or embed
     * @param   string  'link', 'import' or 'embed'
     * @param   string  media attribute to use with 'link' type only, FALSE for none
     * @return  TRUE on success, FALSE otherwise
     */
    function add_css($style, $type = 'link', $media = FALSE) {
        $success = TRUE;
        $css = NULL;

        $this->CI->load->helper('url');
        $filepath = base_url() . $style;

        switch ($type) {
            case 'link':

                $css = '<link type="text/css" rel="stylesheet" href="' . $filepath . '"';
                if ($media) {
                    $css .= ' media="' . $media . '"';
                }
                $css .= ' />';
                break;

            case 'import':
                $css = '<style type="text/css">@import url(' . $filepath . ');</style>';
                break;

            case 'embed':
                $css = '<style type="text/css">';
                $css .= $style;
                $css .= '</style>';
                break;

            default:
                $success = FALSE;
                break;
        }

        // Add to js array if it doesn't already exist
        if ($css != NULL && !in_array($css, $this->css)) {
            $this->css[] = $css;
            $this->write('_styles', $css);
        }

        return $success;
    }

    // --------------------------------------------------------------------

    /**
     * Dynamically include meta tags in the template
     * 
     * @param string $key meta name
     * @param string $value meta content
     * @return bool
     */
    function add_meta($key, $val) {
        $success = FALSE;
        $meta = '<meta name="' . $key . '" content="' . $val . '" />';

        if (!in_array($meta, $this->meta)) {
            $this->meta[] = $meta;
            $this->write('_meta', $meta);
            $success = TRUE;
        }

        return $success;
    }

    /**
     * Render the master template or a single region
     *
     * @access	public
     * @param	string	optionally opt to render a specific region
     * @param	boolean	FALSE to output the rendered template, TRUE to return as a string. Always TRUE when $region is supplied
     * @return	void or string (result of template build)
     */
    function render($region = NULL, $buffer = FALSE, $parse = FALSE) {
        // Just render $region if supplied
        if ($region) { // Display a specific regions contents
            if (isset($this->regions[$region])) {
                $output = $this->_build_content($this->regions[$region]);
            } else {
                show_error("Cannot render the '{$region}' region. The region is undefined.");
            }
        }

        // Build the output array
        else {
            foreach ($this->regions as $name => $region) {
                $this->output[$name] = $this->_build_content($region);
            }

            if ($this->parse_template === TRUE or $parse === TRUE) {
                // Use provided parser class and method to render the template
                $output = $this->CI->{$this->parser}->{$this->parser_method}($this->master, $this->output, TRUE);

                // Parsers never handle output, but we need to mimick it in this case
                if ($buffer === FALSE) {
                    $this->CI->output->set_output($output);
                }
            } else {
                // Use CI's loader class to render the template with our output array
                $output = $this->CI->load->view($this->master, $this->output, $buffer);
            }
        }

        return $output;
    }

    // --------------------------------------------------------------------

    /**
     * Load the master template or a single region
     *
     * DEPRECATED!
     * 
     * Use render() to compile and display your template and regions
     */
    function load($region = NULL, $buffer = FALSE) {
        $region = NULL;
        $this->render($region, $buffer);
    }

    // --------------------------------------------------------------------

    /**
     * Build a region from it's contents. Apply wrapper if provided
     *
     * @access	private
     * @param	string	region to build
     * @param	string	HTML element to wrap regions in; like '<div>'
     * @param	array	Multidimensional array of HTML elements to apply to $wrapper
     * @return	string	Output of region contents
     */
    function _build_content($region, $wrapper = NULL, $attributes = NULL) {
        $output = NULL;

        // Can't build an empty region. Exit stage left
        if (!isset($region['content']) or !count($region['content'])) {
            return FALSE;
        }

        // Possibly overwrite wrapper and attributes
        if ($wrapper) {
            $region['wrapper'] = $wrapper;
        }
        if ($attributes) {
            $region['attributes'] = $attributes;
        }

        // Open the wrapper and add attributes
        if (isset($region['wrapper'])) {
            // This just trims off the closing angle bracket. Like '<p>' to '<p'
            $output .= substr($region['wrapper'], 0, strlen($region['wrapper']) - 1);

            // Add HTML attributes
            if (isset($region['attributes']) && is_array($region['attributes'])) {
                foreach ($region['attributes'] as $name => $value) {
                    // We don't validate HTML attributes. Imagine someone using a custom XML template..
                    $output .= " $name=\"$value\"";
                }
            }

            $output .= ">";
        }

        // Output the content items.
        foreach ($region['content'] as $content) {
            $output .= $content;
        }

        // Close the wrapper tag
        if (isset($region['wrapper'])) {
            // This just turns the wrapper into a closing tag. Like '<p>' to '</p>'
            $output .= str_replace('<', '</', $region['wrapper']) . "\n";
        }

        return $output;
    }

}

// END Template Class

/* End of file Template.php */
/* Location: ./application/libraries/Template.php */

Step 3. So we need to load the template library only once and the template library will be used in subsequent requets. So autoload it using autoload.php configuration under <project root>/application/config/ directory.

$autoload['libraries'] = array('template');

Step 4. Create a template view file template.php and put it under <project root>/aplication/views/template/ directory. The below file is self explanatory if you see the comments.

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
		<!-- meta keywords specific to the page -->
        {_meta}
		<!-- page title specific to the page -->
        <title>{title}</title>
        <!--[if IE]> <script> (function() { var html5 = ("abbr,article,aside,audio,canvas,datalist,details," + "figure,footer,header,hgroup,mark,menu,meter,nav,output," + "progress,section,time,video").split(','); for (var i = 0; i < html5.length; i++) { document.createElement(html5[i]); } try { document.execCommand('BackgroundImageCache', false, true); } catch(e) {} })(); </script> <![endif]-->
		<!-- template style -->
		<link type="text/css" rel="stylesheet" href="<?php echo base_url(); ?>assets/css/template.css"/>
		<!-- other style sheet -->
        <link type="text/css" rel="stylesheet" href="<?php echo base_url(); ?>assets/css/other.css"/>
		<!-- js file -->
        <script src="<?php echo base_url(); ?>assets/js/jquery-1.9.1.min.js"></script>
		<!-- style sheets specific to the page -->
        {_styles}
		<!-- js files specific to the page -->
        {_scripts}
    </head>
    <body>
        <div id='headerpic-wrapper'>
            <div class='clearfix' id='topnav'>
                <div class='menu-topnav-container'>
                    <ul class='menu' id='menu-topnav'>
                            <li><a href=''>Signin</a></li>
                            <li><a href=''>Signup</a></li>
                            <li><a class='trigger' href='#'>My Activities</a>
                                <ul>
                                    <li>
                                        <a href=''>My Feedback</a>
                                    </li>
                                    <li>
                                        <a href=''>My Blogs</a>
                                    </li>
                                    <li>
                                        <a href=''>Post Blog</a>
                                    </li>
                                </ul>
                            </li>
                            <li><a class='trigger' href=''>Account</a>
                                <ul>
                                    <li>
                                        <a href=''>Change Email</a>
                                    </li>
                                    <li>
                                        <a href=''>Change Password</a>
                                    </li>
                                </ul>
                        </li>
                        <li><a href=''>Singout</a></li>
                        <li><a class='trigger' href='#'>Find Us</a>
                            <ul>
                                <li><a href='#'>Facebook</a></li>
                                <li><a href='#'>Twitter</a></li>
                                <li><a href='#'>Google +</a></li>
                            </ul>
                        </li>
                    </ul>
                </div>
            </div>
        </div><!-- end header-wrapper -->
        <div id='menuwrapperpic'>
            <div id='menuwrapper'>
                <ul id='menubar'>
                    <li><a href=''><img border='0' src='assets/img/template/home_white.png' style='padding:0px;'/></a></li>
                    <li><a class='trigger' href=''>Interview FAQs</a>
                        <ul>
                            <li><a href=''>Category 1</a></li>
							<li><a href=''>Category 2</a></li>
							<li><a href=''>Category 3</a></li>
                        </ul>
                    </li>
                    <li><a href=''>About</a></li>
                    <li><a href=''>Contact</a></li>
                </ul>
                <br class='clearit'/>
            </div>
        </div>
        <div class='clearfix' id='page'>
            <div class='maincontent' id='contentleft'>
                <p id='breadcrumbs'>
                    
                </p>                
                <div class='posts-by-3'>
                    <div class='main section' id='main'>
						<!-- content specific to the page -->
                        {content}
                    </div>
                    <div style='clear: both;'></div>
                </div>
            </div>
            <div id='sidebar-wrapper'>
                <div class='sidebar section' id='sidebar'>
                    <div class='widget PopularPosts' id='PopularPosts1'>
                        <h2>Popular Posts</h2>
                        <div class='widget-content popular-posts'>
                            <ul>
                                
                            </ul>
                            <div class='clear'></div>
                        </div>
                    </div>
                    <div class='widget LinkList' id='LinkList1'>
                        <h2>Recent Posts</h2>
                        <div class='widget-content'>
                            <ul>
                                
                            </ul>
                            <div style="clear:both;"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div style="clear:both;" id="footer">
            <a href=''>www.roytuts.com</a> &#169; 2012 - <?php echo date('Y'); ?> | Designed by <a href=''>Soumitra Sarkar</a> | <a href=''>Privacy</a> | <a href=''>Terms &amp; Conditions</a>
        </div>        
    </body>
</html>

Step 5. Now we will see how to use the template file. Create a home.php controller file and put it under <project root>/application/controllers/ directory.

<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');

/**
 * Description of home
 *
 * @author Admin
 */
class Home extends Public_Controller {

    function __construct() {
        parent::__construct();
    }

    public function index() {
		$data['home'] = 'This is a Home page. Using Template Library is easy to create content';
        $this->template->write('title', 'Welcome to Codeigniter Template Library', TRUE);
        $this->template->write_view('content', 'home', $data, TRUE);
        $this->template->render();
    }

}

/* End of file home.php */
/* Location: ./application/controllers/home.php */

The $data[‘home’] variable contains the text which will be shown in home.php file using $home variable as shown in below step.

Step 6. Create a home.php view file and put it under <project root>/application/views/ directory.

<div class='widget'>
	<?php echo $home;?>
</div>

Step 7. Now change the default controller in routes.php file.

$route['default_controller'] = "home";

Step 8. Now run the application you will see the expected output.

Download the source code from template.

Thanks for your reading.

Leave a Reply

Your email address will not be published. Required fields are marked *