ExpressionEngine

2.5.0 User Guide

SafeCracker Module

Introduction

SafeCracker makes it possible to add and edit entries from outside of the Control Panel using a Stand-Alone Entry Form (SAEF). Thank you to Barrett Newton for developing SafeCracker and working with EllisLab to provide it to the ExpressionEngine community.

  • Allows guest (logged out) users to use the entry form, with optional CAPTCHA support.
  • Edit existing entries, and only edit the fields you need. Fields not in your form will be left intact.
  • Adds or edits entries based on the presence of an entry_id and/or url_title.
  • Allows use of the entry_id or url_title in your return URL, so that you may redirect to the entry that was just created. Useful for multi-page forms.
  • Specify a default status, or set forms to override default statuses.
  • Specify different return URLs for different member groups by the group_id. Send visitors to one page, and admins to another.
  • Server-side form validation using the CodeIgniter Form Validation class.
  • Handles AJAX requests and can output responses in JSON.
  • Includes an optional SafeCracker File Fieldtype.

Using SafeCracker

Including Assets

If you plan on using the Datepicker or formatting buttons, include a link to the SAEF stylesheet in your template:

<link href="{path=css/_ee_saef_css}" type="text/css" rel="stylesheet" media="screen">

SafeCracker will automatically load jQuery for you. If you prefer to include your own version of jQuery, use the include_jquery= parameter.

Form Inputs

Most Channel Fields are available to use via input fields, including:

Title

Set the title of the entry. This is a required parameter.

<label for="title">Title</label>
<input type="text" name="title" id="title" value="{title}" size="50" maxlength="100" onkeyup="liveUrlTitle();">

URL Title

Set the URL title of the entry.

<label for="url_title">URL Title</label>
<input type="text" name="url_title" id="url_title" value="{url_title}" maxlength="75" size="50">

Entry Date

Set the date of the entry, which must be in the format YYYY-MM-DD hh:mm PM.

<p>Date <br> <input type="text" name="entry_date" value="{entry_date}" maxlength="23" size="25"></p>

Expiration Date

Set the expiration date of the entry, which must be in the format YYYY-MM-DD hh:mm PM.

<p>Expiration Date <br>
        <input type="text" name="expiration_date" value="{expiration_date}" maxlength="23" size="25">
</p>

Categories

Set the entry’s categories.

{category_menu}
        <label for="categories">Categories</label>
        <select name="category[]" id="categories" size="4" multiple="multiple">
                {select_options}
        </select>
{/category_menu}

Or use the alternative syntax.

<label for="categories">Categories</label>
<select name="category[]" id="categories" size="4" multiple="multiple">
        {categories}
                <option value="{category_id}"{selected}>{category_name}</option>
        {/categories}
</select>

Status

Set the entry’s status.

{status_menu}
        <p>Status<br>
                <select name="status">
                        {select_options}
                </select>
        </p>
{/status_menu}

Or use the alternative syntax.

<label for="status">Status</label>
<select name="status" id="status">
        {statuses}
                <option value="{status}"{selected}>{status}</option>
        {/statuses}
</select>

Other Channel Fields

Set other channel fields. Use the field name as the form input. Make use of the {field:my_field_name} and {options:my_field_name} tags.

<input type="text" name="my_field_name" id="my_field_name" value="{my_field_name}">
{field:my_field_name}

<select name="my_field_name" id="my_field_name">
        {options:my_field_name}
                <option value="{option_value}"{selected}>{option_name}</option>
        {/options:my_field_name}
</select>

Parameters

allow_comments=

allow_comments="yes"

Whether to allow comments on the submitted entry. If this parameter is not specified, the Channel’s Allow comments in this channel? preference will be used.

author_only=

author_only="yes"

Only allow the author of the entry to edit the entry. Defaults to “no”.

channel=

channel="news"

The short name of the channel. This is a required parameter.

class=

class="safecracker"

Specify the CSS class.

