Hashtag Markup
Introduction
This document defines and explains the syntax of the Hashtag Markup Language. For more information about processing Hashtag Markup using the Hashtag Framework, see the Setup Guide, or the Development Guide.
Conventions
These conventions will be used when describing Hashtag Markup syntax.
Bold | ⇒ | Markup keyword — Literal value |
Italic | ⇒ | Variable name — Replaced with arbitrary value |
( A | B ) | ⇒ | Mandatory Choice, options delimited with | |
[ ] | ⇒ | Optional / Optional Choice |
… | ⇒ | Optionally repeat |
These terms will be used to describe Hashtag Markup.
Tag | ⇒ | Markup that begins with <# and ends with #> |
Command | ⇒ | Tag content that begins with a command keyword |
Block | ⇒ | Tag containing multiple Commands, delimited with ; |
Directive | ⇒ | Command that extends a previous Command in the same Block |
Template | ⇒ | Markup that is processed conditionally or repetitively |
Markup Comments
Comments allow for private notes to be added to Hashtag Markup. Comments are stripped from Markup by the Hashtag Framework, and never delivered to the end-user. Single-line comments begin with // wherever a Command could start, ending with any vertical-whitespace character. Multi-line comments begin with <#: and end with :#>.
// single-line comment
Command ; // single-line comment
#>
multi-line comment
multi-line comment :#>
Variables
Hashtag Variables store a value that can later be referenced by name to use the stored value. Variables are not assigned a type, such as number or text, rather Contexts can be applied when storing or using the values. Variable values can be injected into Markup using Variable Tags. Variables are either Global, or Local to a Template.
Buckets
Hashtag Buckets are collections of variables using the same delimited prefix. Variable Buckets are period . delimited, for example: user.name and user.address are both in the user Bucket. Buckets can be sent as collections of values to external APIs. The print bucket Command creates a nested HTML representation of all Variable names and values in a Bucket, useful for development testing. The empty bucket Command deletes all Variables in a Bucket. Bucket Loop Templates enable processing every Variable value in a given Bucket.
Reserved Buckets
The following Buckets are reserved by the Hashtag Framework: System, Config, Request, URL, URI, GET, POST, Form, Session, Cookie, and Cache.
Session, Cookie, and Cache are special Buckets that store Variable values using different methods. The Session bucket uses the configured PHP Session Handler, generally set to use an in-memory cache. Setting a value in the Session bucket will make it available in any future requests made by the same user. The Cookie bucket is populated with HTTP Cookie values sent with the request. Setting a value in the Cookie bucket will include the new value in the response, instructing the browser to send it back with any future requests. The Cache bucket uses the configured key→value store, such as Memcached. Setting a value in the Cache bucket will make it available in any future requests made by any user, but values may be deleted at any time to make room for new values.
The Config bucket is populated with the current Hashtag Framework Configuration. To learn more, read the Configuration Guide
System Bucket
The Hashtag Framework provides the following values in the reserved System Bucket:
Name | Description |
---|---|
date | Sortable Date — YYYY/MM/DD |
date_time | Date with 12h Time with Timezone |
date_time_short | Sortable Date with 24h Time — YYYY/MM/DD HH:MM:SS |
timestamp | Whole seconds since Unix Epoch |
timestamp_float
timestamp_long |
Seconds since Unix Epoch with decimal precision |
time | 12H Time with Timezone |
time_short | 24H Time |
month | 2 digit Month number — Leading 0 for 1-9 |
month_short | 1-2 digit Month number |
month_name | Month Name |
month_name_short | 3 Letter Month Name |
day | 2 digit Day of month number — Leading 0 for 1-9 |
day_short | 1-2 digit Day of month number |
day_name | Day of the week — Monday, Tuesday... |
day_name_short | 3 Letter Day of the week — Mon, Tue... |
year | Current Year |
domain | Current Domain |
page | Current Page Name |
request | Request URI |
host | Host name — Domain with optional Port |
host_url | URL of the Host |
secure_host_url | Secure URL of the Host |
session_id | Session ID for current user |
referrer | Referring URL — Ensures a trailing ? |
referring_host | Referring Host |
referring_host_url | Referring Host URL |
secure_referring_host_url | Secure URL for the Referring Host |
secure_referring_page_url | Secure URL for the Referring Page |
referring_scheme | Protocol Scheme from the Referring URL |
referring_query | Query string from the Referring URL |
remote_addr | Remote End-User IP Address |
Request Bucket
The Hashtag Framework automatically adds all HTTP POST and GET values to the reserved Request Bucket. HTTP POST values are also added to the Post Bucket. HTTP GET values are also set in the URL, URI, and Get Bucket.
Applying Contexts
Hashtag Contexts can control how values are interpreted or formatted. For example, encoding user provided text for inclusion in a HTML page, or adjusting a timestamp value according to the end user timezone. Contexts can be applied to variables directly, or to string values in many Commands. Contexts are case-insensitive, and can be chained.
Context | Description | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Text Contexts |
|||||||||||||||||||||||||||
lower
lowercase |
Converts all characters to lowercase | ||||||||||||||||||||||||||
upper
uppercase |
Converts all characters to UPPERCASE | ||||||||||||||||||||||||||
trim
trimmed |
Strips all whitespace characters from both ends | ||||||||||||||||||||||||||
name
label word |
Strips all non-alphanumeric characters except _ and - | ||||||||||||||||||||||||||
HTML
web websafe |
Converts HTML control characters into their HTML encodings, and converts new-line characters into HTML <br> tags. All user provided data that is intended to be displayed as-is in an HTML page should use this context to prevent HTML/CSS/JavaScript injection. | ||||||||||||||||||||||||||
pre | Similar to HTML context, but new-line characters are not converted to HTML <br> tags | ||||||||||||||||||||||||||
csv | Replaces " characters with "" so the value is safe to inject in a "double-quoted CSV value" | ||||||||||||||||||||||||||
URL
URI |
Convert URL control characters into their URL encodings. Any variable injected into a URL query param that may contain URL control characters should use this context to avoid URL corruption. | ||||||||||||||||||||||||||
Numeric Contexts |
|||||||||||||||||||||||||||
number
numeric decimal |
Strips everything except 0-9, the negation sign (-), and the decimal separator (.) | ||||||||||||||||||||||||||
integer
int |
Converts to numeric then strips any decimal value. default is 0. | ||||||||||||||||||||||||||
multiple "number" | Converts to numeric then multiplies by number. | ||||||||||||||||||||||||||
hex | Converts numeric to hexadecimal value. default is 0. | ||||||||||||||||||||||||||
abs | Converts to numeric then strips any negation. default is 0. | ||||||||||||||||||||||||||
pluralized "format string" | Converts value to numeric, then uses the | character to split format string. If the value is 1, the first half of the split format string is appended to the value after a space; Otherwise, the 2nd half of the format string is appended to the value after a space. | ||||||||||||||||||||||||||
negativeswitch "format string" | Converts value to numeric, then uses the | character to split format string. If the value is negative, the first half of the split format string is returned; Otherwise, the 2nd half of the format string is returned. | ||||||||||||||||||||||||||
changepercent | Converts value to numeric with 2 decimal places, then appends % after a space, and prepends either + or - before a space. | ||||||||||||||||||||||||||
currency | Strips all non-numeric characters, rounds to 2 decimals, and formats as X,XXX.XX | ||||||||||||||||||||||||||
altcurrency | Strips all non-numeric characters, rounds to 2 decimals, and formats as X.XXX,XX | ||||||||||||||||||||||||||
dollar
dollars USD |
Strips all non-numeric characters, rounds to 2 decimals, and formats as $ X,XXX.XX | ||||||||||||||||||||||||||
euro
euros EUR |
Strips all non-numeric characters, rounds to 2 decimals, and formats as € X.XXX,XX | ||||||||||||||||||||||||||
Date & Time Contexts |
|||||||||||||||||||||||||||
timespan
span seconds |
Converts a value in the format h:mm:ss to total number of seconds | ||||||||||||||||||||||||||
minutes | Converts a value in the format h:mm:ss to total number of minutes | ||||||||||||||||||||||||||
hours | Converts a value in the format h:mm:ss to total number of hours | ||||||||||||||||||||||||||
timestamp | converts date values into total number of seconds since jan 1st 1970 (unix timestamp). both of these formats are supported: "09/19/2013 8:30 AM", "1979-01-17 07:43:34". | ||||||||||||||||||||||||||
day | Converts the value into a timestamp, then returns the integer day of month for the date | ||||||||||||||||||||||||||
month | Converts the value into a timestamp, then returns the integer month of year for the date | ||||||||||||||||||||||||||
year | Converts the value into a timestamp, then returns the year for the date | ||||||||||||||||||||||||||
timestamp + adjustment
timestamp - adjustment |
converts the value into a timestamp, then applies the adjustment.
|
||||||||||||||||||||||||||
timespan "format string" | Replacement tokens for format string:
d = days hh = 2 digit hours h = 1-2 digit hours mm = 2 digit minutes m = 1-2 digit minutes ss = 2 digit seconds s = 1-2 digit seconds |
||||||||||||||||||||||||||
date | Converts the value into a timestamp, then returns the date formatted as m/d/Y | ||||||||||||||||||||||||||
date "format string"
datetime "format string" |
replacement tokens for "format string"
M = 2 digit month MM = full month name D = 2 digit day of month DD = day of month with suffix (1st, 2nd, …) Y = 4 digit year hh = 2 digit hour in 24 hour time h = 1-2 digit hour in 12 hour time mm = 2 digit minutes m = 1-2 digit minutes ss = 2 digit seconds s = 1-2 digit seconds A = AM or PM |
||||||||||||||||||||||||||
datetime | Converts the value into a timestamp, then returns the date formatted as m/d/Y g:i:s A | ||||||||||||||||||||||||||
phpdate "format string" | Replacement tokens for format string are defined by PHP as date function tokens. | ||||||||||||||||||||||||||
Timezone Adjustments |
|||||||||||||||||||||||||||
tz
timezone |
The "session.timezone" or "session.tz" value will be applied, and the datetime or timestamp string will be converted and returned in its original format | ||||||||||||||||||||||||||
tz "timezone"
timezone "timezone" |
timezone value will be applied and the datetime or timestamp string will be converted and returned in its original format | ||||||||||||||||||||||||||
tz using variable
timezone using variable |
variable will be applied and the datetime or timestamp string will be converted and returned in its original format | ||||||||||||||||||||||||||
Hash Algorithms |
|||||||||||||||||||||||||||
hash [
salted by "string" |
salted by variable |
using "algorithm" ]…
|
Value is hashed using an optional salt provided as a "string" or variable value. The default hash algorithm is sha256. Hashtag supports all of the hash algorithms supported by PHP. | ||||||||||||||||||||||||||
Form Contexts |
|||||||||||||||||||||||||||
querylink | Parses the value as a URL, strips any duplicate URL query params, and ensures the URL has a "?" | ||||||||||||||||||||||||||
bucket | Splits the value on . characters, trims whitespace, and returns the first half of the split value. | ||||||||||||||||||||||||||
key | Splits the value on . characters, trims whitespace, and returns the second half of the split value. |
Set Command
The set Command stores a value for a Variable. Contexts can be applied to the end of the command. The named variable can include Bucket names nested with . period characters. The system Bucket is reserved, and can not be used for storing values using the set Command.
multi-line
value
""" [ as context ]… ;
The math_expression can include Variable Tags, but after those values are injected, the resulting expression can only contain whitespace and these characters: 0123456789.+-*/()^!%.
The set Command has built in support to generate a new UUID value and store it as a variable.
When using random cents, the generated random number will have 2 digit decimal precision. An alternate syntax using the .. operator is also supported.
All of the logical_comparison filters supported by include when Directives can be used to filter random records.
All of the logical_comparison filters supported by include when Directives can be used to filter counted records.
The set Command has built in support to lookup a Google Drive Folder ID by name. If the folder doesn’t exist, it will be created automatically, and the ID for the new Folder will be set for the variable. When a new Google Drive Folder is created, the public or private keyword is used to set permissions.
Round Command
The round Command is used to round a value to a specified number of decimal places.
Replace Command
The replace Command is to used to alter a value, finding and replacing a string or pattern with another string.
The optional i keyword enables case insensitive matching. The more readable case insensitive is also supported, as well as simply insensitive or ci. The pattern keyword for Regular Expression matching can be replaced with re, regex, or regular expression.
Append Command
The append Command is to used to alter a value by appending with another string. An optional using value can be provided to join non-blank values, such as when creating a comma separated list.
Increment Command
The increment Command is to used to alter a numeric value by adding another value.
Decrement Command
The decrement Command is to used to alter a numeric value by subtracting another value.
Print Command
The print Command allows for outputting a string of text, that may include Variable Tags or applied Contexts.
The optional if set else conditional can be used when the original text contains only Variable Tags, and alternate text should be printed when the original text results in only white-space after Variable Tag values are injected.
Redirect Command
The redirect Command is used to redirect the request to another page URL.
Note: The semi-colon ; is optional when a Tag contains only a single redirect Command.
Conditionals — If, Else
Conditionals are used to limit execution based on logical expressions. Hashtag Markup supports multiple forms of Conditionals: Templates and { Blocks }.
Template
[<# else if logical_expression #>
Template ]…
[<# else #>
Template ]
<# end if #>
A logical_expression is a comparison of "double-quoted" values that may include Variable Tags. Comparison operators include: is, =, ==, ===, is not, !=, !==, <>, >, >=, <, <=. ( Paren ) nesting is also supported, with logical operators: and, &&, or, ||, xor, not, !.
( Command(s); Template | Template )
[ } else if ( logical_expression ) {
( Command(s); Template | Template ) ]…
[ } else {
( Command(s); Template | Template ) ]
} #>
Conditional { Blocks } can simplify Markup in many cases, however, the Hashtag Framework may misinterpret JavaScript } else { structures in the Template in some cases. Conditional Templates should be used in most cases.
Bucket Loops
Hashtag Loops are used to process all Variables in a Bucket. Loops can be nested by increasing the number of leading # in the start and end Tags.
[ loop_directive; ]…
#>
Template
<# end loop #>
When a local_variable is not provided to save the key or value, then the local variables <# key #> and <# value #> will be set.
Range Loops
Hashtag Range Loops are used to repeatedly process a template while incrementing a counter. Loops can be nested by increasing the number of leading # in the start and end Tags.
[ loop_directive; ]…
#>
Template
<# end loop #>
[ loop_directive; ]…
#>
Template
<# end loop #>
The math_expression can include Variable Tags, but after those values are injected, the resulting expression can only contain whitespace and these characters: 0123456789.+-*/()^!%.
When a local_variable is not provided to save the loop counter value, the local variable <# value #> will be set.
Loop Until Conditional
Hashtag Loops Until are used to repeatedly process a Template Until a Conditional is met. Loops can be nested by increasing the leading number of # in the start and end Tags.
[ loop_directive; ]…
#>
Template
<# end loop #>
[ loop_directive; ]…
#>
Template
<# end loop #>
A logical_expression is a comparison of "double-quoted" values that may include Variable Tags. Comparison operators include: is, =, ==, ===, is not, !=, !==, <>, >, >=, <, <=. ( Paren ) nesting is also supported, with logical operators: and, &&, or, ||, xor, not, !.
Lists
Hashtag Lists allow for sets of data records to be retrieved and processed. Multiple back-ends are supported for listed records, including Google Sheets, SQL Databases, and Google Drive Folders.
[ list_directive; ]…
#>
[ <# start list_template #>
<# end list_template #>
<# end list #>
header | ⇒ | Template processed first, only when rows exist |
row | ⇒ | Template processed for each row in the list |
footer | ⇒ | Template processed last, only when rows exist |
no results | ⇒ | Template processed only when no rows exist |
The start list Block defines the source of the data records, as well as any Directives that further sort, filter, process, or paginate the records.
[ list_directive; ]…
#>
The table_name value is stripped of non-word characters, and converted to lowercase before it is used as an SQL Table name. List values will be named according to the column names from the SQL Table.
[ list_directive; ]…
#>
A Google Sheet List will default to the first worksheet if a worksheet name is not selected. Use the include from directive to select a worksheet by name. The sheet_id or sheet_name can include Variable Tags. Local Template variables will be set according the header values for each column in the 1st row.
[ list_directive; ]…
#>
Google Drive Folder List values include: id, uuid, title, name, description, filename, extension, size, type, kind, icon_url, drive_url, thumbnail_url, web_url, download_url, drive_download_url, alternate_url, image_height, image_width, created_on, updated_on, last_modified_by_username.
List Directives
The start list Block can include multiple Directives to further relate, filter, process, sort, or paginate the data. Some Directives have different syntax or capabilities based on the source of the data, such as the differences between SQL Databases and Google Sheets.
Include When — Filter Records
The include when Directive uses a logical_expression similar to Conditionals, but further allows the first operand in comparison expressions to be a field name instead of a "quoted value".
SQL Database Lists support these additional regular expression comparison operators in logical_expression: ~, REGEXP, RLIKE. SQL Database Lists also support the additional comparison operator: in, that compares field values against a quoted comma-separated list of values. SQL Database Lists also support the additional comparison operator: contains, that matches field values containing the quoted value. When the second operand of a comparison expression is a "quoted value" immediately follwed by if set, the expression will be ignored if injecting Variable Tag values results in only whitespace.
[ from "worksheet_name" ]
[ when logical_expression ] ;
Google Sheet Lists support choosing a specific Worksheet with the include from Directive.
Sort Order
The sort by Directive allows for records to be ordered before they are processed. Alternatively, the order by Directive is works exactly the same.
When a type isn't provided, alphabetic ordering is used. When asc or desc is not provided, sorting will be done in ascending order. Instead of asc or desc, a more readable in ascending order or in descending order can be used.
numeric | ⇒ | Uses numeric ordering |
dollars | ⇒ | Strips $ characters, then uses numeric ordering |
upper | ⇒ | Case insensitive alphabetic ordering |
Relate Records
The relate Directive allows related records to be joined together and included as List rows.
When the must keyword is used, only items that have related records will be included.
When relating multiple SQL Database Tables, the show unique Directive will place a limit of one row per record from table_name, regardless of how many related records were matched. There is also support for ( paren ) grouping with AND / OR conditionals.
Exclude Columns
The include columns and exclude columns Directives limit the amount of data that is queried and returned from the database. By default, all field values are queried and made available as Local Template Variables.
Set to Total of
The set to total of Directive allows a Local Template Variable to be incremented by a field value for each row.
The set to total of Command can also be used in the Footer Template, however field is replaced with a Local <# variable #> Tag.
Pager — Rows Per Page
The show number rows per page Directive limits the number of records processed for the List. The Hashtag Framework creates an HTML pager with links to navigate through the pages of records.
A table_name is provided instead of rows when multiple SQL Tables are related together.
Link Pager Anchor
The link pager Directive can be used to append a string value to pager URLs.
Hide Pager
When a rows per page Directive is used, the Hashtag Framework creates an HTML pager. By default, the pager is included before and after the List. When there is only a single page of records, the pager is not included. The show and hide Directives can be used to only include the HTML pager before or after the list, or not at all.
Limit Rows
The limit Directive can be used to set a maximum number of records to process.
Cache List
The cache Directive can be used to store the results of the List for all pages. A Cached List can significantly improve performance for high traffic pages, or for data that doesn't change often.
Save to Variable
The save to Directive can be used to store the List result content in a Hashtag Variable instead of including it in the page.
List Template Variables
List Templates provide additional Local Variables to track the total number of rows, and the current row number.
<# numberofrows #> | ⇒ | Total number of rows in the list |
<# rownumber #> | ⇒ | Current row number starting with 1 |
<# lastrow #> | ⇒ | returns "yes" when the current row is the last row, blank otherwise |
Row Template Commands
Additional Commands are available in the List row Template.
The apply row Command will save all of the Local Row Bucket values to a Global Bucket that can be used after the List. When a bucket_name is not provided, the SQL Table name will be used.
The row loop Command creates a Template that is continually processed for rows that match a given field value. This is used when tables are related together, allowing all related records to be processed for the current row.
Template
<# end row loop #>
The break Command provides controls for List processing. This can be used within a row loop to jump to the next row or the next loop.
Forms
Hashtag Forms provide handlers to process and store submitted data. Multiple back-ends are supported for storing records, including Google Sheets and SQL Databases.
[ form_directive; ]…
#>
Form Template
<# end form #>
The start form Block can define a data back-end for storing records. An optional record_id can be set to pre-populate the form with data from an existing record. Form Directives can be used to set attributes for the HTML <form> tag, or to define Form Action Commands. The Form Template supports all HTML 5 compliant form elements. Tags can be added as attributes to form input elements, this names their field value, and includes it with submitted data.
[ form_directive; ]…
#>
[ "worksheet_name" ] [ row_id ] ;
[ form_directive; ]…
#>
Action Only Forms do not automatically store records of submitted data, but Form Actions can still be used to create or update existing records when the form is processed.
[ form_directive; ]…
#>
Form Directives
The start form Block can include multiple Directives that further control how the form is styled and validated, and how submitted data is handled.
The form Bucket is used to set attributes for the HTML <form> tag, such as class.
Restrict Posts
The restrict posts Directive requires form submissions to include a security code, such as a password or CAPTCHA. The restricted Form Action can be used to redirect failed submissions to a different URL.
[ when restricted redirect to "URL" ; ]
[ when restricted redirect to "URL" ; ]
The form body must include a <# google recaptcha #> tag, which will be replaced with an HTML div tag.
Form Actions
The when form_action Directive sets Commands to be processed when specific Form Actions are triggered. Multiple Directives can be set for each Form Action. Any call JavaScript Command will be executed before the HTML Form is submitted. If the JavaScript evaluates as false the HTML Form will not be submitted.
( Command | call JavaScript ) ;
creating | ⇒ | Processed when a new record is created |
updating | ⇒ | Processed when an existing record is updated |
deleting | ⇒ | Processed when an existing record is deleted |
processing | ⇒ | Processed for Action Only Form submissions |
done | ⇒ | Processed after all other Form Actions are processed |
When Form Action Commands are processed, <# form. field #> Local Variable Tags will inject field values submitted with the form. The <# form.id #> Local Variable Tag can always be used to reference the stored record ID. When existing records are being updated or deleted, Local Variables will be set for each field in the record.
Custom Form Actions are named with <# form_action button #> attributes, added to any HTML button in the Form Template. The default Form Actions are triggered by buttons with these attributes: <# create button #>, <# update button #>, or <# delete button #>. When a form is pre-populated with data from an existing record, the create button will not be included, otherwise the update and delete buttons will not be included. Action Only Forms can use a <# process button #> attribute to trigger the processing Form Action.
Form Template
Hashtag Form Templates support all HTML Form Elements, including the latest HTML 5 Validated Input Types. The following HTML Form Elements can be Tagged as a field by adding a <# field_name #> attribute: input, textarea, select, and button.
A preset value for a field input element can be set using the value attribute, however, all preset values are overwritten when an existing record is loaded. Textarea elements are also overwritten when an existing record record is loaded, and any select elements will have the selected attribute set for the option element that matches the existing record.
For radio input types, the field Tag must be added as an attribute for each radio input choice.
Form Action Button Tags can be added as attributes to any submit or button input types, or <button> tags.
Form Templates are processed as Hashtag Markup before they are parsed for field tags.
Input Validation
Form element attributes, such as required, are validated using added JavaScript when HTML 5 is not supported. Inputs are further validated by the Hashtag Framework Form Handler when data is submitted, but before any records are stored or Form Actions are processed. When submitted data fails validation, the request is redirected back to the Form with errors indicated. The formnovalidate attribute can be added to any button to disable validation.
These HTML Form Input types are validated: email, integer, number, url, date, and range. The Hashtag Framework further supports the decimal, dollars, USD, and datetime Input types.
These HTML Form element attributes are validated: required, pattern, min, max, and step. The Hashtag Framework further supports the unique and case-insensitive-unique attributes, ensuring the field value is unique over all records stored in the same SQL Database Table.
File Uploads
To save uploaded file information in stored records, any <input type="file"> tags in the Form Template can include a field Tag attribute. The Hashtag Framework supports multiple back-ends for storing uploaded files, and can be configured for any local filesystem, Google Cloud Storage, or Amazon S3. A separate back-end can be configured to store private files, which are not directly web accessible. If a back-end was not configured to store uploaded files, PHP may still store the files in a temporary directory, and they will be kept there.
The following field values are added to records with File Uploads:
field | ⇒ | Filename of the uploaded file |
field _type | ⇒ | The mime type provided with the uploaded file |
field _path | ⇒ | The filepath for the stored file |
field _web_url | ⇒ | Public URL for the stored file, unless private keyword set |
field _image_width | ⇒ | Only set for image file uploads |
field _image_height | ⇒ | Only set for image file uploads |
If the Google API has been configured, the following attribute can be used to upload files to Google Drive, regardless of the back-end configured to store file uploads.
The following additional field values are added to records with File Uploads to Google Drive:
field _drive_url | ⇒ | Private URL to edit the file on Google Drive |
field _drive_web_url | ⇒ | Public URL to download the file from Google Drive |
field _drive_thumbnail_url | ⇒ | Public URL for thumbnail image on Google Drive |
Checklist Forms
Checklist Forms are a hybrid of a List and a Form. Standard List Templates are supported to display the included records. Form Templates are extended to support checkbox inputs that allow individual records to be selected.
[ list_directive; | form_directive; | checklist_form_directive; ]…
#>
[ <# start list_template #>
<# end list_template #>
<# end checklist form #>
The start checklist form Block defines the source of the data records, as well as List Directives that further sort, filter, process, or paginate the records. Form Directives are also supported to set HTML <form> tag attributes, or set commands for Form Actions.
[ list_directive; | form_directive; | checklist_form_directive; ]…
#>
Checklist Form Actions
The when form_action Directive is extended to support the additional states: checked, and unchecked.
( Command | call JavaScript ) ;
Checklist Form Templates
The <# checklist item #> Tag can be added as an attribute to any HTML <input type="checkbox"> tag in the row Template. When the checklist is processed, the checked or unchecked Form Actions will be triggered based on this checkbox state.
JSON-RPC Forms & Workers
Hashtag JSON-RPC Forms provide simple methods to create HTML form interfaces powered by JavaScript to send and receive data. JSON-RPC Workers handle requests by processing a Template for the requested action, then return either a result or error.
[ form_directive; ]…
#>
Form Template
[ <# start button_action state #>
<# end button_action state #>
<# end json-rpc form #>
request | ⇒ | JavaScript processed when a request is sent |
response | ⇒ | JavaScript processed when a response is received |
result | ⇒ | JavaScript processed when the response includes a result |
error | ⇒ | JavaScript processed when the response includes a error |
For each state, when JavaScript is processed, an object variable with the same name as the state is provided to hold relevant values.
[ worker_directive; ]…
#>
[ <# start button_action #>
<# end button_action #>
<# end json-rpc worker #>
Data provided with the request is made available in the params Bucket. To return data with the response, the button_action Templates use set Commands to store values in the result or error Bucket. When values have been set in the error Bucket, the result Bucket values will not be included in the response, as JSON-RPC does not allow responses with both result and error.
Record Commands
The following Commands are available to manipulate stored records: apply, create, update, clone, and delete. Multiple back-ends are supported for storing records, such as Google Sheets and SQL Databases.
Apply Record
The apply Command loads a record, then stores all field values as Bucket Variables.
If a record_id is not provided provided, the earliest created record for the Table will be applied. If an alias is not provided, the record will be applied as the table_name.
If the record does not exist, an optional redirect URL can be provided.
[ "worksheet_name" ] row_id [ as "alias" ] ;
Create Record
The create record Command allows new records to be created. Multiple back-ends are supported, including Google Sheets and SQL Databases.
[ create_record_directive; ]…
[ "worksheet_name" ] [ as "alias" ] ;
[ create_record_directive; ]…
Update Record
The update record Command allows for existing records to be updated with new field values. The record is referenced by ID. Each record in a SQL Database table has a column named uuid that is aliased as id. Each row in a Google Sheet has a column with a header row value of Row ID that defaults to column T, but can be located in any column.
[ update_record_directive; ]…
[ "worksheet_name" ] row_id [ as "alias" ] ;
[ update_record_directive; ]…
Clone Record
The clone Command allows for existing records to be duplicated, and assigned a new ID. When an alias is provided, the new record values are stored in the named Bucket.
Delete Record
The delete record Command allows for an existing record to be deleted.
[ "worksheet_name" ] row_id ;
Delete Record List
The delete record list Command allows for multiple existing records to be deleted based on further Directives.
Delete Record List Directives
The delete record list Block can include multiple Directives to further relate, filter, process, sort, or paginate the data. Some Directives have different syntax or capabilities based on the source of the data, such as the differences between SQL Databases and Google Sheets.
Delete When — Filter Records
The delete when Directive uses a logical_expression similar to Conditionals, but further allows the first operand in comparison expressions to be a field name instead of a "quoted value".
SQL Database Lists support these additional regular expression comparison operators in logical_expression: ~, REGEXP, RLIKE. SQL Database Lists also support the additional comparison operator: in, that compares field values against a quoted comma-separated list of values. SQL Database Lists also support the additional comparison operator: contains, that matches field values containing the quoted value. When the second operand of a comparison expression is a "quoted value" immediately follwed by if set, the expression will be ignored if injecting Variable Tag values results in only whitespace. An alternate keyword syntax using filter instead of delete when is also supported.
Relate Records
The relate Directive allows related records to be joined together to create a list of records to delete.
When the must keyword is used, only items that have related records will be included.
When relating multiple SQL Database Tables, the show unique Directive will place a limit of one row per record from table_name, regardless of how many related records were matched. There is also support for ( paren ) grouping with AND / OR conditionals.
Delete All Records
The delete all records Command allows for completely removing all Records, including their back-end storage container.
Import Google Sheet
The import Command is used for importing a Google Sheet into an SQL Database.
[ "worksheet_name" ] into sql_table_name ;
[ import_directive; ]…
When no import_directive is provided, the first row will be assumed to be the column name header, fields will be automatically mapped to SQL Table columns with the same name as the header. Existing records are deleted unless the preserve existing records Directive is given.
When the as key keyword is used, the named field will be used as the primary key, and its value will serve as the record id value.
Export into Google Sheet
The export Command is used for exporting an SQL Database Table into a Google Sheet.
( "sheet_name" | sheet_id ) [ "worksheet_name" ] ;
Include Command
The include Command allows Hashtag Markup to be pulled in from another source, and then processed.
Include Google Doc
Google Doc content can be pulled in using an include Command, and optionally processed as Hashtag Markup.
If the processed keyword is omitted, the Google Doc content will not be processed as Hashtag Markup. If the raw keyword is set, the Google Doc will be returned exactly as Google provides it; otherwise, it will be stripped of its HTML container, the CSS will be localized, and any redirected links will be converted to direct links.
Note: The semi-colon ; is optional when a Tag contains only a single include Command.
Restricting Access
The restrict access Command checks for a security group membership in the current session, and redirects to an authentication page if access was not granted.
To grant membership to a security group, use the grant access Command.
To revoke membership to a security group, use the revoke access Command.
Note: The semi-colon ; is optional when a Tag contains only a single access Command.
Transactional Locks
The obtain lock Command provides for safe transactional processing. When the named Lock can not be obtained, the request will be queued, and retried for a default of 20 seconds. Lock Directives can set the number of seconds before attempts to obtain a lock timeout, or a landing page to redirect failed requests.
[ lock_directive; ]…
The release lock Command completes a transaction, allowing the next request waiting on the named Lock to continue.
Cache Templates
Cache Templates allow for the results of complex or costly processes to be saved and reused. Multiple back-ends are supported for storing the results, defaulting to the configured cache Bucket, using reserved keys. Cache Directives can be used to set a different back-end for storing results, or to set an expiration time.
[ cache_directive; ]…
#>
Template
<# end cache #>
The delete cache Command deletes the stored results for a named Cache Template. The results will be regenerated the next time the Cache Template is processed.
Chance Templates
Chance Templates allow for Random non-deterministic processing of Hashtag Markup.
Template
<# end chance #>
Switch Templates
Switch Templates allow for Deterministic processing based on a Variable value.
[ <# start case " string " #>
Template
<# end case #> ]…
[ <# start default case #>
Template
<# end case #> ]
<# end switch #>
Call External API
The call Command allows HTTP requests to be sent to external hosts. the default method is POST. The response text is saved to the named to Bucket. If the response is JSON encoded, it will be decoded and stored as individual Variables in the Bucket. The with Bucket values will be sent with the request as JSON.
The optional using method can be set to any HTTP request method: GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE.
If the Google API has been configured, any call to the domains spreadsheets.google.com or www.googleapis.com will include a validated OAuth Access Token.
Send Email
The send email Command requires additional Directives. Email Directives set parameters such as to and subject.
to = "email_address [, email_address]…" ;
[ cc = "email_address [, email_address]…" ; ]
[ bcc = "email_address [, email_address]…" ; ]
[ from_name = "( name | email_address )" ; ]
[ subject = "text" ; ]
[ type = " ( html | text ) " ; ]
[ bodypage = "filepath" ; ]
[ body = """
"""; ]
The Hashtag Framework uses the configured PHP Email settings, however, most email sent directly from web servers will be flagged as spam unless many additional steps are taken. 3rd-party Email delivery providers, such as SendGrid, can be configured to simplify the process. If the Google API has been configured, Email can be delivered through Gmail using the send gmail Command with the same Directives.
Send SMS
The send sms Command is used to send SMS messages. Additional Directives are required to set values for the to phone number, and the message.
to = "phone_number" ;
message = "message" ;
SMS messages are delivered through 3rd party providers, such as Twilio or OpenMarket. A from phone number is configured for the Hashtag Framework, along with the SMS provider.
PHP Blocks
The Hashtag Framework supports PHP Blocks in Hashtag Markup. PHP Blocks are evaluated as local functions, so PHP Variables must be declared global to be used in other PHP Blocks. Hashtag Variables are always available in PHP Blocks.
PHP Template
?>
The Hashtag Framework provides the following PHP Functions while processing PHP Templates:
hashtag_get_value ( $name )
Return the value of a Hashtag Global Variable
|
hashtag_get_local_value ( $name )
Return the value of a Hashtag Local Variable
|
hashtag_set_value ( $name, $value )
Set a Hashtag Global Variable value
|
hashtag_set_local_value ( $name, $value )
Set a Hashtag Local Variable value
|
hashtag_html_dump ( $var, $label=null )
Human readable dump of a PHP Variable in HTML context
|
hashtag_new_uuid ( )
Generate and return a new UUID
|
hashtag_db_query ( $sql ) |
hashtag_db_exec ( $sql ) |
hashtag_db_query_params ( $sql, $params=array() ) |
hashtag_db_fetch ( $result ) |
hashtag_db_fetch_column ( $result, $column=null ) |
hashtag_db_fetch_all ( $result ) |
hashtag_db_get_instance_value ( $instance, $column ) |
hashtag_db_get_instance ( $instance ) |
hashtag_db_set_instance_value ( $instance, $column, $value ) |
hashtag_db_create_instance ( $sql_table_name ) |
hashtag_db_ensure_table_columns ( $sql_table_name, $columns=array() ) |
hashtag_db_error ( )
Returns either false, or an array of information about errors from the last query
|
hashtag_insert_row_into_google_sheet_by_id ( $row, $sheet_id, $worksheet=null ) |
hashtag_insert_row_into_google_sheet_by_name ( $row, $sheet_name, $worksheet=null ) |
hashtag_process ( $string )
Process a string of text as Hashtag Markup
|
hashtag_empty_bucket ( $bucket ) |
hashtag_array_to_bucket ( $array, $bucket ) |
hashtag_bucket_to_array ( $bucket ) |
hashtag_empty_local_bucket ( $bucket ) |
hashtag_array_to_local_bucket ( $array, $bucket ) |
hashtag_local_bucket_to_array ( $bucket ) |
hashtag_flush_google_sheet_cache ( $namespace=null ) |
hashtag_ensure_columns_in_google_sheet_by_id ( $columns, $sheet_id, $worksheet=null ) |
hashtag_ensure_columns_in_google_sheet_by_name ( $columns, $sheet_name, $worksheet=null ) |
hashtag_ensure_row_id_for_google_sheet_by_id ( $sheet_id, $worksheet=null ) |
hashtag_ensure_row_id_for_google_sheet_by_name ( $sheet_name, $worksheet=null ) |
Ready To Go?
Get started developing with Hashtag Markup by using the resources below.
Related Links
Related Projects
These projects use the Hashtag Framework to support Hashtag Markup based platforms.