This document contains an example for a `ResultPrinter` both for the PHP and JavaScript part and before diving into the details, please make sure you have read ["Writing a result printer"](https://github.com/SemanticMediaWiki/SemanticMediaWiki/blob/master/docs/architecture/writing.resultprinter.md).

## PHP

<pre>
namespace SMW\Query\ResultPrinters;

use SMW\Query\QueryResult;
use SMWDataItem as DataItem;
use SMWDataValue as DataValue;
use MediaWiki\Html\Html;

/**
 * Boilerplate query printer
 *
 * Add your description here ...
 *
 * @license GNU GPL v2+
 * @since 3.0
 *
 * @author mwjames
 */
class BoilerplateResultPrinter extends ResultPrinter {

	/**
	 * @see ResultPrinter::getName
	 *
	 * {@inheritDoc}
	 */
	public function getName() {
		// Add your result printer name here
		return wfMessage( 'foo-boilerplate' )->text();
	}

	/**
	 * @see ResultPrinter::getParamDefinitions
	 *
	 * {@inheritDoc}
	 */
	public function getParamDefinitions( array $definitions ) {
		$definitions = parent::getParamDefinitions( $definitions );

		// Add your parameters here

		// Example of a unit parameter
		$definitions['unit'] = [
			'message' => 'foo-paramdesc-unit',
			'default' => '',
		];

		return $definitions;
	}

	/**
	 * @see ResultPrinter::getResources
	 *
	 * {@inheritDoc}
	 */
	protected function getResources() {

		// Add resource definitions that has been registered with `Resource.php`
		// Resource definitions contain scripts, styles, messages etc.

		return [
			'modules' => [
				'foo.boilerplate'
			],
			'styles' => [
				'foo.boilerplate.styles'
			]
		];
	}

	/**
	 * @see ResultPrinter::getResultText
	 *
	 * {@inheritDoc}
	 */
	protected function getResultText( QueryResult $queryResult, $outputMode ) {

		// Data processing
		// It is advisable to separate data processing from output logic
		$data = $this->preprocess( $queryResult, $outputMode );

		// Check if the data processing returned any results otherwise just bailout
		if ( $data === [] ) {
			// Add an error message to return method
			return $queryResult->addErrors( 'some-error' );
		} else {
			// Add options if needed to format the output

			// $outputMode can be specified as
			// SMW_OUTPUT_HTML
			// SMW_OUTPUT_FILE
			// SMW_OUTPUT_WIKI

			// For implementing template support this options has to be set but if you
			// manipulate data via jQuery/JavaScript it is less likely that you need
			// this option since templates will influence how wiki text is parsed
			// but will have no influence in how a HTML representation is altered
			// $this->hasTemplates = true;

			$options = [
				'mode' => $outputMode
			];

			// Return formatted results
			return $this->buildHTML( $data, $options );
		}
	}

	/**
	 * Returns an array with data
	 *
	 * @return array
	 */
	private function preprocess( QueryResult $queryResult, $outputMode ) {

		$data = [];

		// This is an example implementation on how to select available data from
		// a result set. Please make appropriate adoptions necessary for your
		// application.

		// Some methods are declared as private to show case which objects are
		// directly accessible within QueryResult

		// Get all SMWDIWikiPage objects that make up the results
		// $subjects = $this->getSubjects( $queryResult->getResults() );

		// Get all print requests property labels
		// $labels = $this->getLabels( $queryResult->getPrintRequests() );

		/**
		 * Get all values for all rows that belong to the result set
		 *
		 * @var ResultArray $rows
		 */
		while ( $rows = $queryResult->getNext() ) {

			/**
			 * @var ResultArray $field
			 * @var DataValue $dataValue
			 */
			foreach ( $rows as $field ) {

				// Initialize the array each time it passes a new row to avoid data from
				// a previous row is remaining
				$rowData = [];

				// Get the label for the current property
				$propertyLabel = $field->getPrintRequest()->getLabel();

				// Get the label for the current subject
				// getTitle()->getText() will return only the main text without the
				// fragment(#) which can be arbitrary in case subobjects are involved

				// getTitle()->getFullText() will return the text with the fragment(#)
				// which is important when using subobjects
				$subjectLabel = $field->getResultSubject()->getTitle()->getFullText();

				while ( ( $dataValue = $field->getNextDataValue() ) !== false ) {

					// Get the data value item
					$rowData[] = $this->getDataValueItem( $dataValue->getDataItem()->getDIType(), $dataValue );
				}

				// Example how to build a hierarchical array by collecting all values
				// belonging to one subject/row using labels as array key representation
				$data[$subjectLabel][$propertyLabel][] = $rowData;
			}
		}

		// Return the data
		// return array( 'labels' => $labels, 'subjects' => $subjects, 'data' => $data );
		return $data;
	}

	/**
	 * A quick getway method to find all SMWDIWikiPage objects that make up the
	 * results
	 *
	 * @return array
	 */
	private function getSubjects( $result ) {
		$subjects = [];

		foreach ( $result as $wikiDIPage ) {
			$subjects[] = $wikiDIPage->getTitle()->getText();
		}
		return $subjects;
	}

	/**
	 * Get all print requests property labels
	 *
	 * @return array
	 */
	private function getLabels( $result ) {
		$printRequestsLabels = [];

		foreach ( $result as $printRequests ) {
			$printRequestsLabels[] = $printRequests->getLabel();
		}
		return $printRequestsLabels;
	}

	/**
	 * Get a single data value item
	 *
	 * @return mixed
	 */
	private function getDataValueItem( $type, DataValue $dataValue ) {

		if ( $type == DataItem::TYPE_NUMBER ) {

			// Set unit if available
			$dataValue->setOutputFormat( $this->params['unit'] );

			// Check if unit is available and return the converted value otherwise
			// just return a plain number
			if ( $dataValue->getUnit() !== '' ) {
				return $dataValue->getShortWikiText();
			}

			return $dataValue->getNumber();
		}

		// For all other data types return the wikivalue
		return $dataValue->getWikiValue();
	}

	/**
	 * Prepare data for the output
	 *
	 * @return string
	 */
	protected function buildHTML( $data, $options ) {

		// The generated ID is to distinguish similar instances of the same
		// printer that can appear within the same page
		$id = uniqid( 'foo-boilerplate-' . rand( 1, 10000 ) );

		// Used to set that the output and being treated as HTML (opposed to plain wiki text)
		$this->isHTML = true;

		// Correct escaping is vital to minimize possibilities of malicious code snippets
		// and also a coherent string evaluation therefore it is recommended
		// that data transferred to the JS plugin is JSON encoded

		// Assign the ID to make a data instance readily available and distinguishable
		// from other content within the same page
		$requireHeadItem = [ $id => json_encode( $data ) ];
		\SMWOutputs::requireHeadItem( $id, \Skin::makeVariablesScript( $requireHeadItem ) );

		// Add two elements a outer wrapper that is assigned a class which the JS plugin
		// can select and will fetch all instances of the same result printer and an inner
		// container which is set invisible (display=none) for as long as the JS plugin
		// holds the content hidden. It is normally the place where the "hard work"
		// is done hidden from the user until it is ready.
		// The JS plugin can prepare the output within this container without presenting
		// unfinished visual content, to avoid screen clutter and improve user experience.
		return Html::rawElement(
			'div',
			[
				'class' => 'foo-boilerplate'
			],
			Html::element(
				'div',
				[
					'id' => $id,
					'class' => 'container',
					'style' => 'display:none;'
				]
			)
		);
	}

}
</pre>

## JavaScript

<pre>
/**
 * @license GNU GPL v2+
 * @since 3.0
 *
 * @author mwjames
 */
( function( $, mw ) {

	// Use EcmaScript 5 to improve code quality and check with jshint/jslint
	// if the code adheres standard coding conventions

	// Strict mode eliminates some JavaScript pitfalls
	'use strict';

	// Passing jshint
	/*global mediaWiki:true */

	/**
	 * @type Object
	 */
	foo = {};

	/**
	 * Base constructor for objects representing a boilerplate instance
	 *
	 * @type Object
	 */

	// If you have default values to be set during the instantiation
	// $.extend ... can be used here
	foo.boilerplate = function() {};

	foo.boilerplate.prototype = {
		// Specify your functions and parameters
		show: function( context ) {
			return context.each( function() {

				// Ensure variables have only local scope otherwise leaked content might
				// cause issues for other plugins
				var that = $( this );

				// Find the container instance that was created by the PHP output
				// and store it as "container" variable which all preceding steps
				// working on a localized instance
				var container = that.find( '.container' );

				// Find the ID that connects to the current instance with the published data
				var id = container.attr( 'id' );

				// Fetch the stored data with help of mw.config.get() method and the current instance ID
				// @see https://www.mediawiki.org/wiki/ResourceLoader/Default_modules#mediaWiki.config
				var json = mw.config.get( id );

				// Parse the fetched json string and convert it back into objects/arrays
				var data = typeof json === 'string' ? jQuery.parseJSON( json ) : json;

				// You got everything you need to work your magic
				// A clean instance, data from the wiki, and a separate container

				// If you need to see what data you've got from your result printer
				// it is always helpful to do

				// console.log( data );

				// Happy coding ...
			} );
		}
	};

	/**
	 * Implementation and representation of the boilerplate instance
	 *
	 * @type Object
	 */

	// Create class instance
	var boilerplate = new foo.boilerplate();

	$( document ).ready(function() {

		// Use the class selector to find all instances relevant to the "boilerplate" printer
		// since a wiki page can have more than one instance of the same result printer
		// .each() ensures instances are handled separately
		$( '.foo-boilerplate' ).each(function() {

			// Access methods available through the boilerplate class
			boilerplate.show( $( this ) );
		} );
	} );

} )( jQuery, mediaWiki );
</pre>
