Skip to content

Commit 2b8efd8

Browse files
authored
Merge pull request #90 from rask/feature/html-template-import
Importable HTML templates for forms
2 parents a4a58da + 837bc08 commit 2b8efd8

6 files changed

Lines changed: 207 additions & 3 deletions

File tree

.editorconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
root = true
2+
3+
[*.php]
4+
indent_style = space
5+
indent_width = 2

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Use standard HTML5 markup to create fully functional forms for WordPress
1313
- Email notifications of received form submissions
1414
- Full file upload support to Media Library with input type=file
1515
- Multilingual support with Polylang
16+
- Predefined static HTML forms via filter hooks
1617

1718
## Why?
1819

@@ -207,3 +208,51 @@ The attribute will render as is on the `<form>` element
207208
```html
208209
<form class="libre-form libre-form-1" data-custom-attr="contactme">
209210
```
211+
212+
## Importing forms from a predefined HTML template
213+
214+
Sometimes a project might require static forms which are not supposed to
215+
be editable in the admin panel.
216+
217+
This plugin allows you to define HTML forms in your project source code
218+
and import them into the form admin for specific forms.
219+
220+
### Creating a static HTML template
221+
222+
The simplest way is to create a HTML5 file and read its contents. Other
223+
options include using Twig to render HTML templates.
224+
225+
Remember: WPLF will insert `form` tags on its own, meaning you only have
226+
to create the markup which sits directly inside the `form` tags.
227+
228+
### Importing a template into WPLF
229+
230+
Once you're done creating a form template, you need to inform
231+
WPLF about it. You can use the `wplf_import_html_template`
232+
filter hook for this:
233+
234+
```php
235+
<?php
236+
237+
add_filter( 'wplf_import_html_template', function ( $template, $form_id ) {
238+
$some_form_id = 123;
239+
240+
if ( $form_id === $some_form_id ) {
241+
// You can also render Twig templates and similar here
242+
return file_get_contents( '/path/to/template/file.html' );
243+
}
244+
245+
return $template;
246+
}, 10, 2 );
247+
```
248+
249+
The `$template` variable should be a raw HTML string. If it is set to
250+
`null` no template will be imported.
251+
252+
After a template is imported for a certain form the form's editview will
253+
be set to read only mode, meaning you must make changes to the static
254+
HTML template in code instead of editing the form inside the admin
255+
panel.
256+
257+
Otherwise the form should function normally, meaning you can use WPLF
258+
features as always.

assets/styles/wplf-admin-form.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* wp-libre-form admin styles
3+
*/
4+
5+
.wplf-template-override-notice {
6+
line-height: 20px;
7+
padding: 1ex 0;
8+
margin-top: 1em;
9+
color: #666;
10+
font-style: italic;
11+
}

classes/class-cpt-wplf-form.php

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public function __construct() {
2727
add_action( 'save_post', array( $this, 'save_cpt' ) );
2828
add_filter( 'content_save_pre', array( $this, 'strip_form_tags' ), 10, 1 );
2929
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes_cpt' ) );
30+
add_action( 'add_meta_boxes', array( $this, 'maybe_load_imported_template' ), 10, 2 );
3031
add_action( 'admin_enqueue_scripts', array( $this, 'admin_post_scripts_cpt' ), 10, 1 );
3132

3233
// edit.php view
@@ -131,7 +132,7 @@ public function disable_tinymce( $default ) {
131132
}
132133

133134
/**
134-
* Include custom JS on the edit screen
135+
* Include custom JS and CSS on the edit screen
135136
*/
136137
public function admin_post_scripts_cpt( $hook ) {
137138
global $post;
@@ -146,8 +147,13 @@ public function admin_post_scripts_cpt( $hook ) {
146147
return;
147148
}
148149

150+
$assets_url = plugins_url( 'assets', dirname( __FILE__ ) );
151+
149152
// enqueue the custom JS for this view
150-
wp_enqueue_script( 'wplf-form-edit-js', plugins_url( 'assets/scripts/wplf-admin-form.js', dirname( __FILE__ ) ) );
153+
wp_enqueue_script( 'wplf-form-edit-js', $assets_url . '/scripts/wplf-admin-form.js' );
154+
155+
// enqueue the custom CSS for this view
156+
wp_enqueue_style( 'wplf-form-edit-css', $assets_url . '/styles/wplf-admin-form.css' );
151157
}
152158

153159

@@ -460,6 +466,138 @@ class="code"
460466
<?php
461467
}
462468