datepicker=

datepicker="no"

Adds the datepicker to your date fields. Defaults to “yes”.

dynamic_title=

dynamic_title="[your_custom_field] Submission"

Dynamically set the title of your entry based on your entry’s data. Use brackets [ ] instead of the standard curly braces.

entry_id=

entry_id="{segment_3}"

The entry_id of the channel entry you wish to edit. If both this and url_title are empty, the entry form will add a new entry.

error_handling=

error_handling="inline"

Choose to display error messages inline (see Error Messages). By default, errors are displayed with the user message template.

id=

id="safecracker"

Specify the CSS id.

include_jquery=

include_jquery="no"

Includes jQuery automatically. Defaults to “yes”.

Note: If you are using your own copy of jQuery you will need to load it before the SafeCracker form.

json=

json="yes"

Output your results in JSON format, instead of performing a redirect.

logged_out_member_id=

logged_out_member_id="3"

In order to allow logged out users to use the entry form, you must specify a member_id which SafeCracker will use as the author of the entry.

preserve_checkboxes=

preserve_checkboxes="yes"

If you are using an entry form to edit only some of your entry (like a form just to change status, for example), you should use this parameter. HTML checkboxes have an interesting property, which is that if unchecked, they are not sent in the POST request. Because of this unique nature, SafeCracker cannot distinguish between an unchecked checkbox and an intentional omission of the field itself from your form. You are provided this parameter to preserve the existing values without having to use a hidden field. Defaults to “no”.

require_entry=

require_entry="yes"

Require an entry to edit via the entry_id or url_title parameters. Disables new entries. Defaults to “no”.

return=

return="site/ENTRY_ID"

Specify a path to redirect the user to after an entry submission. You may use the constants ENTRY_ID and URL_TITLE, which will be replaced with the entry’s entry_id or url_title, respectively. This is a required parameter.

return_X=

return_X="site/thanks"

Specify a path to redirect the user to after an entry submission, based on the user’s member group. Replace X with the group_id of the member group.

rules:my_field_name=

rules:my_field_name="required|min_length[5]"

Add additional validation rules to your fields. Separate multiple rules with the pipe | character. You may use the native CodeIgniter rules (required, matches, min_length, max_length, exact_length, alpha, alpha_numeric, alpha_dash, numeric, integer, is_natural, is_natural_no_zero, valid_email, valid_emails, valid_ip, valid_base64), and these additional ExpressionEngine-specific rules: valid_ee_date.

rte_selector=

rte_selector=".my-custom-class"

This parameter will tell SafeCracker to automatically load ExpressionEngine’s Rich Text Editor Module and apply it to the element(s) matching the jQuery selector you specify. Any valid jQuery selector is acceptable.

The RTE will use the Toolset preference of the currently logged-in user as chosen in Rich Text Editor Preferences. If the user has not chosen a Toolset or is not logged in, the site’s Default Toolset will be used.

You can optionally force a particular toolset ID to use (see below).

rte_toolset_id=

rte_toolset_id="1"

The ID of the Rich Text Editor toolset to use. Toolset IDs are listed on the Rich Text Editor Module Control Panel page.

safecracker_head=

safecracker_head="no"

Adds necessary Javascript to your form. If you don’t require the Javascript functionality, set to “no”. Defaults to “yes”.

secure_action=

secure_action="yes"

Forces the form to use https as its action.. Defaults to “no”.

secure_return=

secure_return="yes"

Force the form to return to https. Defaults to “no”.

site=

site="your_site_name"

Specify the site short name of another site on your MSM installation to add/edit entries for that site.

url_title=

url_title="{segment_3}"

The url_title of the channel entry you wish to edit. If both this and entry_id are empty, the entry form will add a new entry.

use_live_url=

use_live_url="no"

This will disable the url_title from being created automatically based on the title. Use this when you’ve opted to disable safecracker_head. Defaults to yes.

Variables

