// Customise Elementor "section" element to allow layout options (via CSS classes applied to main section element)
$this->register_customisations();
+ // Register widget category with Elementor
+ add_action('elementor/elements/categories_registered', [$this, 'register_widgets_category']);
+
// Register widgets with Elementor
add_action('elementor/widgets/widgets_registered', [$this, 'register_widgets']);
}
}
+ // Ref: https://developers.elementor.com/widget-categories/
+ /* @var $manager \Elementor\Elements_Manager */
+ public function register_widgets_category($manager) {
+ $manager->add_category('cube', ['title' => 'Cubedesigners']);
+ }
+
public function register_widgets() {
$elementor->widgets_manager->register_widget_type( new Widgets\DynamicTable() );
$elementor->widgets_manager->register_widget_type( new Widgets\FancyList() );
$elementor->widgets_manager->register_widget_type( new Widgets\JustifiedList() );
+ $elementor->widgets_manager->register_widget_type( new Widgets\Form() );
}
protected function _customise_sections() {
--- /dev/null
+<?php
+
+namespace Cube\Elementor\Widgets;
+
+use Elementor\Controls_Manager;
+use Cube\Forms\Base as BaseForm;
+
+use function Roots\view;
+
+class Form extends _Base {
+
+ protected $_has_template_content = false; // Tell Elementor that content is all rendered dynamically
+
+ // Widget name / ID
+ public function get_name() {
+ return 'cube-form';
+ }
+
+ // Elementor widget title
+ public function get_title() {
+ return __( 'Formulaire', 'cube' );
+ }
+
+ // Elementor interface icon
+ public function get_icon() {
+ return 'eicon-form-horizontal';
+ }
+
+ /**
+ * List of scripts the widget depends on.
+ * Used to set scripts dependencies required to run the widget.
+ *
+ * @since 1.0.0
+ * @access public
+ * @return array Widget scripts dependencies.
+ */
+ public function get_script_depends() {
+ return [];
+ }
+ /**
+ * Register the widget controls.
+ * Adds different input fields to allow the user to change and customize the widget settings.
+ *
+ * @since 1.0.0
+ * @access protected
+ */
+ protected function _register_controls() {
+
+ $form_base = new BaseForm();
+ $forms = $form_base->get_forms();
+
+ $this->start_controls_section(
+ 'section_content',
+ [
+ 'label' => __( 'Formulaire', 'cube' ),
+ ]
+ );
+
+ $this->add_control(
+ 'form_name',
+ [
+ 'type' => Controls_Manager::SELECT,
+ 'label' => __( 'Formulaire', 'cube' ),
+ 'label_block' => true,
+ 'default' => '',
+ 'options' => ['' => __('Sélectionner', 'cube')]
+ + array_combine(array_keys($forms), array_map('ucfirst', array_keys($forms)))
+ ]
+ );
+
+ $this->add_control(
+ 'destination',
+ [
+ 'type' => Controls_Manager::TEXT,
+ 'label' => __("L'adresse e-mail de destination", 'cube'),
+ 'label_block' => true,
+ 'default' => '',
+ 'placeholder' => $form_base->get_destination(),
+ ]
+ );
+
+ $this->end_controls_section();
+
+ $this->common_controls();
+ }
+ /**
+ * Render the widget output on the frontend.
+ * Written in PHP and used to generate the final HTML.
+ *
+ * @since 1.0.0
+ * @access protected
+ */
+ protected function render() {
+
+ $form_name = $this->get_settings('form_name');
+ $destination = $this->get_settings('destination');
+
+ // Serialize and encode configuration for use in hidden field
+ // Currently only the form name and destination address is set but this might be extended in the future
+ $config = base64_encode(serialize(compact('form_name', 'destination')));
+
+ $base_form = new BaseForm();
+ $forms = $base_form->get_forms();
+
+ if (!empty($form_name) && array_key_exists($form_name, $forms)) {
+ /* @var $form BaseForm */
+ $form = new $forms[$form_name];
+ $form->init();
+ echo view("forms.common.wrapper", compact('form', 'form_name', 'config'));
+ }
+
+ echo '';
+ }
+}
// Where to display the widgets in the Elementor interface
// Ref: https://developers.elementor.com/widget-categories/
+ // See Elementor/Setup.php for definition of the category
public function get_categories() {
- return [ 'theme-elements' ];
+ return ['cube'];
}
// Wrapper for including all common controls
namespace Cube\Forms;
use function Roots\asset;
+use function Roots\view;
class Base
{
private $action_name = 'cube_forms_process'; // Name of the AJAX action
- private $destination = 'avis-medical@ccv-montpellier.fr'; // Default, can be overridden
+ private $destination = 'ccv@ccv-montpellier.fr'; // Default, can be overridden
private $forms = [ // All available forms
'consultation' => Consultation::class,
private $fields = [];
private $data;
+ public $form_title = '';
+
// Field types
const BINARY = 'binary';
const CHECKBOX = 'checkbox';
wp_send_json_error(new \WP_Error('nonce', 'Failed security validation'));
}
- // Next, check which form is being sent and if it is valid
- $form_name = $_POST['_form_name'] ?? null;
+ // Next, get the form configuration and decode + unserialize it
+ $config = unserialize(base64_decode($_POST['config']));
+
+ //check which form is being sent and if it is valid
+ $form_name = $config['form_name'] ?? null;
if (!($form_name && array_key_exists($form_name, $this->forms))) {
wp_send_json_error(new \WP_Error('invalid_form', "Unknown form ($form_name)"));
/* @var $form Base */
$form = new $this->forms[$form_name];
$form->register_fields();
+ $form->set_destination($config['destination']);
$form->data = $this->get_form_data();
$form->process();
exit;
$this->pre_process();
- echo "SENDING FORM TO: {$this->destination}\n\n";
+ $headers = [];
+ $data = [];
+
+ $to = $this->destination;
+ $from = 'CCV <no-reply@ccv-montpellier.fr';
+ $subject = $this->form_title;
+ $content_type = 'text/html';
+ $charset = get_bloginfo('charset');
+ $headers[] = sprintf('Content-Type: %s; charset=%s', $content_type, $charset);
+ $headers[] = sprintf('From: %s', $from);
+ // Gather filled fields into label/value pairs
foreach ($this->fields as $field_name => $field) {
+ // TODO: handle file upload fields - should it be removed from HTML and just attached? Or include the filename reference?
if ($value = $this->data($field_name)) {
- if (is_array($value)) $value = "\n- " . implode("\n- ", $value);
- echo "{$field['title']} {$value}\n";
+ $data[$field['title']] = $value;
}
}
- // ...
+ $message = view('forms.common.email', compact('data'));
+
+ $success = wp_mail($to, $subject, $message, $headers);
+
+ if ($success) {
+ wp_send_json_success(__('Success !', 'ccv'));
+ } else {
+ wp_send_json_error();
+ }
$this->post_process();
}
return '<button type="'. $settings['type'] .'" class="'. $settings['class'] .'">'. $text .'</button>';
}
- function set_destination($address) {
- $this->destination = $address;
+
+ public function get_destination() {
+ return $this->destination;
+ }
+
+ public function set_destination($address = '') {
+ if (!empty($address)) {
+ $this->destination = $address;
+ }
}
/**
class Consultation extends Base
{
+ public function __construct() {
+ $this->form_title = __('Formulaire de consultation', 'ccv');
+ }
+
public function register_scripts() {
parent::register_scripts();
class Training extends Base
{
+ public function __construct() {
+ $this->form_title = __('Demande de formation', 'ccv');
+ }
+
public function register_scripts() {
parent::register_scripts();
}
Elementor\Setup::class,
CPT\Person::class,
CPT\ScientificNews::class,
- Shortcodes\CCVForm::class,
Forms\Base::class,
];
}
+++ /dev/null
-<?php
-
-namespace Cube\Shortcodes;
-
-use Cube\Forms;
-use function Roots\view;
-
-class CCVForm {
-
- public $forms = [];
-
- /**
- * Common setup, will be automatically triggered by Init class if included
- */
- public function register() {
-
- // Declare available forms (the key is the template name and the value is the form class)
- $this->forms = [
- 'consultation' => Forms\Consultation::class,
- 'training' => Forms\Training::class,
- ];
-
- // Register [ccv_form] shortcode
- add_shortcode('ccv_form', [$this, 'shortcode']);
- }
-
- public function shortcode($attributes) {
-
- extract(shortcode_atts([
- 'name' => '', // Name of the form template
- ], $attributes));
-
- if (array_key_exists($name, $this->forms)) {
- /* @var $form Forms\Base */
- $form = new $this->forms[$name];
- $form->init();
- return view("forms/wrapper", compact('form', 'name'));
- }
-
- return false;
- }
-
-}
--- /dev/null
+<?php
+
+namespace App\Composers;
+
+use Roots\Acorn\View\Composer;
+
+class FormEmail extends Composer
+{
+ protected static $views = [
+ 'forms.common.email',
+ ];
+
+ public function with() {
+
+ $current_language = 'fr'; // Default fallback
+
+ // Fetch languages from Polylang
+ if (function_exists('pll_current_language')) {
+ $current_language = pll_current_language('slug'); // Get the two letter language code
+ }
+
+ return compact('current_language');
+ }
+}
}
// Prevent vw / % units from getting too small
- +below(700px) {
+ +below(600px) {
// Only do this if we are dealing with a percentage or vw unit
if (unit(value) is '%' || unit(value) is 'vw') {
- $min = 700px * unit(value / 100, '') // Convert percentage to a decimal
+ $min = 600px * unit(value / 100, '') // Convert percentage to a decimal
{property}: round($min)
}
}
outline: none
background-color: transparent
+textarea
+ @apply bg-white
+
input[type="text"], input[type="email"], input[type="number"], select
appearance: none
border: none
--- /dev/null
+{{-- EMAIL TEMPLATE --}}
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html lang="{{ $current_language }}" xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>CCV Formulaire</title>
+ <style type="text/css">
+ body {
+ font-family: Arial, sans-serif;
+ }
+ </style>
+ </head>
+ <body>
+ <table cellpadding="10" cellspacing="0" border="0">
+ @foreach($data as $label => $value)
+ <tr @if ($loop->even) bgcolor="#eeeeee" @endif>
+ <td valign="top"><strong>{{ $label }}</strong></td>
+ <td>
+ @if (is_array($value))
+ <ul style="margin-left: 0">
+ <li>{!! implode('</li><li>', $value) !!}</li>
+ </ul>
+ @else
+ {!! nl2br($value) !!}
+ @endif
+ </td>
+ </tr>
+ @endforeach
+ </table>
+ </body>
+</html>
--- /dev/null
+{{-- FORM WRAPPER--}}
+<form class="cube-form">
+
+ <noscript>
+ <div class="px-4v py-1v text-red font-bold italic">
+ {{ __("Cette demande nécessite l'emploi de JavaScript qui, soit a été désactivé, soit n'est pas reconnu par votre fureteur.", 'ccv') }}
+ </div>
+ </noscript>
+
+ <input type="hidden" name="config" value="{{ $config }}">
+
+ @includeIf("forms/$form_name")
+
+</form>
// Once the form is processed, this will be used to look up the e-mail address.
'options' => array_combine(array_keys($form->get_field_options('surgeon')), array_keys($form->get_field_options('surgeon'))),
'placeholder' => [
- '' => __('Sélectionner') // First select option
+ '' => __('Sélectionner', 'ccv') // First select option
]
]) !!}
</div>
+++ /dev/null
-{{-- FORM WRAPPER--}}
-<form class="cube-form">
-
- <noscript>
- <div class="px-4v py-1v text-red font-bold italic">
- {{ __("Cette demande nécessite l'emploi de JavaScript qui, soit a été désactivé, soit n'est pas reconnu par votre fureteur.", 'ccv') }}
- </div>
- </noscript>
-
- <input type="hidden" name="_form_name" value="{{ $name }}">
-
- @includeIf("forms/$name")
-
-</form>