469+
/**
470+
* Check and maybe load a static HTML template for a specific form.
471+
*
472+
* Hooked to `add_meta_boxes`.
473+
*
474+
* @param string $post_type Post type for which editor is being rendered for.
475+
* @param \WP_Post $post Current post object.
476+
*
477+
* @return void
478+
*/
479+
function maybe_load_imported_template( $post_type, $post ) {
480+
if ( $post_type !== 'wplf-form' || $post->post_status === 'auto-draft' ) {
481+
return;
482+
}
483+
484+
$form_id = (int) $post->ID;
485+
486+
/**
487+
* Allows importing a static HTML template for a specific form ID.
488+
*
489+
* If the template returned is `null` then no template is loaded.
490+
*
491+
* @param string|null $template_content Raw HTML to import for a form.
492+
* @param int $form_id Form ID (WP_Post ID) to import template for.
493+
*/
494+
$template_content = apply_filters( 'wplf_import_html_template', null, $form_id );
495+
496+
if ( $template_content === null ) {
497+
return;
498+
}
499+
500+
// Clear unwanted form tags. WPLF will insert those by itself when rendering a form.
501+
$template_content = preg_replace( '%<form ?[^>]*?>%', '', $template_content );
502+
$template_content = preg_replace( '%</form>%', '', $template_content );
503+
504+
$this->override_form_template( $template_content, $form_id );
505+
}
506+
507+
/**
508+
* Override a form's template with an imported template file.
509+
*
510+
* @param string $template_content Raw HTML content to use for the form content.
511+
* @param int $form_id ID of form we're overriding the template for.
512+
*
513+
* @return void
514+
*/
515+
protected function override_form_template( $template_content, $form_id ) {
516+
$this->maybe_persist_override_template( $template_content, $form_id );
517+
518+
static $times_content_replaced = 0;
519+
520+
// Make the editor textarea uneditable.
521+
add_filter( 'the_editor', function ( $editor ) {
522+
if ( ! preg_match( '%id="wp-content-editor-container"%', $editor ) ) {
523+
return $editor;
524+
}
525+
526+
$editor = preg_replace( '%\<textarea %', '<textarea readonly="readonly" ', $editor );
527+
528+
$notice = _x(
529+
'This form template is being overridden by code, you must edit it in your project code',
530+
'Template override notice in form edit admin view',
531+
'wp-libre-form'
532+
);
533+
534+
$notice = sprintf( '<div class="wplf-template-override-notice">%s</div>', $notice );
535+
536+
return $notice . $editor;
537+
} );
538+
539+
// Custom settings for the form editor.
540+
add_filter( 'wp_editor_settings', function ( $settings, $editor_id ) {
541+
if ( $editor_id !== 'content' ) {
542+
return $settings;
543+
}
544+
545+
$settings['tinymce'] = false;
546+
$settings['quicktags'] = false;
547+
$settings['media_buttons'] = false;
548+
549+
return $settings;
550+
}, 10, 2 );
551+
552+
// Replace all editor content with template content.
553+
add_filter( 'the_editor_content', function ( $content ) use ( $template_content, &$times_content_replaced ) {
554+
// This is hacky, yes. We only want to override the content for the first
555+
// editor field we come by, meaning 99% of the time we hit the wanted form
556+
// template editor field at the top of the edit view page.
557+
if ( $times_content_replaced > 0 ) {
558+
return $content;
559+
}
560+
561+
$times_content_replaced++;
562+
563+
return $template_content;
564+
} );
565+
}
566+
567+
/**
568+
* Check if we need to auto-persist the form template override into WP database.
569+
*
570+
* @param string $template Template to maybe persist.
571+
* @param int $form_id Form ID to persist template for.
572+
* @param bool $force Force a persist even though not required?
573+
*
574+
* @return void
575+
*/
576+
protected function maybe_persist_override_template( $template, $form_id, $force = false ) {
577+
$hash_transient = 'wplf_form_tmpl_hash_' . $form_id;
578+
$template_hash = md5( $template );
579+
$stored_hash = get_transient( $hash_transient );
580+
581+
if ( ! $force && $template_hash === $stored_hash ) {
582+
return;
583+
}
584+
585+
// Safe-guard to prevent accidental infinite loops.
586+
remove_action( 'save_post', array( $this, 'save_cpt' ) );
587+
588+
$updated = wp_update_post( array(
589+
'ID' => (int) $form_id,
590+
'post_content' => $template,
591+
) );
592+
593+
add_action( 'save_post', array( $this, 'save_cpt' ) );
594+
595+
// Maybe we should do something else than just silently fail if persisting failed above.
596+
if ( $updated ) {
597+
set_transient( $hash_transient, $template_hash, HOUR_IN_SECONDS * 8 );
598+
}
599+
}
600+
463601
/**
464602
* Handles saving our post meta
465603
*/

composer.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

readme.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Use standard HTML5 markup to create fully functional forms for WordPress
2222
- Email notifications of received form submissions
2323
- Full file upload support to Media Library with input type=file
2424
- Multilingual support with Polylang
25+
- Predefined static HTML markup for forms via filter hooks
2526

2627
**Why?**
2728

0 commit comments

Comments
 (0)