Custom Field Single Tag

{my_field_name}

Display a custom field’s data

Custom Field Tag Pair

{my_field_name}{/my_field_name}

Display a custom field’s data using the Fieldtype API’s replace_tag method. Useful for fieldtypes with complex data, such as a Matrix field.

field:my_field_name

{field:my_field_name}

Display a custom field using the Fieldtype API’s display_field method. Useful for fieldtypes that use complex markup, for instance a WYSIWYG fieldtype.

error:my_field_name

{error:my_field_name}

If you have chosen inline error handling, you can display the error for the specified field. You may also use this syntax for non-custom fields, like title and url_title.

label:my_field_name

{label:my_field_name}

Display a custom field’s label.

instructions:my_field_name

{instructions:my_field_name}

Display a custom field’s instructions.

selected_option:my_field_name

{selected_option:my_field_name}

In an edit form, display the selected option for the specified custom field.

selected_option:my_field_name:label

{selected_option:my_field_name:label}

In an edit form, display the label of the selected option for the specified custom field.

options:my_field_name

<select name="my_field_name">
        {options:my_field_name}
                <option value="{option_value}"{selected}>{option_name}</option>
        {/options:my_field_name}
</select>

If using a field with options, such as Checkboxes or Dropdown, you can display the options in a loop, to give you more control over the markup. You have the four following sub-variables: {option_value}, {option_name}, {selected} and {checked}.

custom_fields

{custom_fields}
        <label for="{field_name}">{if required}* {/if}{field_label}</label>
        {field_instructions}
        {formatting_buttons}

        {if error}
                <p class="error">{error}</p>
        {/if}

        {if textarea}
                <textarea id="{field_name}" name="{field_name}" dir="{text_direction}" rows="{rows}">{field_data}</textarea>
        {/if}

        {if text}
                <input type="text" dir="{text_direction}" id="{field_name}" name="{field_name}" value="{field_data}" maxlength="{maxlength}" size="50">
        {/if}

        {if select}
                <select id="{field_name}" name="{field_name}">
                        {options}<option value="{option_value}"{selected}>{option_name}</option>{/options}
                </select>
        {/if}

        {if date}
                <input type="text" id="{field_name}" name="{field_name}" value="{field_data}" size="50">
        {/if}

        {if checkbox}
                {options}
                        <label class="checkbox">{option_value}
                                <input type="checkbox" id="{field_name}" name="{field_name}[]" value="{option_value}"{checked}>
                        </label>
                {/options}
        {/if}

        {if radio}
                {options}
                        <label class="checkbox">{option_value}
                                <input type="radio" id="{field_name}" name="{field_name}" value="{option_value}"{checked}>
                        </label>
                {/options}
        {/if}

        {if safecracker_file}
                {display_field}
        {/if}

        {if relationship}
                <select id="{field_name}" name="{field_name}">
                        {options}
                                <option value="{option_value}"{selected}>{option_name}</option>
                        {/options}
                </select>
        {/if}

        {if multiselect}
                <select id="{field_name}" name="{field_name}[]" multiple="multiple">
                        {options}
                                <option value="{option_value}"{selected}>{option_name}</option>
                        {/options}
                </select>
        {/if}
{/custom_fields}

The template parsing for the custom_fields loop is weak, and we know it. To get it to work we recommend removing fieldtype conditionals for fieldtypes that are not installed or are not applicable to the selected channel.

Loop through the custom fields for the selected channel. Use conditionals based on the field type to control the display of your custom fields. To simply print out the field, you can use {display_field} within your field type conditional. The extension settings page contains a list of your fieldtypes and their short names for reference.

Within this loop, you have the following single variables:

{field_name}
{field_label}
{field_id}
{error}
{field_instructions}
{formatting_buttons} - Shows the EE formatting buttons if have that option selected for that field
{display_field} - Displays the field as it appears in the CP (using the fieldtype API display_field method)
{text_direction}
{rows} - For textareas
{field_data} - If used in an edit form, the custom field data for that entry.
{maxlength} - For text inputs

You also have the options tag pair for fields with options:

{options}
        <option value="{option_value}"{selected}>{option_name}</option>
{/options}

And the following conditionals:

{if required} {/if}
{if your_field_type} {/if}
{if error} {/if}

captcha

{if captcha}
        <label for="captcha">Please enter the word you see in the image below:</label>
        {captcha}
        <input type="text" name="captcha" value="{captcha_word}" maxlength="20">
{/if}

safecracker_head

{safecracker_head}

Many custom fields require additional css and/or javascript. This additional markup is automatically added to the end of your form, unless you use this variable to display it elsewhere.

global_errors

{global_errors}{error}{/global_errors}

If you have chosen inline error handling, you can display global entry submission errors.

global_errors:count

{if global_errors:count}{/if}

If you have chosen inline error handling, you can display the number global entry submission errors.

field_errors

{field_errors}{error}{/field_errors}

If you have chosen inline error handling, you can display field-related entry submission errors.

field_errors:count

{if field_errors:count}{/if}

If you have chosen inline error handling, you can display the number field-related entry submission errors.

Form Validation

SafeCracker uses the CodeIgniter Form Validation class. You can create field-by-field validation rules. By default, SafeCracker will display validation errors using the ExpressionEngine user message template. If you prefer, you can also use inline error handling to display form validation errors in the context of your form.

Allowing Guests to Post Entries

In order to allow guests to use your SafeCracker Entry Form, you must first take a few steps to set up.

  1. Create a new member group (optional). You may use an existing member group if you prefer, but you are advised to create a new member group with very limited privileges.

  2. Edit the member group. Adjust the member group’s Channel Posting Privileges and Channel Assignment.

  3. Create a new member (optional). You may use an existing member if you prefer.

  4. Select this member for the channel you’re working with in the SafeCracker settings. OR, note the member id, and use that as the

    logged_out_member_id
    

    parameter of your entry form.

SafeCracker File Fieldtype

The SafeCracker File fieldtype is a simple file fieldtype for creating file fields without the entire file manager. You are presented with a simple file input, and if applicable, a thumbnail and a “remove file” checkbox. You specify the upload location in the field settings. SafeCracker File may be used in both SafeCracker Entry Forms and the CP Publish Form. It is also a Matrix celltype.

Examples

See SafeCracker Examples for more complete examples of SafeCracker usage.

User Contributed Notes

Posted by: Simon Job on 11 May 2012 9:54pm
Simon Job's avatar

If using the Rich Text Editor, the conditional between {custom_fields} is “rte”. i.e.

{if rte}
  
<textarea id="{field_name}" name="{field_name}" dir="{text_direction}" rows="{rows}">{field_data}</textarea>
{/if} 
Posted by: EpicVoyage on 3 May 2012 11:27am
EpicVoyage's avatar

When you need to send an administrator to the Control Panel after a submission (ie. after a fully customized entry form), the return and return_x parameters will accept a GET query string as long as the name and value contain only alpha-numeric, - and _ characters.

Good:

/admin.php?S=0&D=cp&C=addons_modules&M=some_module&page=finished 

Bad (note the period):

/admin.php?S=0&D=cp&C=addons_modules&M=some_module&amount=50.35 

The last example will be mangled by the security filtering code (note the semi-colon):

http://www.example.com/admin.php?S=0&D=cp&C=addons_modules&M=some_module&amount;=50.35 

If you absolutely need that period in the value (or any other character not named above), you have two options. The first is to use only a single letter as the variable name. The second is to pick a non- alpha-numeric character as the first or second letter of your variable name. Both of these will solve our problem:

/admin.php?S=0&D=cp&C=addons_modules&M=some_module&a=50.35 
/admin.php?S=0&D=cp&C=addons_modules&M=some_module&_amount=50.35 

This applies to off-site query strings as well.

Posted by: JT Thompson on 28 April 2012 11:04pm
JT Thompson's avatar

If you want to make a duplicate of an existing entry you can use javascript to change the hidden entry_id field to 0 and it will create a duplicate.

/* example duplicate entry in same channel using jQuery */
$(document).ready(function() {
 
// make duplicate code
 
$('#publishForm input[name=entry_id]').val(0);
}); 

If you want to make the copy to a different channel (with an identical channel field group) you can change the hidden channel_id field.

/* example duplicate entry in different channel using jQuery */
$(document).ready(function() {
 
// make duplicate code
 
$('#publishForm input[name=entry_id]').val(0);
 $(
'#publishForm input[name=channel_id]').val(14);
}); 

You should also change the hidden author_id field to match the user creating the entry.

/* example duplicate entry with new author using jQuery */
$(document).ready(function() {
 
// make duplicate code
 
$('#publishForm input[name=entry_id]').val(0);
 $(
'#publishForm input[name=author_id]').val(2567);
}); 

Going one step farther to create a duplicate entry on a different website (for those using MSM with duplicate channel setups) change the hidden site_id field.

/* example duplicate entry in different site using jQuery */
$(document).ready(function() {
 
// make duplicate code
 
$('#publishForm input[name=entry_id]').val(0);
 $(
'#publishForm input[name=site_id]').val(2);
}); 

Don’t forget you will want to give the duplicate entry a new title and url_title value (a unique url_title is mandatory in most cases).

/* example duplicate entry with new title and url_title using jQuery */
$(document).ready(function() {
 
// make duplicate code
 
$('#publishForm input[name=title]').val'copy-of-' + $('#publishForm input[name=title]').val() );
 $(
'#publishForm input[name=url_title]').val'copy-of-' + $('#publishForm input[name=url_title]').val() );
}); 

Of course you can do these things with straight javascript (no jQuery) if you’d like. Just include the scrip tags after the safecracker end tag.

/* example javascript at end of safecracker end tag using jQuery */
<script type="text/javascript">
<!--
//
 
$(document).ready(function() {
  
// make duplicate code
  
$('#publishForm input[name=entry_id]').val(0);
  $(
'#publishForm input[name=channel_id]').val(14);
  $(
'#publishForm input[name=author_id]').val(2567);
  $(
'#publishForm input[name=title]').val'copy-of-' + $('#publishForm input[name=title]').val() );
  $(
'#publishForm input[name=url_title]').val'copy-of-' + $('#publishForm input[name=url_title]').val() );
 
});
// End -->
</script> 

You can use EE tags to fill in the author_id and channel_id javascript values if you want (no need to hardcode them), hope you enjoy this trick, it saved me many hours of development time.

Posted by: jensa on 25 April 2012 9:03am
jensa's avatar

Using the code from the example above will fail if used outside the {custom_fields} tag. Here is a correct version of a Checkbox inside a variable pair:

{options:my_field_name}
  
<label class="checkbox">{option_value}
   
<input type="checkbox" id="my_field_name[]" name="my_field_name[]" value="{option_value}"{checked}>
  </
label>
{/options:my_field_name} 

Note that I’m using the field name directly in the code for the input (id/name) with a following square bracket. If you try to use the code above, {field_name} will not be parsed and you will get a “Disallowed Key Characters” error.

Posted by: Hop Studios on 9 February 2012 2:27pm
Hop Studios's avatar

STATUS is also an acceptable parameter in the exp:safecracker tag—you don’t need to use a hidden field.

Posted by: Rob Sanchez on 12 January 2012 4:18pm
Rob Sanchez's avatar

If you’re using inline errors, you can create custom error messages by using the error conditional:

{if error:your_field}
    Your custom error message
.
{/if} 

You must have an ExpressionEngine license and have attained a forum rank of "Lab Assistant" (100 posts) to contribute notes to the User Guide